From df1e3dce7beb7fe3bc6c7bd893c232c585cfbf3e Mon Sep 17 00:00:00 2001 From: Debug <49997488+DebugOk@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:08:44 +0100 Subject: [PATCH] Merge master up to 31/10 (#365) * Update deathhead_r_leg.png (#21226) * Add hint for the examine trigger effect (#21166) * examine locale * examine trigger desc * Automatic changelog update * cornmeal is actually obtainable now (#21162) * do the thing * lets find out * Update Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --------- Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * Automatic changelog update * Healing skeletons by pouring milk over them (and clean pie remains off their skulls) (#21231) * mvp done - skellies can heal by spillink regular milk on themselves and clean themselves off creaming with water * added other types of healing milk, also made a separate reaction to oat milk - it has almost no calcium in it * fixed indent error, made a dumb mistake * Automatic changelog update * Fix anomaly locators frantically beeping when entering detection range. (#21178) * reset beep timer when out of range * prevent deficit from impacting beep timing * Automatic changelog update * Remove "mk --> mmm, okay" and "u --> you" to chatsan anti slang (#21177) * Automatic changelog update * Change ListContainer to send null when selected is removed from the data (#20595) * fix feeding unremovable items (#21234) * Automatic changelog update * Power switchable refactor (#20419) Co-authored-by: deltanedas <@deltanedas:kde.org> * simple space mobs cant be flashed (#20784) Co-authored-by: deltanedas <@deltanedas:kde.org> * give roundstart borgs names (#20081) Co-authored-by: deltanedas <@deltanedas:kde.org> * fix searching on vending machines (#21233) * syndicate snack box (#21024) Co-authored-by: deltanedas <@deltanedas:kde.org> * Fix DockingControl (#21238) * Shadow Dimension visual pack (#21237) Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Potato battery update + potato AI (#21142) Co-authored-by: metalgearsloth * Adds AttemptEntity(Uns|S)tickEvent. (#20728) * try-stick * convert spider charge to attempt-stick-events * Automatic changelog update * Automatic changelog update * Add missing changelog for storage refactor revert (#21259) * Automatic changelog update * BBQ rib sandwich (#21180) * Fix missing toggle fullscreen loc string (#21264) * Cave Decoration pack (#21265) * add chromite chasm * add desert chasm * snow chasm * finish * fixes and tweaks (#21172) * Automatic changelog update * Fix ItemPlacer (#21160) This is going to lead to many entities being ticked unnecessarily and performance problems. * headrev spawn music (#21119) * headrev spawn music * :trollface: * skill issue * double skill issue * :trollface: * :trollface: * :trollface: * Automatic changelog update * Techfab resprite + department fab sprites (#21136) * Fix popup messages appearing when someone tries to open a door without a tool. (#21099) * The fixTM * typo fix * addressing review * Show "departed and moved on" for when a ghost role is taken (#21092) * fix ghost role not counting for "departed and moved on" * I don't think that bit was needed so away it goes * hopefully finish the upsream merge * Automatic changelog update * Implant whitelist/blacklisting (#20678) * add whitelist and blacklist to implant and implanter components * handle whitelist and blacklist in systems * move hardcoded whitelist/blacklist to base implanter + add admeme implanter * give implants sensible whitelists * cleaner CheckTarget and fix * remove unused imports * network lists --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Automatic changelog update * Ion storm event (#20277) * ion storm event prototype + locale * add lawsets * use lawsets, make borgs ion storm targets * ion storm rule and ion storm target * lawset prototype * use lawsets * update silicon law system to use lawsets and support ion storm event * new toys * fix * more fix * fixy * ion storm admin logging * assigning laws makes borg provide its own laws, other stuff * 1h reoccurence * 50% chance * better call saul * emagLaws is required * add announcment audio * fixy * family friendly gaming * fixy * address reviews * fixy * more fixy and no erp * pro --------- Co-authored-by: deltanedas <@deltanedas:kde.org> * Automatic changelog update * A return to foam (foam rework) (#20831) * Automatic changelog update * ERT Loadout overhaul + Real deathsquad mobs + ERT fixes (#21230) * "assist with medical efforts" * CentComm official description change * give cburn ert mask * Ert medic hardsuit uses blood-red medic values * description changes, they all used to use the blood-red description * ert engineer hardsuit uses cburn values, good for handling all possible engineering problems. * janitor hardsuit uses cburn values for extreme messes, otherwise we'd send the non eva variant. * spawn suffix changes * shorten suffix * drop armor from ert jumpsuits * drop armor from DS jumpsuit * add more armor to death squad to make up for removed armor in the uniform. * give sec gas masks armor, give syndicate gas masks armor. ERT gas mask uses syndicate mask values * add nanotrasen * removed duplicate * give centcom IDs their hud icon * replace all ert bulletproof armor with basic universal armor * replace all oxygen tanks with air tanks; species is random. * remove gun and meds from ert engineer kit * give ert engineer materials * remove weapons and meds from janitor ert * give ert janitor light replacer * remove ert sec pulse weapons, admins will assign loadout. Either the lecter or enforcer, probably. * Give ert sec the security pistol kit * typo * give eva ert sec pistol * give eva janitor ert gas mask * give jani purple gloves * medical gloves for medical ert * replicate security loadout to leader * quick ert lecter spawns for lazy admins * better suffixes to find them easier * add cburn to ertspawn * Replace "Spawn" with "role" * Add death squad. Give ert engineer gas analyzer. * death squad using wrong equipment * typo * missing ghost roles on lecter loadouts * add freedom implanter to deathsquad * deathsquad ghost role text * Operative sounds better * give Ds flashbang box (why isn't it entirely filled?) * fix typo. add energy shield to DS * fix typos * all centcomm roles are now mindshielded. These cannot be removed. * Rider didnt include some of the changes ? * give zipties instead of cuffs for mass arrests! * upgrade ERT survival boxes to extended capacity * give cburn extended oxygen too * Automatic changelog update * Restore Leviathan's 80 pop cap (#21281) * Un-revert IPlayerManager refactor (#21244) * Update engine to v172.0.0 (#21288) * Hopefully fix Delta commands * Bandaid tests (#21292) * rename the rocks (#21275) * Make crystals noRot (#21279) IDK might be better. Ideally the anchoring would be offset 0-0 but this is the world we live in atm. * Fix nukies sound not played (#21268) * Play sound and sending greeting message works for nukies now!!!!! * oops * silly change * Automatic changelog update * Fix hijack objective (#21241) * Fix hijack * Max difficulty * Remove GridModifiedEvent (#21291) * Update submodule to 173.0.0 (#21296) * Fix namespace error (#21298) * Update yaml sequence option in editorconfig (#21297) * Fix namespace (#21299) * fix cburn bag issue, make new bag entity for them and filled bag entity (#21295) * Health analyzer UI improve (#17280) * Automatic changelog update * User accessible playtime (#21242) Co-authored-by: metalgearsloth * Automatic changelog update * Moves cloning comp & cloning event to shared (#21253) * Generalizes solution overflow & slightly increases space lube yield (#21094) * generalize SolutionSpikeOverflowEvent * let reactions overflow * spacelube: 3 -> 5 * restore TryMixAndOverflow threshold cap * Automatic changelog update * Move ActorComponent to shared (#21293) * Update engine to v174.0.0 (#21311) * Fix planet command help message (#21312) * Wearable bee plush (#20623) * add * fix * temporary change, needs fixing * mayb fix * actually fix FR * yes * Automatic changelog update * remove pulse rifle from ert medic (#21310) * Automatic changelog update * Atomic bomb add uranium (#21143) * fix: Incendiary bullets no longer deal cold, acid, or shock damage that ignores all armor. * Atomic bomb * Action bugfixes (#21321) * Disable OOC during round (#21323) * Fix PDA notifications when creating a news entry using the Mass-Media console. (#21320) * Automatic changelog update * Update belt.yml (#21317) changes the chief engineer's belt to remove the lv wires (they take up a lot of space and are easy to get anyways) in exchange for a holofan, a t-ray, and a gas analyzer (first time coding ever this might have to be edited) * New foam sprites (edge sprites) (#21308) * New foam sprites (icon smoothing) * changed to edge sprites for foam * fix * edges for metal foams * fix * Fix bola stam damage, bring back old construction requirements (#21340) * Automatic changelog update * Added thermal insulation to flannel jackets (#21273) * Automatic changelog update * Space Asshole Gear (#21243) * Add Space Asshole Coat * Add sledgehammer * Adjust sledgehammer damage values * Add copyright string to sledgehammer * Fix broken slot highlight in midnight theme. (#21331) * Update Patrons.yml (#21344) * Thicken thindow bounds (#21280) * Automatic changelog update * 1984 mouse AI (#21353) * Automatic changelog update * Pumpkins, jack o' lanterns and pumpkin hat resprite (#21176) * Pumpkin textures * Pumpkin prototypes * Jack o lantern prototypes and pumpkin cake * Finishing touches * Arbitrageloose * Restore old pumpkin helmet sprites (God I hope it works) * Update ground_lighting.yml (#21350) * fix fireaxe swing (#21346) * Automatic changelog update * Enable skeletons temporarily for Halloween (#21356) * Automatic changelog update * Revert "Enable skeletons temporarily for Halloween (#21356)" This reverts commit ad1780bec1b14a3f3eaa370024e12c8b8b94a804. * Automatic changelog update * Update Changelog.yml * Pea Plants (#20504) * Add Pea Plants * Pea soup * Update flavor-profiles.ftl * Update seeds.yml * Add seeds to vendors * Make things more expensive to fix free money exploit * Update textures * Revert "Update textures" This reverts commit b1b7046504afc7468742b0722f601d98684a1c89. Vines dont grow straight into the air. * Shift up 4 pixels * Fuck autofix conflitcs * Shift up 3 more pizels * I finally got byond working so I made sure they were EXACTLY the same * Address Reviews? I think? --------- Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> * Automatic changelog update * fix smoke not transferring (#21332) * Automatic changelog update * Fix the organtype (#21347) * Automatic changelog update * Candy Bucket for Halloween (#21257) * Added candy bucket and component to update appearance of held containers akin to it * cleanup newline * newline was load-bearing * moved component to Shared, cleanup * newline is spooky * You build and run without errors, stop pretending otherwise * Updated for new storage system in master branch * Revert "Candy Bucket for Halloween (#21257)" This reverts commit 74f1098008e4cd6e13778a385e3f69712e4833d7. That moment when you have to sneak changes in via other commits. I'd literally rather just skip this entire entity instead of trying to change the added stuff. * Fix whitelist code * Fix missing namespaces and other errors * Remove duplicate flavor * Fix cargo arbitrage --------- Co-authored-by: Fluffiest Floofers Co-authored-by: liltenhead <104418166+liltenhead@users.noreply.github.com> Co-authored-by: PJBot Co-authored-by: Stealthbomber16 <100171035+Stealthbomber16@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Co-authored-by: Myakot <30875116+Myakot@users.noreply.github.com> Co-authored-by: TemporalOroboros Co-authored-by: Mr. 27 <45323883+27alaing@users.noreply.github.com> Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> Co-authored-by: Doru991 <75124791+Doru991@users.noreply.github.com> Co-authored-by: metalgearsloth Co-authored-by: DrSmugleaf Co-authored-by: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Co-authored-by: faint <46868845+ficcialfaint@users.noreply.github.com> Co-authored-by: nmajask Co-authored-by: JoeHammad1844 <130668733+JoeHammad1844@users.noreply.github.com> Co-authored-by: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Co-authored-by: crazybrain23 <44417085+crazybrain23@users.noreply.github.com> Co-authored-by: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Co-authored-by: Morb <14136326+Morb0@users.noreply.github.com> Co-authored-by: Artjom Co-authored-by: Repo <47093363+Titian3@users.noreply.github.com> Co-authored-by: keronshb <54602815+keronshb@users.noreply.github.com> Co-authored-by: Ubaser <134914314+UbaserB@users.noreply.github.com> Co-authored-by: kerisargit <108146620+kerisargit@users.noreply.github.com> Co-authored-by: Simon <63975668+Simyon264@users.noreply.github.com> Co-authored-by: Yousifb26 <132729941+Yousifb26@users.noreply.github.com> Co-authored-by: brainfood1183 <113240905+brainfood1183@users.noreply.github.com> Co-authored-by: Subversionary <109166122+Subversionary@users.noreply.github.com> Co-authored-by: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Co-authored-by: Vasilis Co-authored-by: I.K <45953835+notquitehadouken@users.noreply.github.com> Co-authored-by: ZeroDayDaemon <60460608+ZeroDayDaemon@users.noreply.github.com> Co-authored-by: LankLTE <135308300+LankLTE@users.noreply.github.com> Co-authored-by: Bixkitts <72874643+Bixkitts@users.noreply.github.com> --- .editorconfig | 5 +- Content.Client/Actions/ActionsSystem.cs | 9 +- .../Managers/ClientAdminManager.cs | 2 +- .../CustomControls/PlayerListControl.xaml.cs | 6 +- .../UI/Tabs/AdminTab/TeleportWindow.xaml.cs | 1 - Content.Client/Alerts/ClientAlertsSystem.cs | 9 +- .../CharacterInfo/CharacterInfoSystem.cs | 12 - .../Visualizers/FoamVisualizerSystem.cs | 23 +- .../Visualizers/FoamVisualsComponent.cs | 12 +- .../Construction/ConstructionSystem.cs | 6 +- Content.Client/Drugs/DrugOverlaySystem.cs | 9 +- Content.Client/Drunk/DrunkSystem.cs | 9 +- Content.Client/Eye/Blinding/BlindingSystem.cs | 18 +- .../Eye/Blinding/BlurryVisionSystem.cs | 11 +- Content.Client/Eye/EyeLerpingSystem.cs | 4 +- Content.Client/Fullscreen/FullscreenHook.cs | 2 +- Content.Client/Gameplay/GameplayStateBase.cs | 2 +- Content.Client/Ghost/GhostSystem.cs | 12 +- Content.Client/Hands/Systems/HandsSystem.cs | 8 +- .../UI/HealthAnalyzerWindow.xaml | 40 +- .../UI/HealthAnalyzerWindow.xaml.cs | 219 ++-- .../HealthOverlay/HealthOverlaySystem.cs | 13 +- .../Info/PlaytimeStats/PlaytimeStatsEntry.cs | 39 + .../PlaytimeStats/PlaytimeStatsEntry.xaml | 20 + .../Info/PlaytimeStats/PlaytimeStatsHeader.cs | 86 ++ .../PlaytimeStats/PlaytimeStatsHeader.xaml | 29 + .../Info/PlaytimeStats/PlaytimeStatsWindow.cs | 146 +++ .../PlaytimeStats/PlaytimeStatsWindow.xaml | 25 + .../Inventory/ClientInventorySystem.cs | 9 +- .../Nyanotrasen/Overlays/DogVisionSystem.cs | 11 +- Content.Client/Overlays/EquipmentHudSystem.cs | 9 +- .../Physics/Controllers/MoverController.cs | 17 +- .../JobRequirementsManager.cs | 22 +- Content.Client/Players/PlayerSystem.cs | 4 +- Content.Client/Popups/PopupSystem.cs | 1 - .../Power/Generator/GeneratorWindow.xaml.cs | 15 +- .../Power/Generator/PowerSwitchableSystem.cs | 7 + .../Preferences/UI/CharacterSetupGui.xaml | 7 +- .../Preferences/UI/CharacterSetupGui.xaml.cs | 3 + .../ReplaySpectatorSystem.Movement.cs | 2 +- .../ReplaySpectatorSystem.Position.cs | 12 +- .../ReplaySpectatorSystem.Spectate.cs | 14 +- .../Replay/Spectator/ReplaySpectatorSystem.cs | 3 +- Content.Client/Sandbox/SandboxSystem.cs | 2 +- Content.Client/Shuttles/UI/DockingControl.cs | 4 +- .../Storage/StorageBoundUserInterface.cs | 4 +- Content.Client/Traits/ParacusiaSystem.cs | 6 +- .../UserInterface/Controls/ListContainer.cs | 8 +- .../Character/CharacterUIController.cs | 8 +- .../Systems/Chat/ChatUIController.cs | 31 +- .../DamageOverlayUiController.cs | 10 +- .../Systems/Sandbox/SandboxUIController.cs | 2 +- .../UI/VendingMachineMenu.xaml | 2 +- .../UI/VendingMachineMenu.xaml.cs | 7 +- .../VendingMachineBoundUserInterface.cs | 12 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 3 +- Content.IntegrationTests/Pair/TestPair.cs | 8 +- .../Tests/Actions/ActionsAddedTest.cs | 4 +- .../Tests/Administration/Logs/AddTests.cs | 8 +- .../Tests/Administration/Logs/QueryTests.cs | 5 +- Content.IntegrationTests/Tests/CargoTest.cs | 2 +- .../Tests/Cleanup/EuiManagerTest.cs | 2 +- .../Tests/Interaction/InteractionTest.cs | 5 +- .../Tests/Minds/GhostRoleTests.cs | 3 +- .../Tests/Minds/MindTests.EntityDeletion.cs | 13 +- .../Tests/Minds/MindTests.Helpers.cs | 30 +- .../Tests/Minds/MindTests.ReconnectTests.cs | 39 +- .../Tests/Minds/MindTests.cs | 11 +- .../Tests/Toolshed/ToolshedTest.cs | 7 +- Content.MapRenderer/Painters/MapPainter.cs | 2 +- Content.PatreonParser/Program.cs | 2 +- .../Access/Systems/AccessOverriderSystem.cs | 1 + .../AdminPermsChangedEventArgs.cs | 6 +- .../Administration/Commands/AGhost.cs | 3 +- .../Commands/AdminWhoCommand.cs | 3 +- .../Commands/AnnounceUiCommand.cs | 3 +- .../Administration/Commands/BanCommand.cs | 11 +- .../Administration/Commands/BanListCommand.cs | 4 +- .../Commands/BanPanelCommand.cs | 8 +- .../Administration/Commands/ControlMob.cs | 3 +- .../Administration/Commands/DSay.cs | 4 +- .../Administration/Commands/DeAdminCommand.cs | 4 +- .../Commands/ExplosionCommand.cs | 3 +- .../Administration/Commands/FaxUiCommand.cs | 3 +- .../Commands/OpenAdminLogsCommand.cs | 3 +- .../Commands/OpenAdminNotesCommand.cs | 4 +- .../Commands/OpenPermissionsCommand.cs | 4 +- .../Commands/OpenUserVisibleNotesCommand.cs | 3 +- .../Administration/Commands/PardonCommand.cs | 3 +- .../Commands/PlayGlobalSoundCommand.cs | 1 - .../Administration/Commands/ReAdminCommand.cs | 4 +- .../Administration/Commands/SetAdminOOC.cs | 4 +- .../Administration/Commands/SetMindCommand.cs | 1 + .../Commands/SetOutfitCommand.cs | 5 +- .../Administration/Commands/WarpCommand.cs | 4 +- .../ContentNetworkResourceManager.cs | 4 +- .../Logs/AdminLogManager.Json.cs | 6 +- .../Logs/Converters/EntityUidConverter.cs | 2 +- .../Logs/Converters/PlayerSessionConverter.cs | 6 +- .../Administration/Managers/AdminManager.cs | 52 +- .../Administration/Managers/BanManager.cs | 3 +- .../Administration/Managers/IAdminManager.cs | 15 +- .../Administration/Managers/IBanManager.cs | 4 +- .../Administration/Notes/AdminNotesManager.cs | 2 +- .../Administration/Notes/AdminNotesSystem.cs | 2 +- .../Notes/IAdminNotesManager.cs | 2 +- .../QuickDialogSystem.OpenDialog.cs | 10 +- .../Administration/QuickDialogSystem.cs | 7 +- .../Administration/Systems/AdminSystem.cs | 8 +- .../Systems/AdminTestArenaSystem.cs | 4 +- .../Systems/AdminVerbSystem.Antags.cs | 4 +- .../Systems/AdminVerbSystem.Tools.cs | 4 +- .../Administration/Systems/AdminVerbSystem.cs | 5 +- .../Administration/Systems/BwoinkSystem.cs | 5 +- .../Administration/Toolshed/AdminsCommand.cs | 6 +- Content.Server/Afk/AFKSystem.cs | 9 +- Content.Server/Afk/AfkManager.cs | 15 +- Content.Server/Afk/Events/AFKEvent.cs | 6 +- Content.Server/Afk/Events/UnAFKEvent.cs | 6 +- Content.Server/Alert/Commands/ClearAlert.cs | 3 +- Content.Server/Alert/Commands/ShowAlert.cs | 3 +- .../Commands/SetAlertLevelCommand.cs | 5 +- .../Anomaly/AnomalySystem.Scanner.cs | 2 +- Content.Server/Antag/AntagSelectionSystem.cs | 9 +- .../Arcade/BlockGame/BlockGame.Ui.cs | 20 +- .../BlockGame/BlockGameArcadeComponent.cs | 6 +- .../Arcade/BlockGame/BlockGameArcadeSystem.cs | 6 +- .../Atmos/Commands/DeleteGasCommand.cs | 3 +- .../Atmos/Commands/ShowAtmosCommand.cs | 3 +- .../EntitySystems/AtmosDebugOverlaySystem.cs | 11 +- .../Atmos/EntitySystems/GasAnalyzerSystem.cs | 1 + .../Atmos/EntitySystems/GasTankSystem.cs | 7 - .../EntitySystems/GasTileOverlaySystem.cs | 7 +- .../Atmos/Monitor/Systems/AirAlarmSystem.cs | 2 +- .../EntitySystems/GasPressurePumpSystem.cs | 1 + .../EntitySystems/GasVolumePumpSystem.cs | 1 + .../Trinary/EntitySystems/GasFilterSystem.cs | 1 + .../Trinary/EntitySystems/GasMixerSystem.cs | 1 + .../Unary/EntitySystems/GasCanisterSystem.cs | 1 + .../Body/Commands/AddHandCommand.cs | 3 +- .../Body/Commands/AttachBodyPartCommand.cs | 4 +- .../Body/Commands/DestroyMechanismCommand.cs | 3 +- .../Body/Commands/RemoveHandCommand.cs | 3 +- Content.Server/Body/Systems/BodySystem.cs | 2 +- .../Body/Systems/InternalsSystem.cs | 8 + .../Cargo/Systems/CargoSystem.Orders.cs | 2 +- .../CartridgeLoader/CartridgeLoaderSystem.cs | 6 +- .../Chat/Commands/AdminChatCommand.cs | 3 +- Content.Server/Chat/Commands/LOOCCommand.cs | 3 +- Content.Server/Chat/Commands/MeCommand.cs | 3 +- Content.Server/Chat/Commands/OOCCommand.cs | 3 +- Content.Server/Chat/Commands/SayCommand.cs | 3 +- .../Chat/Commands/SuicideCommand.cs | 3 +- .../Chat/Commands/WhisperCommand.cs | 3 +- Content.Server/Chat/Managers/ChatManager.cs | 16 +- Content.Server/Chat/Managers/IChatManager.cs | 12 +- Content.Server/Chat/Systems/ChatSystem.cs | 20 +- .../Chemistry/Components/SmokeComponent.cs | 26 - .../EntitySystems/ChemistryGuideDataSystem.cs | 1 + .../EntitySystems/ChemistrySystem.Injector.cs | 4 +- .../EntitySystems/SolutionSpikableSystem.cs | 34 +- .../EntitySystems/SolutionTransferSystem.cs | 2 +- .../ReactionEffects/AreaReactionEffect.cs | 14 +- Content.Server/Chunking/ChunkingSystem.cs | 6 +- Content.Server/Cloning/CloningSystem.cs | 18 - .../Cloning/Components/CloningPodComponent.cs | 107 -- .../Systems/ChameleonClothingSystem.cs | 1 + Content.Server/Commands/CommandUtils.cs | 7 +- .../Configurable/ConfigurationSystem.cs | 1 + .../Commands/FixRotationsCommand.cs | 3 +- .../Commands/TileReplaceCommand.cs | 3 +- .../Construction/Commands/TileWallsCommand.cs | 5 +- .../ConstructionSystem.Initial.cs | 2 +- Content.Server/Crayon/CrayonSystem.cs | 2 +- .../CrewManifest/CrewManifestSystem.cs | 17 +- .../Damage/Commands/GodModeCommand.cs | 4 +- .../Damage/ForceSay/DamageForceSaySystem.cs | 4 +- Content.Server/Database/UserDbDataManager.cs | 14 +- Content.Server/Decals/DecalSystem.cs | 13 +- .../Administration/Commands/LoadCharacter.cs | 11 +- .../Administration/Commands/SpawnCharacter.cs | 8 +- .../DeltaV/Harpy/HarpySingerSystem.cs | 1 + .../DeltaV/NPC/Roboisseur/RoboisseurSystem.cs | 1 + .../Systems/NetworkConfiguratorSystem.cs | 1 + .../Disposal/Mailing/MailingUnitSystem.cs | 1 + .../Disposal/TubeConnectionsCommand.cs | 3 +- .../Unit/EntitySystems/DisposalUnitSystem.cs | 1 + Content.Server/Doors/Systems/AirlockSystem.cs | 18 +- Content.Server/EUI/BaseEui.cs | 2 +- Content.Server/EUI/EuiManager.cs | 2 +- .../Ensnaring/EnsnareableSystem.Ensnaring.cs | 13 +- .../EntityList/SpawnEntityListCommand.cs | 3 +- Content.Server/Examine/ExamineSystem.cs | 5 +- .../PuddleDebugDebugOverlaySystem.cs | 8 +- .../EntitySystems/PuddleSystem.Spillable.cs | 11 +- .../Fluids/EntitySystems/SmokeSystem.cs | 281 +++-- Content.Server/Fluids/ShowFluidsCommand.cs | 3 +- .../Systems/ForensicScannerSystem.cs | 1 + .../GameTicking/Commands/JoinGameCommand.cs | 3 +- .../GameTicking/Commands/ObserveCommand.cs | 3 +- .../GameTicking/Commands/RespawnCommand.cs | 2 +- .../Commands/ToggleReadyCommand.cs | 3 +- .../GameTicking/GameTicker.GamePreset.cs | 6 +- .../GameTicking/GameTicker.Lobby.cs | 8 +- .../GameTicking/GameTicker.Player.cs | 31 +- .../GameTicking/GameTicker.RoundFlow.cs | 21 +- .../GameTicking/GameTicker.Spawning.cs | 28 +- .../Components/RevolutionaryRuleComponent.cs | 2 +- .../Rules/Components/TraitorRuleComponent.cs | 4 +- .../Rules/InactivityTimeRestartRuleSystem.cs | 1 + .../Rules/KillCalloutRuleSystem.cs | 2 +- .../GameTicking/Rules/NukeopsRuleSystem.cs | 40 +- .../GameTicking/Rules/PiratesRuleSystem.cs | 4 +- .../GameTicking/Rules/RespawnRuleSystem.cs | 4 +- .../GameTicking/Rules/TraitorRuleSystem.cs | 13 +- .../GameTicking/Rules/ZombieRuleSystem.cs | 10 +- Content.Server/Ghost/Ghost.cs | 3 +- Content.Server/Ghost/GhostSystem.cs | 1 + .../Roles/Components/TakeGhostRoleEvent.cs | 2 +- Content.Server/Ghost/Roles/GhostRoleSystem.cs | 10 +- .../GhostKick/GhostKickUserOnTriggerSystem.cs | 2 +- .../Gravity/GravityGeneratorSystem.cs | 4 +- Content.Server/Hands/Systems/HandsSystem.cs | 9 +- .../Christmas/LimitedItemGiverSystem.cs | 2 +- .../HumanoidAppearanceSystem.Modifier.cs | 6 +- Content.Server/Implants/ImplanterSystem.cs | 31 +- .../Instruments/InstrumentComponent.cs | 4 +- .../Instruments/InstrumentSystem.cs | 6 +- .../Interaction/InteractionSystem.cs | 12 +- Content.Server/Interaction/TilePryCommand.cs | 5 +- .../KillTracking/KillTrackingSystem.cs | 2 +- .../MagicMirror/MagicMirrorSystem.cs | 5 +- Content.Server/Mapping/MappingCommand.cs | 2 +- Content.Server/Maps/GridDraggingSystem.cs | 9 +- .../MassMedia/Systems/NewsSystem.cs | 2 +- Content.Server/Mech/Systems/MechSystem.cs | 1 + Content.Server/Medical/DefibrillatorSystem.cs | 2 +- .../Medical/HealthAnalyzerSystem.cs | 1 + Content.Server/Mind/Commands/RenameCommand.cs | 2 +- Content.Server/Mind/MindSystem.cs | 88 +- Content.Server/Mind/Toolshed/MindCommand.cs | 6 +- Content.Server/Mobs/CritMobActionsSystem.cs | 2 +- Content.Server/Morgue/MorgueSystem.cs | 2 +- Content.Server/Motd/MOTDCommand.cs | 7 +- Content.Server/Motd/MOTDSystem.cs | 14 +- Content.Server/Motd/SetMOTDCommand.cs | 7 +- .../Movement/Systems/LagCompensationSystem.cs | 2 +- Content.Server/NPC/Commands/NPCCommand.cs | 3 +- Content.Server/NPC/HTN/HTNSystem.cs | 7 +- .../NPC/Pathfinding/PathfindingSystem.cs | 4 +- .../NPC/Systems/NPCSteeringSystem.cs | 4 +- Content.Server/NPC/Systems/NPCSystem.cs | 1 + .../Ninja/Systems/SpiderChargeSystem.cs | 19 +- .../EntitySystems/NodeGroupSystem.cs | 7 +- .../EntitySystems/AnimalHusbandrySystem.cs | 2 +- .../Nutrition/EntitySystems/FoodSystem.cs | 4 + Content.Server/Nutrition/Hungry.cs | 4 +- .../Psionics/PsionicAbilitiesSystem.cs | 1 + .../Nyanotrasen/Chat/TSayCommand.cs | 5 +- .../Commands/TileWindowsCommand.cs | 3 +- .../PlayTimeTrackingManager.Whitelist.cs | 8 +- .../Psionics/Dreams/DreamSystem.cs | 1 + .../Nyanotrasen/Psionics/PsionicsCommands.cs | 1 + .../Research/Oracle/OracleSystem.cs | 1 + .../StationEvents/Events/MassMindSwapRule.cs | 1 + .../Commands/ListObjectivesCommand.cs | 2 +- .../Components/HijackShuttleComponent.cs | 8 - .../HijackShuttleConditionComponent.cs | 11 + .../Systems/HijackShuttleConditionSystem.cs | 6 +- Content.Server/PAI/PAISystem.cs | 2 +- Content.Server/PDA/PdaSystem.cs | 8 +- Content.Server/PDA/Ringer/RingerSystem.cs | 3 +- Content.Server/Paper/PaperSystem.cs | 6 +- Content.Server/Parallax/BiomeSystem.cs | 3 +- .../ParticleAcceleratorSystem.ControlBox.cs | 17 +- .../ParticleAcceleratorSystem.Parts.cs | 4 +- .../ParticleAcceleratorLimiterWireAction.cs | 2 +- .../ParticleAcceleratorStrengthWireAction.cs | 3 +- .../ParticleAcceleratorToggleWireAction.cs | 2 +- .../Controllers/RandomWalkController.cs | 1 + .../Pinpointer/ProximityBeeperSystem.cs | 3 + Content.Server/Pinpointer/StationMapSystem.cs | 1 + .../PlayTimeTrackingManager.cs | 41 +- .../PlayTimeTrackingSystem.cs | 13 +- Content.Server/Players/PlayerData.cs | 30 - Content.Server/Players/PlayerSystem.cs | 4 +- .../Pointing/EntitySystems/PointingSystem.cs | 5 +- Content.Server/Points/PointSystem.cs | 2 +- Content.Server/Popups/PopupSystem.cs | 1 - .../Generator/PortableGeneratorSystem.cs | 12 +- .../PowerSwitchableGeneratorSystem.cs | 111 -- .../Power/Generator/PowerSwitchableSystem.cs | 123 +++ Content.Server/Prayer/PrayerSystem.cs | 7 +- .../Managers/IServerPreferencesManager.cs | 8 +- .../Managers/ServerPreferencesManager.cs | 8 +- Content.Server/Pulling/PullingSystem.cs | 2 +- .../Systems/RadiationSystem.Debug.cs | 2 +- .../Radio/EntitySystems/HeadsetSystem.cs | 2 +- .../Radio/EntitySystems/RadioSystem.cs | 2 +- .../Research/Systems/ResearchSystem.Client.cs | 3 +- Content.Server/Salvage/SalvageRulerCommand.cs | 3 +- .../Sandbox/Commands/ColorNetworkCommand.cs | 3 +- Content.Server/Sandbox/SandboxSystem.cs | 1 + .../SensorMonitoringConsoleComponent.cs | 2 +- .../SensorMonitoringConsoleSystem.UI.cs | 4 +- .../ServerUpdates/ServerUpdateManager.cs | 1 + .../Systems/EmergencyShuttleSystem.cs | 3 +- .../Silicons/Borgs/BorgSystem.Modules.cs | 2 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 2 +- .../Silicons/Laws/SiliconLawSystem.cs | 88 +- .../Speech/EntitySystems/MeleeSpeechSystem.cs | 1 + .../SprayPainter/SprayPainterSystem.cs | 1 + .../Station/Systems/StationJobsSystem.cs | 2 +- .../Components/IonStormRuleComponent.cs | 9 + .../Components/VentClogRuleComponent.cs | 28 +- .../StationEvents/Events/IonStormRule.cs | 273 +++++ .../StationEvents/Events/VentClogRule.cs | 7 +- .../Sticky/Events/EntityStuckEvent.cs | 23 + Content.Server/Sticky/Systems/StickySystem.cs | 33 +- .../Storage/EntitySystems/StorageSystem.cs | 3 +- .../Store/Systems/StoreSystem.Ui.cs | 1 + Content.Server/Strip/StrippableSystem.cs | 1 + .../SurveillanceCameraMicrophoneSystem.cs | 2 +- .../SurveillanceCameraMonitorSystem.cs | 1 + .../Systems/SurveillanceCameraRouterSystem.cs | 3 +- .../Systems/SurveillanceCameraSystem.cs | 3 +- Content.Server/Tabletop/TabletopSession.cs | 4 +- .../Tabletop/TabletopSystem.Session.cs | 8 +- Content.Server/Tabletop/TabletopSystem.cs | 8 +- .../Commands/AdminDebug/ACmdCommand.cs | 4 +- .../Toolshed/Commands/VisualizeCommand.cs | 3 +- .../Uplink/Commands/AddUplinkCommand.cs | 5 +- .../UserInterface/ActivatableUIComponent.cs | 4 +- .../UserInterface/ActivatableUISystem.cs | 8 +- .../UserInterface/IntrinsicUISystem.cs | 1 + .../UserInterface/StatValuesCommand.cs | 3 +- Content.Server/Verbs/VerbSystem.cs | 5 +- Content.Server/VoiceMask/VoiceMaskSystem.cs | 1 + Content.Server/Voting/IVoteHandle.cs | 4 +- .../Voting/Managers/IVoteManager.cs | 6 +- .../Managers/VoteManager.DefaultVotes.cs | 12 +- Content.Server/Voting/Managers/VoteManager.cs | 31 +- Content.Server/Voting/VoteCommands.cs | 9 +- Content.Server/Voting/VoteOptions.cs | 8 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 4 +- Content.Server/Wires/WiresSystem.cs | 4 +- .../Systems/ArtifactAnalyzerSystem.cs | 3 +- .../Effects/Systems/FoamArtifactSystem.cs | 6 +- Content.Server/Zombies/ZombieSystem.cs | 1 + .../Actions/ActionContainerSystem.cs | 3 + Content.Shared/Actions/SharedActionsSystem.cs | 15 +- .../Managers/ISharedAdminManager.cs | 2 +- Content.Shared/Buckle/SharedBuckleSystem.cs | 2 +- .../Components/SmokeAffectedComponent.cs | 24 + .../Chemistry/Components/SmokeComponent.cs | 34 + .../EntitySystems/SolutionContainerSystem.cs | 128 ++- .../Reaction/ChemicalReactionSystem.cs | 14 +- Content.Shared/Cloning/CloningPodComponent.cs | 142 +++ .../Cloning/SharedCloningPodComponent.cs | 18 - .../Containers/ItemSlot/ItemSlotsComponent.cs | 3 + .../Containers/ItemSlot/ItemSlotsSystem.cs | 2 +- .../Doors/Systems/SharedDoorBoltSystem.cs | 14 +- .../Components/EnsnaringComponent.cs | 7 + .../SharedHandsSystem.Interactions.cs | 2 +- .../Implants/Components/ImplanterComponent.cs | 14 + .../Components/SubdermalImplantComponent.cs | 15 + .../Implants/SharedImplanterSystem.cs | 13 + .../Interaction/SharedInteractionSystem.cs | 2 +- Content.Shared/Mind/MindComponent.cs | 2 +- Content.Shared/Mind/SharedMindSystem.cs | 11 +- .../Movement/Events/MoveInputEvent.cs | 2 - .../Systems/SharedContentEyeSystem.cs | 2 +- .../Systems/SharedMoverController.Input.cs | 2 +- Content.Shared/Placeable/ItemPlacerSystem.cs | 9 +- .../{PlayerData.cs => ContentPlayerData.cs} | 19 +- Content.Shared/Players/PlayerDataExt.cs | 30 + Content.Shared/Players/SharedPlayerSystem.cs | 4 +- Content.Shared/Popups/SharedPopupSystem.cs | 1 - .../Generator/PowerSwitchableComponent.cs | 82 ++ .../PowerSwitchableGeneratorComponent.cs | 61 -- .../SharedPowerSwitchableGeneratorSystem.cs | 23 - .../Generator/SharedPowerSwitchableSystem.cs | 72 ++ .../Prying/Components/PryingComponent.cs | 2 + Content.Shared/Prying/Systems/PryingSystem.cs | 25 +- .../Pulling/Systems/SharedPullingSystem.cs | 2 +- Content.Shared/Roles/JobRequirements.cs | 1 - Content.Shared/Roles/Jobs/SharedJobSystem.cs | 2 +- .../Components/EmagSiliconLawComponent.cs | 31 +- .../Components/IonStarmTargetComponent.cs | 54 + .../Components/SiliconLawBoundComponent.cs | 11 +- .../Components/SiliconLawProviderComponent.cs | 15 +- .../Silicons/Laws/SiliconLawPrototype.cs | 21 +- .../Silicons/Laws/SiliconLawsetPrototype.cs | 69 ++ .../SubFloor/SharedSubFloorHideSystem.cs | 9 - .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 2 +- .../Audio/Ambience/Antag/attributions.yml | 6 +- .../Audio/Ambience/Antag/headrev_start.ogg | Bin 0 -> 171100 bytes .../Audio/Announcements/attributions.yml | 4 + Resources/Audio/Announcements/ion_storm.ogg | Bin 0 -> 50216 bytes Resources/Changelog/Changelog.yml | 479 ++++----- .../ConfigPresets/WizardsDen/leviathan.toml | 2 +- .../ConfigPresets/WizardsDen/salamander.toml | 2 +- Resources/Credits/Patrons.yml | 28 +- .../Locale/en-US/administration/antag.ftl | 2 +- .../en-US/escape-menu/ui/options-menu.ftl | 1 + .../Locale/en-US/flavors/flavor-profiles.ftl | 1 + .../ghost/roles/ghost-role-component.ftl | 9 +- Resources/Locale/en-US/implant/implant.ftl | 1 + .../Locale/en-US/info/playtime-stats.ftl | 10 + .../Locale/en-US/job/job-description.ftl | 2 +- Resources/Locale/en-US/maps/planet.ftl | 4 +- .../components/health-analyzer-component.ftl | 1 + .../conditions/hijack-shuttle-condition.ftl | 2 - Resources/Locale/en-US/pai/pai-system.ftl | 2 + .../en-US/power/components/generator.ftl | 23 +- .../preferences/ui/character-setup-gui.ftl | 1 + .../reagents/meta/consumable/food/food.ftl | 3 + Resources/Locale/en-US/seeds/seeds.ftl | 6 +- Resources/Locale/en-US/species/skeleton.ftl | 2 + .../Locale/en-US/speech/speech-chatsan.ftl | 20 +- .../en-US/station-events/events/ion-storm.ftl | 90 ++ .../Locale/en-US/store/uplink-catalog.ftl | 3 + Resources/Locale/en-US/tiles/tiles.ftl | 1 + .../en-US/xenoarchaeology/artifact-hints.ftl | 1 + .../Prototypes/Catalog/Cargo/cargo_botany.yml | 4 +- .../Catalog/Cargo/cargo_vending.yml | 4 +- .../Fills/Backpacks/StarterGear/backpack.yml | 57 +- .../Catalog/Fills/Backpacks/duffelbag.yml | 333 +++--- .../Catalog/Fills/Crates/botany.yml | 1 + .../Prototypes/Catalog/Fills/Items/belt.yml | 7 +- .../VendingMachines/Inventories/seeds.yml | 2 + .../VendingMachines/Inventories/theater.yml | 2 +- .../Prototypes/Catalog/uplink_catalog.yml | 10 + Resources/Prototypes/Datasets/Names/borg.yml | 18 + Resources/Prototypes/Datasets/ion_storm.yml | 990 ++++++++++++++++++ .../Prototypes/DeltaV/Flavors/flavors.yml | 5 - .../Entities/Clothing/Back/duffel.yml | 146 +-- .../Clothing/Head/base_clothinghead.yml | 2 +- .../Entities/Clothing/Head/misc.yml | 14 +- .../Entities/Clothing/Masks/masks.yml | 21 +- .../Entities/Clothing/OuterClothing/coats.yml | 11 + .../Clothing/OuterClothing/hardsuits.yml | 22 +- .../Entities/Clothing/OuterClothing/misc.yml | 8 +- .../Entities/Clothing/Uniforms/jumpsuits.yml | 25 +- .../Entities/Effects/chemistry_effects.yml | 174 +-- .../Mobs/Cyborgs/base_borg_chassis.yml | 7 +- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 1 + .../Entities/Mobs/NPCs/simplemob.yml | 1 - .../Entities/Mobs/Player/humanoid.yml | 102 +- .../Entities/Mobs/Player/silicon.yml | 7 +- .../Entities/Mobs/Species/skeleton.yml | 34 + .../Consumable/Food/Containers/box.yml | 51 + .../Objects/Consumable/Food/burger.yml | 6 +- .../Objects/Consumable/Food/ingredients.yml | 13 - .../Objects/Consumable/Food/meals.yml | 2 + .../Objects/Consumable/Food/produce.yml | 75 ++ .../Entities/Objects/Consumable/Food/soup.yml | 2 +- .../Entities/Objects/Decoration/flora.yml | 100 +- .../Objects/Decoration/jackolantern.yml | 61 ++ .../Entities/Objects/Decoration/mining.yml | 179 ++++ .../Entities/Objects/Devices/pda.yml | 2 +- .../Prototypes/Entities/Objects/Fun/pai.yml | 29 + .../Prototypes/Entities/Objects/Fun/toys.yml | 11 + .../Objects/Misc/identification_cards.yml | 3 +- .../Entities/Objects/Misc/implanters.yml | 16 + .../Entities/Objects/Misc/potatoai_chip.yml | 17 + .../Objects/Misc/subdermal_implants.yml | 21 + .../Entities/Objects/Misc/torch.yml | 3 + .../Entities/Objects/Power/powercells.yml | 11 +- .../Objects/Specific/Hydroponics/seeds.yml | 23 +- .../Objects/Specific/Robotics/mmi.yml | 2 +- .../Weapons/Guns/Battery/battery_guns.yml | 10 +- .../Objects/Weapons/Melee/fireaxe.yml | 2 +- .../Objects/Weapons/Melee/sledgehammer.yml | 22 + .../Objects/Weapons/Throwable/bola.yml | 6 +- .../Prototypes/Entities/Stations/base.yml | 5 +- .../Structures/Decoration/crystals.yml | 1 + .../Structures/Lighting/ground_lighting.yml | 2 + .../Entities/Structures/Machines/lathe.yml | 1 + .../Power/Generation/portable_generator.yml | 33 +- .../Entities/Structures/Power/chargers.yml | 3 + .../Entities/Structures/Walls/asteroid.yml | 9 +- .../Entities/Structures/Windows/window.yml | 2 +- Resources/Prototypes/Entities/Tiles/chasm.yml | 34 +- .../Entities/Tiles/shadow_basalt.yml | 83 ++ Resources/Prototypes/Flavors/flavors.yml | 5 + Resources/Prototypes/GameRules/events.yml | 15 + Resources/Prototypes/Hydroponics/seeds.yml | 57 +- Resources/Prototypes/Objectives/traitor.yml | 14 + .../Reagents/Consumable/Drink/alcohol.yml | 2 +- .../Reagents/Consumable/Food/food.yml | 8 + Resources/Prototypes/Reagents/gases.yml | 6 + .../Graphs/fun/jack_o_lantern.yml | 13 + .../Construction/Graphs/weapons/bola.yml | 9 +- .../Recipes/Cooking/meal_recipes.yml | 26 +- .../Crafting/Graphs/improvised/potato.yml | 74 ++ .../Prototypes/Recipes/Crafting/potato.yml | 32 + .../Prototypes/Recipes/Reactions/cleaning.yml | 2 +- .../Prototypes/Recipes/Reactions/food.yml | 49 +- .../Roles/Jobs/Fun/emergencyresponseteam.yml | 80 +- .../Roles/Jobs/Fun/misc_startinggear.yml | 21 +- Resources/Prototypes/Tiles/floors.yml | 20 + .../Prototypes/XenoArch/artifact_triggers.yml | 1 + Resources/Prototypes/silicon-laws.yml | 50 + Resources/Prototypes/tags.yml | 12 + .../Head/Misc/pumpkin.rsi/icon-flash.png | Bin 0 -> 304 bytes .../Clothing/Head/Misc/pumpkin.rsi/meta.json | 9 +- ...ped-HELMET.png => off-equipped-HELMET.png} | Bin .../{inhand-left.png => off-inhand-left.png} | Bin ...{inhand-right.png => off-inhand-right.png} | Bin .../equipped-OUTERCLOTHING.png | Bin 0 -> 718 bytes .../Coats/space_asshole.rsi/icon.png | Bin 0 -> 359 bytes .../Coats/space_asshole.rsi/inhand-left.png | Bin 0 -> 344 bytes .../Coats/space_asshole.rsi/inhand-right.png | Bin 0 -> 342 bytes .../Coats/space_asshole.rsi/meta.json | 26 + .../Textures/Effects/foam.rsi/foam-east.png | Bin 0 -> 18163 bytes .../Textures/Effects/foam.rsi/foam-north.png | Bin 0 -> 18178 bytes .../Textures/Effects/foam.rsi/foam-south.png | Bin 0 -> 18231 bytes .../Textures/Effects/foam.rsi/foam-west.png | Bin 0 -> 18242 bytes .../Effects/foam.rsi/iron_foam-east.png | Bin 0 -> 15536 bytes .../Effects/foam.rsi/iron_foam-north.png | Bin 0 -> 15686 bytes .../Effects/foam.rsi/iron_foam-south.png | Bin 0 -> 15603 bytes .../Effects/foam.rsi/iron_foam-west.png | Bin 0 -> 18428 bytes .../foam.rsi/{ironfoam.png => iron_foam.png} | Bin ...mfoam-dissolve.png => m_foam-dissolve.png} | Bin .../Textures/Effects/foam.rsi/m_foam-east.png | Bin 0 -> 15460 bytes .../Effects/foam.rsi/m_foam-north.png | Bin 0 -> 15597 bytes .../Effects/foam.rsi/m_foam-south.png | Bin 0 -> 15500 bytes .../Textures/Effects/foam.rsi/m_foam-west.png | Bin 0 -> 15596 bytes .../foam.rsi/{mfoam.png => m_foam.png} | Bin Resources/Textures/Effects/foam.rsi/meta.json | 100 +- .../Effects/foam.rsi/metal_foam-east.png | Bin 0 -> 18287 bytes .../Effects/foam.rsi/metal_foam-north.png | Bin 0 -> 18460 bytes .../Effects/foam.rsi/metal_foam-south.png | Bin 0 -> 18347 bytes .../Effects/foam.rsi/metal_foam-west.png | Bin 0 -> 18472 bytes .../{metalfoam.png => metal_foam.png} | Bin .../Interface/Classic/slot_highlight.png | Bin 0 -> 123 bytes .../Moth/moth_parts.rsi/deathhead_r_leg.png | Bin 423 -> 552 bytes .../Flora/flora_shadow_trees.rsi/meta.json | 29 + .../Flora/flora_shadow_trees.rsi/tree01.png | Bin 0 -> 5323 bytes .../Flora/flora_shadow_trees.rsi/tree02.png | Bin 0 -> 4671 bytes .../Flora/flora_shadow_trees.rsi/tree03.png | Bin 0 -> 5093 bytes .../Flora/flora_shadow_trees.rsi/tree04.png | Bin 0 -> 5216 bytes .../Flora/flora_shadow_trees.rsi/tree05.png | Bin 0 -> 4801 bytes .../Flora/flora_shadow_trees.rsi/tree06.png | Bin 0 -> 5196 bytes .../Flora/flora_stalagmite.rsi/meta.json | 29 + .../flora_stalagmite.rsi/stalagmite1.png | Bin 0 -> 714 bytes .../flora_stalagmite.rsi/stalagmite2.png | Bin 0 -> 557 bytes .../flora_stalagmite.rsi/stalagmite3.png | Bin 0 -> 733 bytes .../flora_stalagmite.rsi/stalagmite4.png | Bin 0 -> 695 bytes .../flora_stalagmite.rsi/stalagmite5.png | Bin 0 -> 610 bytes .../flora_stalagmite.rsi/stalagmite6.png | Bin 0 -> 579 bytes .../Objects/Decoration/mines.rsi/meta.json | 29 + .../Decoration/mines.rsi/sign_left.png | Bin 0 -> 422 bytes .../Decoration/mines.rsi/sign_right.png | Bin 0 -> 423 bytes .../Objects/Decoration/mines.rsi/support.png | Bin 0 -> 404 bytes .../Decoration/mines.rsi/support_beams.png | Bin 0 -> 364 bytes .../Decoration/mines.rsi/support_wall.png | Bin 0 -> 571 bytes .../mines.rsi/support_wall_broken.png | Bin 0 -> 852 bytes .../Devices/health_analyzer.rsi/airloss.png | Bin 0 -> 4254 bytes .../Devices/health_analyzer.rsi/brute.png | Bin 0 -> 4254 bytes .../Devices/health_analyzer.rsi/burn.png | Bin 0 -> 414 bytes .../Devices/health_analyzer.rsi/genetic.png | Bin 0 -> 4235 bytes .../Devices/health_analyzer.rsi/meta.json | 29 + .../Devices/health_analyzer.rsi/toxin.png | Bin 0 -> 4254 bytes .../Devices/health_analyzer.rsi/unknown.png | Bin 0 -> 4235 bytes .../Objects/Fun/pai.rsi/icon-potato-off.png | Bin 0 -> 483 bytes .../Textures/Objects/Fun/pai.rsi/meta.json | 17 +- .../Objects/Fun/pai.rsi/potato-base.png | Bin 0 -> 476 bytes .../Fun/pai.rsi/potato-off-overlay.png | Bin 0 -> 162 bytes .../Objects/Fun/pai.rsi/potato-on-overlay.png | Bin 0 -> 159 bytes .../Fun/pai.rsi/potato-searching-overlay.png | Bin 0 -> 186 bytes .../Fun/toys.rsi/bee-equipped-HELMET.png | Bin 0 -> 1606 bytes .../Objects/Fun/toys.rsi/bee-inhand-left.png | Bin 0 -> 1355 bytes .../Objects/Fun/toys.rsi/bee-inhand-right.png | Bin 0 -> 1341 bytes .../Textures/Objects/Fun/toys.rsi/meta.json | 18 +- .../Objects/Misc/potatoai_chip.rsi/icon.png | Bin 0 -> 235 bytes .../Objects/Misc/potatoai_chip.rsi/meta.json | 14 + .../Objects/Power/power_cells.rsi/meta.json | 2 +- .../Objects/Power/power_cells.rsi/potato.png | Bin 946 -> 463 bytes .../Specific/Hydroponics/pea.rsi/dead.png | Bin 0 -> 163 bytes .../Specific/Hydroponics/pea.rsi/harvest.png | Bin 0 -> 265 bytes .../Specific/Hydroponics/pea.rsi/meta.json | 32 + .../Specific/Hydroponics/pea.rsi/produce.png | Bin 0 -> 501 bytes .../Specific/Hydroponics/pea.rsi/seed.png | Bin 0 -> 335 bytes .../Specific/Hydroponics/pea.rsi/stage-1.png | Bin 0 -> 157 bytes .../Specific/Hydroponics/pea.rsi/stage-2.png | Bin 0 -> 188 bytes .../Specific/Hydroponics/pea.rsi/stage-3.png | Bin 0 -> 229 bytes .../Hydroponics/pumpkin.rsi/carved.png | Bin 0 -> 783 bytes .../Specific/Hydroponics/pumpkin.rsi/dead.png | Bin 0 -> 262 bytes .../Hydroponics/pumpkin.rsi/harvest.png | Bin 0 -> 336 bytes .../Hydroponics/pumpkin.rsi/lantern.png | Bin 0 -> 773 bytes .../Hydroponics/pumpkin.rsi/meta.json | 47 + .../Hydroponics/pumpkin.rsi/produce.png | Bin 0 -> 306 bytes .../Specific/Hydroponics/pumpkin.rsi/seed.png | Bin 0 -> 195 bytes .../Hydroponics/pumpkin.rsi/stage-1.png | Bin 0 -> 235 bytes .../Hydroponics/pumpkin.rsi/stage-2.png | Bin 0 -> 284 bytes .../Hydroponics/pumpkin.rsi/stage-3.png | Bin 0 -> 305 bytes .../Specific/Robotics/mmi.rsi/meta.json | 2 +- .../Weapons/Melee/sledgehammer.rsi/icon.png | Bin 0 -> 357 bytes .../Melee/sledgehammer.rsi/inhand-left.png | Bin 0 -> 428 bytes .../Melee/sledgehammer.rsi/inhand-right.png | Bin 0 -> 427 bytes .../Weapons/Melee/sledgehammer.rsi/meta.json | 30 + .../sledgehammer.rsi/wielded-inhand-left.png | Bin 0 -> 402 bytes .../sledgehammer.rsi/wielded-inhand-right.png | Bin 0 -> 389 bytes .../Structures/Machines/techfab.rsi/ammo.png | Bin 700 -> 657 bytes .../Structures/Machines/techfab.rsi/cargo.png | Bin 0 -> 645 bytes .../Structures/Machines/techfab.rsi/engi.png | Bin 0 -> 651 bytes .../Structures/Machines/techfab.rsi/icon.png | Bin 6790 -> 1122 bytes .../Machines/techfab.rsi/inserting.png | Bin 5782 -> 713 bytes .../Structures/Machines/techfab.rsi/med.png | Bin 666 -> 647 bytes .../Structures/Machines/techfab.rsi/meta.json | 17 +- .../Structures/Machines/techfab.rsi/sci.png | Bin 0 -> 677 bytes .../Structures/Machines/techfab.rsi/sec.png | Bin 0 -> 663 bytes .../Machines/techfab.rsi/service.png | Bin 0 -> 648 bytes .../Structures/Machines/techfab.rsi/unlit.png | Bin 5472 -> 648 bytes .../basalt_chasm.rsi}/chasm.png | Bin .../basalt_chasm.rsi}/chasm0.png | Bin .../basalt_chasm.rsi}/chasm1.png | Bin .../basalt_chasm.rsi}/chasm2.png | Bin .../basalt_chasm.rsi}/chasm3.png | Bin .../basalt_chasm.rsi}/chasm4.png | Bin .../basalt_chasm.rsi}/chasm5.png | Bin .../basalt_chasm.rsi}/chasm6.png | Bin .../basalt_chasm.rsi}/chasm7.png | Bin .../basalt_chasm.rsi}/full.png | Bin .../basalt_chasm.rsi}/meta.json | 0 .../Chasms/chromite_chasm.rsi/chasm.png | Bin 0 -> 180 bytes .../Chasms/chromite_chasm.rsi/chasm0.png | Bin 0 -> 1402 bytes .../Chasms/chromite_chasm.rsi/chasm1.png | Bin 0 -> 920 bytes .../Chasms/chromite_chasm.rsi/chasm2.png | Bin 0 -> 1402 bytes .../Chasms/chromite_chasm.rsi/chasm3.png | Bin 0 -> 920 bytes .../Chasms/chromite_chasm.rsi/chasm4.png | Bin 0 -> 926 bytes .../Chasms/chromite_chasm.rsi/chasm5.png | Bin 0 -> 478 bytes .../Chasms/chromite_chasm.rsi/chasm6.png | Bin 0 -> 926 bytes .../Chasms/chromite_chasm.rsi/chasm7.png | Bin 0 -> 96 bytes .../Planet/Chasms/chromite_chasm.rsi/full.png | Bin 0 -> 974 bytes .../Chasms/chromite_chasm.rsi/meta.json | 49 + .../Planet/Chasms/desert_chasm.rsi/chasm.png | Bin 0 -> 272 bytes .../Planet/Chasms/desert_chasm.rsi/chasm0.png | Bin 0 -> 2295 bytes .../Planet/Chasms/desert_chasm.rsi/chasm1.png | Bin 0 -> 1298 bytes .../Planet/Chasms/desert_chasm.rsi/chasm2.png | Bin 0 -> 2295 bytes .../Planet/Chasms/desert_chasm.rsi/chasm3.png | Bin 0 -> 1298 bytes .../Planet/Chasms/desert_chasm.rsi/chasm4.png | Bin 0 -> 1464 bytes .../Planet/Chasms/desert_chasm.rsi/chasm5.png | Bin 0 -> 635 bytes .../Planet/Chasms/desert_chasm.rsi/chasm6.png | Bin 0 -> 1464 bytes .../Planet/Chasms/desert_chasm.rsi/chasm7.png | Bin 0 -> 96 bytes .../Planet/Chasms/desert_chasm.rsi/full.png | Bin 0 -> 1951 bytes .../Planet/Chasms/desert_chasm.rsi/meta.json | 49 + .../Planet/Chasms/snow_chasm.rsi/chasm.png | Bin 0 -> 183 bytes .../Planet/Chasms/snow_chasm.rsi/chasm0.png | Bin 0 -> 1574 bytes .../Planet/Chasms/snow_chasm.rsi/chasm1.png | Bin 0 -> 904 bytes .../Planet/Chasms/snow_chasm.rsi/chasm2.png | Bin 0 -> 1574 bytes .../Planet/Chasms/snow_chasm.rsi/chasm3.png | Bin 0 -> 904 bytes .../Planet/Chasms/snow_chasm.rsi/chasm4.png | Bin 0 -> 806 bytes .../Planet/Chasms/snow_chasm.rsi/chasm5.png | Bin 0 -> 489 bytes .../Planet/Chasms/snow_chasm.rsi/chasm6.png | Bin 0 -> 806 bytes .../Planet/Chasms/snow_chasm.rsi/chasm7.png | Bin 0 -> 96 bytes .../Planet/Chasms/snow_chasm.rsi/full.png | Bin 0 -> 1225 bytes .../Planet/Chasms/snow_chasm.rsi/meta.json | 49 + .../Tiles/Planet/shadowbasalt.rsi/basalt1.png | Bin 0 -> 968 bytes .../Tiles/Planet/shadowbasalt.rsi/basalt2.png | Bin 0 -> 1016 bytes .../Tiles/Planet/shadowbasalt.rsi/basalt3.png | Bin 0 -> 1310 bytes .../Tiles/Planet/shadowbasalt.rsi/basalt4.png | Bin 0 -> 867 bytes .../Tiles/Planet/shadowbasalt.rsi/basalt5.png | Bin 0 -> 736 bytes .../Tiles/Planet/shadowbasalt.rsi/meta.json | 66 ++ Resources/Textures/Tiles/attributions.yml | 5 + Resources/Textures/Tiles/chromite.png | Bin 0 -> 3171 bytes RobustToolbox | 2 +- 669 files changed, 7000 insertions(+), 2617 deletions(-) create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.cs create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.xaml create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.cs create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.xaml create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.cs create mode 100644 Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.xaml create mode 100644 Content.Client/Power/Generator/PowerSwitchableSystem.cs delete mode 100644 Content.Server/Chemistry/Components/SmokeComponent.cs delete mode 100644 Content.Server/Cloning/Components/CloningPodComponent.cs delete mode 100644 Content.Server/Objectives/Components/HijackShuttleComponent.cs create mode 100644 Content.Server/Objectives/Components/HijackShuttleConditionComponent.cs delete mode 100644 Content.Server/Players/PlayerData.cs delete mode 100644 Content.Server/Power/Generator/PowerSwitchableGeneratorSystem.cs create mode 100644 Content.Server/Power/Generator/PowerSwitchableSystem.cs create mode 100644 Content.Server/StationEvents/Components/IonStormRuleComponent.cs create mode 100644 Content.Server/StationEvents/Events/IonStormRule.cs create mode 100644 Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs create mode 100644 Content.Shared/Chemistry/Components/SmokeComponent.cs create mode 100644 Content.Shared/Cloning/CloningPodComponent.cs delete mode 100644 Content.Shared/Cloning/SharedCloningPodComponent.cs rename Content.Shared/Players/{PlayerData.cs => ContentPlayerData.cs} (75%) create mode 100644 Content.Shared/Players/PlayerDataExt.cs create mode 100644 Content.Shared/Power/Generator/PowerSwitchableComponent.cs delete mode 100644 Content.Shared/Power/Generator/PowerSwitchableGeneratorComponent.cs delete mode 100644 Content.Shared/Power/Generator/SharedPowerSwitchableGeneratorSystem.cs create mode 100644 Content.Shared/Power/Generator/SharedPowerSwitchableSystem.cs create mode 100644 Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs create mode 100644 Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs create mode 100644 Resources/Audio/Ambience/Antag/headrev_start.ogg create mode 100644 Resources/Audio/Announcements/attributions.yml create mode 100644 Resources/Audio/Announcements/ion_storm.ogg create mode 100644 Resources/Locale/en-US/info/playtime-stats.ftl delete mode 100644 Resources/Locale/en-US/objectives/conditions/hijack-shuttle-condition.ftl create mode 100644 Resources/Locale/en-US/species/skeleton.ftl create mode 100644 Resources/Locale/en-US/station-events/events/ion-storm.ftl create mode 100644 Resources/Prototypes/Datasets/Names/borg.yml create mode 100644 Resources/Prototypes/Datasets/ion_storm.yml create mode 100644 Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml create mode 100644 Resources/Prototypes/Entities/Objects/Decoration/mining.yml create mode 100644 Resources/Prototypes/Entities/Objects/Misc/potatoai_chip.yml create mode 100644 Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml create mode 100644 Resources/Prototypes/Entities/Tiles/shadow_basalt.yml create mode 100644 Resources/Prototypes/Recipes/Construction/Graphs/fun/jack_o_lantern.yml create mode 100644 Resources/Prototypes/Recipes/Crafting/Graphs/improvised/potato.yml create mode 100644 Resources/Prototypes/Recipes/Crafting/potato.yml create mode 100644 Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/icon-flash.png rename Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/{equipped-HELMET.png => off-equipped-HELMET.png} (100%) rename Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/{inhand-left.png => off-inhand-left.png} (100%) rename Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/{inhand-right.png => off-inhand-right.png} (100%) create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/meta.json create mode 100644 Resources/Textures/Effects/foam.rsi/foam-east.png create mode 100644 Resources/Textures/Effects/foam.rsi/foam-north.png create mode 100644 Resources/Textures/Effects/foam.rsi/foam-south.png create mode 100644 Resources/Textures/Effects/foam.rsi/foam-west.png create mode 100644 Resources/Textures/Effects/foam.rsi/iron_foam-east.png create mode 100644 Resources/Textures/Effects/foam.rsi/iron_foam-north.png create mode 100644 Resources/Textures/Effects/foam.rsi/iron_foam-south.png create mode 100644 Resources/Textures/Effects/foam.rsi/iron_foam-west.png rename Resources/Textures/Effects/foam.rsi/{ironfoam.png => iron_foam.png} (100%) rename Resources/Textures/Effects/foam.rsi/{mfoam-dissolve.png => m_foam-dissolve.png} (100%) create mode 100644 Resources/Textures/Effects/foam.rsi/m_foam-east.png create mode 100644 Resources/Textures/Effects/foam.rsi/m_foam-north.png create mode 100644 Resources/Textures/Effects/foam.rsi/m_foam-south.png create mode 100644 Resources/Textures/Effects/foam.rsi/m_foam-west.png rename Resources/Textures/Effects/foam.rsi/{mfoam.png => m_foam.png} (100%) create mode 100644 Resources/Textures/Effects/foam.rsi/metal_foam-east.png create mode 100644 Resources/Textures/Effects/foam.rsi/metal_foam-north.png create mode 100644 Resources/Textures/Effects/foam.rsi/metal_foam-south.png create mode 100644 Resources/Textures/Effects/foam.rsi/metal_foam-west.png rename Resources/Textures/Effects/foam.rsi/{metalfoam.png => metal_foam.png} (100%) create mode 100644 Resources/Textures/Interface/Classic/slot_highlight.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/meta.json create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree01.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree02.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree03.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree04.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree05.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree06.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/meta.json create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite1.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite2.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite3.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite4.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite5.png create mode 100644 Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite6.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/meta.json create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/sign_left.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/sign_right.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/support.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/support_beams.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/support_wall.png create mode 100644 Resources/Textures/Objects/Decoration/mines.rsi/support_wall_broken.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/airloss.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/brute.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/burn.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/genetic.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/toxin.png create mode 100644 Resources/Textures/Objects/Devices/health_analyzer.rsi/unknown.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/icon-potato-off.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/potato-base.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/potato-off-overlay.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/potato-on-overlay.png create mode 100644 Resources/Textures/Objects/Fun/pai.rsi/potato-searching-overlay.png create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/bee-equipped-HELMET.png create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/bee-inhand-left.png create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/bee-inhand-right.png create mode 100644 Resources/Textures/Objects/Misc/potatoai_chip.rsi/icon.png create mode 100644 Resources/Textures/Objects/Misc/potatoai_chip.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/dead.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/harvest.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/produce.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/seed.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-1.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-2.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-3.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/carved.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/dead.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/harvest.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/lantern.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/produce.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/seed.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-1.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-2.png create mode 100644 Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-3.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/Structures/Machines/techfab.rsi/cargo.png create mode 100644 Resources/Textures/Structures/Machines/techfab.rsi/engi.png create mode 100644 Resources/Textures/Structures/Machines/techfab.rsi/sci.png create mode 100644 Resources/Textures/Structures/Machines/techfab.rsi/sec.png create mode 100644 Resources/Textures/Structures/Machines/techfab.rsi/service.png rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm0.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm1.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm2.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm3.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm4.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm5.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm6.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/chasm7.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/full.png (100%) rename Resources/Textures/Tiles/Planet/{chasm.rsi => Chasms/basalt_chasm.rsi}/meta.json (100%) create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm0.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm1.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm2.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm3.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm4.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm5.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm6.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm7.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/full.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/meta.json create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm0.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm1.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm2.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm3.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm4.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm5.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm6.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm7.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/full.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/meta.json create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm0.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm1.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm2.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm3.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm4.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm5.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm6.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm7.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/full.png create mode 100644 Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/meta.json create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt1.png create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt2.png create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt3.png create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt4.png create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt5.png create mode 100644 Resources/Textures/Tiles/Planet/shadowbasalt.rsi/meta.json create mode 100644 Resources/Textures/Tiles/chromite.png diff --git a/.editorconfig b/.editorconfig index a8ce1d6b68..59ca35cc9a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -338,5 +338,8 @@ dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter resharper_braces_for_ifelse = required_for_multiline resharper_keep_existing_attribute_arrangement = true -[*.{csproj,xml,yml,dll.config,msbuildproj,targets}] +[*.{csproj,xml,yml,yaml,dll.config,msbuildproj,targets}] indent_size = 2 + +[{*.yaml,*.yml}] +ij_yaml_indent_sequence_value = false diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 83d927c94b..a487e5d8d8 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -2,7 +2,6 @@ using System.IO; using System.Linq; using Content.Shared.Actions; using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.Player; using Robust.Shared.ContentPack; using Robust.Shared.GameStates; @@ -41,8 +40,8 @@ namespace Content.Client.Actions public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(HandleComponentState); SubscribeLocalEvent(OnInstantHandleState); @@ -196,12 +195,12 @@ namespace Content.Client.Actions return GetActions(user); } - private void OnPlayerAttached(EntityUid uid, ActionsComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, ActionsComponent component, LocalPlayerAttachedEvent args) { LinkAllActions(component); } - private void OnPlayerDetached(EntityUid uid, ActionsComponent component, PlayerDetachedEvent? args = null) + private void OnPlayerDetached(EntityUid uid, ActionsComponent component, LocalPlayerDetachedEvent? args = null) { UnlinkAllActions(); } diff --git a/Content.Client/Administration/Managers/ClientAdminManager.cs b/Content.Client/Administration/Managers/ClientAdminManager.cs index 8978e2fd6d..1a1366c6f2 100644 --- a/Content.Client/Administration/Managers/ClientAdminManager.cs +++ b/Content.Client/Administration/Managers/ClientAdminManager.cs @@ -4,7 +4,7 @@ using Robust.Client.Console; using Robust.Client.Player; using Robust.Shared.ContentPack; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Client.Administration.Managers diff --git a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs index 6142e3a831..5fa28bf1ac 100644 --- a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs +++ b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs @@ -22,7 +22,7 @@ namespace Content.Client.Administration.UI.CustomControls private List _playerList = new(); private readonly List _sortedPlayerList = new(); - public event Action? OnSelectionChanged; + public event Action? OnSelectionChanged; public IReadOnlyList PlayerInfo => _playerList; public Func? OverrideText; @@ -46,9 +46,9 @@ namespace Content.Client.Administration.UI.CustomControls BackgroundPanel.PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)}; } - private void PlayerListItemPressed(BaseButton.ButtonEventArgs args, ListData data) + private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data) { - if (data is not PlayerListData {Info: var selectedPlayer}) + if (args == null || data is not PlayerListData {Info: var selectedPlayer}) return; if (args.Event.Function == EngineKeyFunctions.UIClick) { diff --git a/Content.Client/Administration/UI/Tabs/AdminTab/TeleportWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/AdminTab/TeleportWindow.xaml.cs index c5a9bd036a..1978b5c3c0 100644 --- a/Content.Client/Administration/UI/Tabs/AdminTab/TeleportWindow.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/AdminTab/TeleportWindow.xaml.cs @@ -5,7 +5,6 @@ using Robust.Client.Console; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.IoC; -using Robust.Shared.Players; namespace Content.Client.Administration.UI.Tabs.AdminTab { diff --git a/Content.Client/Alerts/ClientAlertsSystem.cs b/Content.Client/Alerts/ClientAlertsSystem.cs index bb6d2d4df4..5089022415 100644 --- a/Content.Client/Alerts/ClientAlertsSystem.cs +++ b/Content.Client/Alerts/ClientAlertsSystem.cs @@ -1,7 +1,6 @@ using System.Linq; using Content.Shared.Alert; using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.Player; using Robust.Shared.Prototypes; @@ -22,8 +21,8 @@ public sealed class ClientAlertsSystem : AlertsSystem { base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(ClientAlertsHandleState); } @@ -69,7 +68,7 @@ public sealed class ClientAlertsSystem : AlertsSystem SyncAlerts?.Invoke(this, component.Alerts); } - private void OnPlayerAttached(EntityUid uid, AlertsComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, AlertsComponent component, LocalPlayerAttachedEvent args) { if (_playerManager.LocalPlayer?.ControlledEntity != uid) return; @@ -87,7 +86,7 @@ public sealed class ClientAlertsSystem : AlertsSystem ClearAlerts?.Invoke(this, EventArgs.Empty); } - private void OnPlayerDetached(EntityUid uid, AlertsComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, AlertsComponent component, LocalPlayerDetachedEvent args) { ClearAlerts?.Invoke(this, EventArgs.Empty); } diff --git a/Content.Client/CharacterInfo/CharacterInfoSystem.cs b/Content.Client/CharacterInfo/CharacterInfoSystem.cs index 93bd86d140..844a352a18 100644 --- a/Content.Client/CharacterInfo/CharacterInfoSystem.cs +++ b/Content.Client/CharacterInfo/CharacterInfoSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.CharacterInfo; using Content.Shared.Objectives; -using Robust.Client.GameObjects; using Robust.Client.Player; using Robust.Client.UserInterface; @@ -11,14 +10,11 @@ public sealed class CharacterInfoSystem : EntitySystem [Dependency] private readonly IPlayerManager _players = default!; public event Action? OnCharacterUpdate; - public event Action? OnCharacterDetached; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeNetworkEvent(OnCharacterInfoEvent); } @@ -33,14 +29,6 @@ public sealed class CharacterInfoSystem : EntitySystem RaiseNetworkEvent(new RequestCharacterInfoEvent(GetNetEntity(entity.Value))); } - private void OnPlayerAttached(PlayerAttachSysMessage msg) - { - if (msg.AttachedEntity == default) - { - OnCharacterDetached?.Invoke(); - } - } - private void OnCharacterInfoEvent(CharacterInfoEvent msg, EntitySessionEventArgs args) { var entity = GetEntity(msg.NetEntity); diff --git a/Content.Client/Chemistry/Visualizers/FoamVisualizerSystem.cs b/Content.Client/Chemistry/Visualizers/FoamVisualizerSystem.cs index ec582ee094..2ee88956ff 100644 --- a/Content.Client/Chemistry/Visualizers/FoamVisualizerSystem.cs +++ b/Content.Client/Chemistry/Visualizers/FoamVisualizerSystem.cs @@ -1,8 +1,6 @@ -using Content.Shared.Smoking; -using Robust.Shared.Spawners; +using Content.Shared.Chemistry.Components; using Robust.Client.Animations; using Robust.Client.GameObjects; -using Robust.Shared.Network; using Robust.Shared.Timing; namespace Content.Client.Chemistry.Visualizers; @@ -18,6 +16,7 @@ public sealed class FoamVisualizerSystem : VisualizerSystem(OnComponentInit); + SubscribeLocalEvent(OnAnimationComplete); } public override void Update(float frameTime) @@ -27,11 +26,11 @@ public sealed class FoamVisualizerSystem : VisualizerSystem(); + var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var comp, out var despawn)) + while (query.MoveNext(out var uid, out var comp, out var smoke)) { - if (despawn.Lifetime > 1f) + if (_timing.CurTime < comp.StartTime + TimeSpan.FromSeconds(smoke.Duration) - TimeSpan.FromSeconds(comp.AnimationTime)) continue; // Despawn animation. @@ -48,6 +47,7 @@ public sealed class FoamVisualizerSystem : VisualizerSystem private void OnComponentInit(EntityUid uid, FoamVisualsComponent comp, ComponentInit args) { + comp.StartTime = _timing.CurTime; comp.Animation = new Animation { Length = TimeSpan.FromSeconds(comp.AnimationTime), @@ -58,12 +58,21 @@ public sealed class FoamVisualizerSystem : VisualizerSystem(uid, out var sprite)) + sprite.Visible = false; + } } public enum FoamVisualLayers : byte diff --git a/Content.Client/Chemistry/Visualizers/FoamVisualsComponent.cs b/Content.Client/Chemistry/Visualizers/FoamVisualsComponent.cs index b09c74aa0f..8199efa42e 100644 --- a/Content.Client/Chemistry/Visualizers/FoamVisualsComponent.cs +++ b/Content.Client/Chemistry/Visualizers/FoamVisualsComponent.cs @@ -1,5 +1,6 @@ using Robust.Client.Animations; using Robust.Client.Graphics; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Client.Chemistry.Visualizers; @@ -15,18 +16,21 @@ public sealed partial class FoamVisualsComponent : Component /// public const string AnimationKey = "foamdissolve_animation"; + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan StartTime; + /// /// How long the foam visually dissolves for. /// - [DataField("animationTime")] - public float AnimationTime = 0.6f; + [DataField] + public float AnimationTime = 0.5f; /// /// The state of the entities base sprite RSI that is displayed when the foam dissolves. /// Cannot use because it does not have and I am not making an engine PR at this time. /// - [DataField("animationState")] - public string State = "foam-dissolve"; + [DataField] + public string AnimationState = "foam-dissolve"; /// /// The animation used while the foam dissolves. diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index 98d2dfd414..9fc638cea2 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -38,7 +38,7 @@ namespace Content.Client.Construction base.Initialize(); UpdatesOutsidePrediction = true; - SubscribeLocalEvent(HandlePlayerAttached); + SubscribeLocalEvent(HandlePlayerAttached); SubscribeNetworkEvent(HandleAckStructure); SubscribeNetworkEvent(OnConstructionGuideReceived); @@ -110,9 +110,9 @@ namespace Content.Client.Construction ClearGhost(msg.GhostId); } - private void HandlePlayerAttached(PlayerAttachSysMessage msg) + private void HandlePlayerAttached(LocalPlayerAttachedEvent msg) { - var available = IsCraftingAvailable(msg.AttachedEntity); + var available = IsCraftingAvailable(msg.Entity); UpdateCraftingAvailability(available); } diff --git a/Content.Client/Drugs/DrugOverlaySystem.cs b/Content.Client/Drugs/DrugOverlaySystem.cs index 7be63b4c50..ec0d014072 100644 --- a/Content.Client/Drugs/DrugOverlaySystem.cs +++ b/Content.Client/Drugs/DrugOverlaySystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Drugs; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; @@ -24,18 +23,18 @@ public sealed class DrugOverlaySystem : EntitySystem SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); _overlay = new(); } - private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerAttachedEvent args) { _overlayMan.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, SeeingRainbowsComponent component, LocalPlayerDetachedEvent args) { _overlay.Intoxication = 0; _overlayMan.RemoveOverlay(_overlay); diff --git a/Content.Client/Drunk/DrunkSystem.cs b/Content.Client/Drunk/DrunkSystem.cs index 0573b2ff3e..4f2ec70b56 100644 --- a/Content.Client/Drunk/DrunkSystem.cs +++ b/Content.Client/Drunk/DrunkSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Drunk; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; @@ -19,18 +18,18 @@ public sealed class DrunkSystem : SharedDrunkSystem SubscribeLocalEvent(OnDrunkInit); SubscribeLocalEvent(OnDrunkShutdown); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); _overlay = new(); } - private void OnPlayerAttached(EntityUid uid, DrunkComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, DrunkComponent component, LocalPlayerAttachedEvent args) { _overlayMan.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, DrunkComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, DrunkComponent component, LocalPlayerDetachedEvent args) { _overlay.CurrentBoozePower = 0; _overlayMan.RemoveOverlay(_overlay); diff --git a/Content.Client/Eye/Blinding/BlindingSystem.cs b/Content.Client/Eye/Blinding/BlindingSystem.cs index f0b760d838..f255f7ef01 100644 --- a/Content.Client/Eye/Blinding/BlindingSystem.cs +++ b/Content.Client/Eye/Blinding/BlindingSystem.cs @@ -1,17 +1,7 @@ - -using Content.Shared.Eye.Blinding; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; -using System; -using System.Collections.Generic; -using System.Linq; -using Content.Shared.Administration; -using Content.Shared.Administration.Events; using Content.Shared.Eye.Blinding.Components; using Content.Shared.GameTicking; -using Robust.Shared.GameObjects; -using Robust.Shared.Network; namespace Content.Client.Eye.Blinding; @@ -31,20 +21,20 @@ public sealed class BlindingSystem : EntitySystem SubscribeLocalEvent(OnBlindInit); SubscribeLocalEvent(OnBlindShutdown); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeNetworkEvent(RoundRestartCleanup); _overlay = new(); } - private void OnPlayerAttached(EntityUid uid, BlindableComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, BlindableComponent component, LocalPlayerAttachedEvent args) { _overlayMan.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, BlindableComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, BlindableComponent component, LocalPlayerDetachedEvent args) { _overlayMan.RemoveOverlay(_overlay); _lightManager.Enabled = true; diff --git a/Content.Client/Eye/Blinding/BlurryVisionSystem.cs b/Content.Client/Eye/Blinding/BlurryVisionSystem.cs index 1bac2a97bf..8be5b4ed93 100644 --- a/Content.Client/Eye/Blinding/BlurryVisionSystem.cs +++ b/Content.Client/Eye/Blinding/BlurryVisionSystem.cs @@ -1,9 +1,6 @@ -using Content.Shared.Eye.Blinding; using Content.Shared.Eye.Blinding.Components; -using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Player; -using Robust.Shared.GameStates; namespace Content.Client.Eye.Blinding; @@ -20,18 +17,18 @@ public sealed class BlurryVisionSystem : EntitySystem SubscribeLocalEvent(OnBlurryInit); SubscribeLocalEvent(OnBlurryShutdown); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); _overlay = new(); } - private void OnPlayerAttached(EntityUid uid, BlurryVisionComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, BlurryVisionComponent component, LocalPlayerAttachedEvent args) { _overlayMan.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, BlurryVisionComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, BlurryVisionComponent component, LocalPlayerDetachedEvent args) { _overlayMan.RemoveOverlay(_overlay); } diff --git a/Content.Client/Eye/EyeLerpingSystem.cs b/Content.Client/Eye/EyeLerpingSystem.cs index 8e54196b81..b46921a9b4 100644 --- a/Content.Client/Eye/EyeLerpingSystem.cs +++ b/Content.Client/Eye/EyeLerpingSystem.cs @@ -30,7 +30,7 @@ public sealed class EyeLerpingSystem : EntitySystem SubscribeLocalEvent(OnAttached); SubscribeLocalEvent(HandleMapChange); - SubscribeLocalEvent(OnDetached); + SubscribeLocalEvent(OnDetached); UpdatesAfter.Add(typeof(TransformSystem)); UpdatesAfter.Add(typeof(PhysicsSystem)); @@ -94,7 +94,7 @@ public sealed class EyeLerpingSystem : EntitySystem AddEye(ev.Entity, ev.Component, true); } - private void OnDetached(EntityUid uid, LerpingEyeComponent component, PlayerDetachedEvent args) + private void OnDetached(EntityUid uid, LerpingEyeComponent component, LocalPlayerDetachedEvent args) { if (!component.ManuallyAdded) RemCompDeferred(uid, component); diff --git a/Content.Client/Fullscreen/FullscreenHook.cs b/Content.Client/Fullscreen/FullscreenHook.cs index 78a0151736..7917fddfbb 100644 --- a/Content.Client/Fullscreen/FullscreenHook.cs +++ b/Content.Client/Fullscreen/FullscreenHook.cs @@ -4,7 +4,7 @@ using Robust.Client.Input; using Robust.Shared.Input.Binding; using Robust.Shared; using Robust.Shared.Configuration; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Client.Fullscreen; public sealed class FullscreenHook diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs index 788a4e5dff..454c063260 100644 --- a/Content.Client/Gameplay/GameplayStateBase.cs +++ b/Content.Client/Gameplay/GameplayStateBase.cs @@ -16,7 +16,7 @@ using Robust.Shared.Console; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Client.Gameplay diff --git a/Content.Client/Ghost/GhostSystem.cs b/Content.Client/Ghost/GhostSystem.cs index 5727534109..a89d0858d9 100644 --- a/Content.Client/Ghost/GhostSystem.cs +++ b/Content.Client/Ghost/GhostSystem.cs @@ -58,10 +58,10 @@ namespace Content.Client.Ghost SubscribeLocalEvent(OnGhostRemove); SubscribeLocalEvent(OnGhostState); - SubscribeLocalEvent(OnGhostPlayerAttach); - SubscribeLocalEvent(OnGhostPlayerDetach); + SubscribeLocalEvent(OnGhostPlayerAttach); + SubscribeLocalEvent(OnGhostPlayerDetach); - SubscribeLocalEvent(OnPlayerAttach); + SubscribeLocalEvent(OnPlayerAttach); SubscribeNetworkEvent(OnGhostWarpsResponse); SubscribeNetworkEvent(OnUpdateGhostRoleCount); @@ -130,7 +130,7 @@ namespace Content.Client.Ghost PlayerRemoved?.Invoke(component); } - private void OnGhostPlayerAttach(EntityUid uid, GhostComponent component, PlayerAttachedEvent playerAttachedEvent) + private void OnGhostPlayerAttach(EntityUid uid, GhostComponent component, LocalPlayerAttachedEvent localPlayerAttachedEvent) { if (uid != _playerManager.LocalPlayer?.ControlledEntity) return; @@ -161,13 +161,13 @@ namespace Content.Client.Ghost return true; } - private void OnGhostPlayerDetach(EntityUid uid, GhostComponent component, PlayerDetachedEvent args) + private void OnGhostPlayerDetach(EntityUid uid, GhostComponent component, LocalPlayerDetachedEvent args) { if (PlayerDetach(uid)) component.IsAttached = false; } - private void OnPlayerAttach(PlayerAttachedEvent ev) + private void OnPlayerAttach(LocalPlayerAttachedEvent ev) { if (!HasComp(ev.Entity)) PlayerDetach(ev.Entity); diff --git a/Content.Client/Hands/Systems/HandsSystem.cs b/Content.Client/Hands/Systems/HandsSystem.cs index ed40589f7f..31de7ec143 100644 --- a/Content.Client/Hands/Systems/HandsSystem.cs +++ b/Content.Client/Hands/Systems/HandsSystem.cs @@ -42,8 +42,8 @@ namespace Content.Client.Hands.Systems { base.Initialize(); - SubscribeLocalEvent(HandlePlayerAttached); - SubscribeLocalEvent(HandlePlayerDetached); + SubscribeLocalEvent(HandlePlayerAttached); + SubscribeLocalEvent(HandlePlayerDetached); SubscribeLocalEvent(OnHandsStartup); SubscribeLocalEvent(OnHandsShutdown); SubscribeLocalEvent(HandleComponentState); @@ -361,12 +361,12 @@ namespace Content.Client.Hands.Systems #region Gui - private void HandlePlayerAttached(EntityUid uid, HandsComponent component, PlayerAttachedEvent args) + private void HandlePlayerAttached(EntityUid uid, HandsComponent component, LocalPlayerAttachedEvent args) { OnPlayerHandsAdded?.Invoke(component); } - private void HandlePlayerDetached(EntityUid uid, HandsComponent component, PlayerDetachedEvent args) + private void HandlePlayerDetached(EntityUid uid, HandsComponent component, LocalPlayerDetachedEvent args) { OnPlayerHandsRemoved?.Invoke(); } diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml index 1f64feec2b..b78c3c6a56 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml @@ -1,9 +1,33 @@  - - - + SetSize="250 100"> + + + + + \ No newline at end of file diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs index 1c5a3373e1..36f7a08b96 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs @@ -1,5 +1,5 @@ +using System.Linq; using System.Numerics; -using System.Text; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; @@ -8,85 +8,182 @@ using Content.Shared.MedicalScanner; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.UserInterface.Controls; +using Robust.Client.ResourceManagement; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Client.HealthAnalyzer.UI { [GenerateTypedNameReferences] public sealed partial class HealthAnalyzerWindow : DefaultWindow { + private readonly IEntityManager _entityManager; + private readonly SpriteSystem _spriteSystem; + private readonly IPrototypeManager _prototypes; + private readonly IResourceCache _cache; + + private const int AnalyzerHeight = 430; + private const int AnalyzerWidth = 300; + public HealthAnalyzerWindow() { RobustXamlLoader.Load(this); + + var dependencies = IoCManager.Instance!; + _entityManager = dependencies.Resolve(); + _spriteSystem = _entityManager.System(); + _prototypes = dependencies.Resolve(); + _cache = dependencies.Resolve(); } public void Populate(HealthAnalyzerScannedUserMessage msg) { - var text = new StringBuilder(); - var entities = IoCManager.Resolve(); - var target = entities.GetEntity(msg.TargetEntity); + GroupsContainer.RemoveAllChildren(); - if (msg.TargetEntity != null && entities.TryGetComponent(target, out var damageable)) + var target = _entityManager.GetEntity(msg.TargetEntity); + + if (target == null + || !_entityManager.TryGetComponent(target, out var damageable)) { - string entityName = "Unknown"; - if (msg.TargetEntity != null && - entities.HasComponent(target.Value)) - { - entityName = Identity.Name(target.Value, entities); - } - - IReadOnlyDictionary damagePerGroup = damageable.DamagePerGroup; - IReadOnlyDictionary damagePerType = damageable.Damage.DamageDict; - - text.Append($"{Loc.GetString("health-analyzer-window-entity-health-text", ("entityName", entityName))}\n\n"); - - - text.Append($"{Loc.GetString("health-analyzer-window-entity-temperature-text", ("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - 273f:F1} °C"))}\n"); - - - text.Append($"{Loc.GetString("health-analyzer-window-entity-blood-level-text", ("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %"))}\n\n"); - - - // Damage - text.Append($"{Loc.GetString("health-analyzer-window-entity-damage-total-text", ("amount", damageable.TotalDamage))}\n"); - - HashSet shownTypes = new(); - - var protos = IoCManager.Resolve(); - - // Show the total damage and type breakdown for each damage group. - foreach (var (damageGroupId, damageAmount) in damagePerGroup) - { - if (damageAmount == 0) - { - continue; - } - text.Append($"\n{Loc.GetString("health-analyzer-window-damage-group-text", ("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)), ("amount", damageAmount))}"); - - // Show the damage for each type in that group. - var group = protos.Index(damageGroupId); - foreach (var type in group.DamageTypes) - { - if (damagePerType.TryGetValue(type, out var typeAmount) ) - { - // If damage types are allowed to belong to more than one damage group, they may appear twice here. Mark them as duplicate. - if (!shownTypes.Contains(type) && typeAmount > 0) - { - shownTypes.Add(type); - text.Append($"\n- {Loc.GetString("health-analyzer-window-damage-type-text", ("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)), ("amount", typeAmount))}"); - } - } - } - text.AppendLine(); - } - Diagnostics.Text = text.ToString(); - SetSize = new Vector2(250, 600); + NoPatientDataText.Visible = true; + return; } - else + + NoPatientDataText.Visible = false; + + string entityName = Loc.GetString("health-analyzer-window-entity-unknown-text"); + if (_entityManager.HasComponent(target.Value)) { - Diagnostics.Text = Loc.GetString("health-analyzer-window-no-patient-data-text"); - SetSize = new Vector2(250, 100); + entityName = Identity.Name(target.Value, _entityManager); } + + PatientName.Text = Loc.GetString( + "health-analyzer-window-entity-health-text", + ("entityName", entityName) + ); + + Temperature.Text = Loc.GetString("health-analyzer-window-entity-temperature-text", + ("temperature", float.IsNaN(msg.Temperature) ? "N/A" : $"{msg.Temperature - 273f:F1} °C") + ); + + BloodLevel.Text = Loc.GetString("health-analyzer-window-entity-blood-level-text", + ("bloodLevel", float.IsNaN(msg.BloodLevel) ? "N/A" : $"{msg.BloodLevel * 100:F1} %") + ); + + patientDamageAmount.Text = Loc.GetString( + "health-analyzer-window-entity-damage-total-text", + ("amount", damageable.TotalDamage) + ); + + var damageSortedGroups = + damageable.DamagePerGroup.OrderBy(damage => damage.Value) + .ToDictionary(x => x.Key, x => x.Value); + IReadOnlyDictionary damagePerType = damageable.Damage.DamageDict; + + DrawDiagnosticGroups(damageSortedGroups, damagePerType); + + SetHeight = AnalyzerHeight; + SetWidth = AnalyzerWidth; + } + + private void DrawDiagnosticGroups( + Dictionary groups, IReadOnlyDictionary damageDict) + { + HashSet shownTypes = new(); + + // Show the total damage and type breakdown for each damage group. + foreach (var (damageGroupId, damageAmount) in groups.Reverse()) + { + if (damageAmount == 0) + continue; + + var groupTitleText = $"{Loc.GetString( + "health-analyzer-window-damage-group-text", + ("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)), + ("amount", damageAmount) + )}"; + + var groupContainer = new BoxContainer + { + Margin = new Thickness(0, 0, 0, 15), + Align = BoxContainer.AlignMode.Begin, + Orientation = BoxContainer.LayoutOrientation.Vertical, + }; + + groupContainer.AddChild(CreateDiagnosticGroupTitle(groupTitleText, damageGroupId, damageAmount.Int())); + + GroupsContainer.AddChild(groupContainer); + + // Show the damage for each type in that group. + var group = _prototypes.Index(damageGroupId); + + foreach (var type in group.DamageTypes) + { + if (damageDict.TryGetValue(type, out var typeAmount) && typeAmount > 0) + { + // If damage types are allowed to belong to more than one damage group, + // they may appear twice here. Mark them as duplicate. + if (shownTypes.Contains(type)) + continue; + + shownTypes.Add(type); + + var damageString = Loc.GetString( + "health-analyzer-window-damage-type-text", + ("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)), + ("amount", typeAmount) + ); + + groupContainer.AddChild(CreateDiagnosticItemLabel(damageString.Insert(0, "- "))); + } + } + } + } + + private Texture GetTexture(string texture) + { + var rsiPath = new ResPath("/Textures/Objects/Devices/health_analyzer.rsi"); + var rsiSprite = new SpriteSpecifier.Rsi(rsiPath, texture); + + var rsi = _cache.GetResource(rsiSprite.RsiPath).RSI; + if (!rsi.TryGetState(rsiSprite.RsiState, out var state)) + { + rsiSprite = new SpriteSpecifier.Rsi(rsiPath, "unknown"); + } + + return _spriteSystem.Frame0(rsiSprite); + } + + private static Label CreateDiagnosticItemLabel(string text) + { + return new Label + { + Margin = new Thickness(2, 2), + Text = text, + }; + } + + private BoxContainer CreateDiagnosticGroupTitle(string text, string id, int damageAmount) + { + var rootContainer = new BoxContainer + { + VerticalAlignment = VAlignment.Bottom, + Orientation = BoxContainer.LayoutOrientation.Horizontal + }; + + rootContainer.AddChild(new TextureRect + { + Margin = new Thickness(0, 3), + SetSize = new Vector2(30, 30), + Texture = GetTexture(id.ToLower()) + }); + + rootContainer.AddChild(CreateDiagnosticItemLabel(text)); + + return rootContainer; } } } diff --git a/Content.Client/HealthOverlay/HealthOverlaySystem.cs b/Content.Client/HealthOverlay/HealthOverlaySystem.cs index baeb4fe025..29ac937199 100644 --- a/Content.Client/HealthOverlay/HealthOverlaySystem.cs +++ b/Content.Client/HealthOverlay/HealthOverlaySystem.cs @@ -3,8 +3,8 @@ using Content.Shared.Damage; using Content.Shared.GameTicking; using Content.Shared.Mobs.Components; using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.Graphics; +using Robust.Client.Player; namespace Content.Client.HealthOverlay { @@ -13,9 +13,9 @@ namespace Content.Client.HealthOverlay { [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IEntityManager _entities = default!; + [Dependency] private readonly IPlayerManager _player = default!; private readonly Dictionary _guis = new(); - private EntityUid? _attachedEntity; private bool _enabled; public bool Enabled @@ -42,7 +42,6 @@ namespace Content.Client.HealthOverlay base.Initialize(); SubscribeNetworkEvent(Reset); - SubscribeLocalEvent(HandlePlayerAttached); } public void Reset(RoundRestartCleanupEvent ev) @@ -53,12 +52,6 @@ namespace Content.Client.HealthOverlay } _guis.Clear(); - _attachedEntity = default; - } - - private void HandlePlayerAttached(PlayerAttachSysMessage message) - { - _attachedEntity = message.AttachedEntity; } public override void FrameUpdate(float frameTime) @@ -70,7 +63,7 @@ namespace Content.Client.HealthOverlay return; } - if (_attachedEntity is not {} ent || Deleted(ent)) + if (_player.LocalEntity is not {} ent || Deleted(ent)) { return; } diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.cs b/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.cs new file mode 100644 index 0000000000..aff01800f9 --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.cs @@ -0,0 +1,39 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Info.PlaytimeStats; + +[GenerateTypedNameReferences] +public sealed partial class PlaytimeStatsEntry : ContainerButton +{ + public TimeSpan Playtime { get; private set; } // new TimeSpan property + + public PlaytimeStatsEntry(string role, TimeSpan playtime, StyleBox styleBox) + { + RobustXamlLoader.Load(this); + + RoleLabel.Text = role; + Playtime = playtime; // store the TimeSpan value directly + PlaytimeLabel.Text = ConvertTimeSpanToHoursMinutes(playtime); // convert to string for display + BackgroundColorPanel.PanelOverride = styleBox; + } + + private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan) + { + var hours = (int)timeSpan.TotalHours; + var minutes = timeSpan.Minutes; + + var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes)); + return formattedTimeLoc; + } + + public void UpdateShading(StyleBoxFlat styleBox) + { + BackgroundColorPanel.PanelOverride = styleBox; + } + public string? PlaytimeText => PlaytimeLabel.Text; + + public string? RoleText => RoleLabel.Text; +} diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.xaml b/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.xaml new file mode 100644 index 0000000000..97a66e5cc2 --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsEntry.xaml @@ -0,0 +1,20 @@ + + + + + diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.cs b/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.cs new file mode 100644 index 0000000000..b005c641f7 --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.cs @@ -0,0 +1,86 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Input; + +namespace Content.Client.Info.PlaytimeStats; + +[GenerateTypedNameReferences] +public sealed partial class PlaytimeStatsHeader : ContainerButton +{ + public event Action? OnHeaderClicked; + private SortDirection _roleDirection = SortDirection.Ascending; + private SortDirection _playtimeDirection = SortDirection.Descending; + + public PlaytimeStatsHeader() + { + RobustXamlLoader.Load(this); + + RoleLabel.OnKeyBindDown += RoleClicked; + PlaytimeLabel.OnKeyBindDown += PlaytimeClicked; + + UpdateLabels(); + } + + public enum Header : byte + { + Role, + Playtime + } + public enum SortDirection : byte + { + Ascending, + Descending + } + + private void HeaderClicked(GUIBoundKeyEventArgs args, Header header) + { + if (args.Function != EngineKeyFunctions.UIClick) + { + return; + } + + switch (header) + { + case Header.Role: + _roleDirection = _roleDirection == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending; + break; + case Header.Playtime: + _playtimeDirection = _playtimeDirection == SortDirection.Ascending ? SortDirection.Descending : SortDirection.Ascending; + break; + } + + UpdateLabels(); + OnHeaderClicked?.Invoke(header, header == Header.Role ? _roleDirection : _playtimeDirection); + args.Handle(); + } + private void UpdateLabels() + { + RoleLabel.Text = Loc.GetString("ui-playtime-header-role-type") + + (_roleDirection == SortDirection.Ascending ? " ↓" : " ↑"); + PlaytimeLabel.Text = Loc.GetString("ui-playtime-header-role-time") + + (_playtimeDirection == SortDirection.Ascending ? " ↓" : " ↑"); + } + + private void RoleClicked(GUIBoundKeyEventArgs args) + { + HeaderClicked(args, Header.Role); + } + + private void PlaytimeClicked(GUIBoundKeyEventArgs args) + { + HeaderClicked(args, Header.Playtime); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + RoleLabel.OnKeyBindDown -= RoleClicked; + PlaytimeLabel.OnKeyBindDown -= PlaytimeClicked; + } + } +} diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.xaml b/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.xaml new file mode 100644 index 0000000000..4cf4d8e2cc --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsHeader.xaml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.cs b/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.cs new file mode 100644 index 0000000000..3b54bf82da --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.cs @@ -0,0 +1,146 @@ +using System.Linq; +using System.Text.RegularExpressions; +using Content.Client.Players.PlayTimeTracking; +using Content.Client.UserInterface.Controls; +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Info.PlaytimeStats; + +[GenerateTypedNameReferences] +public sealed partial class PlaytimeStatsWindow : FancyWindow +{ + [Dependency] private readonly JobRequirementsManager _jobRequirementsManager = default!; + private ISawmill _sawmill = Logger.GetSawmill("PlaytimeStatsWindow"); + private readonly Color _altColor = Color.FromHex("#292B38"); + private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); + private bool _useAltColor; + + public PlaytimeStatsWindow() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + + PopulatePlaytimeHeader(); + PopulatePlaytimeData(); + } + + private void PopulatePlaytimeHeader() + { + var header = new PlaytimeStatsHeader(); + header.OnHeaderClicked += HeaderClicked; + header.BackgroundColorPlaytimePanel.PanelOverride = new StyleBoxFlat(_altColor); + RolesPlaytimeList.AddChild(header); + } + + private void HeaderClicked(PlaytimeStatsHeader.Header header, PlaytimeStatsHeader.SortDirection direction) + { + switch (header) + { + case PlaytimeStatsHeader.Header.Role: + SortByRole(direction); + break; + case PlaytimeStatsHeader.Header.Playtime: + SortByPlaytime(direction); + break; + } + } + + private void SortByRole(PlaytimeStatsHeader.SortDirection direction) + { + var header = RolesPlaytimeList.GetChild(0) as PlaytimeStatsHeader; + + var entries = RolesPlaytimeList.Children.OfType().ToList(); + + RolesPlaytimeList.RemoveAllChildren(); + + if (header != null) + RolesPlaytimeList.AddChild(header); + + var sortedEntries = (direction == PlaytimeStatsHeader.SortDirection.Ascending) + ? entries.OrderBy(entry => entry.RoleText).ToList() + : entries.OrderByDescending(entry => entry.RoleText).ToList(); + + _useAltColor = false; + + foreach (var entry in sortedEntries) + { + var styleBox = new StyleBoxFlat { BackgroundColor = _useAltColor ? _altColor : _defaultColor }; + entry.UpdateShading(styleBox); + RolesPlaytimeList.AddChild(entry); + _useAltColor ^= true; + } + } + + private void SortByPlaytime(PlaytimeStatsHeader.SortDirection direction) + { + var header = RolesPlaytimeList.GetChild(0) as PlaytimeStatsHeader; + + var entries = RolesPlaytimeList.Children.OfType().ToList(); + + RolesPlaytimeList.RemoveAllChildren(); + + if (header != null) + RolesPlaytimeList.AddChild(header); + + var sortedEntries = (direction == PlaytimeStatsHeader.SortDirection.Ascending) + ? entries.OrderBy(entry => entry.Playtime).ToList() + : entries.OrderByDescending(entry => entry.Playtime).ToList(); + + _useAltColor = false; + + foreach (var entry in sortedEntries) + { + var styleBox = new StyleBoxFlat { BackgroundColor = _useAltColor ? _altColor : _defaultColor }; + entry.UpdateShading(styleBox); + RolesPlaytimeList.AddChild(entry); + _useAltColor ^= true; + } + } + + + private void PopulatePlaytimeData() + { + var overallPlaytime = _jobRequirementsManager.FetchOverallPlaytime(); + + var formattedPlaytime = ConvertTimeSpanToHoursMinutes(overallPlaytime); + OverallPlaytimeLabel.Text = Loc.GetString("ui-playtime-overall", ("time", formattedPlaytime)); + + var rolePlaytimes = _jobRequirementsManager.FetchPlaytimeByRoles(); + + RolesPlaytimeList.RemoveAllChildren(); + PopulatePlaytimeHeader(); + + foreach (var rolePlaytime in rolePlaytimes) + { + var role = rolePlaytime.Key; + var playtime = rolePlaytime.Value; + AddRolePlaytimeEntryToTable(Loc.GetString(role), playtime.ToString()); + } + } + + private void AddRolePlaytimeEntryToTable(string role, string playtimeString) + { + if (TimeSpan.TryParse(playtimeString, out var playtime)) + { + var entry = new PlaytimeStatsEntry(role, playtime, + new StyleBoxFlat(_useAltColor ? _altColor : _defaultColor)); + RolesPlaytimeList.AddChild(entry); + _useAltColor ^= true; + } + else + { + _sawmill.Error($"The provided playtime string '{playtimeString}' is not in the correct format."); + } + } + + private static string ConvertTimeSpanToHoursMinutes(TimeSpan timeSpan) + { + var hours = (int) timeSpan.TotalHours; + var minutes = timeSpan.Minutes; + + var formattedTimeLoc = Loc.GetString("ui-playtime-time-format", ("hours", hours), ("minutes", minutes)); + return formattedTimeLoc; + } +} diff --git a/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.xaml b/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.xaml new file mode 100644 index 0000000000..b38394d9a3 --- /dev/null +++ b/Content.Client/Info/PlaytimeStats/PlaytimeStatsWindow.xaml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/Content.Client/Inventory/ClientInventorySystem.cs b/Content.Client/Inventory/ClientInventorySystem.cs index ffff392aa4..f0a12b3b1f 100644 --- a/Content.Client/Inventory/ClientInventorySystem.cs +++ b/Content.Client/Inventory/ClientInventorySystem.cs @@ -10,7 +10,6 @@ using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Content.Shared.Storage; using JetBrains.Annotations; -using Robust.Client.GameObjects; using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Shared.Containers; @@ -43,8 +42,8 @@ namespace Content.Client.Inventory UpdatesOutsidePrediction = true; base.Initialize(); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(OnShutdown); @@ -113,12 +112,12 @@ namespace Content.Client.Inventory OnUnlinkInventory?.Invoke(); } - private void OnPlayerDetached(EntityUid uid, InventorySlotsComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, InventorySlotsComponent component, LocalPlayerDetachedEvent args) { OnUnlinkInventory?.Invoke(); } - private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, InventorySlotsComponent component, LocalPlayerAttachedEvent args) { if (TryGetSlots(uid, out var definitions)) { diff --git a/Content.Client/Nyanotrasen/Overlays/DogVisionSystem.cs b/Content.Client/Nyanotrasen/Overlays/DogVisionSystem.cs index 8c252132a3..7cd0f69ae5 100644 --- a/Content.Client/Nyanotrasen/Overlays/DogVisionSystem.cs +++ b/Content.Client/Nyanotrasen/Overlays/DogVisionSystem.cs @@ -19,22 +19,17 @@ public sealed partial class DogVisionSystem : EntitySystem SubscribeLocalEvent(OnDogVisionInit); SubscribeLocalEvent(OnDogVisionShutdown); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + _player.LocalPlayerAttached += OnAttachedChanged; + _player.LocalPlayerDetached += OnAttachedChanged; _overlay = new(); } - private void OnPlayerAttached(EntityUid uid, DogVisionComponent component, PlayerAttachedEvent args) + private void OnAttachedChanged(EntityUid uid) { _overlayMan.AddOverlay(_overlay); } - private void OnPlayerDetached(EntityUid uid, DogVisionComponent component, PlayerDetachedEvent args) - { - _overlayMan.RemoveOverlay(_overlay); - } - private void OnDogVisionInit(EntityUid uid, DogVisionComponent component, ComponentInit args) { if (_player.LocalPlayer?.ControlledEntity == uid) diff --git a/Content.Client/Overlays/EquipmentHudSystem.cs b/Content.Client/Overlays/EquipmentHudSystem.cs index 1d5ec03291..ac618691d8 100644 --- a/Content.Client/Overlays/EquipmentHudSystem.cs +++ b/Content.Client/Overlays/EquipmentHudSystem.cs @@ -1,7 +1,6 @@ using Content.Shared.GameTicking; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; -using Robust.Client.GameObjects; using Robust.Client.Player; namespace Content.Client.Overlays; @@ -24,8 +23,8 @@ public abstract class EquipmentHudSystem : EntitySystem where T : IComponent SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnRemove); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(OnCompEquip); SubscribeLocalEvent(OnCompUnequip); @@ -65,12 +64,12 @@ public abstract class EquipmentHudSystem : EntitySystem where T : IComponent RefreshOverlay(uid); } - private void OnPlayerAttached(PlayerAttachedEvent args) + private void OnPlayerAttached(LocalPlayerAttachedEvent args) { RefreshOverlay(args.Entity); } - private void OnPlayerDetached(PlayerDetachedEvent args) + private void OnPlayerDetached(LocalPlayerDetachedEvent args) { if (_player.LocalPlayer?.ControlledEntity == null) Deactivate(); diff --git a/Content.Client/Physics/Controllers/MoverController.cs b/Content.Client/Physics/Controllers/MoverController.cs index 54c5c3de15..52340b3391 100644 --- a/Content.Client/Physics/Controllers/MoverController.cs +++ b/Content.Client/Physics/Controllers/MoverController.cs @@ -1,7 +1,6 @@ using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; using Content.Shared.Pulling.Components; -using Robust.Client.GameObjects; using Robust.Client.Physics; using Robust.Client.Player; using Robust.Shared.Physics.Components; @@ -17,10 +16,10 @@ namespace Content.Client.Physics.Controllers public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnRelayPlayerAttached); - SubscribeLocalEvent(OnRelayPlayerDetached); - SubscribeLocalEvent(OnPlayerAttached); - SubscribeLocalEvent(OnPlayerDetached); + SubscribeLocalEvent(OnRelayPlayerAttached); + SubscribeLocalEvent(OnRelayPlayerDetached); + SubscribeLocalEvent(OnPlayerAttached); + SubscribeLocalEvent(OnPlayerDetached); SubscribeLocalEvent(OnUpdatePredicted); SubscribeLocalEvent(OnUpdateRelayTargetPredicted); @@ -54,7 +53,7 @@ namespace Content.Client.Physics.Controllers // What if the entity is being pulled by a vehicle controlled by the player? } - private void OnRelayPlayerAttached(EntityUid uid, RelayInputMoverComponent component, PlayerAttachedEvent args) + private void OnRelayPlayerAttached(EntityUid uid, RelayInputMoverComponent component, LocalPlayerAttachedEvent args) { Physics.UpdateIsPredicted(uid); Physics.UpdateIsPredicted(component.RelayEntity); @@ -62,7 +61,7 @@ namespace Content.Client.Physics.Controllers SetMoveInput(inputMover, MoveButtons.None); } - private void OnRelayPlayerDetached(EntityUid uid, RelayInputMoverComponent component, PlayerDetachedEvent args) + private void OnRelayPlayerDetached(EntityUid uid, RelayInputMoverComponent component, LocalPlayerDetachedEvent args) { Physics.UpdateIsPredicted(uid); Physics.UpdateIsPredicted(component.RelayEntity); @@ -70,12 +69,12 @@ namespace Content.Client.Physics.Controllers SetMoveInput(inputMover, MoveButtons.None); } - private void OnPlayerAttached(EntityUid uid, InputMoverComponent component, PlayerAttachedEvent args) + private void OnPlayerAttached(EntityUid uid, InputMoverComponent component, LocalPlayerAttachedEvent args) { SetMoveInput(component, MoveButtons.None); } - private void OnPlayerDetached(EntityUid uid, InputMoverComponent component, PlayerDetachedEvent args) + private void OnPlayerDetached(EntityUid uid, InputMoverComponent component, LocalPlayerDetachedEvent args) { SetMoveInput(component, MoveButtons.None); } diff --git a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs index 0e559d0f8c..5027f77663 100644 --- a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs +++ b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs @@ -1,6 +1,4 @@ using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; using Content.Shared.CCVar; using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; @@ -123,4 +121,24 @@ public sealed partial class JobRequirementsManager reason = reasons.Count == 0 ? null : FormattedMessage.FromMarkup(string.Join('\n', reasons)); return reason == null; } + + public TimeSpan FetchOverallPlaytime() + { + return _roles.TryGetValue("Overall", out var overallPlaytime) ? overallPlaytime : TimeSpan.Zero; + } + + public IEnumerable> FetchPlaytimeByRoles() + { + var jobsToMap = _prototypes.EnumeratePrototypes(); + + foreach (var job in jobsToMap) + { + if (_roles.TryGetValue(job.PlayTimeTracker, out var locJobName)) + { + yield return new KeyValuePair(job.Name, locJobName); + } + } + } + + } diff --git a/Content.Client/Players/PlayerSystem.cs b/Content.Client/Players/PlayerSystem.cs index d5ce4ec197..dba95ef7a6 100644 --- a/Content.Client/Players/PlayerSystem.cs +++ b/Content.Client/Players/PlayerSystem.cs @@ -1,11 +1,11 @@ using Content.Shared.Players; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Client.Players; public sealed class PlayerSystem : SharedPlayerSystem { - public override PlayerData? ContentData(ICommonSession? session) + public override ContentPlayerData? ContentData(ICommonSession? session) { return null; } diff --git a/Content.Client/Popups/PopupSystem.cs b/Content.Client/Popups/PopupSystem.cs index 1d4ca19ce2..d68272a107 100644 --- a/Content.Client/Popups/PopupSystem.cs +++ b/Content.Client/Popups/PopupSystem.cs @@ -9,7 +9,6 @@ using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Replays; using Robust.Shared.Timing; diff --git a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs index d3949807b7..0b8f94ceae 100644 --- a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs +++ b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs @@ -14,6 +14,7 @@ public sealed partial class GeneratorWindow : FancyWindow [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly ILocalizationManager _loc = default!; + private readonly SharedPowerSwitchableSystem _switchable; private readonly FuelGeneratorComponent? _component; private PortableGeneratorComponentBuiState? _lastState; @@ -24,6 +25,7 @@ public sealed partial class GeneratorWindow : FancyWindow IoCManager.InjectDependencies(this); _entityManager.TryGetComponent(entity, out _component); + _switchable = _entityManager.System(); EntityView.SetEntity(entity); TargetPower.IsValid += IsValid; @@ -99,17 +101,16 @@ public sealed partial class GeneratorWindow : FancyWindow StatusLabel.SetOnlyStyleClass("Danger"); } - var canSwitch = _entityManager.TryGetComponent(_entity, out PowerSwitchableGeneratorComponent? switchable); + var canSwitch = _entityManager.TryGetComponent(_entity, out PowerSwitchableComponent? switchable); OutputSwitchLabel.Visible = canSwitch; OutputSwitchButton.Visible = canSwitch; - if (canSwitch) + if (switchable != null) { - var isHV = switchable!.ActiveOutput == PowerSwitchableGeneratorOutput.HV; - OutputSwitchLabel.Text = - Loc.GetString(isHV ? "portable-generator-ui-switch-hv" : "portable-generator-ui-switch-mv"); - OutputSwitchButton.Text = - Loc.GetString(isHV ? "portable-generator-ui-switch-to-mv" : "portable-generator-ui-switch-to-hv"); + var voltage = _switchable.VoltageString(_switchable.GetVoltage(_entity, switchable)); + OutputSwitchLabel.Text = Loc.GetString("portable-generator-ui-current-output", ("voltage", voltage)); + var nextVoltage = _switchable.VoltageString(_switchable.GetNextVoltage(_entity, switchable)); + OutputSwitchButton.Text = Loc.GetString("power-switchable-switch-voltage", ("voltage", nextVoltage)); OutputSwitchButton.Disabled = state.On; } diff --git a/Content.Client/Power/Generator/PowerSwitchableSystem.cs b/Content.Client/Power/Generator/PowerSwitchableSystem.cs new file mode 100644 index 0000000000..b235dee77d --- /dev/null +++ b/Content.Client/Power/Generator/PowerSwitchableSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Power.Generator; + +namespace Content.Client.Power.Generator; + +public sealed class PowerSwitchableSystem : SharedPowerSwitchableSystem +{ +} diff --git a/Content.Client/Preferences/UI/CharacterSetupGui.xaml b/Content.Client/Preferences/UI/CharacterSetupGui.xaml index 5db8610475..9a76029ce0 100644 --- a/Content.Client/Preferences/UI/CharacterSetupGui.xaml +++ b/Content.Client/Preferences/UI/CharacterSetupGui.xaml @@ -10,10 +10,13 @@ - public void Populate(List inventory, string? filter = null) + public void Populate(List inventory, out List filteredInventory, string? filter = null) { + filteredInventory = new(); + if (inventory.Count == 0) { VendingContents.Clear(); @@ -93,6 +93,7 @@ namespace Content.Client.VendingMachines.UI vendingItem.Text = $"{itemName} [{entry.Amount}]"; vendingItem.Icon = icon; + filteredInventory.Add(i); } SetSizeAfterUpdate(longestEntry.Length, inventory.Count); diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs index ab310144d5..6f28ddb31f 100644 --- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs +++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Client.VendingMachines.UI; using Content.Shared.VendingMachines; -using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; using System.Linq; @@ -14,6 +13,9 @@ namespace Content.Client.VendingMachines [ViewVariables] private List _cachedInventory = new(); + [ViewVariables] + private List _cachedFilteredIndex = new(); + public VendingMachineBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -32,7 +34,7 @@ namespace Content.Client.VendingMachines _menu.OnItemSelected += OnItemSelected; _menu.OnSearchChanged += OnSearchChanged; - _menu.Populate(_cachedInventory); + _menu.Populate(_cachedInventory, out _cachedFilteredIndex); _menu.OpenCentered(); } @@ -46,7 +48,7 @@ namespace Content.Client.VendingMachines _cachedInventory = newState.Inventory; - _menu?.Populate(_cachedInventory); + _menu?.Populate(_cachedInventory, out _cachedFilteredIndex, _menu.SearchBar.Text); } private void OnItemSelected(ItemList.ItemListSelectedEventArgs args) @@ -54,7 +56,7 @@ namespace Content.Client.VendingMachines if (_cachedInventory.Count == 0) return; - var selectedItem = _cachedInventory.ElementAtOrDefault(args.ItemIndex); + var selectedItem = _cachedInventory.ElementAtOrDefault(_cachedFilteredIndex.ElementAtOrDefault(args.ItemIndex)); if (selectedItem == null) return; @@ -78,7 +80,7 @@ namespace Content.Client.VendingMachines private void OnSearchChanged(string? filter) { - _menu?.Populate(_cachedInventory, filter); + _menu?.Populate(_cachedInventory, out _cachedFilteredIndex, filter); } } } diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index 397032cd15..2d2883d8b7 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -16,7 +16,8 @@ using Robust.Client.State; using Robust.Shared.Input; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; namespace Content.Client.Weapons.Melee; diff --git a/Content.IntegrationTests/Pair/TestPair.cs b/Content.IntegrationTests/Pair/TestPair.cs index 2971573ff2..2672b4db56 100644 --- a/Content.IntegrationTests/Pair/TestPair.cs +++ b/Content.IntegrationTests/Pair/TestPair.cs @@ -3,13 +3,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Content.Server.GameTicking; -using Content.Server.Players; -using Content.Shared.Mind; using Content.Shared.Players; -using Robust.Server.Player; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.UnitTesting; @@ -30,8 +28,8 @@ public sealed partial class TestPair public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!; public RobustIntegrationTest.ClientIntegrationInstance Client { get; private set; } = default!; - public IPlayerSession? Player => (IPlayerSession?) Server.PlayerMan.Sessions.FirstOrDefault(); - public PlayerData? PlayerData => Player?.Data.ContentData(); + public ICommonSession? Player => Server.PlayerMan.Sessions.FirstOrDefault(); + public ContentPlayerData? PlayerData => Player?.Data.ContentData(); public PoolTestLogHandler ServerLogHandler { get; private set; } = default!; public PoolTestLogHandler ClientLogHandler { get; private set; } = default!; diff --git a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs index 01f8bdd938..01daeea93c 100644 --- a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs +++ b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs @@ -3,8 +3,6 @@ using Content.Shared.Actions; using Content.Shared.CombatMode; using Robust.Server.Player; using Robust.Shared.GameObjects; -using Robust.Shared.Players; -using PlayerManager = Robust.Client.Player.PlayerManager; namespace Content.IntegrationTests.Tests.Actions; @@ -26,7 +24,7 @@ public sealed class ActionsAddedTest var sEntMan = server.ResolveDependency(); var cEntMan = client.ResolveDependency(); var clientSession = client.ResolveDependency().LocalPlayer?.Session; - var serverSession = server.ResolveDependency().ServerSessions.Single(); + var serverSession = server.ResolveDependency().Sessions.Single(); var sActionSystem = server.System(); var cActionSystem = client.System(); diff --git a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs index 6562a26b5e..98c7363a6c 100644 --- a/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs +++ b/Content.IntegrationTests/Tests/Administration/Logs/AddTests.cs @@ -7,8 +7,6 @@ using Content.Shared.Administration.Logs; using Content.Shared.Database; using Robust.Server.Player; using Robust.Shared.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.Utility; namespace Content.IntegrationTests.Tests.Administration.Logs; @@ -177,7 +175,7 @@ public sealed class AddTests await server.WaitPost(() => { - var player = sPlayers.ServerSessions.First(); + var player = sPlayers.Sessions.First(); playerGuid = player.UserId; Assert.DoesNotThrow(() => @@ -280,7 +278,7 @@ public sealed class AddTests await server.WaitPost(() => { - var player = sPlayers.ServerSessions.Single(); + var player = sPlayers.Sessions.Single(); sAdminLogSystem.Add(LogType.Unknown, $"{player} {player} test log: {guid}"); }); @@ -318,7 +316,7 @@ public sealed class AddTests await server.WaitPost(() => { - var player = sPlayers.ServerSessions.Single(); + var player = sPlayers.Sessions.Single(); sAdminLogSystem.Add(LogType.Unknown, $"{player:first} {player:second} test log: {guid}"); }); diff --git a/Content.IntegrationTests/Tests/Administration/Logs/QueryTests.cs b/Content.IntegrationTests/Tests/Administration/Logs/QueryTests.cs index 1155edfad2..5a58757d53 100644 --- a/Content.IntegrationTests/Tests/Administration/Logs/QueryTests.cs +++ b/Content.IntegrationTests/Tests/Administration/Logs/QueryTests.cs @@ -5,6 +5,7 @@ using Content.Server.GameTicking; using Content.Shared.Database; using Robust.Server.Player; using Robust.Shared.GameObjects; +using Robust.Shared.Player; namespace Content.IntegrationTests.Tests.Administration.Logs; @@ -27,11 +28,11 @@ public sealed class QueryTests var date = DateTime.UtcNow; var guid = Guid.NewGuid(); - IPlayerSession player = default; + ICommonSession player = default; await server.WaitPost(() => { - player = sPlayers.ServerSessions.First(); + player = sPlayers.Sessions.First(); sAdminLogSystem.Add(LogType.Unknown, $"{player.AttachedEntity:Entity} test log: {guid}"); }); diff --git a/Content.IntegrationTests/Tests/CargoTest.cs b/Content.IntegrationTests/Tests/CargoTest.cs index 0b9de6993e..66135279d5 100644 --- a/Content.IntegrationTests/Tests/CargoTest.cs +++ b/Content.IntegrationTests/Tests/CargoTest.cs @@ -49,7 +49,7 @@ public sealed class CargoTest await pair.CleanReturnAsync(); } [Test] - public async Task NoCargoBountyArbitageTest() + public async Task NoCargoBountyArbitrageTest() { await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; diff --git a/Content.IntegrationTests/Tests/Cleanup/EuiManagerTest.cs b/Content.IntegrationTests/Tests/Cleanup/EuiManagerTest.cs index 9aac4e2892..e2bff03501 100644 --- a/Content.IntegrationTests/Tests/Cleanup/EuiManagerTest.cs +++ b/Content.IntegrationTests/Tests/Cleanup/EuiManagerTest.cs @@ -25,7 +25,7 @@ public sealed class EuiManagerTest await server.WaitAssertion(() => { - var clientSession = sPlayerManager.ServerSessions.Single(); + var clientSession = sPlayerManager.Sessions.Single(); var ui = new AdminAnnounceEui(); eui.OpenEui(ui, clientSession); }); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index b4b6c2239f..df77410e54 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -14,6 +14,7 @@ using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Mind; +using Content.Shared.Players; using Robust.Client.Input; using Robust.Client.UserInterface; using Robust.Server.GameObjects; @@ -21,7 +22,7 @@ using Robust.Server.Player; using Robust.Shared.GameObjects; using Robust.Shared.Log; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.UnitTesting; @@ -67,7 +68,7 @@ public abstract partial class InteractionTest protected NetEntity Player; protected ICommonSession ClientSession = default!; - protected IPlayerSession ServerSession = default!; + protected ICommonSession ServerSession = default!; public EntityUid? ClientTarget; diff --git a/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs b/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs index 28e49645c9..22a185798e 100644 --- a/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs +++ b/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs @@ -5,6 +5,7 @@ using Content.Server.Ghost.Roles.Components; using Content.Server.Players; using Content.Shared.Ghost; using Content.Shared.Mind; +using Content.Shared.Players; using Robust.Shared.Console; using Robust.Shared.GameObjects; using Robust.Shared.Map; @@ -43,7 +44,7 @@ public sealed class GhostRoleTests var sPlayerMan = server.ResolveDependency(); var conHost = client.ResolveDependency(); var mindSystem = entMan.System(); - var session = sPlayerMan.ServerSessions.Single(); + var session = sPlayerMan.Sessions.Single(); var originalMindId = session.ContentData()!.Mind!.Value; // Spawn player entity & attach diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs b/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs index 9fc68ef93d..a67a45ecb4 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Server.Players; using Content.Shared.Ghost; using Content.Shared.Mind; +using Content.Shared.Players; using Robust.Server.Console; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -35,7 +36,7 @@ public sealed partial class MindTests MindComponent mind = default!; await server.WaitAssertion(() => { - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); playerEnt = entMan.SpawnEntity(null, MapCoordinates.Nullspace); visitEnt = entMan.SpawnEntity(null, MapCoordinates.Nullspace); @@ -81,7 +82,7 @@ public sealed partial class MindTests var entMan = server.ResolveDependency(); var mapManager = server.ResolveDependency(); var playerMan = server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); var mindSystem = entMan.EntitySysManager.GetEntitySystem(); @@ -128,7 +129,7 @@ public sealed partial class MindTests var entMan = server.ResolveDependency(); var playerMan = server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); Assert.That(!entMan.HasComponent(player.AttachedEntity), "Player was initially a ghost?"); @@ -162,7 +163,7 @@ public sealed partial class MindTests var mindSystem = entMan.EntitySysManager.GetEntitySystem(); var mind = GetMind(pair); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); #pragma warning disable NUnit2045 // Interdependent assertions. Assert.That(player.AttachedEntity, Is.Not.Null); Assert.That(entMan.EntityExists(player.AttachedEntity)); @@ -218,7 +219,7 @@ public sealed partial class MindTests var playerMan = server.ResolveDependency(); var serverConsole = server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); var ghost = await BecomeGhost(pair); @@ -263,7 +264,7 @@ public sealed partial class MindTests var playerMan = server.ResolveDependency(); var serverConsole = server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); EntityUid ghost = default!; diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs index f71a6ad5f9..d6b30d60a0 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs @@ -1,14 +1,17 @@ using System.Linq; using Content.IntegrationTests.Pair; +using Content.Server.Mind; using Content.Server.Players; using Content.Shared.Ghost; using Content.Shared.Mind; +using Content.Shared.Players; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.IntegrationTests.Tests.Minds; @@ -36,7 +39,7 @@ public sealed partial class MindTests var playerMan = pair.Server.ResolveDependency(); var mindSys = entMan.System(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); EntityUid entity = default; EntityUid mindId = default!; @@ -71,7 +74,7 @@ public sealed partial class MindTests EntityUid mindId = default!; MindComponent mind = default!; - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); await pair.Server.WaitAssertion(() => { var oldUid = player.AttachedEntity; @@ -116,20 +119,25 @@ public sealed partial class MindTests /// private static (EntityUid Id, MindComponent Comp) GetMind(Pair.TestPair pair) { - var playerMan = pair.Server.ResolveDependency(); - var entMan = pair.Server.ResolveDependency(); - var player = playerMan.ServerSessions.SingleOrDefault(); + var playerMan = pair.Server.PlayerMan; + var entMan = pair.Server.EntMan; + var player = playerMan.Sessions.SingleOrDefault(); Assert.That(player, Is.Not.Null); var mindId = player.ContentData()!.Mind!.Value; Assert.That(mindId, Is.Not.EqualTo(default(EntityUid))); var mind = entMan.GetComponent(mindId); + ActorComponent actor = default!; Assert.Multiple(() => { + Assert.That(player, Is.EqualTo(mind.Session), "Player session does not match mind session"); + Assert.That(entMan.System().GetMind(player.UserId), Is.EqualTo(mindId)); Assert.That(player.AttachedEntity, Is.EqualTo(mind.CurrentEntity), "Player is not attached to the mind's current entity."); Assert.That(entMan.EntityExists(mind.OwnedEntity), "The mind's current entity does not exist"); Assert.That(mind.VisitingEntity == null || entMan.EntityExists(mind.VisitingEntity), "The minds visited entity does not exist."); + Assert.That(entMan.TryGetComponent(mind.CurrentEntity, out actor)); }); + Assert.That(actor.PlayerSession, Is.EqualTo(mind.Session)); return (mindId, mind); } @@ -139,7 +147,7 @@ public sealed partial class MindTests var netManager = pair.Client.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); var entMan = pair.Server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); var mindId = player.ContentData()!.Mind!.Value; var mind = entMan.GetComponent(mindId); @@ -161,21 +169,21 @@ public sealed partial class MindTests { var netManager = pair.Client.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); - Assert.That(!playerMan.ServerSessions.Any()); + Assert.That(!playerMan.Sessions.Any()); await Task.WhenAll(pair.Client.WaitIdleAsync(), pair.Client.WaitIdleAsync()); pair.Client.SetConnectTarget(pair.Server); await pair.Client.WaitPost(() => netManager.ClientConnect(null!, 0, username)); await pair.RunTicksSync(5); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); Assert.That(player.Status, Is.EqualTo(SessionStatus.InGame)); } - private static async Task DisconnectReconnect(Pair.TestPair pair) + private static async Task DisconnectReconnect(Pair.TestPair pair) { var playerMan = pair.Server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); var name = player.Name; var id = player.UserId; @@ -183,7 +191,7 @@ public sealed partial class MindTests await Connect(pair, name); // Session has changed - var newSession = playerMan.ServerSessions.Single(); + var newSession = playerMan.Sessions.Single(); Assert.Multiple(() => { Assert.That(newSession, Is.Not.EqualTo(player)); diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.ReconnectTests.cs b/Content.IntegrationTests/Tests/Minds/MindTests.ReconnectTests.cs index ea2110c03a..3cac766825 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.ReconnectTests.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.ReconnectTests.cs @@ -1,6 +1,8 @@ using System.Linq; using Content.Shared.Ghost; using Content.Shared.Mind; +using NUnit.Framework.Interfaces; +using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.GameObjects; using Robust.Shared.Map; @@ -49,7 +51,7 @@ public sealed partial class MindTests var mind = GetMind(pair); var playerMan = pair.Server.ResolveDependency(); - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); var name = player.Name; var user = player.UserId; Assert.That(mind.Comp.OwnedEntity, Is.Not.Null); @@ -72,7 +74,7 @@ public sealed partial class MindTests // Reconnect await Connect(pair, name); - player = playerMan.ServerSessions.Single(); + player = playerMan.Sessions.Single(); Assert.Multiple(() => { Assert.That(user, Is.EqualTo(player.UserId)); @@ -127,8 +129,10 @@ public sealed partial class MindTests var mindSys = entMan.System(); var mind = GetMind(pair); + Assert.Null(mind.Comp.VisitingEntity); + // Make player visit a new mob - var original = mind.Comp.CurrentEntity; + var original = mind.Comp.OwnedEntity; EntityUid visiting = default; await pair.Server.WaitAssertion(() => { @@ -137,6 +141,7 @@ public sealed partial class MindTests }); await pair.RunTicksSync(5); + Assert.That(mind.Comp.VisitingEntity, Is.EqualTo(visiting)); await DisconnectReconnect(pair); // Player is back in control of the visited mob, mind was preserved @@ -150,4 +155,32 @@ public sealed partial class MindTests await pair.CleanReturnAsync(); } + + // This test will do the following + // - connect as a normal player + // - disconnect + // - reconnect + // - assert that they return to the original entity. + [Test] + public async Task TestReconnect() + { + await using var pair = await SetupPair(); + var mind = GetMind(pair); + + Assert.Null(mind.Comp.VisitingEntity); + Assert.NotNull(mind.Comp.OwnedEntity); + var entity = mind.Comp.OwnedEntity; + + await pair.RunTicksSync(5); + await DisconnectReconnect(pair); + await pair.RunTicksSync(5); + + var newMind = GetMind(pair); + + Assert.Null(newMind.Comp.VisitingEntity); + Assert.That(newMind.Comp.OwnedEntity, Is.EqualTo(entity)); + Assert.That(newMind.Id, Is.EqualTo(mind.Id)); + + await pair.CleanReturnAsync(); + } } diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.cs b/Content.IntegrationTests/Tests/Minds/MindTests.cs index 3ad61bcdf0..c9788b80a6 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.cs @@ -11,6 +11,7 @@ using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; using Content.Shared.Mind; using Content.Shared.Mind.Components; +using Content.Shared.Players; using Content.Shared.Roles; using Content.Shared.Roles.Jobs; using Robust.Server.Console; @@ -345,7 +346,7 @@ public sealed partial class MindTests EntityUid entity = default!; EntityUid mindId = default!; MindComponent mind = default!; - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); await server.WaitAssertion(() => { @@ -406,12 +407,6 @@ public sealed partial class MindTests await pair.CleanReturnAsync(); } - // TODO Implement - /*[Test] - public async Task TestPlayerCanReturnFromGhostWhenDead() - { - }*/ - [Test] public async Task TestGhostDoesNotInfiniteLoop() { @@ -432,7 +427,7 @@ public sealed partial class MindTests EntityUid ghost = default!; EntityUid mindId = default!; MindComponent mind = default!; - var player = playerMan.ServerSessions.Single(); + var player = playerMan.Sessions.Single(); await server.WaitAssertion(() => { diff --git a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs index ca7eeac199..d6aec781a9 100644 --- a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs +++ b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs @@ -2,8 +2,7 @@ using System.Collections.Generic; using Content.IntegrationTests.Pair; using Content.Server.Administration.Managers; -using Robust.Server.Player; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Errors; using Robust.Shared.Toolshed.Syntax; @@ -60,7 +59,7 @@ public abstract class ToolshedTest : IInvocationContext AdminManager = Server.ResolveDependency(); } - protected bool InvokeCommand(string command, out object? result, IPlayerSession? session = null) + protected bool InvokeCommand(string command, out object? result, ICommonSession? session = null) { return Toolshed.InvokeCommand(this, command, null, out result); } @@ -95,7 +94,7 @@ public abstract class ToolshedTest : IInvocationContext return true; } - protected IPlayerSession? InvocationSession { get; set; } + protected ICommonSession? InvocationSession { get; set; } public ICommonSession? Session { diff --git a/Content.MapRenderer/Painters/MapPainter.cs b/Content.MapRenderer/Painters/MapPainter.cs index b799db78a5..8f3dd59baf 100644 --- a/Content.MapRenderer/Painters/MapPainter.cs +++ b/Content.MapRenderer/Painters/MapPainter.cs @@ -68,7 +68,7 @@ namespace Content.MapRenderer.Painters await server.WaitPost(() => { - var playerEntity = sPlayerManager.ServerSessions.Single().AttachedEntity; + var playerEntity = sPlayerManager.Sessions.Single().AttachedEntity; if (playerEntity.HasValue) { diff --git a/Content.PatreonParser/Program.cs b/Content.PatreonParser/Program.cs index 60a320006f..ff6646eda3 100644 --- a/Content.PatreonParser/Program.cs +++ b/Content.PatreonParser/Program.cs @@ -80,7 +80,7 @@ foreach (var record in reader.GetRecords()) var tier = tiers[0]; var tierName = content.Included.SingleOrDefault(i => i.Id == tier.Id && i.Type == tier.Type)?.Attributes.Title; - if (tierName == null) + if (tierName == null || tierName == "Free") continue; if (record.Trigger == "members:delete") diff --git a/Content.Server/Access/Systems/AccessOverriderSystem.cs b/Content.Server/Access/Systems/AccessOverriderSystem.cs index 3ec767c200..147ac70a6d 100644 --- a/Content.Server/Access/Systems/AccessOverriderSystem.cs +++ b/Content.Server/Access/Systems/AccessOverriderSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Interaction; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; +using Robust.Shared.Player; using static Content.Shared.Access.Components.AccessOverriderComponent; namespace Content.Server.Access.Systems; diff --git a/Content.Server/Administration/AdminPermsChangedEventArgs.cs b/Content.Server/Administration/AdminPermsChangedEventArgs.cs index 24ca7aca68..07eb416be6 100644 --- a/Content.Server/Administration/AdminPermsChangedEventArgs.cs +++ b/Content.Server/Administration/AdminPermsChangedEventArgs.cs @@ -1,5 +1,5 @@ using Content.Shared.Administration; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Administration { @@ -8,7 +8,7 @@ namespace Content.Server.Administration /// public sealed class AdminPermsChangedEventArgs : EventArgs { - public AdminPermsChangedEventArgs(IPlayerSession player, AdminFlags? flags) + public AdminPermsChangedEventArgs(ICommonSession player, AdminFlags? flags) { Player = player; Flags = flags; @@ -17,7 +17,7 @@ namespace Content.Server.Administration /// /// The player that had their admin permissions changed. /// - public IPlayerSession Player { get; } + public ICommonSession Player { get; } /// /// The admin flags of the player. Null if the player is no longer an admin. diff --git a/Content.Server/Administration/Commands/AGhost.cs b/Content.Server/Administration/Commands/AGhost.cs index 42a8600ff1..2d1a15a0be 100644 --- a/Content.Server/Administration/Commands/AGhost.cs +++ b/Content.Server/Administration/Commands/AGhost.cs @@ -2,7 +2,6 @@ using Content.Shared.Administration; using Content.Shared.Ghost; using Content.Shared.Mind; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -18,7 +17,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("Nah"); diff --git a/Content.Server/Administration/Commands/AdminWhoCommand.cs b/Content.Server/Administration/Commands/AdminWhoCommand.cs index 8e6c402c4e..9765e8385f 100644 --- a/Content.Server/Administration/Commands/AdminWhoCommand.cs +++ b/Content.Server/Administration/Commands/AdminWhoCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Administration.Managers; using Content.Server.Afk; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Utility; @@ -35,7 +34,7 @@ public sealed class AdminWhoCommand : IConsoleCommand if (adminData.Title is { } title) sb.Append($": [{title}]"); - if (shell.Player is IPlayerSession player && adminMgr.HasAdminFlag(player, AdminFlags.Admin)) + if (shell.Player is { } player && adminMgr.HasAdminFlag(player, AdminFlags.Admin)) { if (afk.IsAfk(admin)) sb.Append(" [AFK]"); diff --git a/Content.Server/Administration/Commands/AnnounceUiCommand.cs b/Content.Server/Administration/Commands/AnnounceUiCommand.cs index c4cd7f13e4..d80db96686 100644 --- a/Content.Server/Administration/Commands/AnnounceUiCommand.cs +++ b/Content.Server/Administration/Commands/AnnounceUiCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration.UI; using Content.Server.EUI; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -17,7 +16,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("This does not work from the server console."); diff --git a/Content.Server/Administration/Commands/BanCommand.cs b/Content.Server/Administration/Commands/BanCommand.cs index 58a801e410..156fdf496a 100644 --- a/Content.Server/Administration/Commands/BanCommand.cs +++ b/Content.Server/Administration/Commands/BanCommand.cs @@ -1,15 +1,8 @@ using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Text; using Content.Server.Administration.Managers; -using Content.Server.Administration.Notes; -using Content.Server.Database; -using Content.Server.GameTicking; using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.Database; -using Content.Shared.Players.PlayTimeTracking; using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; @@ -84,7 +77,7 @@ public sealed class BanCommand : LocalizedCommands } var located = await _locator.LookupIdByNameOrIdAsync(target); - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (located == null) { @@ -102,7 +95,7 @@ public sealed class BanCommand : LocalizedCommands { if (args.Length == 1) { - var options = _playerManager.ServerSessions.Select(c => c.Name).OrderBy(c => c).ToArray(); + var options = _playerManager.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray(); return CompletionResult.FromHintOptions(options, LocalizationManager.GetString("cmd-ban-hint")); } diff --git a/Content.Server/Administration/Commands/BanListCommand.cs b/Content.Server/Administration/Commands/BanListCommand.cs index 1c2be52394..a5bc97dce3 100644 --- a/Content.Server/Administration/Commands/BanListCommand.cs +++ b/Content.Server/Administration/Commands/BanListCommand.cs @@ -36,7 +36,7 @@ public sealed class BanListCommand : LocalizedCommands return; } - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { var bans = await _dbManager.GetServerBansAsync(data.LastAddress, data.UserId, data.LastHWId, false); @@ -67,7 +67,7 @@ public sealed class BanListCommand : LocalizedCommands return CompletionResult.Empty; var playerMgr = IoCManager.Resolve(); - var options = playerMgr.ServerSessions.Select(c => c.Name).OrderBy(c => c).ToArray(); + var options = playerMgr.Sessions.Select(c => c.Name).OrderBy(c => c).ToArray(); return CompletionResult.FromHintOptions(options, Loc.GetString("cmd-banlist-hint")); } } diff --git a/Content.Server/Administration/Commands/BanPanelCommand.cs b/Content.Server/Administration/Commands/BanPanelCommand.cs index 6036e5aa6e..9f9ec9e89f 100644 --- a/Content.Server/Administration/Commands/BanPanelCommand.cs +++ b/Content.Server/Administration/Commands/BanPanelCommand.cs @@ -1,12 +1,6 @@ using Content.Shared.Administration; using Robust.Shared.Console; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Content.Server.EUI; -using Robust.Server.Player; namespace Content.Server.Administration.Commands; @@ -21,7 +15,7 @@ public sealed class BanPanelCommand : LocalizedCommands public override async void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError(Loc.GetString("cmd-banpanel-server")); return; diff --git a/Content.Server/Administration/Commands/ControlMob.cs b/Content.Server/Administration/Commands/ControlMob.cs index 8fc74c61d4..317461a373 100644 --- a/Content.Server/Administration/Commands/ControlMob.cs +++ b/Content.Server/Administration/Commands/ControlMob.cs @@ -1,6 +1,5 @@ using Content.Server.Mind; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -16,7 +15,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteLine("shell-server-cannot"); return; diff --git a/Content.Server/Administration/Commands/DSay.cs b/Content.Server/Administration/Commands/DSay.cs index 79b0e8db7d..61b47d7856 100644 --- a/Content.Server/Administration/Commands/DSay.cs +++ b/Content.Server/Administration/Commands/DSay.cs @@ -1,7 +1,5 @@ -using Content.Server.Chat; using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -17,7 +15,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("shell-only-players-can-run-this-command"); diff --git a/Content.Server/Administration/Commands/DeAdminCommand.cs b/Content.Server/Administration/Commands/DeAdminCommand.cs index c2bbfa7a33..cf65941200 100644 --- a/Content.Server/Administration/Commands/DeAdminCommand.cs +++ b/Content.Server/Administration/Commands/DeAdminCommand.cs @@ -1,10 +1,8 @@ using Content.Server.Administration.Managers; using Content.Shared.Administration; using JetBrains.Annotations; -using Robust.Server.Player; using Robust.Shared.Console; - namespace Content.Server.Administration.Commands { [UsedImplicitly] @@ -17,7 +15,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You cannot use this command from the server console."); diff --git a/Content.Server/Administration/Commands/ExplosionCommand.cs b/Content.Server/Administration/Commands/ExplosionCommand.cs index d48b69a5ad..56ed78b2e2 100644 --- a/Content.Server/Administration/Commands/ExplosionCommand.cs +++ b/Content.Server/Administration/Commands/ExplosionCommand.cs @@ -3,7 +3,6 @@ using Content.Server.EUI; using Content.Server.Explosion.EntitySystems; using Content.Shared.Administration; using Content.Shared.Explosion; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -21,7 +20,7 @@ public sealed class OpenExplosionEui : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteError("This does not work from the server console."); diff --git a/Content.Server/Administration/Commands/FaxUiCommand.cs b/Content.Server/Administration/Commands/FaxUiCommand.cs index b06d36d08b..cf9e97e399 100644 --- a/Content.Server/Administration/Commands/FaxUiCommand.cs +++ b/Content.Server/Administration/Commands/FaxUiCommand.cs @@ -1,7 +1,6 @@ using Content.Server.EUI; using Content.Server.Fax.AdminUI; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands; @@ -16,7 +15,7 @@ public sealed class FaxUiCommand : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("shell-only-players-can-run-this-command"); diff --git a/Content.Server/Administration/Commands/OpenAdminLogsCommand.cs b/Content.Server/Administration/Commands/OpenAdminLogsCommand.cs index 9f28dc907c..47ff3e1a1c 100644 --- a/Content.Server/Administration/Commands/OpenAdminLogsCommand.cs +++ b/Content.Server/Administration/Commands/OpenAdminLogsCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration.Logs; using Content.Server.EUI; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands; @@ -15,7 +14,7 @@ public sealed class OpenAdminLogsCommand : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteLine("This does not work from the server console."); return; diff --git a/Content.Server/Administration/Commands/OpenAdminNotesCommand.cs b/Content.Server/Administration/Commands/OpenAdminNotesCommand.cs index 147c0d6a82..e6ae4f7616 100644 --- a/Content.Server/Administration/Commands/OpenAdminNotesCommand.cs +++ b/Content.Server/Administration/Commands/OpenAdminNotesCommand.cs @@ -1,7 +1,5 @@ using Content.Server.Administration.Notes; -using Content.Server.Database; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands; @@ -17,7 +15,7 @@ public sealed class OpenAdminNotesCommand : IConsoleCommand public async void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This does not work from the server console."); return; diff --git a/Content.Server/Administration/Commands/OpenPermissionsCommand.cs b/Content.Server/Administration/Commands/OpenPermissionsCommand.cs index 78d56cb4fb..fd3227d4aa 100644 --- a/Content.Server/Administration/Commands/OpenPermissionsCommand.cs +++ b/Content.Server/Administration/Commands/OpenPermissionsCommand.cs @@ -1,10 +1,8 @@ using Content.Server.Administration.UI; using Content.Server.EUI; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; - namespace Content.Server.Administration.Commands { [AdminCommand(AdminFlags.Permissions)] @@ -16,7 +14,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("This does not work from the server console."); diff --git a/Content.Server/Administration/Commands/OpenUserVisibleNotesCommand.cs b/Content.Server/Administration/Commands/OpenUserVisibleNotesCommand.cs index d61114fcae..507c7ab279 100644 --- a/Content.Server/Administration/Commands/OpenUserVisibleNotesCommand.cs +++ b/Content.Server/Administration/Commands/OpenUserVisibleNotesCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration.Notes; using Content.Shared.Administration; using Content.Shared.CCVar; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; @@ -27,7 +26,7 @@ public sealed class OpenUserVisibleNotesCommand : IConsoleCommand return; } - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This does not work from the server console."); return; diff --git a/Content.Server/Administration/Commands/PardonCommand.cs b/Content.Server/Administration/Commands/PardonCommand.cs index 869024eb7c..9cbaaece31 100644 --- a/Content.Server/Administration/Commands/PardonCommand.cs +++ b/Content.Server/Administration/Commands/PardonCommand.cs @@ -1,7 +1,6 @@ using System.Text; using Content.Server.Database; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -15,7 +14,7 @@ namespace Content.Server.Administration.Commands public async void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; var dbMan = IoCManager.Resolve(); if (args.Length != 1) diff --git a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs index ec5b21dcee..fdf067181d 100644 --- a/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs +++ b/Content.Server/Administration/Commands/PlayGlobalSoundCommand.cs @@ -6,7 +6,6 @@ using Robust.Shared.Audio; using Robust.Shared.Console; using Robust.Shared.ContentPack; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Prototypes; namespace Content.Server.Administration.Commands; diff --git a/Content.Server/Administration/Commands/ReAdminCommand.cs b/Content.Server/Administration/Commands/ReAdminCommand.cs index 12ff13221a..a3f5993766 100644 --- a/Content.Server/Administration/Commands/ReAdminCommand.cs +++ b/Content.Server/Administration/Commands/ReAdminCommand.cs @@ -1,9 +1,7 @@ using Content.Server.Administration.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; - namespace Content.Server.Administration.Commands { [AnyCommand] @@ -15,7 +13,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You cannot use this command from the server console."); diff --git a/Content.Server/Administration/Commands/SetAdminOOC.cs b/Content.Server/Administration/Commands/SetAdminOOC.cs index bb11b938d8..27528e1940 100644 --- a/Content.Server/Administration/Commands/SetAdminOOC.cs +++ b/Content.Server/Administration/Commands/SetAdminOOC.cs @@ -1,8 +1,6 @@ - using Content.Server.Database; using Content.Server.Preferences.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Administration.Commands @@ -16,7 +14,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (!(shell.Player is IPlayerSession)) + if (shell.Player == null) { shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); return; diff --git a/Content.Server/Administration/Commands/SetMindCommand.cs b/Content.Server/Administration/Commands/SetMindCommand.cs index b9ff329ed2..5310c2dd7f 100644 --- a/Content.Server/Administration/Commands/SetMindCommand.cs +++ b/Content.Server/Administration/Commands/SetMindCommand.cs @@ -2,6 +2,7 @@ using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.Mind; using Content.Shared.Mind.Components; +using Content.Shared.Players; using Robust.Server.Player; using Robust.Shared.Console; diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs index 28172ee6c5..97c1fa0656 100644 --- a/Content.Server/Administration/Commands/SetOutfitCommand.cs +++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs @@ -9,9 +9,8 @@ using Content.Shared.Inventory; using Content.Shared.PDA; using Content.Shared.Preferences; using Content.Shared.Roles; -using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Console; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.Administration.Commands @@ -57,7 +56,7 @@ namespace Content.Server.Administration.Commands if (args.Length == 1) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError(Loc.GetString("set-outfit-command-is-not-player-error")); return; diff --git a/Content.Server/Administration/Commands/WarpCommand.cs b/Content.Server/Administration/Commands/WarpCommand.cs index 30a6d127aa..0d6da0d993 100644 --- a/Content.Server/Administration/Commands/WarpCommand.cs +++ b/Content.Server/Administration/Commands/WarpCommand.cs @@ -4,11 +4,9 @@ using Content.Server.Warps; using Content.Shared.Administration; using Content.Shared.Follower; using Content.Shared.Ghost; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Map; -using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -28,7 +26,7 @@ namespace Content.Server.Administration.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("Only players can use this command"); diff --git a/Content.Server/Administration/ContentNetworkResourceManager.cs b/Content.Server/Administration/ContentNetworkResourceManager.cs index 0d3f3291e6..dd95a2d897 100644 --- a/Content.Server/Administration/ContentNetworkResourceManager.cs +++ b/Content.Server/Administration/ContentNetworkResourceManager.cs @@ -1,8 +1,8 @@ using Content.Server.Database; using Content.Shared.CCVar; -using Robust.Server.Player; using Robust.Server.Upload; using Robust.Shared.Configuration; +using Robust.Shared.Player; using Robust.Shared.Upload; namespace Content.Server.Administration; @@ -22,7 +22,7 @@ public sealed class ContentNetworkResourceManager _netRes.OnResourceUploaded += OnUploadResource; } - private async void OnUploadResource(IPlayerSession session, NetworkResourceUploadMessage msg) + private async void OnUploadResource(ICommonSession session, NetworkResourceUploadMessage msg) { if (StoreUploaded) await _serverDb.AddUploadedResourceLogAsync(session.UserId, DateTime.Now, msg.RelativePath.ToString(), msg.Data); diff --git a/Content.Server/Administration/Logs/AdminLogManager.Json.cs b/Content.Server/Administration/Logs/AdminLogManager.Json.cs index 63f30c7a66..0a67d61cef 100644 --- a/Content.Server/Administration/Logs/AdminLogManager.Json.cs +++ b/Content.Server/Administration/Logs/AdminLogManager.Json.cs @@ -3,8 +3,8 @@ using System.Text.Json; using System.Text.Json.Serialization; using Content.Server.Administration.Logs.Converters; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Map; +using Robust.Shared.Player; namespace Content.Server.Administration.Logs; @@ -44,7 +44,7 @@ public sealed partial class AdminLogManager var value = properties[key]; value = value switch { - IPlayerSession player => new SerializablePlayer(player), + ICommonSession player => new SerializablePlayer(player), EntityCoordinates entityCoordinates => new SerializableEntityCoordinates(_entityManager, entityCoordinates), _ => value }; @@ -56,7 +56,7 @@ public sealed partial class AdminLogManager { EntityUid id => id, EntityStringRepresentation rep => rep.Uid, - IPlayerSession {AttachedEntity: {Valid: true}} session => session.AttachedEntity, + ICommonSession {AttachedEntity: {Valid: true}} session => session.AttachedEntity, IComponent component => component.Owner, _ => null }; diff --git a/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs b/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs index 2fc1a2b627..78d81af33c 100644 --- a/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs +++ b/Content.Server/Administration/Logs/Converters/EntityUidConverter.cs @@ -1,5 +1,5 @@ using System.Text.Json; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Administration.Logs.Converters; diff --git a/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs b/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs index 0605c2db2a..c1567448cc 100644 --- a/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs +++ b/Content.Server/Administration/Logs/Converters/PlayerSessionConverter.cs @@ -1,5 +1,5 @@ using System.Text.Json; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Administration.Logs.Converters; @@ -36,9 +36,9 @@ public sealed class PlayerSessionConverter : AdminLogConverter _admins = new(); + private readonly Dictionary _admins = new(); private readonly HashSet _promotedPlayers = new(); public event Action? OnPermsChanged; - public IEnumerable ActiveAdmins => _admins + public IEnumerable ActiveAdmins => _admins .Where(p => p.Value.Data.Active) .Select(p => p.Key); - public IEnumerable AllAdmins => _admins.Select(p => p.Key); + public IEnumerable AllAdmins => _admins.Select(p => p.Key); private readonly AdminCommandPermissions _commandPermissions = new(); private readonly AdminCommandPermissions _toolshedCommandPermissions = new(); @@ -56,7 +56,7 @@ namespace Content.Server.Administration.Managers public AdminData? GetAdminData(ICommonSession session, bool includeDeAdmin = false) { - if (_admins.TryGetValue((IPlayerSession)session, out var reg) && (reg.Data.Active || includeDeAdmin)) + if (_admins.TryGetValue(session, out var reg) && (reg.Data.Active || includeDeAdmin)) { return reg.Data; } @@ -66,13 +66,13 @@ namespace Content.Server.Administration.Managers public AdminData? GetAdminData(EntityUid uid, bool includeDeAdmin = false) { - if (_playerManager.TryGetSessionByEntity(uid, out var session) && session is IPlayerSession playerSession) - return GetAdminData(playerSession, includeDeAdmin); + if (_playerManager.TryGetSessionByEntity(uid, out var session)) + return GetAdminData(session, includeDeAdmin); return null; } - public void DeAdmin(IPlayerSession session) + public void DeAdmin(ICommonSession session) { if (!_admins.TryGetValue(session, out var reg)) { @@ -95,7 +95,7 @@ namespace Content.Server.Administration.Managers UpdateAdminStatus(session); } - public void ReAdmin(IPlayerSession session) + public void ReAdmin(ICommonSession session) { if (!_admins.TryGetValue(session, out var reg)) { @@ -119,7 +119,7 @@ namespace Content.Server.Administration.Managers UpdateAdminStatus(session); } - public async void ReloadAdmin(IPlayerSession player) + public async void ReloadAdmin(ICommonSession player) { var data = await LoadAdminData(player); var curAdmin = _admins.GetValueOrDefault(player); @@ -236,7 +236,7 @@ namespace Content.Server.Administration.Managers _toolshed.ActivePermissionController = this; } - public void PromoteHost(IPlayerSession player) + public void PromoteHost(ICommonSession player) { _promotedPlayers.Add(player.UserId); @@ -250,7 +250,7 @@ namespace Content.Server.Administration.Managers } // NOTE: Also sends commands list for non admins.. - private void UpdateAdminStatus(IPlayerSession session) + private void UpdateAdminStatus(ICommonSession session) { var msg = new MsgUpdateAdminStatus(); @@ -290,7 +290,7 @@ namespace Content.Server.Administration.Managers } } - private async void LoginAdminMaybe(IPlayerSession session) + private async void LoginAdminMaybe(ICommonSession session) { var adminDat = await LoadAdminData(session); if (adminDat == null) @@ -323,7 +323,7 @@ namespace Content.Server.Administration.Managers UpdateAdminStatus(session); } - private async Task<(AdminData dat, int? rankId, bool specialLogin)?> LoadAdminData(IPlayerSession session) + private async Task<(AdminData dat, int? rankId, bool specialLogin)?> LoadAdminData(ICommonSession session) { var promoteHost = IsLocal(session) && _cfg.GetCVar(CCVars.ConsoleLoginLocal) || _promotedPlayers.Contains(session.UserId) @@ -387,7 +387,7 @@ namespace Content.Server.Administration.Managers } } - private static bool IsLocal(IPlayerSession player) + private static bool IsLocal(ICommonSession player) { var ep = player.ConnectedClient.RemoteEndPoint; var addr = ep.Address; @@ -419,7 +419,7 @@ namespace Content.Server.Administration.Managers return false; } - public bool CanCommand(IPlayerSession session, string cmdName) + public bool CanCommand(ICommonSession session, string cmdName) { if (_commandPermissions.AnyCommands.Contains(cmdName)) { @@ -474,7 +474,7 @@ namespace Content.Server.Administration.Managers return true; } - var data = GetAdminData((IPlayerSession)user); + var data = GetAdminData(user); if (data == null) { // Player isn't an admin. @@ -520,32 +520,32 @@ namespace Content.Server.Administration.Managers return (attribs.Length != 0, attribs); } - public bool CanViewVar(IPlayerSession session) + public bool CanViewVar(ICommonSession session) { return CanCommand(session, "vv"); } - public bool CanAdminPlace(IPlayerSession session) + public bool CanAdminPlace(ICommonSession session) { return GetAdminData(session)?.CanAdminPlace() ?? false; } - public bool CanScript(IPlayerSession session) + public bool CanScript(ICommonSession session) { return GetAdminData(session)?.CanScript() ?? false; } - public bool CanAdminMenu(IPlayerSession session) + public bool CanAdminMenu(ICommonSession session) { return GetAdminData(session)?.CanAdminMenu() ?? false; } - public bool CanAdminReloadPrototypes(IPlayerSession session) + public bool CanAdminReloadPrototypes(ICommonSession session) { return GetAdminData(session)?.CanAdminReloadPrototypes() ?? false; } - private void SendPermsChangedEvent(IPlayerSession session) + private void SendPermsChangedEvent(ICommonSession session) { var flags = GetAdminData(session)?.Flags; OnPermsChanged?.Invoke(new AdminPermsChangedEventArgs(session, flags)); @@ -553,7 +553,7 @@ namespace Content.Server.Administration.Managers private sealed class AdminReg { - public readonly IPlayerSession Session; + public readonly ICommonSession Session; public AdminData Data; public int? RankId; @@ -561,7 +561,7 @@ namespace Content.Server.Administration.Managers // Such as console.loginlocal or promotehost public bool IsSpecialLogin; - public AdminReg(IPlayerSession session, AdminData data) + public AdminReg(ICommonSession session, AdminData data) { Data = data; Session = session; diff --git a/Content.Server/Administration/Managers/BanManager.cs b/Content.Server/Administration/Managers/BanManager.cs index 765df17b17..4d51d35576 100644 --- a/Content.Server/Administration/Managers/BanManager.cs +++ b/Content.Server/Administration/Managers/BanManager.cs @@ -15,6 +15,7 @@ using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -283,7 +284,7 @@ public sealed class BanManager : IBanManager, IPostInjectInit SendRoleBans(player); } - public void SendRoleBans(IPlayerSession pSession) + public void SendRoleBans(ICommonSession pSession) { var roleBans = _cachedRoleBans.GetValueOrDefault(pSession.UserId) ?? new HashSet(); var bans = new MsgRoleBans() diff --git a/Content.Server/Administration/Managers/IAdminManager.cs b/Content.Server/Administration/Managers/IAdminManager.cs index eeed5cc36e..a52ec7b099 100644 --- a/Content.Server/Administration/Managers/IAdminManager.cs +++ b/Content.Server/Administration/Managers/IAdminManager.cs @@ -1,9 +1,8 @@ using Content.Shared.Administration; using Content.Shared.Administration.Managers; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Toolshed; - namespace Content.Server.Administration.Managers { /// @@ -22,12 +21,12 @@ namespace Content.Server.Administration.Managers /// /// This does not include admins that are de-adminned. /// - IEnumerable ActiveAdmins { get; } + IEnumerable ActiveAdmins { get; } /// /// Gets all admins currently on the server, even de-adminned ones. /// - IEnumerable AllAdmins { get; } + IEnumerable AllAdmins { get; } /// /// De-admins an admin temporarily so they are effectively a normal player. @@ -35,18 +34,18 @@ namespace Content.Server.Administration.Managers /// /// De-adminned admins are able to re-admin at any time if they so desire. /// - void DeAdmin(IPlayerSession session); + void DeAdmin(ICommonSession session); /// /// Re-admins a de-adminned admin. /// - void ReAdmin(IPlayerSession session); + void ReAdmin(ICommonSession session); /// /// Re-loads the permissions of an player in case their admin data changed DB-side. /// /// - void ReloadAdmin(IPlayerSession player); + void ReloadAdmin(ICommonSession player); /// /// Reloads admin permissions for all admins with a certain rank. @@ -57,7 +56,7 @@ namespace Content.Server.Administration.Managers void Initialize(); - void PromoteHost(IPlayerSession player); + void PromoteHost(ICommonSession player); bool TryGetCommandFlags(CommandSpec command, out AdminFlags[]? flags); } diff --git a/Content.Server/Administration/Managers/IBanManager.cs b/Content.Server/Administration/Managers/IBanManager.cs index 8458feac8d..dafe3d35bd 100644 --- a/Content.Server/Administration/Managers/IBanManager.cs +++ b/Content.Server/Administration/Managers/IBanManager.cs @@ -2,8 +2,8 @@ using System.Collections.Immutable; using System.Net; using System.Threading.Tasks; using Content.Shared.Database; -using Robust.Server.Player; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.Administration.Managers; @@ -55,5 +55,5 @@ public interface IBanManager /// Sends role bans to the target /// /// Player's session - public void SendRoleBans(IPlayerSession pSession); + public void SendRoleBans(ICommonSession pSession); } diff --git a/Content.Server/Administration/Notes/AdminNotesManager.cs b/Content.Server/Administration/Notes/AdminNotesManager.cs index 8a7846663f..0c1e7f3daa 100644 --- a/Content.Server/Administration/Notes/AdminNotesManager.cs +++ b/Content.Server/Administration/Notes/AdminNotesManager.cs @@ -11,7 +11,7 @@ using Content.Shared.Database; using Content.Shared.Players.PlayTimeTracking; using Robust.Shared.Configuration; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Administration.Notes; diff --git a/Content.Server/Administration/Notes/AdminNotesSystem.cs b/Content.Server/Administration/Notes/AdminNotesSystem.cs index fd9f3f6bfa..f2eb033dca 100644 --- a/Content.Server/Administration/Notes/AdminNotesSystem.cs +++ b/Content.Server/Administration/Notes/AdminNotesSystem.cs @@ -1,13 +1,13 @@ using Content.Server.Administration.Commands; using Content.Server.Chat.Managers; using Content.Server.EUI; -using Content.Shared.Chat; using Content.Shared.Database; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Administration.Notes; diff --git a/Content.Server/Administration/Notes/IAdminNotesManager.cs b/Content.Server/Administration/Notes/IAdminNotesManager.cs index ae7133c56d..a726bd11c8 100644 --- a/Content.Server/Administration/Notes/IAdminNotesManager.cs +++ b/Content.Server/Administration/Notes/IAdminNotesManager.cs @@ -2,7 +2,7 @@ using System.Threading.Tasks; using Content.Server.Database; using Content.Shared.Administration.Notes; using Content.Shared.Database; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Administration.Notes; diff --git a/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs b/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs index 521bee776f..fb013a88ad 100644 --- a/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs +++ b/Content.Server/Administration/QuickDialogSystem.OpenDialog.cs @@ -1,6 +1,6 @@ using Content.Shared.Administration; using JetBrains.Annotations; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Administration; @@ -16,7 +16,7 @@ public sealed partial class QuickDialogSystem /// The action to execute upon the dialog being cancelled. /// Type of the input. [PublicAPI] - public void OpenDialog(IPlayerSession session, string title, string prompt, Action okAction, + public void OpenDialog(ICommonSession session, string title, string prompt, Action okAction, Action? cancelAction = null) { OpenDialogInternal( @@ -53,7 +53,7 @@ public sealed partial class QuickDialogSystem /// Type of the first input. /// Type of the second input. [PublicAPI] - public void OpenDialog(IPlayerSession session, string title, string prompt1, string prompt2, + public void OpenDialog(ICommonSession session, string title, string prompt1, string prompt2, Action okAction, Action? cancelAction = null) { OpenDialogInternal( @@ -96,7 +96,7 @@ public sealed partial class QuickDialogSystem /// Type of the second input. /// Type of the third input. [PublicAPI] - public void OpenDialog(IPlayerSession session, string title, string prompt1, string prompt2, + public void OpenDialog(ICommonSession session, string title, string prompt1, string prompt2, string prompt3, Action okAction, Action? cancelAction = null) { OpenDialogInternal( @@ -142,7 +142,7 @@ public sealed partial class QuickDialogSystem /// Type of the third input. /// Type of the fourth input. [PublicAPI] - public void OpenDialog(IPlayerSession session, string title, string prompt1, string prompt2, + public void OpenDialog(ICommonSession session, string title, string prompt1, string prompt2, string prompt3, string prompt4, Action okAction, Action? cancelAction = null) { OpenDialogInternal( diff --git a/Content.Server/Administration/QuickDialogSystem.cs b/Content.Server/Administration/QuickDialogSystem.cs index 51b8cf79c2..96423e5223 100644 --- a/Content.Server/Administration/QuickDialogSystem.cs +++ b/Content.Server/Administration/QuickDialogSystem.cs @@ -1,12 +1,9 @@ -using System.ComponentModel; -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics.CodeAnalysis; using Content.Shared.Administration; -using Microsoft.CodeAnalysis.CSharp.Syntax; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Serialization.TypeSerializers.Interfaces; namespace Content.Server.Administration; @@ -87,7 +84,7 @@ public sealed partial class QuickDialogSystem : EntitySystem _openDialogsByUser.Remove(user); } - private void OpenDialogInternal(IPlayerSession session, string title, List entries, QuickDialogButtonFlag buttons, Action okAction, Action cancelAction) + private void OpenDialogInternal(ICommonSession session, string title, List entries, QuickDialogButtonFlag buttons, Action okAction, Action cancelAction) { var did = GetDialogId(); RaiseNetworkEvent( diff --git a/Content.Server/Administration/Systems/AdminSystem.cs b/Content.Server/Administration/Systems/AdminSystem.cs index 5a3e1d9217..29ad854550 100644 --- a/Content.Server/Administration/Systems/AdminSystem.cs +++ b/Content.Server/Administration/Systems/AdminSystem.cs @@ -109,7 +109,7 @@ namespace Content.Server.Administration.Systems } } - public void UpdatePlayerList(IPlayerSession player) + public void UpdatePlayerList(ICommonSession player) { _playerList[player.UserId] = GetPlayerInfo(player.Data, player); @@ -203,7 +203,7 @@ namespace Content.Server.Administration.Systems UpdatePanicBunker(); } - private void SendFullPlayerList(IPlayerSession playerSession) + private void SendFullPlayerList(ICommonSession playerSession) { var ev = new FullPlayerListEvent(); @@ -212,7 +212,7 @@ namespace Content.Server.Administration.Systems RaiseNetworkEvent(ev, playerSession.ConnectedClient); } - private PlayerInfo GetPlayerInfo(IPlayerData data, IPlayerSession? session) + private PlayerInfo GetPlayerInfo(SessionData data, ICommonSession? session) { var name = data.UserName; var entityName = string.Empty; @@ -326,7 +326,7 @@ namespace Content.Server.Administration.Systems /// chat messages and showing a popup to other players. /// Their items are dropped on the ground. /// - public void Erase(IPlayerSession player) + public void Erase(ICommonSession player) { var entity = player.AttachedEntity; _chat.DeleteMessagesBy(player); diff --git a/Content.Server/Administration/Systems/AdminTestArenaSystem.cs b/Content.Server/Administration/Systems/AdminTestArenaSystem.cs index e65acf571c..e3671bcdfb 100644 --- a/Content.Server/Administration/Systems/AdminTestArenaSystem.cs +++ b/Content.Server/Administration/Systems/AdminTestArenaSystem.cs @@ -1,8 +1,8 @@ using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.Administration.Systems; @@ -20,7 +20,7 @@ public sealed class AdminTestArenaSystem : EntitySystem public Dictionary ArenaMap { get; private set; } = new(); public Dictionary ArenaGrid { get; private set; } = new(); - public (EntityUid Map, EntityUid? Grid) AssertArenaLoaded(IPlayerSession admin) + public (EntityUid Map, EntityUid? Grid) AssertArenaLoaded(ICommonSession admin) { if (ArenaMap.TryGetValue(admin.UserId, out var arenaMap) && !Deleted(arenaMap) && !Terminating(arenaMap)) { diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs index 6fe526af11..245fad4b33 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs @@ -7,10 +7,8 @@ using Content.Shared.Humanoid; using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Verbs; -using Robust.Server.GameObjects; using Robust.Shared.Utility; -using Content.Server.GameTicking.Rules.Components; -using System.Linq; +using Robust.Shared.Player; namespace Content.Server.Administration.Systems; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs index b52e56009d..d7df3faee2 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs @@ -1,12 +1,10 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; -using Content.Server.Administration.Commands; using Content.Server.Administration.Components; using Content.Server.Atmos; using Content.Server.Atmos.Components; using Content.Server.Cargo.Components; -using Content.Server.Damage.Components; using Content.Server.Doors.Systems; using Content.Server.Hands.Systems; using Content.Server.Power.Components; @@ -30,12 +28,12 @@ using Content.Shared.PDA; using Content.Shared.Stacks; using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; -using Robust.Server.GameObjects; using Robust.Server.Physics; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Administration.Systems; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs index 0f0c562356..bc065745f5 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs @@ -24,11 +24,10 @@ using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Server.Console; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Toolshed; @@ -427,7 +426,7 @@ namespace Content.Server.Administration.Systems } } - public void OpenEditSolutionsEui(IPlayerSession session, EntityUid uid) + public void OpenEditSolutionsEui(ICommonSession session, EntityUid uid) { if (session.AttachedEntity == null) return; diff --git a/Content.Server/Administration/Systems/BwoinkSystem.cs b/Content.Server/Administration/Systems/BwoinkSystem.cs index 98e5af1126..31ef285a88 100644 --- a/Content.Server/Administration/Systems/BwoinkSystem.cs +++ b/Content.Server/Administration/Systems/BwoinkSystem.cs @@ -17,6 +17,7 @@ using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -119,7 +120,7 @@ namespace Content.Server.Administration.Systems _typingUpdateTimestamps[args.SenderSession.UserId] = (_timing.RealTime, msg.Typing); // Non-admins can only ever type on their own ahelp, guard against fake messages - var isAdmin = _adminManager.GetAdminData((IPlayerSession) args.SenderSession)?.HasFlag(AdminFlags.Adminhelp) ?? false; + var isAdmin = _adminManager.GetAdminData(args.SenderSession)?.HasFlag(AdminFlags.Adminhelp) ?? false; var channel = isAdmin ? msg.Channel : args.SenderSession.UserId; var update = new BwoinkPlayerTypingUpdated(channel, args.SenderSession.Name, msg.Typing); @@ -376,7 +377,7 @@ namespace Content.Server.Administration.Systems protected override void OnBwoinkTextMessage(BwoinkTextMessage message, EntitySessionEventArgs eventArgs) { base.OnBwoinkTextMessage(message, eventArgs); - var senderSession = (IPlayerSession) eventArgs.SenderSession; + var senderSession = eventArgs.SenderSession; // TODO: Sanitize text? // Confirm that this person is actually allowed to send a message here. diff --git a/Content.Server/Administration/Toolshed/AdminsCommand.cs b/Content.Server/Administration/Toolshed/AdminsCommand.cs index aa82e0f1d9..1d64f748fd 100644 --- a/Content.Server/Administration/Toolshed/AdminsCommand.cs +++ b/Content.Server/Administration/Toolshed/AdminsCommand.cs @@ -1,6 +1,6 @@ using Content.Server.Administration.Managers; using Content.Shared.Administration; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Toolshed; namespace Content.Server.Administration.Toolshed; @@ -11,13 +11,13 @@ public sealed class AdminsCommand : ToolshedCommand [Dependency] private readonly IAdminManager _admin = default!; [CommandImplementation("active")] - public IEnumerable Active() + public IEnumerable Active() { return _admin.ActiveAdmins; } [CommandImplementation("all")] - public IEnumerable All() + public IEnumerable All() { return _admin.AllAdmins; } diff --git a/Content.Server/Afk/AFKSystem.cs b/Content.Server/Afk/AFKSystem.cs index 0938f45f73..f634a415dc 100644 --- a/Content.Server/Afk/AFKSystem.cs +++ b/Content.Server/Afk/AFKSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Afk.Events; using Content.Server.GameTicking; using Content.Shared.CCVar; @@ -24,7 +23,7 @@ public sealed class AFKSystem : EntitySystem private float _checkDelay; private TimeSpan _checkTime; - private readonly HashSet _afkPlayers = new(); + private readonly HashSet _afkPlayers = new(); public override void Initialize() { @@ -73,11 +72,9 @@ public sealed class AFKSystem : EntitySystem _checkTime = _timing.CurTime + TimeSpan.FromSeconds(_checkDelay); - foreach (var session in Filter.GetAllPlayers()) + foreach (var pSession in Filter.GetAllPlayers()) { - if (session.Status != SessionStatus.InGame) continue; - - var pSession = (IPlayerSession) session; + if (pSession.Status != SessionStatus.InGame) continue; var isAfk = _afkManager.IsAfk(pSession); if (isAfk && _afkPlayers.Add(pSession)) diff --git a/Content.Server/Afk/AfkManager.cs b/Content.Server/Afk/AfkManager.cs index 24cd1e28ce..52dc7715df 100644 --- a/Content.Server/Afk/AfkManager.cs +++ b/Content.Server/Afk/AfkManager.cs @@ -5,6 +5,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Input; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Afk @@ -20,13 +21,13 @@ namespace Content.Server.Afk /// /// The player to check. /// True if the player is AFK, false otherwise. - bool IsAfk(IPlayerSession player); + bool IsAfk(ICommonSession player); /// /// Resets AFK status for the player as if they just did an action and are definitely not AFK. /// /// The player to set AFK status for. - void PlayerDidAction(IPlayerSession player); + void PlayerDidAction(ICommonSession player); void Initialize(); } @@ -40,7 +41,7 @@ namespace Content.Server.Afk [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConsoleHost _consoleHost = default!; - private readonly Dictionary _lastActionTimes = new(); + private readonly Dictionary _lastActionTimes = new(); public void Initialize() { @@ -55,7 +56,7 @@ namespace Content.Server.Afk HandleInputCmd); } - public void PlayerDidAction(IPlayerSession player) + public void PlayerDidAction(ICommonSession player) { if (player.Status == SessionStatus.Disconnected) // Make sure we don't re-add to the dictionary if the player is disconnected now. @@ -64,7 +65,7 @@ namespace Content.Server.Afk _lastActionTimes[player] = _gameTiming.RealTime; } - public bool IsAfk(IPlayerSession player) + public bool IsAfk(ICommonSession player) { if (!_lastActionTimes.TryGetValue(player, out var time)) // Some weird edge case like disconnected clients. Just say true I guess. @@ -87,13 +88,13 @@ namespace Content.Server.Afk private void ConsoleHostOnAnyCommandExecuted(IConsoleShell shell, string commandname, string argstr, string[] args) { - if (shell.Player is IPlayerSession player) + if (shell.Player is { } player) PlayerDidAction(player); } private void HandleInputCmd(FullInputCmdMessage msg, EntitySessionEventArgs args) { - PlayerDidAction((IPlayerSession) args.SenderSession); + PlayerDidAction(args.SenderSession); } } } diff --git a/Content.Server/Afk/Events/AFKEvent.cs b/Content.Server/Afk/Events/AFKEvent.cs index 6adb950e47..ee9d548043 100644 --- a/Content.Server/Afk/Events/AFKEvent.cs +++ b/Content.Server/Afk/Events/AFKEvent.cs @@ -1,4 +1,4 @@ -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Afk.Events; @@ -8,9 +8,9 @@ namespace Content.Server.Afk.Events; [ByRefEvent] public readonly struct AFKEvent { - public readonly IPlayerSession Session; + public readonly ICommonSession Session; - public AFKEvent(IPlayerSession playerSession) + public AFKEvent(ICommonSession playerSession) { Session = playerSession; } diff --git a/Content.Server/Afk/Events/UnAFKEvent.cs b/Content.Server/Afk/Events/UnAFKEvent.cs index 3dd034583c..0983c256f0 100644 --- a/Content.Server/Afk/Events/UnAFKEvent.cs +++ b/Content.Server/Afk/Events/UnAFKEvent.cs @@ -1,4 +1,4 @@ -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Afk.Events; @@ -8,9 +8,9 @@ namespace Content.Server.Afk.Events; [ByRefEvent] public readonly struct UnAFKEvent { - public readonly IPlayerSession Session; + public readonly ICommonSession Session; - public UnAFKEvent(IPlayerSession playerSession) + public UnAFKEvent(ICommonSession playerSession) { Session = playerSession; } diff --git a/Content.Server/Alert/Commands/ClearAlert.cs b/Content.Server/Alert/Commands/ClearAlert.cs index e43f06413c..1759612702 100644 --- a/Content.Server/Alert/Commands/ClearAlert.cs +++ b/Content.Server/Alert/Commands/ClearAlert.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.Commands; using Content.Shared.Administration; using Content.Shared.Alert; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Alert.Commands @@ -16,7 +15,7 @@ namespace Content.Server.Alert.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity == null) { shell.WriteLine("You don't have an entity."); diff --git a/Content.Server/Alert/Commands/ShowAlert.cs b/Content.Server/Alert/Commands/ShowAlert.cs index edb634b546..11901e9af0 100644 --- a/Content.Server/Alert/Commands/ShowAlert.cs +++ b/Content.Server/Alert/Commands/ShowAlert.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.Commands; using Content.Shared.Administration; using Content.Shared.Alert; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Alert.Commands @@ -16,7 +15,7 @@ namespace Content.Server.Alert.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity == null) { shell.WriteLine("You cannot run this from the server or without an attached entity."); diff --git a/Content.Server/AlertLevel/Commands/SetAlertLevelCommand.cs b/Content.Server/AlertLevel/Commands/SetAlertLevelCommand.cs index 009a8b5f23..2c432a2419 100644 --- a/Content.Server/AlertLevel/Commands/SetAlertLevelCommand.cs +++ b/Content.Server/AlertLevel/Commands/SetAlertLevelCommand.cs @@ -3,7 +3,6 @@ using Content.Server.Administration; using Content.Server.Station.Systems; using Content.Shared.Administration; using JetBrains.Annotations; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.AlertLevel.Commands @@ -19,7 +18,7 @@ namespace Content.Server.AlertLevel.Commands public CompletionResult GetCompletion(IConsoleShell shell, string[] args) { var levelNames = new string[] {}; - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity != null) { var stationUid = EntitySystem.Get().GetOwningStation(player.AttachedEntity.Value); @@ -54,7 +53,7 @@ namespace Content.Server.AlertLevel.Commands return; } - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity == null) { shell.WriteLine(Loc.GetString("shell-only-players-can-run-this-command")); diff --git a/Content.Server/Anomaly/AnomalySystem.Scanner.cs b/Content.Server/Anomaly/AnomalySystem.Scanner.cs index caff031ace..30b3d99497 100644 --- a/Content.Server/Anomaly/AnomalySystem.Scanner.cs +++ b/Content.Server/Anomaly/AnomalySystem.Scanner.cs @@ -3,7 +3,7 @@ using Content.Shared.Anomaly; using Content.Shared.Anomaly.Components; using Content.Shared.DoAfter; using Content.Shared.Interaction; -using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Anomaly; diff --git a/Content.Server/Antag/AntagSelectionSystem.cs b/Content.Server/Antag/AntagSelectionSystem.cs index 5e323f5ab8..737b723d39 100644 --- a/Content.Server/Antag/AntagSelectionSystem.cs +++ b/Content.Server/Antag/AntagSelectionSystem.cs @@ -22,6 +22,7 @@ using Content.Server.Station.Systems; using Content.Server.Shuttles.Systems; using Content.Shared.Mobs; using Robust.Server.Containers; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.Antag; @@ -88,9 +89,9 @@ public sealed class AntagSelectionSystem : GameRuleSystem out List chosen, bool includeHeads = false) { - var allPlayers = _playerSystem.ServerSessions.ToList(); - var playerList = new List(); - var prefList = new List(); + var allPlayers = _playerSystem.Sessions.ToList(); + var playerList = new List(); + var prefList = new List(); chosen = new List(); foreach (var player in allPlayers) { @@ -116,7 +117,7 @@ public sealed class AntagSelectionSystem : GameRuleSystem var antags = Math.Clamp(allPlayers.Count / antagsPerPlayer, 1, maxAntags); for (var antag = 0; antag < antags; antag++) { - IPlayerSession chosenPlayer = null!; + ICommonSession? chosenPlayer = null; if (prefList.Count == 0) { if (playerList.Count == 0) diff --git a/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs b/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs index 92a96ea226..ef69600783 100644 --- a/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs +++ b/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs @@ -1,6 +1,6 @@ using Content.Shared.Arcade; -using Robust.Server.Player; using System.Linq; +using Robust.Shared.Player; namespace Content.Server.Arcade.BlockGame; @@ -166,7 +166,7 @@ public sealed partial class BlockGame /// /// The message to send to a specific player/spectator. /// The target recipient. - private void SendMessage(BoundUserInterfaceMessage message, IPlayerSession session) + private void SendMessage(BoundUserInterfaceMessage message, ICommonSession session) { if (_uiSystem.TryGetUi(_owner, BlockGameUiKey.Key, out var bui)) _uiSystem.TrySendUiMessage(bui, message, session); @@ -176,7 +176,7 @@ public sealed partial class BlockGame /// Handles sending the current state of the game to a player that has just opened the UI. /// /// The target recipient. - public void UpdateNewPlayerUI(IPlayerSession session) + public void UpdateNewPlayerUI(ICommonSession session) { if (_gameOver) { @@ -209,7 +209,7 @@ public sealed partial class BlockGame /// Handles broadcasting the full player-visible game state to a specific player/spectator. /// /// The target recipient. - private void FullUpdate(IPlayerSession session) + private void FullUpdate(ICommonSession session) { UpdateFieldUI(session); SendNextPieceUpdate(session); @@ -235,7 +235,7 @@ public sealed partial class BlockGame /// Handles broadcasting the current location of all of the blocks in the playfield + the active piece to a specific player/spectator. /// /// The target recipient. - public void UpdateFieldUI(IPlayerSession session) + public void UpdateFieldUI(ICommonSession session) { if (!Started) return; @@ -283,7 +283,7 @@ public sealed partial class BlockGame /// Broadcasts the state of the next queued piece to a specific viewer. /// /// The target recipient. - private void SendNextPieceUpdate(IPlayerSession session) + private void SendNextPieceUpdate(ICommonSession session) { SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(NextPiece.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.NextBlock), session); } @@ -303,7 +303,7 @@ public sealed partial class BlockGame /// Broadcasts the state of the currently held piece to a specific viewer. /// /// The target recipient. - private void SendHoldPieceUpdate(IPlayerSession session) + private void SendHoldPieceUpdate(ICommonSession session) { if (HeldPiece.HasValue) SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(HeldPiece.Value.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.HoldBlock), session); @@ -323,7 +323,7 @@ public sealed partial class BlockGame /// Broadcasts the current game level to a specific viewer. /// /// The target recipient. - private void SendLevelUpdate(IPlayerSession session) + private void SendLevelUpdate(ICommonSession session) { SendMessage(new BlockGameMessages.BlockGameLevelUpdateMessage(Level), session); } @@ -340,7 +340,7 @@ public sealed partial class BlockGame /// Broadcasts the current game score to a specific viewer. /// /// The target recipient. - private void SendPointsUpdate(IPlayerSession session) + private void SendPointsUpdate(ICommonSession session) { SendMessage(new BlockGameMessages.BlockGameScoreUpdateMessage(Points), session); } @@ -357,7 +357,7 @@ public sealed partial class BlockGame /// Broadcasts the current game high score positions to a specific viewer. /// /// The target recipient. - private void SendHighscoreUpdate(IPlayerSession session) + private void SendHighscoreUpdate(ICommonSession session) { SendMessage(new BlockGameMessages.BlockGameHighScoreUpdateMessage(_arcadeSystem.GetLocalHighscores(), _arcadeSystem.GetGlobalHighscores()), session); } diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs index 268d5be4d2..5613d91544 100644 --- a/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs +++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs @@ -1,4 +1,4 @@ -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Arcade.BlockGame; @@ -13,10 +13,10 @@ public sealed partial class BlockGameArcadeComponent : Component /// /// The player currently playing the active session of NT-BG. /// - public IPlayerSession? Player = null; + public ICommonSession? Player = null; /// /// The players currently viewing (but not playing) the active session of NT-BG. /// - public readonly List Spectators = new(); + public readonly List Spectators = new(); } diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs index dac29accc9..ecc5bfd3e2 100644 --- a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs +++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs @@ -2,7 +2,7 @@ using Content.Server.Power.Components; using Content.Server.UserInterface; using Content.Shared.Arcade; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Arcade.BlockGame; @@ -30,7 +30,7 @@ public sealed class BlockGameArcadeSystem : EntitySystem } } - private void UpdatePlayerStatus(EntityUid uid, IPlayerSession session, PlayerBoundUserInterface? bui = null, BlockGameArcadeComponent? blockGame = null) + private void UpdatePlayerStatus(EntityUid uid, ICommonSession session, PlayerBoundUserInterface? bui = null, BlockGameArcadeComponent? blockGame = null) { if (!Resolve(uid, ref blockGame)) return; @@ -67,7 +67,7 @@ public sealed class BlockGameArcadeSystem : EntitySystem private void OnAfterUiClose(EntityUid uid, BlockGameArcadeComponent component, BoundUIClosedEvent args) { - if (args.Session is not IPlayerSession session) + if (args.Session is not { } session) return; if (component.Player != session) diff --git a/Content.Server/Atmos/Commands/DeleteGasCommand.cs b/Content.Server/Atmos/Commands/DeleteGasCommand.cs index 0f0c399b11..9e7594c024 100644 --- a/Content.Server/Atmos/Commands/DeleteGasCommand.cs +++ b/Content.Server/Atmos/Commands/DeleteGasCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; using Content.Shared.Atmos; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; @@ -20,7 +19,7 @@ namespace Content.Server.Atmos.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid? gridId; Gas? gas = null; diff --git a/Content.Server/Atmos/Commands/ShowAtmosCommand.cs b/Content.Server/Atmos/Commands/ShowAtmosCommand.cs index 5ad73ec906..263ef947d0 100644 --- a/Content.Server/Atmos/Commands/ShowAtmosCommand.cs +++ b/Content.Server/Atmos/Commands/ShowAtmosCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration; using Content.Server.Atmos.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Atmos.Commands @@ -15,7 +14,7 @@ namespace Content.Server.Atmos.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You must be a player to use this command."); diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index 34f558a252..90edd4caed 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -10,6 +10,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Player; namespace Content.Server.Atmos.EntitySystems { @@ -27,7 +28,7 @@ namespace Content.Server.Atmos.EntitySystems /// To modify it see and /// . /// - private readonly HashSet _playerObservers = new(); + private readonly HashSet _playerObservers = new(); /// /// Overlay update ticks per second. @@ -48,17 +49,17 @@ namespace Content.Server.Atmos.EntitySystems _playerManager.PlayerStatusChanged -= OnPlayerStatusChanged; } - public bool AddObserver(IPlayerSession observer) + public bool AddObserver(ICommonSession observer) { return _playerObservers.Add(observer); } - public bool HasObserver(IPlayerSession observer) + public bool HasObserver(ICommonSession observer) { return _playerObservers.Contains(observer); } - public bool RemoveObserver(IPlayerSession observer) + public bool RemoveObserver(ICommonSession observer) { if (!_playerObservers.Remove(observer)) { @@ -76,7 +77,7 @@ namespace Content.Server.Atmos.EntitySystems /// /// The observer to toggle. /// true if added, false if removed. - public bool ToggleObserver(IPlayerSession observer) + public bool ToggleObserver(ICommonSession observer) { if (HasObserver(observer)) { diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 0d7ad48f88..16ddf1f933 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; using static Content.Shared.Atmos.Components.GasAnalyzerComponent; namespace Content.Server.Atmos.EntitySystems diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs index df867d3516..17715435b2 100644 --- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs @@ -12,7 +12,6 @@ using Content.Shared.Toggleable; using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.Physics.Systems; @@ -60,12 +59,6 @@ namespace Content.Server.Atmos.EntitySystems private void OnGasTankToggleInternals(Entity ent, ref GasTankToggleInternalsMessage args) { - if (args.Session is not IPlayerSession playerSession || - playerSession.AttachedEntity == null) - { - return; - } - ToggleInternals(ent); } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index c229ef50c9..b0e8cf71c7 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -16,6 +16,7 @@ using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Player; using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -35,7 +36,7 @@ namespace Content.Server.Atmos.EntitySystems [Robust.Shared.IoC.Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Robust.Shared.IoC.Dependency] private readonly ChunkingSystem _chunkingSys = default!; - private readonly Dictionary>> _lastSentChunks = new(); + private readonly Dictionary>> _lastSentChunks = new(); // Oh look its more duplicated decal system code! private ObjectPool> _chunkIndexPool = @@ -286,12 +287,12 @@ namespace Content.Server.Atmos.EntitySystems // Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range // If they are, check if they need the new data to send (i.e. if there's an overlay for the gas). // Afterwards we reset all the chunk data for the next time we tick. - var players = _playerManager.ServerSessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); + var players = _playerManager.Sessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); var opts = new ParallelOptions { MaxDegreeOfParallelism = _parMan.ParallelProcessCount }; Parallel.ForEach(players, opts, p => UpdatePlayer(p, curTick)); } - private void UpdatePlayer(IPlayerSession playerSession, GameTick curTick) + private void UpdatePlayer(ICommonSession playerSession, GameTick curTick) { var chunksInRange = _chunkingSys.GetChunksForSession(playerSession, ChunkSize, _chunkIndexPool, _chunkViewerPool); var previouslySent = _lastSentChunks[playerSession]; diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs index 0ef49be46a..190ac9d5c9 100644 --- a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs @@ -15,11 +15,11 @@ using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; using Content.Shared.Atmos.Piping.Unary.Components; using Content.Shared.DeviceLinking; -using Content.Shared.DeviceNetwork; using Content.Shared.DeviceNetwork.Systems; using Content.Shared.Interaction; using Content.Shared.Wires; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Atmos.Monitor.Systems; diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs index e857b02b94..75167dfbc2 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.Binary.EntitySystems { diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index 19ad8175aa..66bd28eaac 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -18,6 +18,7 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.Binary.EntitySystems { diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs index 69a0178a01..7032e7fe0e 100644 --- a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs +++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.Trinary.EntitySystems { diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs index ce2213d535..f6ad51fb24 100644 --- a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs +++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.Trinary.EntitySystems { diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index 416e2e4f64..14a1e5e456 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -17,6 +17,7 @@ using Content.Shared.Interaction; using Content.Shared.Lock; using Robust.Server.GameObjects; using Robust.Shared.Containers; +using Robust.Shared.Player; namespace Content.Server.Atmos.Piping.Unary.EntitySystems; diff --git a/Content.Server/Body/Commands/AddHandCommand.cs b/Content.Server/Body/Commands/AddHandCommand.cs index 308295c06c..655d0c88f9 100644 --- a/Content.Server/Body/Commands/AddHandCommand.cs +++ b/Content.Server/Body/Commands/AddHandCommand.cs @@ -4,7 +4,6 @@ using Content.Server.Body.Systems; using Content.Shared.Administration; using Content.Shared.Body.Components; using Content.Shared.Body.Part; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -27,7 +26,7 @@ namespace Content.Server.Body.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid entity; EntityUid hand; diff --git a/Content.Server/Body/Commands/AttachBodyPartCommand.cs b/Content.Server/Body/Commands/AttachBodyPartCommand.cs index 267b520808..24604b88b7 100644 --- a/Content.Server/Body/Commands/AttachBodyPartCommand.cs +++ b/Content.Server/Body/Commands/AttachBodyPartCommand.cs @@ -1,10 +1,8 @@ -using System.Linq; using Content.Server.Administration; using Content.Server.Body.Systems; using Content.Shared.Administration; using Content.Shared.Body.Components; using Content.Shared.Body.Part; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Body.Commands @@ -20,7 +18,7 @@ namespace Content.Server.Body.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid bodyId; EntityUid? partUid; diff --git a/Content.Server/Body/Commands/DestroyMechanismCommand.cs b/Content.Server/Body/Commands/DestroyMechanismCommand.cs index 6ad0631150..3aa28f4072 100644 --- a/Content.Server/Body/Commands/DestroyMechanismCommand.cs +++ b/Content.Server/Body/Commands/DestroyMechanismCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.Body.Systems; using Content.Shared.Administration; using Content.Shared.Body.Components; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Random; @@ -17,7 +16,7 @@ namespace Content.Server.Body.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("Only a player can run this command."); diff --git a/Content.Server/Body/Commands/RemoveHandCommand.cs b/Content.Server/Body/Commands/RemoveHandCommand.cs index 729db4bc44..4a2956ae7a 100644 --- a/Content.Server/Body/Commands/RemoveHandCommand.cs +++ b/Content.Server/Body/Commands/RemoveHandCommand.cs @@ -4,7 +4,6 @@ using Content.Server.Body.Systems; using Content.Shared.Administration; using Content.Shared.Body.Components; using Content.Shared.Body.Part; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Random; @@ -22,7 +21,7 @@ namespace Content.Server.Body.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("Only a player can run this command."); diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index f2f848c488..242b02d78c 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -116,7 +116,7 @@ public sealed class BodySystem : SharedBodySystem if (!Resolve(bodyId, ref body, false)) return new HashSet(); - if (LifeStage(bodyId) >= EntityLifeStage.Terminating || EntityManager.IsQueuedForDeletion(bodyId)) + if (TerminatingOrDeleted(bodyId) || EntityManager.IsQueuedForDeletion(bodyId)) return new HashSet(); var xform = Transform(bodyId); diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index ec4faa345c..17a6544976 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -197,6 +197,14 @@ public sealed class InternalsSystem : EntitySystem return true; } + public bool AreInternalsWorking(EntityUid uid, InternalsComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return false; + + return AreInternalsWorking(component); + } + public bool AreInternalsWorking(InternalsComponent component) { return TryComp(component.BreathToolEntity, out BreathToolComponent? breathTool) && diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index d9327b5150..f659357ad3 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -8,7 +8,7 @@ using Content.Shared.Cargo.Events; using Content.Shared.Cargo.Prototypes; using Content.Shared.Database; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; diff --git a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs index 9f7acce4fd..02b2eee771 100644 --- a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs +++ b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs @@ -6,9 +6,9 @@ using Content.Shared.CartridgeLoader; using Content.Shared.Interaction; using Robust.Server.Containers; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Player; namespace Content.Server.CartridgeLoader; @@ -98,7 +98,7 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem /// and use this method to update its state so the cartridge loaders state can be added to it. /// /// - public void UpdateUiState(EntityUid loaderUid, IPlayerSession? session, CartridgeLoaderComponent? loader) + public void UpdateUiState(EntityUid loaderUid, ICommonSession? session, CartridgeLoaderComponent? loader) { if (!Resolve(loaderUid, ref loader)) return; @@ -122,7 +122,7 @@ public sealed class CartridgeLoaderSystem : SharedCartridgeLoaderSystem /// This method is called "UpdateCartridgeUiState" but cartridges and a programs are the same. A cartridge is just a program as a visible item. /// /// - public void UpdateCartridgeUiState(EntityUid loaderUid, BoundUserInterfaceState state, IPlayerSession? session = default!, CartridgeLoaderComponent? loader = default!) + public void UpdateCartridgeUiState(EntityUid loaderUid, BoundUserInterfaceState state, ICommonSession? session = default!, CartridgeLoaderComponent? loader = default!) { if (!Resolve(loaderUid, ref loader)) return; diff --git a/Content.Server/Chat/Commands/AdminChatCommand.cs b/Content.Server/Chat/Commands/AdminChatCommand.cs index 8aa95ffee1..979051e9d3 100644 --- a/Content.Server/Chat/Commands/AdminChatCommand.cs +++ b/Content.Server/Chat/Commands/AdminChatCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration; using Content.Server.Chat.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Chat.Commands @@ -15,7 +14,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = (IPlayerSession?) shell.Player; + var player = shell.Player; if (player == null) { diff --git a/Content.Server/Chat/Commands/LOOCCommand.cs b/Content.Server/Chat/Commands/LOOCCommand.cs index a897a0b2bf..9e16193fc3 100644 --- a/Content.Server/Chat/Commands/LOOCCommand.cs +++ b/Content.Server/Chat/Commands/LOOCCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; @@ -15,7 +14,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This command cannot be run from the server."); return; diff --git a/Content.Server/Chat/Commands/MeCommand.cs b/Content.Server/Chat/Commands/MeCommand.cs index 36f86cf4d6..e763d5656e 100644 --- a/Content.Server/Chat/Commands/MeCommand.cs +++ b/Content.Server/Chat/Commands/MeCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; @@ -15,7 +14,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This command cannot be run from the server."); return; diff --git a/Content.Server/Chat/Commands/OOCCommand.cs b/Content.Server/Chat/Commands/OOCCommand.cs index bef2024608..36f6303fbd 100644 --- a/Content.Server/Chat/Commands/OOCCommand.cs +++ b/Content.Server/Chat/Commands/OOCCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Chat.Commands @@ -14,7 +13,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This command cannot be run from the server."); return; diff --git a/Content.Server/Chat/Commands/SayCommand.cs b/Content.Server/Chat/Commands/SayCommand.cs index 7c2125d8c1..273f908c9a 100644 --- a/Content.Server/Chat/Commands/SayCommand.cs +++ b/Content.Server/Chat/Commands/SayCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; @@ -15,7 +14,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This command cannot be run from the server."); return; diff --git a/Content.Server/Chat/Commands/SuicideCommand.cs b/Content.Server/Chat/Commands/SuicideCommand.cs index 389ff039bf..c967ba78d7 100644 --- a/Content.Server/Chat/Commands/SuicideCommand.cs +++ b/Content.Server/Chat/Commands/SuicideCommand.cs @@ -1,7 +1,6 @@ using Content.Server.GameTicking; using Content.Shared.Administration; using Content.Shared.Mind; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; @@ -18,7 +17,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteLine(Loc.GetString("shell-cannot-run-command-from-server")); return; diff --git a/Content.Server/Chat/Commands/WhisperCommand.cs b/Content.Server/Chat/Commands/WhisperCommand.cs index 41eba8b384..c88e2519ee 100644 --- a/Content.Server/Chat/Commands/WhisperCommand.cs +++ b/Content.Server/Chat/Commands/WhisperCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Chat.Systems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; @@ -15,7 +14,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("This command cannot be run from the server."); return; diff --git a/Content.Server/Chat/Managers/ChatManager.cs b/Content.Server/Chat/Managers/ChatManager.cs index 88e143d24e..59a9d305bd 100644 --- a/Content.Server/Chat/Managers/ChatManager.cs +++ b/Content.Server/Chat/Managers/ChatManager.cs @@ -10,11 +10,9 @@ using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Database; using Content.Shared.Mind; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Replays; using Robust.Shared.Utility; @@ -51,8 +49,8 @@ namespace Content.Server.Chat.Managers private bool _oocEnabled = true; private bool _adminOocEnabled = true; - public Dictionary SenderKeys { get; } = new(); - public Dictionary> SenderEntities { get; } = new(); + public Dictionary SenderKeys { get; } = new(); + public Dictionary> SenderEntities { get; } = new(); public void Initialize() { @@ -79,7 +77,7 @@ namespace Content.Server.Chat.Managers DispatchServerAnnouncement(Loc.GetString(val ? "chat-manager-admin-ooc-chat-enabled-message" : "chat-manager-admin-ooc-chat-disabled-message")); } - public void DeleteMessagesBy(IPlayerSession player) + public void DeleteMessagesBy(ICommonSession player) { var key = SenderKeys.GetValueOrDefault(player); var entities = SenderEntities.GetValueOrDefault(player) ?? new HashSet(); @@ -165,7 +163,7 @@ namespace Content.Server.Chat.Managers /// The player sending the message. /// The message. /// The type of message. - public void TrySendOOCMessage(IPlayerSession player, string message, OOCChatType type) + public void TrySendOOCMessage(ICommonSession player, string message, OOCChatType type) { // Check if message exceeds the character limit if (message.Length > MaxMessageLength) @@ -189,7 +187,7 @@ namespace Content.Server.Chat.Managers #region Private API - private void SendOOC(IPlayerSession player, string message) + private void SendOOC(ICommonSession player, string message) { if (_adminManager.IsAdmin(player)) { @@ -226,7 +224,7 @@ namespace Content.Server.Chat.Managers _adminLogger.Add(LogType.Chat, LogImpact.Low, $"OOC from {player:Player}: {message}"); } - private void SendAdminChat(IPlayerSession player, string message) + private void SendAdminChat(ICommonSession player, string message) { if (!_adminManager.IsAdmin(player)) { @@ -326,7 +324,7 @@ namespace Content.Server.Chat.Managers } } - public bool MessageCharacterLimit(IPlayerSession? player, string message) + public bool MessageCharacterLimit(ICommonSession? player, string message) { var isOverLength = false; diff --git a/Content.Server/Chat/Managers/IChatManager.cs b/Content.Server/Chat/Managers/IChatManager.cs index 10103f011d..5317b3054e 100644 --- a/Content.Server/Chat/Managers/IChatManager.cs +++ b/Content.Server/Chat/Managers/IChatManager.cs @@ -1,8 +1,6 @@ using Content.Shared.Chat; -using Robust.Server.Player; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Players; namespace Content.Server.Chat.Managers { @@ -12,12 +10,12 @@ namespace Content.Server.Chat.Managers /// Keys identifying messages sent by a specific player, used when sending /// /// - Dictionary SenderKeys { get; } + Dictionary SenderKeys { get; } /// /// Tracks which entities a player was attached to while sending messages. /// - Dictionary> SenderEntities { get; } + Dictionary> SenderEntities { get; } void Initialize(); @@ -30,7 +28,7 @@ namespace Content.Server.Chat.Managers void DispatchServerMessage(ICommonSession player, string message, bool suppressLog = false); - void TrySendOOCMessage(IPlayerSession player, string message, OOCChatType type); + void TrySendOOCMessage(ICommonSession player, string message, OOCChatType type); void SendHookOOC(string sender, string message); void SendAdminAnnouncement(string message); @@ -47,8 +45,8 @@ namespace Content.Server.Chat.Managers void ChatMessageToAll(ChatChannel channel, string message, string wrappedMessage, EntityUid source, bool hideChat, bool recordReplay, Color? colorOverride = null, string? audioPath = null, float audioVolume = 0, int? senderKey = null); - bool MessageCharacterLimit(IPlayerSession player, string message); + bool MessageCharacterLimit(ICommonSession player, string message); - void DeleteMessagesBy(IPlayerSession player); + void DeleteMessagesBy(ICommonSession player); } } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 91739d769d..b2eb668641 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -19,6 +19,7 @@ using Content.Shared.Ghost; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Mobs.Systems; +using Content.Shared.Players; using Content.Shared.Radio; using Robust.Server.GameObjects; using Robust.Server.Player; @@ -27,7 +28,6 @@ using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Replays; @@ -151,7 +151,7 @@ public sealed partial class ChatSystem : SharedChatSystem InGameICChatType desiredType, bool hideChat, bool hideLog = false, IConsoleShell? shell = null, - IPlayerSession? player = null, string? nameOverride = null, + ICommonSession? player = null, string? nameOverride = null, bool checkRadioPrefix = true, bool ignoreActionBlocker = false) { @@ -176,7 +176,7 @@ public sealed partial class ChatSystem : SharedChatSystem ChatTransmitRange range, bool hideLog = false, IConsoleShell? shell = null, - IPlayerSession? player = null, + ICommonSession? player = null, string? nameOverride = null, bool checkRadioPrefix = true, bool ignoreActionBlocker = false @@ -261,7 +261,7 @@ public sealed partial class ChatSystem : SharedChatSystem InGameOOCChatType type, bool hideChat, IConsoleShell? shell = null, - IPlayerSession? player = null + ICommonSession? player = null ) { if (!CanSendInGame(message, shell, player)) @@ -555,7 +555,7 @@ public sealed partial class ChatSystem : SharedChatSystem } // ReSharper disable once InconsistentNaming - private void SendLOOC(EntityUid source, IPlayerSession player, string message, bool hideChat) + private void SendLOOC(EntityUid source, ICommonSession player, string message, bool hideChat) { var name = FormattedMessage.EscapeText(Identity.Name(source, EntityManager)); @@ -579,7 +579,7 @@ public sealed partial class ChatSystem : SharedChatSystem _adminLogger.Add(LogType.Chat, LogImpact.Low, $"LOOC from {player:Player}: {message}"); } - private void SendDeadChat(EntityUid source, IPlayerSession player, string message, bool hideChat) + private void SendDeadChat(EntityUid source, ICommonSession player, string message, bool hideChat) { var clients = GetDeadChatClients(); var playerName = Name(source); @@ -636,13 +636,13 @@ public sealed partial class ChatSystem : SharedChatSystem initialResult = MessageRangeCheckResult.Full; break; case ChatTransmitRange.GhostRangeLimit: - initialResult = (data.Observer && data.Range < 0 && !_adminManager.IsAdmin((IPlayerSession) session)) ? MessageRangeCheckResult.HideChat : MessageRangeCheckResult.Full; + initialResult = (data.Observer && data.Range < 0 && !_adminManager.IsAdmin(session)) ? MessageRangeCheckResult.HideChat : MessageRangeCheckResult.Full; break; case ChatTransmitRange.HideChat: initialResult = MessageRangeCheckResult.HideChat; break; case ChatTransmitRange.NoGhosts: - initialResult = (data.Observer && !_adminManager.IsAdmin((IPlayerSession) session)) ? MessageRangeCheckResult.Disallowed : MessageRangeCheckResult.Full; + initialResult = (data.Observer && !_adminManager.IsAdmin(session)) ? MessageRangeCheckResult.Disallowed : MessageRangeCheckResult.Full; break; } var insistHideChat = data.HideChatOverride ?? false; @@ -674,7 +674,7 @@ public sealed partial class ChatSystem : SharedChatSystem /// /// Returns true if the given player is 'allowed' to send the given message, false otherwise. /// - private bool CanSendInGame(string message, IConsoleShell? shell = null, IPlayerSession? player = null) + private bool CanSendInGame(string message, IConsoleShell? shell = null, ICommonSession? player = null) { // Non-players don't have to worry about these restrictions. if (player == null) @@ -702,7 +702,7 @@ public sealed partial class ChatSystem : SharedChatSystem { var newMessage = message.Trim(); newMessage = SanitizeMessageReplaceWords(newMessage); - + if (capitalize) newMessage = SanitizeMessageCapital(newMessage); if (capitalizeTheWordI) diff --git a/Content.Server/Chemistry/Components/SmokeComponent.cs b/Content.Server/Chemistry/Components/SmokeComponent.cs deleted file mode 100644 index 133ad41f13..0000000000 --- a/Content.Server/Chemistry/Components/SmokeComponent.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Content.Shared.Fluids.Components; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Server.Chemistry.Components; - -/// -/// Stores solution on an anchored entity that has touch and ingestion reactions -/// to entities that collide with it. Similar to -/// -[RegisterComponent] -public sealed partial class SmokeComponent : Component -{ - public const string SolutionName = "solutionArea"; - - [DataField("nextReact", customTypeSerializer:typeof(TimeOffsetSerializer))] - public TimeSpan NextReact = TimeSpan.Zero; - - [DataField("spreadAmount")] - public int SpreadAmount = 0; - - /// - /// Have we reacted with our tile yet? - /// - [DataField("reactedTile")] - public bool ReactedTile = false; -} diff --git a/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs index 8cbdd82f07..7485c0e901 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistryGuideDataSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Chemistry.Reagent; using Robust.Server.Player; using Robust.Shared.Enums; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.EntitySystems; diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs index 708651d5cd..6b085d133e 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystem.Injector.cs @@ -1,6 +1,5 @@ using Content.Server.Body.Components; using Content.Server.Chemistry.Components; -using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; @@ -15,8 +14,7 @@ using Content.Shared.DoAfter; using Content.Shared.Mobs.Components; using Content.Shared.Verbs; using Content.Shared.Stacks; -using Robust.Server.GameObjects; -using Content.Shared.Popups; +using Robust.Shared.Player; namespace Content.Server.Chemistry.EntitySystems; diff --git a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs index e27063b1b5..04aa6546a9 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionSpikableSystem.cs @@ -61,35 +61,11 @@ public sealed class SolutionSpikableSystem : EntitySystem return; } - if (_solutionSystem.TryMixAndOverflow(target, - targetSolution, - sourceSolution, - targetSolution.MaxVolume, - out var overflow)) - { - if (overflow.Volume > 0) - { - RaiseLocalEvent(target, new SolutionSpikeOverflowEvent(overflow)); - } + if (!_solutionSystem.ForceAddSolution(target, targetSolution, sourceSolution)) + return; - _popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user); - - sourceSolution.RemoveAllSolution(); - - _triggerSystem.Trigger(source, user); - } - } -} - -public sealed class SolutionSpikeOverflowEvent : HandledEntityEventArgs -{ - /// - /// The solution that's been overflowed from the spike. - /// - public Solution Overflow { get; } - - public SolutionSpikeOverflowEvent(Solution overflow) - { - Overflow = overflow; + _popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user); + sourceSolution.RemoveAllSolution(); + _triggerSystem.Trigger(source, user); } } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs index 99f8c1a517..d2666417cf 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -4,12 +4,12 @@ using JetBrains.Annotations; using Robust.Server.GameObjects; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Interaction; using Content.Shared.Popups; +using Robust.Shared.Player; namespace Content.Server.Chemistry.EntitySystems { diff --git a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs index e6eaab8a59..291a654422 100644 --- a/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs +++ b/Content.Server/Chemistry/ReactionEffects/AreaReactionEffect.cs @@ -1,4 +1,3 @@ -using Content.Server.Chemistry.Components; using Content.Server.Fluids.EntitySystems; using Content.Shared.Audio; using Content.Shared.Chemistry.EntitySystems; @@ -10,7 +9,6 @@ using Content.Shared.Maps; using JetBrains.Annotations; using Robust.Shared.Audio; using Robust.Shared.Map; -using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -71,18 +69,10 @@ namespace Content.Server.Chemistry.ReactionEffects var coords = grid.MapToGrid(transform.MapPosition); var ent = args.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid()); - if (!args.EntityManager.TryGetComponent(ent, out var smokeComponent)) - { - Logger.Error("Couldn't get AreaEffectComponent from " + _prototypeId); - args.EntityManager.QueueDeleteEntity(ent); - return; - } - var smoke = args.EntityManager.System(); - smokeComponent.SpreadAmount = spreadAmount; - smoke.Start(ent, smokeComponent, splitSolution, _duration); + smoke.StartSmoke(ent, splitSolution, _duration, spreadAmount); - SoundSystem.Play(_sound.GetSound(), Filter.Pvs(args.SolutionEntity), args.SolutionEntity, AudioHelpers.WithVariation(0.125f)); + args.EntityManager.System().PlayPvs(_sound, args.SolutionEntity, AudioHelpers.WithVariation(0.125f)); } } } diff --git a/Content.Server/Chunking/ChunkingSystem.cs b/Content.Server/Chunking/ChunkingSystem.cs index 4ef44d1678..6f44c43be8 100644 --- a/Content.Server/Chunking/ChunkingSystem.cs +++ b/Content.Server/Chunking/ChunkingSystem.cs @@ -1,12 +1,12 @@ using System.Linq; using Content.Shared.Decals; using Microsoft.Extensions.ObjectPool; -using Robust.Server.Player; using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Shared.Chunking; @@ -41,7 +41,7 @@ public sealed class ChunkingSystem : EntitySystem private void OnPvsRangeChanged(float value) => _baseViewBounds = Box2.UnitCentered.Scale(value); public Dictionary> GetChunksForSession( - IPlayerSession session, + ICommonSession session, int chunkSize, ObjectPool> indexPool, ObjectPool>> viewerPool, @@ -52,7 +52,7 @@ public sealed class ChunkingSystem : EntitySystem return chunks; } - private HashSet GetSessionViewers(IPlayerSession session) + private HashSet GetSessionViewers(ICommonSession session) { var viewers = new HashSet(); if (session.Status != SessionStatus.InGame || session.AttachedEntity is null) diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 28e9c8eea5..a16c47dbcd 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -377,22 +377,4 @@ namespace Content.Server.Cloning ClonesWaitingForMind.Clear(); } } - - /// - /// Raised after a new mob got spawned when cloning a humanoid - /// - [ByRefEvent] - public struct CloningEvent - { - public bool NameHandled = false; - - public readonly EntityUid Source; - public readonly EntityUid Target; - - public CloningEvent(EntityUid source, EntityUid target) - { - Source = source; - Target = target; - } - } } diff --git a/Content.Server/Cloning/Components/CloningPodComponent.cs b/Content.Server/Cloning/Components/CloningPodComponent.cs deleted file mode 100644 index e2c3f46978..0000000000 --- a/Content.Server/Cloning/Components/CloningPodComponent.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Content.Shared.Cloning; -using Content.Shared.Construction.Prototypes; -using Content.Shared.Materials; -using Robust.Shared.Audio; -using Robust.Shared.Containers; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Cloning.Components -{ - [RegisterComponent] - public sealed partial class CloningPodComponent : Component - { - public const string PodPort = "CloningPodReceiver"; - - [ViewVariables] - public ContainerSlot BodyContainer = default!; - - /// - /// How long the cloning has been going on for. - /// - [ViewVariables] - public float CloningProgress = 0; - - [ViewVariables] - public int UsedBiomass = 70; - - [ViewVariables] - public bool FailedClone = false; - - /// - /// The material that is used to clone entities. - /// - [DataField("requiredMaterial", customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] - public string RequiredMaterial = "Biomass"; - - /// - /// The base amount of time it takes to clone a body - /// - [DataField("baseCloningTime")] - public float BaseCloningTime = 30f; - - /// - /// The multiplier for cloning duration - /// - [DataField("partRatingSpeedMultiplier")] - public float PartRatingSpeedMultiplier = 0.75f; - - /// - /// The machine part that affects cloning speed - /// - [DataField("machinePartCloningSpeed", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MachinePartCloningSpeed = "Manipulator"; - - /// - /// The current amount of time it takes to clone a body - /// - [ViewVariables(VVAccess.ReadWrite)] - public float CloningTime = 30f; - - /// - /// The mob to spawn on emag - /// - [ViewVariables(VVAccess.ReadWrite), DataField("mobSpawnId", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MobSpawnId = "MobAbomination"; - - /// - /// Emag sound effects. - /// - [DataField("sparkSound")] - public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks") - { - Params = AudioParams.Default.WithVolume(8), - }; - - [DataField("screamSound")] - public SoundSpecifier ScreamSound = new SoundCollectionSpecifier("ZombieScreams") - { - Params = AudioParams.Default.WithVolume(4), - }; - - /// - /// The machine part that affects how much biomass is needed to clone a body. - /// - [DataField("partRatingMaterialMultiplier")] - public float PartRatingMaterialMultiplier = 0.85f; - - /// - /// The current multiplier on the body weight, which determines the - /// amount of biomass needed to clone. - /// - [ViewVariables(VVAccess.ReadWrite)] - public float BiomassRequirementMultiplier = 1; - - /// - /// The machine part that decreases the amount of material needed for cloning - /// - [DataField("machinePartMaterialUse", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MachinePartMaterialUse = "MatterBin"; - - [ViewVariables(VVAccess.ReadWrite)] - public CloningPodStatus Status; - - [ViewVariables] - public EntityUid? ConnectedConsole; - } -} diff --git a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs index 7dc3b8489d..a087ebdd49 100644 --- a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs +++ b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.IdentityManagement.Components; using Content.Shared.Prototypes; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; diff --git a/Content.Server/Commands/CommandUtils.cs b/Content.Server/Commands/CommandUtils.cs index 11adaec9a2..172f3324e3 100644 --- a/Content.Server/Commands/CommandUtils.cs +++ b/Content.Server/Commands/CommandUtils.cs @@ -3,6 +3,7 @@ using System.Globalization; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.Commands { @@ -16,7 +17,7 @@ namespace Content.Server.Commands /// sending a failure to the performer if unable to. /// public static bool TryGetSessionByUsernameOrId(IConsoleShell shell, - string usernameOrId, IPlayerSession performer, [NotNullWhen(true)] out IPlayerSession? session) + string usernameOrId, ICommonSession performer, [NotNullWhen(true)] out ICommonSession? session) { var plyMgr = IoCManager.Resolve(); if (plyMgr.TryGetSessionByUsername(usernameOrId, out session)) return true; @@ -36,7 +37,7 @@ namespace Content.Server.Commands /// sending a failure to the performer if unable to. /// public static bool TryGetAttachedEntityByUsernameOrId(IConsoleShell shell, - string usernameOrId, IPlayerSession performer, out EntityUid attachedEntity) + string usernameOrId, ICommonSession performer, out EntityUid attachedEntity) { attachedEntity = default; if (!TryGetSessionByUsernameOrId(shell, usernameOrId, performer, out var session)) return false; @@ -67,7 +68,7 @@ namespace Content.Server.Commands transform.LocalPosition.Y.ToString(CultureInfo.InvariantCulture)); ruleString = ruleString.Replace("$NAME", entMan.GetComponent(ent).EntityName); - if (shell.Player is IPlayerSession player) + if (shell.Player is { } player) { if (player.AttachedEntity is {Valid: true} p) { diff --git a/Content.Server/Configurable/ConfigurationSystem.cs b/Content.Server/Configurable/ConfigurationSystem.cs index c134c1a87d..eb31149eca 100644 --- a/Content.Server/Configurable/ConfigurationSystem.cs +++ b/Content.Server/Configurable/ConfigurationSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Interaction; using Content.Shared.Tools.Components; using Robust.Server.GameObjects; using Robust.Shared.Containers; +using Robust.Shared.Player; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Server.Configurable; diff --git a/Content.Server/Construction/Commands/FixRotationsCommand.cs b/Content.Server/Construction/Commands/FixRotationsCommand.cs index d23fa0a31b..bdbfaf170d 100644 --- a/Content.Server/Construction/Commands/FixRotationsCommand.cs +++ b/Content.Server/Construction/Commands/FixRotationsCommand.cs @@ -3,7 +3,6 @@ using Content.Server.Power.Components; using Content.Shared.Administration; using Content.Shared.Construction; using Content.Shared.Tag; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map.Components; @@ -21,7 +20,7 @@ namespace Content.Server.Construction.Commands public void Execute(IConsoleShell shell, string argsOther, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid? gridId; var xformQuery = _entManager.GetEntityQuery(); diff --git a/Content.Server/Construction/Commands/TileReplaceCommand.cs b/Content.Server/Construction/Commands/TileReplaceCommand.cs index ed1fba2424..f63fd4c13e 100644 --- a/Content.Server/Construction/Commands/TileReplaceCommand.cs +++ b/Content.Server/Construction/Commands/TileReplaceCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -20,7 +19,7 @@ sealed class TileReplaceCommand : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid? gridId; string tileIdA; string tileIdB; diff --git a/Content.Server/Construction/Commands/TileWallsCommand.cs b/Content.Server/Construction/Commands/TileWallsCommand.cs index 55389e41cc..731d4da7f8 100644 --- a/Content.Server/Construction/Commands/TileWallsCommand.cs +++ b/Content.Server/Construction/Commands/TileWallsCommand.cs @@ -2,10 +2,9 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.Maps; using Content.Shared.Tag; -using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; +using Robust.Server.GameObjects; using Robust.Shared.Map.Components; namespace Content.Server.Construction.Commands @@ -29,7 +28,7 @@ namespace Content.Server.Construction.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid? gridId; switch (args.Length) diff --git a/Content.Server/Construction/ConstructionSystem.Initial.cs b/Content.Server/Construction/ConstructionSystem.Initial.cs index e74edb5da2..21978f2d0c 100644 --- a/Content.Server/Construction/ConstructionSystem.Initial.cs +++ b/Content.Server/Construction/ConstructionSystem.Initial.cs @@ -16,7 +16,7 @@ using Content.Shared.Interaction; using Content.Shared.Inventory; using Content.Shared.Storage; using Robust.Shared.Containers; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Construction diff --git a/Content.Server/Crayon/CrayonSystem.cs b/Content.Server/Crayon/CrayonSystem.cs index d225df2dae..16385d4d7e 100644 --- a/Content.Server/Crayon/CrayonSystem.cs +++ b/Content.Server/Crayon/CrayonSystem.cs @@ -12,8 +12,8 @@ using Content.Shared.Interaction.Events; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Robust.Shared.Player; using Robust.Shared.Prototypes; -using Robust.Shared.Random; namespace Content.Server.Crayon; diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index aed0575324..4c4f17f61d 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -10,10 +10,9 @@ using Content.Shared.CCVar; using Content.Shared.CrewManifest; using Content.Shared.GameTicking; using Content.Shared.StationRecords; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.CrewManifest; @@ -60,7 +59,7 @@ public sealed class CrewManifestSystem : EntitySystem private void OnRequestCrewManifest(RequestCrewManifestMessage message, EntitySessionEventArgs args) { - if (args.SenderSession is not IPlayerSession sessionCast + if (args.SenderSession is not { } sessionCast || !_configManager.GetCVar(CCVars.CrewManifestWithoutEntity)) { return; @@ -93,12 +92,12 @@ public sealed class CrewManifestSystem : EntitySystem private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component, BoundUIClosedEvent ev) { var owningStation = _stationSystem.GetOwningStation(uid); - if (owningStation == null || ev.Session is not IPlayerSession sessionCast) + if (owningStation == null || ev.Session is not { } session) { return; } - CloseEui(owningStation.Value, sessionCast, uid); + CloseEui(owningStation.Value, session, uid); } /// @@ -126,7 +125,7 @@ public sealed class CrewManifestSystem : EntitySystem private void OpenEuiFromBui(EntityUid uid, CrewManifestViewerComponent component, CrewManifestOpenUiMessage msg) { var owningStation = _stationSystem.GetOwningStation(uid); - if (owningStation == null || msg.Session is not IPlayerSession sessionCast) + if (owningStation == null || msg.Session is not { } session) { return; } @@ -136,7 +135,7 @@ public sealed class CrewManifestSystem : EntitySystem return; } - OpenEui(owningStation.Value, sessionCast, uid); + OpenEui(owningStation.Value, session, uid); } /// @@ -145,7 +144,7 @@ public sealed class CrewManifestSystem : EntitySystem /// Station that we're displaying the crew manifest for. /// The player's session. /// If this EUI should be 'owned' by an entity. - public void OpenEui(EntityUid station, IPlayerSession session, EntityUid? owner = null) + public void OpenEui(EntityUid station, ICommonSession session, EntityUid? owner = null) { if (!HasComp(station)) { @@ -252,7 +251,7 @@ public sealed class CrewManifestCommand : IConsoleCommand return; } - if (shell.Player == null || shell.Player is not IPlayerSession session) + if (shell.Player == null || shell.Player is not { } session) { shell.WriteLine("You must run this from a client."); return; diff --git a/Content.Server/Damage/Commands/GodModeCommand.cs b/Content.Server/Damage/Commands/GodModeCommand.cs index 92a0e53f0f..866737f17a 100644 --- a/Content.Server/Damage/Commands/GodModeCommand.cs +++ b/Content.Server/Damage/Commands/GodModeCommand.cs @@ -1,8 +1,6 @@ using Content.Server.Administration; -using Content.Server.Damage.Systems; using Content.Shared.Administration; using Content.Shared.Damage.Systems; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Damage.Commands @@ -18,7 +16,7 @@ namespace Content.Server.Damage.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; EntityUid entity; switch (args.Length) diff --git a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs index 3d3346403a..5bc30cce5d 100644 --- a/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs +++ b/Content.Server/Damage/ForceSay/DamageForceSaySystem.cs @@ -4,9 +4,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Mobs; using Content.Shared.Mobs.Systems; using Content.Shared.Stunnable; -using Robust.Server.GameObjects; -using Robust.Server.Player; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; diff --git a/Content.Server/Database/UserDbDataManager.cs b/Content.Server/Database/UserDbDataManager.cs index f2c506240b..f8b1611fd5 100644 --- a/Content.Server/Database/UserDbDataManager.cs +++ b/Content.Server/Database/UserDbDataManager.cs @@ -2,8 +2,8 @@ using System.Threading.Tasks; using Content.Server.Players.PlayTimeTracking; using Content.Server.Preferences.Managers; -using Robust.Server.Player; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Database; @@ -25,7 +25,7 @@ public sealed class UserDbDataManager // TODO: Ideally connected/disconnected would be subscribed to IPlayerManager directly, // but this runs into ordering issues with game ticker. - public void ClientConnected(IPlayerSession session) + public void ClientConnected(ICommonSession session) { DebugTools.Assert(!_users.ContainsKey(session.UserId), "We should not have any cached data on client connect."); @@ -36,7 +36,7 @@ public sealed class UserDbDataManager _users.Add(session.UserId, data); } - public void ClientDisconnected(IPlayerSession session) + public void ClientDisconnected(ICommonSession session) { _users.Remove(session.UserId, out var data); if (data == null) @@ -49,24 +49,24 @@ public sealed class UserDbDataManager _playTimeTracking.ClientDisconnected(session); } - private async Task Load(IPlayerSession session, CancellationToken cancel) + private async Task Load(ICommonSession session, CancellationToken cancel) { await Task.WhenAll( _prefs.LoadData(session, cancel), _playTimeTracking.LoadData(session, cancel)); } - public Task WaitLoadComplete(IPlayerSession session) + public Task WaitLoadComplete(ICommonSession session) { return _users[session.UserId].Task; } - public bool IsLoadComplete(IPlayerSession session) + public bool IsLoadComplete(ICommonSession session) { return GetLoadTask(session).IsCompleted; } - public Task GetLoadTask(IPlayerSession session) + public Task GetLoadTask(ICommonSession session) { return _users[session.UserId].Task; } diff --git a/Content.Server/Decals/DecalSystem.cs b/Content.Server/Decals/DecalSystem.cs index ed281e05ba..ce2e0711e7 100644 --- a/Content.Server/Decals/DecalSystem.cs +++ b/Content.Server/Decals/DecalSystem.cs @@ -16,6 +16,7 @@ using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Player; using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -36,7 +37,7 @@ namespace Content.Server.Decals [Dependency] private readonly MapSystem _mapSystem = default!; private readonly Dictionary> _dirtyChunks = new(); - private readonly Dictionary>> _previousSentChunks = new(); + private readonly Dictionary>> _previousSentChunks = new(); private static readonly Vector2 _boundsMinExpansion = new(0.01f, 0.01f); private static readonly Vector2 _boundsMaxExpansion = new(1.01f, 1.01f); @@ -197,7 +198,7 @@ namespace Content.Server.Decals private void OnDecalPlacementRequest(RequestDecalPlacementEvent ev, EntitySessionEventArgs eventArgs) { - if (eventArgs.SenderSession is not IPlayerSession session) + if (eventArgs.SenderSession is not { } session) return; // bad @@ -226,7 +227,7 @@ namespace Content.Server.Decals private void OnDecalRemovalRequest(RequestDecalRemovalEvent ev, EntitySessionEventArgs eventArgs) { - if (eventArgs.SenderSession is not IPlayerSession session) + if (eventArgs.SenderSession is not { } session) return; // bad @@ -427,7 +428,7 @@ namespace Content.Server.Decals if (PvsEnabled) { - var players = _playerManager.ServerSessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); + var players = _playerManager.Sessions.Where(x => x.Status == SessionStatus.InGame).ToArray(); var opts = new ParallelOptions { MaxDegreeOfParallelism = _parMan.ParallelProcessCount }; Parallel.ForEach(players, opts, UpdatePlayer); } @@ -435,7 +436,7 @@ namespace Content.Server.Decals _dirtyChunks.Clear(); } - public void UpdatePlayer(IPlayerSession player) + public void UpdatePlayer(ICommonSession player) { var chunksInRange = _chunking.GetChunksForSession(player, ChunkSize, _chunkIndexPool, _chunkViewerPool); var staleChunks = _chunkViewerPool.Get(); @@ -530,7 +531,7 @@ namespace Content.Server.Decals } private void SendChunkUpdates( - IPlayerSession session, + ICommonSession session, Dictionary> updatedChunks, Dictionary> staleChunks) { diff --git a/Content.Server/DeltaV/Administration/Commands/LoadCharacter.cs b/Content.Server/DeltaV/Administration/Commands/LoadCharacter.cs index 1782028f71..425078bcc7 100644 --- a/Content.Server/DeltaV/Administration/Commands/LoadCharacter.cs +++ b/Content.Server/DeltaV/Administration/Commands/LoadCharacter.cs @@ -7,10 +7,12 @@ using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; +using Content.Shared.Players; using Content.Shared.Preferences; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; // This literally only exists because haha felinid oni @@ -30,7 +32,7 @@ public sealed class LoadCharacter : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not ICommonSession player) { shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); return; @@ -118,9 +120,9 @@ public sealed class LoadCharacter : IConsoleCommand var coordinates = player.AttachedEntity != null ? _entityManager.GetComponent(player.AttachedEntity.Value).Coordinates - : _entitySys.GetEntitySystem().GetObserverSpawnPoint(); + : EntitySystem.Get().GetObserverSpawnPoint(); - _entityManager.System() + EntitySystem.Get() .SpawnPlayerMob(coordinates, profile: character, entity: target, job: null, station: null); shell.WriteLine(Loc.GetString("loadcharacter-command-complete")); @@ -134,8 +136,7 @@ public sealed class LoadCharacter : IConsoleCommand return CompletionResult.FromHint(Loc.GetString("shell-argument-uid")); case 2: { - var player = shell.Player as IPlayerSession; - if (player == null) + if (shell.Player is not ICommonSession player) return CompletionResult.Empty; var data = player.ContentData(); diff --git a/Content.Server/DeltaV/Administration/Commands/SpawnCharacter.cs b/Content.Server/DeltaV/Administration/Commands/SpawnCharacter.cs index 0361f4a946..17ea4a56cc 100644 --- a/Content.Server/DeltaV/Administration/Commands/SpawnCharacter.cs +++ b/Content.Server/DeltaV/Administration/Commands/SpawnCharacter.cs @@ -6,10 +6,12 @@ using Content.Server.Preferences.Managers; using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.Mind; +using Content.Shared.Players; using Content.Shared.Preferences; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.DeltaV.Administration.Commands; @@ -26,13 +28,13 @@ public sealed class SpawnCharacter : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not ICommonSession player) { shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); return; } - var mindSystem = _entitySys.GetEntitySystem(); + var mindSystem = _entityManager.System(); var data = player.ContentData(); @@ -90,7 +92,7 @@ public sealed class SpawnCharacter : IConsoleCommand { if (args.Length == 1) { - var player = shell.Player as IPlayerSession; + var player = shell.Player as ICommonSession; if (player == null) return CompletionResult.Empty; diff --git a/Content.Server/DeltaV/Harpy/HarpySingerSystem.cs b/Content.Server/DeltaV/Harpy/HarpySingerSystem.cs index 6e6417b51d..2e0428af19 100644 --- a/Content.Server/DeltaV/Harpy/HarpySingerSystem.cs +++ b/Content.Server/DeltaV/Harpy/HarpySingerSystem.cs @@ -15,6 +15,7 @@ using Content.Shared.Stunnable; using Content.Shared.UserInterface; using Content.Shared.Zombies; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.DeltaV.Harpy diff --git a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs index f8e6b0f65b..69bd37e674 100644 --- a/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs +++ b/Content.Server/DeltaV/NPC/Roboisseur/RoboisseurSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Random.Helpers; using Content.Shared.Kitchen; using Robust.Server.GameObjects; using Content.Server.Materials; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Roboisseur.Roboisseur diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index c250761687..a977a44287 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -17,6 +17,7 @@ using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Audio; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; diff --git a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs index 7993ccc07d..1a819ab0fb 100644 --- a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs +++ b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs @@ -7,6 +7,7 @@ using Content.Server.Power.Components; using Content.Shared.Disposal; using Content.Shared.Interaction; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Disposal.Mailing; diff --git a/Content.Server/Disposal/TubeConnectionsCommand.cs b/Content.Server/Disposal/TubeConnectionsCommand.cs index 7895dcbca6..55e6465937 100644 --- a/Content.Server/Disposal/TubeConnectionsCommand.cs +++ b/Content.Server/Disposal/TubeConnectionsCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.Disposal.Tube; using Content.Server.Disposal.Tube.Components; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Disposal @@ -18,7 +17,7 @@ namespace Content.Server.Disposal public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity == null) { shell.WriteLine(Loc.GetString("shell-only-players-can-run-this-command")); diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index baec99b6a5..0e56d0fb18 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -32,6 +32,7 @@ using Robust.Shared.GameStates; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; diff --git a/Content.Server/Doors/Systems/AirlockSystem.cs b/Content.Server/Doors/Systems/AirlockSystem.cs index ce517febf6..e234ba3304 100644 --- a/Content.Server/Doors/Systems/AirlockSystem.cs +++ b/Content.Server/Doors/Systems/AirlockSystem.cs @@ -6,10 +6,9 @@ using Content.Shared.Doors; using Content.Shared.Doors.Components; using Content.Shared.Doors.Systems; using Content.Shared.Interaction; -using Robust.Server.GameObjects; using Content.Shared.Wires; using Content.Shared.Prying.Components; -using Robust.Shared.Prototypes; +using Robust.Shared.Player; namespace Content.Server.Doors.Systems; @@ -178,11 +177,16 @@ public sealed class AirlockSystem : SharedAirlockSystem private void OnBeforePry(EntityUid uid, AirlockComponent component, ref BeforePryEvent args) { - if (this.IsPowered(uid, EntityManager) && !args.PryPowered) - { - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-powered-message"), uid, args.User); - args.Cancelled = true; - } + if (args.Cancelled) + return; + + if (!this.IsPowered(uid, EntityManager) || args.PryPowered) + return; + + args.Message = "airlock-component-cannot-pry-is-powered-message"; + + args.Cancelled = true; + } public bool CanChangeState(EntityUid uid, AirlockComponent component) diff --git a/Content.Server/EUI/BaseEui.cs b/Content.Server/EUI/BaseEui.cs index 4a41ad40a5..70cbfc3775 100644 --- a/Content.Server/EUI/BaseEui.cs +++ b/Content.Server/EUI/BaseEui.cs @@ -1,6 +1,6 @@ using Content.Shared.Eui; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.EUI { diff --git a/Content.Server/EUI/EuiManager.cs b/Content.Server/EUI/EuiManager.cs index 4d99719525..fe8e486b68 100644 --- a/Content.Server/EUI/EuiManager.cs +++ b/Content.Server/EUI/EuiManager.cs @@ -2,7 +2,7 @@ using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.EUI diff --git a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs index bb1690c935..b04c1296fc 100644 --- a/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs +++ b/Content.Server/Ensnaring/EnsnareableSystem.Ensnaring.cs @@ -1,8 +1,9 @@ using System.Linq; using Content.Server.Body.Systems; using Content.Shared.Alert; -using Content.Shared.Body.Components; using Content.Shared.Body.Part; +using Content.Shared.Damage.Components; +using Content.Shared.Damage.Systems; using Content.Shared.DoAfter; using Content.Shared.Ensnaring; using Content.Shared.Ensnaring.Components; @@ -17,6 +18,7 @@ public sealed partial class EnsnareableSystem [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly BodySystem _body = default!; + [Dependency] private readonly StaminaSystem _stamina = default!; public void InitializeEnsnaring() { @@ -72,6 +74,15 @@ public sealed partial class EnsnareableSystem if (freeLegs <= 0) return; + // Apply stamina damage to target if they weren't ensnared before. + if (ensnareable.IsEnsnared != true) + { + if (TryComp(target, out var stamina)) + { + _stamina.TakeStaminaDamage(target, component.StaminaDamage, with: ensnare); + } + } + component.Ensnared = target; ensnareable.Container.Insert(ensnare); ensnareable.IsEnsnared = true; diff --git a/Content.Server/EntityList/SpawnEntityListCommand.cs b/Content.Server/EntityList/SpawnEntityListCommand.cs index 0891bbd12a..027d25dc2c 100644 --- a/Content.Server/EntityList/SpawnEntityListCommand.cs +++ b/Content.Server/EntityList/SpawnEntityListCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration; using Content.Shared.Administration; using Content.Shared.EntityList; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Prototypes; @@ -22,7 +21,7 @@ namespace Content.Server.EntityList return; } - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError("You must be a player to run this command."); return; diff --git a/Content.Server/Examine/ExamineSystem.cs b/Content.Server/Examine/ExamineSystem.cs index 98aa806885..bb7e07d235 100644 --- a/Content.Server/Examine/ExamineSystem.cs +++ b/Content.Server/Examine/ExamineSystem.cs @@ -3,8 +3,7 @@ using Content.Server.Verbs; using Content.Shared.Examine; using Content.Shared.Verbs; using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Examine @@ -46,7 +45,7 @@ namespace Content.Server.Examine private void ExamineInfoRequest(ExamineSystemMessages.RequestExamineInfoMessage request, EntitySessionEventArgs eventArgs) { - var player = (IPlayerSession) eventArgs.SenderSession; + var player = eventArgs.SenderSession; var session = eventArgs.SenderSession; var channel = player.ConnectedClient; var entity = GetEntity(request.NetEntity); diff --git a/Content.Server/Fluids/EntitySystems/PuddleDebugDebugOverlaySystem.cs b/Content.Server/Fluids/EntitySystems/PuddleDebugDebugOverlaySystem.cs index 59f0a13695..c17eea684d 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleDebugDebugOverlaySystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleDebugDebugOverlaySystem.cs @@ -1,9 +1,9 @@ using System.Numerics; using Content.Shared.Fluids; using Content.Shared.Fluids.Components; -using Robust.Server.Player; using Robust.Shared.Map; using Robust.Shared.Map.Components; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Fluids.EntitySystems; @@ -14,10 +14,10 @@ public sealed class PuddleDebugDebugOverlaySystem : SharedPuddleDebugOverlaySyst [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly PuddleSystem _puddle = default!; - private readonly HashSet _playerObservers = new(); + private readonly HashSet _playerObservers = new(); private List> _grids = new(); - public bool ToggleObserver(IPlayerSession observer) + public bool ToggleObserver(ICommonSession observer) { NextTick ??= _timing.CurTime + Cooldown; @@ -31,7 +31,7 @@ public sealed class PuddleDebugDebugOverlaySystem : SharedPuddleDebugOverlaySyst return true; } - private void RemoveObserver(IPlayerSession observer) + private void RemoveObserver(ICommonSession observer) { if (!_playerObservers.Remove(observer)) { diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs index 39485d60f7..a6d6a5b204 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs @@ -34,7 +34,7 @@ public sealed partial class PuddleSystem SubscribeLocalEvent(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) }); SubscribeLocalEvent>(AddSpillVerb); SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnSpikeOverflow); + SubscribeLocalEvent(OnOverflow); SubscribeLocalEvent(OnDoAfter); } @@ -46,13 +46,12 @@ public sealed partial class PuddleSystem args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon")); } - private void OnSpikeOverflow(EntityUid uid, SpillableComponent component, SolutionSpikeOverflowEvent args) + private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args) { - if (!args.Handled) - { - TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _); - } + if (args.Handled) + return; + TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _); args.Handled = true; } diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index f7732fec62..5459dacf0b 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -1,14 +1,23 @@ using System.Linq; -using Content.Server.Chemistry.Components; +using Content.Server.Administration.Logs; +using Content.Server.Body.Components; +using Content.Server.Body.Systems; using Content.Server.Chemistry.ReactionEffects; using Content.Server.Spreader; +using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Smoking; using Robust.Server.GameObjects; using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -22,70 +31,140 @@ namespace Content.Server.Fluids.EntitySystems; public sealed class SmokeSystem : EntitySystem { // If I could do it all again this could probably use a lot more of puddles. + [Dependency] private readonly IAdminLogManager _logger = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; - [Dependency] private readonly AppearanceSystem _appearance = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + [Dependency] private readonly BloodstreamSystem _blood = default!; + [Dependency] private readonly InternalsSystem _internals = default!; + [Dependency] private readonly ReactiveSystem _reactive = default!; + [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly TransformSystem _transform = default!; + + private EntityQuery _smokeQuery; + private EntityQuery _smokeAffectedQuery; /// public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnSmokeUnpaused); + + _smokeQuery = GetEntityQuery(); + _smokeAffectedQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnStartCollide); + SubscribeLocalEvent(OnEndCollide); SubscribeLocalEvent(OnReactionAttempt); SubscribeLocalEvent(OnSmokeSpread); + SubscribeLocalEvent(OnAffectedUnpaused); + } + + /// + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + var curTime = _timing.CurTime; + while (query.MoveNext(out var uid, out var smoke)) + { + if (curTime < smoke.NextSecond) + continue; + + smoke.NextSecond += TimeSpan.FromSeconds(1); + SmokeReact(uid, smoke.SmokeEntity); + } + } + + private void OnStartCollide(EntityUid uid, SmokeComponent component, ref StartCollideEvent args) + { + if (_smokeAffectedQuery.HasComponent(args.OtherEntity)) + return; + + var smokeAffected = AddComp(args.OtherEntity); + smokeAffected.SmokeEntity = uid; + smokeAffected.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1); + } + + private void OnEndCollide(EntityUid uid, SmokeComponent component, ref EndCollideEvent args) + { + // if we are already in smoke, make sure the thing we are exiting is the current smoke we are in. + if (_smokeAffectedQuery.TryGetComponent(args.OtherEntity, out var smokeAffectedComponent)) + { + if (smokeAffectedComponent.SmokeEntity != uid) + return; + } + + var exists = Exists(uid); + + if (!TryComp(args.OtherEntity, out var body)) + return; + + foreach (var ent in _physics.GetContactingEntities(args.OtherEntity, body)) + { + if (exists && ent == uid) + continue; + + if (!_smokeQuery.HasComponent(ent)) + continue; + + smokeAffectedComponent ??= EnsureComp(args.OtherEntity); + smokeAffectedComponent.SmokeEntity = ent; + return; // exit the function so we don't remove the component. + } + + if (smokeAffectedComponent != null) + RemComp(args.OtherEntity, smokeAffectedComponent); + } + + private void OnAffectedUnpaused(EntityUid uid, SmokeAffectedComponent component, ref EntityUnpausedEvent args) + { + component.NextSecond += args.PausedTime; } private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args) { - if (component.SpreadAmount == 0 - || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) + if (component.SpreadAmount == 0 || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) { RemCompDeferred(uid); return; } - var prototype = MetaData(uid).EntityPrototype; - - if (prototype == null) + if (Prototype(uid) is not { } prototype) { RemCompDeferred(uid); return; } + if (!args.NeighborFreeTiles.Any()) + return; + TryComp(uid, out var timer); - _appearance.TryGetData(uid, SmokeVisuals.Color, out var color); // wtf is the logic behind any of this. - var smokePerSpread = 1 + component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count); + var smokePerSpread = component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count); foreach (var neighbor in args.NeighborFreeTiles) { var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile); var ent = Spawn(prototype.ID, coords); - var neighborSmoke = EnsureComp(ent); - neighborSmoke.SpreadAmount = Math.Max(0, smokePerSpread - 2); // why - 2? who the fuck knows. - component.SpreadAmount--; - args.Updates--; + var spreadAmount = Math.Max(0, smokePerSpread); + component.SpreadAmount -= args.NeighborFreeTiles.Count(); - // Listen this is the old behaviour iunno - Start(ent, neighborSmoke, solution.Clone(), timer?.Lifetime ?? 10f); - - if (color != null) - _appearance.SetData(ent, SmokeVisuals.Color, color); + StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? component.Duration, spreadAmount); if (component.SpreadAmount == 0) { RemCompDeferred(uid); break; } - - if (args.Updates <= 0) - break; } + args.Updates--; + if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1) return; @@ -100,7 +179,6 @@ public sealed class SmokeSystem : EntitySystem continue; smoke.SpreadAmount++; - args.Updates--; component.SpreadAmount--; EnsureComp(neighbor); @@ -110,6 +188,7 @@ public sealed class SmokeSystem : EntitySystem break; } } + } private void OnReactionAttempt(EntityUid uid, SmokeComponent component, ReactionAttemptEvent args) @@ -128,101 +207,117 @@ public sealed class SmokeSystem : EntitySystem } } - private void OnSmokeUnpaused(EntityUid uid, SmokeComponent component, ref EntityUnpausedEvent args) + /// + /// Sets up a smoke component for spreading. + /// + public void StartSmoke(EntityUid uid, Solution solution, float duration, int spreadAmount, SmokeComponent? component = null) { - component.NextReact += args.PausedTime; - } + if (!Resolve(uid, ref component)) + return; - /// - public override void Update(float frameTime) - { - base.Update(frameTime); - var query = EntityQueryEnumerator(); - var curTime = _timing.CurTime; + component.SpreadAmount = spreadAmount; + component.Duration = duration; + component.TransferRate = solution.Volume / duration; + TryAddSolution(uid, solution); + Dirty(uid, component); + EnsureComp(uid); - while (query.MoveNext(out var uid, out var smoke)) + if (TryComp(uid, out var body) && TryComp(uid, out var fixtures)) { - if (smoke.NextReact > curTime) - continue; - - smoke.NextReact += TimeSpan.FromSeconds(1.5); - - SmokeReact(uid, 1f, smoke); + var xform = Transform(uid); + _physics.SetBodyType(uid, BodyType.Dynamic, fixtures, body, xform); + _physics.SetCanCollide(uid, true, manager: fixtures, body: body); + _broadphase.RegenerateContacts(uid, body, fixtures, xform); } + + var timer = EnsureComp(uid); + timer.Lifetime = duration; + + // The tile reaction happens here because it only occurs once. + ReactOnTile(uid, component); } /// - /// Does the relevant smoke reactions for an entity for the specified exposure duration. + /// Does the relevant smoke reactions for an entity. /// - public void SmokeReact(EntityUid uid, float frameTime, SmokeComponent? component = null, TransformComponent? xform = null) + public void SmokeReact(EntityUid entity, EntityUid smokeUid, SmokeComponent? component = null) { - if (!Resolve(uid, ref component, ref xform)) + if (!Resolve(smokeUid, ref component)) return; - if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || + if (!_solutionSystem.TryGetSolution(smokeUid, SmokeComponent.SolutionName, out var solution) || solution.Contents.Count == 0) { return; } + ReactWithEntity(entity, smokeUid, solution, component); + UpdateVisuals(smokeUid); + } + + private void ReactWithEntity(EntityUid entity, EntityUid smokeUid, Solution solution, SmokeComponent? component = null) + { + if (!Resolve(smokeUid, ref component)) + return; + + if (!TryComp(entity, out var bloodstream)) + return; + + var blockIngestion = _internals.AreInternalsWorking(entity); + + var cloneSolution = solution.Clone(); + var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate); + var transferAmount = FixedPoint2.Min(availableTransfer, bloodstream.ChemicalSolution.AvailableVolume); + var transferSolution = cloneSolution.SplitSolution(transferAmount); + + foreach (var reagentQuantity in transferSolution.Contents.ToArray()) + { + if (reagentQuantity.Quantity == FixedPoint2.Zero) + continue; + var reagentProto = _prototype.Index(reagentQuantity.Reagent.Prototype); + + _reactive.ReactionEntity(entity, ReactionMethod.Touch, reagentProto, reagentQuantity, transferSolution); + if (!blockIngestion) + _reactive.ReactionEntity(entity, ReactionMethod.Ingestion, reagentProto, reagentQuantity, transferSolution); + } + + if (blockIngestion) + return; + + if (_blood.TryAddToChemicals(entity, transferSolution, bloodstream)) + { + // Log solution addition by smoke + _logger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity):target} ingested smoke {SolutionContainerSystem.ToPrettyString(transferSolution)}"); + } + } + + private void ReactOnTile(EntityUid uid, SmokeComponent? component = null, TransformComponent? xform = null) + { + if (!Resolve(uid, ref component, ref xform)) + return; + + if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || !solution.Any()) + return; + if (!_mapManager.TryGetGrid(xform.GridUid, out var mapGrid)) return; - var tile = mapGrid.GetTileRef(xform.Coordinates.ToVector2i(EntityManager, _mapManager)); - - var solutionFraction = 1 / Math.Floor(frameTime); - var ents = _lookup.GetEntitiesIntersecting(tile, 0f, flags: LookupFlags.Uncontained).ToArray(); + var tile = mapGrid.GetTileRef(xform.Coordinates.ToVector2i(EntityManager, _mapManager, _transform)); foreach (var reagentQuantity in solution.Contents.ToArray()) { if (reagentQuantity.Quantity == FixedPoint2.Zero) continue; - // NOOP, react with entities on the tile or whatever. + var reagent = _prototype.Index(reagentQuantity.Reagent.Prototype); + reagent.ReactionTile(tile, reagentQuantity.Quantity); } - - foreach (var entity in ents) - { - if (entity == uid) - continue; - - ReactWithEntity(entity, solution, solutionFraction); - } - - UpdateVisuals(uid); - } - - private void UpdateVisuals(EntityUid uid) - { - if (TryComp(uid, out AppearanceComponent? appearance) && - _solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) - { - var color = solution.GetColor(_prototype); - _appearance.SetData(uid, SmokeVisuals.Color, color, appearance); - } - } - - private void ReactWithEntity(EntityUid entity, Solution solution, double solutionFraction) - { - // NOOP due to people complaining constantly. - return; - } - - /// - /// Sets up a smoke component for spreading. - /// - public void Start(EntityUid uid, SmokeComponent component, Solution solution, float duration) - { - TryAddSolution(uid, component, solution); - EnsureComp(uid); - var timer = EnsureComp(uid); - timer.Lifetime = duration; } /// /// Adds the specified solution to the relevant smoke solution. /// - public void TryAddSolution(EntityUid uid, SmokeComponent component, Solution solution) + private void TryAddSolution(EntityUid uid, Solution solution) { if (solution.Volume == FixedPoint2.Zero) return; @@ -237,4 +332,14 @@ public sealed class SmokeSystem : EntitySystem UpdateVisuals(uid); } + + private void UpdateVisuals(EntityUid uid) + { + if (!TryComp(uid, out AppearanceComponent? appearance) || + !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution)) + return; + + var color = solution.GetColor(_prototype); + _appearance.SetData(uid, SmokeVisuals.Color, color, appearance); + } } diff --git a/Content.Server/Fluids/ShowFluidsCommand.cs b/Content.Server/Fluids/ShowFluidsCommand.cs index f122eadea7..71ac273a45 100644 --- a/Content.Server/Fluids/ShowFluidsCommand.cs +++ b/Content.Server/Fluids/ShowFluidsCommand.cs @@ -1,7 +1,6 @@ using Content.Server.Administration; using Content.Server.Fluids.EntitySystems; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Fluids; @@ -15,7 +14,7 @@ public sealed class ShowFluidsCommand : IConsoleCommand public string Help => $"Usage: {Command}"; public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You must be a player to use this command."); diff --git a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs index 69704ddb56..acf7cbd80d 100644 --- a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.Interaction; using Content.Shared.Verbs; using Robust.Server.GameObjects; using Robust.Shared.Audio; +using Robust.Shared.Player; using Robust.Shared.Timing; // todo: remove this stinky LINQy diff --git a/Content.Server/GameTicking/Commands/JoinGameCommand.cs b/Content.Server/GameTicking/Commands/JoinGameCommand.cs index 366e6c4e77..3276b91200 100644 --- a/Content.Server/GameTicking/Commands/JoinGameCommand.cs +++ b/Content.Server/GameTicking/Commands/JoinGameCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.GameTicking; using Content.Shared.Roles; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Prototypes; @@ -30,7 +29,7 @@ namespace Content.Server.GameTicking.Commands return; } - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { diff --git a/Content.Server/GameTicking/Commands/ObserveCommand.cs b/Content.Server/GameTicking/Commands/ObserveCommand.cs index d608dda9c1..747e54e28b 100644 --- a/Content.Server/GameTicking/Commands/ObserveCommand.cs +++ b/Content.Server/GameTicking/Commands/ObserveCommand.cs @@ -1,6 +1,5 @@ using Content.Shared.Administration; using Content.Shared.GameTicking; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.GameTicking.Commands @@ -14,7 +13,7 @@ namespace Content.Server.GameTicking.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { return; } diff --git a/Content.Server/GameTicking/Commands/RespawnCommand.cs b/Content.Server/GameTicking/Commands/RespawnCommand.cs index 057572297f..4f101d0939 100644 --- a/Content.Server/GameTicking/Commands/RespawnCommand.cs +++ b/Content.Server/GameTicking/Commands/RespawnCommand.cs @@ -14,7 +14,7 @@ namespace Content.Server.GameTicking.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (args.Length > 1) { shell.WriteLine("Must provide <= 1 argument."); diff --git a/Content.Server/GameTicking/Commands/ToggleReadyCommand.cs b/Content.Server/GameTicking/Commands/ToggleReadyCommand.cs index e68c4c5fa7..df418c27ee 100644 --- a/Content.Server/GameTicking/Commands/ToggleReadyCommand.cs +++ b/Content.Server/GameTicking/Commands/ToggleReadyCommand.cs @@ -1,5 +1,4 @@ using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.GameTicking.Commands @@ -13,7 +12,7 @@ namespace Content.Server.GameTicking.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (args.Length != 1) { shell.WriteError(Loc.GetString("shell-wrong-arguments-number")); diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index a5e6d7a605..2d7539bd0f 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -11,7 +11,7 @@ using Content.Shared.Ghost; using Content.Shared.Mind; using Content.Shared.Mobs.Components; using JetBrains.Annotations; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.GameTicking { @@ -29,7 +29,7 @@ namespace Content.Server.GameTicking /// public GamePresetPrototype? CurrentPreset { get; private set; } - private bool StartPreset(IPlayerSession[] origReadyPlayers, bool force) + private bool StartPreset(ICommonSession[] origReadyPlayers, bool force) { var startAttempt = new RoundStartAttemptEvent(origReadyPlayers, force); RaiseLocalEvent(startAttempt); @@ -214,7 +214,7 @@ namespace Content.Server.GameTicking { if (mind.Session != null) // Logging is suppressed to prevent spam from ghost attempts caused by movement attempts { - _chatManager.DispatchServerMessage((IPlayerSession) mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), + _chatManager.DispatchServerMessage(mind.Session, Loc.GetString("comp-mind-ghosting-prevented"), true); } diff --git a/Content.Server/GameTicking/GameTicker.Lobby.cs b/Content.Server/GameTicking/GameTicker.Lobby.cs index b7b6a29a5a..1943a82617 100644 --- a/Content.Server/GameTicking/GameTicker.Lobby.cs +++ b/Content.Server/GameTicking/GameTicker.Lobby.cs @@ -1,10 +1,8 @@ using System.Linq; using Content.Shared.GameTicking; using Content.Server.Station.Components; -using Robust.Server.Player; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Players; using System.Text; namespace Content.Server.GameTicking @@ -79,7 +77,7 @@ namespace Content.Server.GameTicking ("roundId", RoundId), ("playerCount", playerCount), ("readyCount", readyCount), ("mapName", stationNames.ToString()),("gmTitle", gmTitle),("desc", desc)); } - private TickerLobbyStatusEvent GetStatusMsg(IPlayerSession session) + private TickerLobbyStatusEvent GetStatusMsg(ICommonSession session) { _playerGameStatuses.TryGetValue(session.UserId, out var status); return new TickerLobbyStatusEvent(RunLevel != GameRunLevel.PreRoundLobby, LobbySong, LobbyBackground,status == PlayerGameStatus.ReadyToPlay, _roundStartTime, RoundPreloadTime, _roundStartTimeSpan, Paused); @@ -87,7 +85,7 @@ namespace Content.Server.GameTicking private void SendStatusToAll() { - foreach (var player in _playerManager.ServerSessions) + foreach (var player in _playerManager.Sessions) { RaiseNetworkEvent(GetStatusMsg(player), player.ConnectedClient); } @@ -148,7 +146,7 @@ namespace Content.Server.GameTicking } } - public void ToggleReady(IPlayerSession player, bool ready) + public void ToggleReady(ICommonSession player, bool ready) { if (!_playerGameStatuses.ContainsKey(player.UserId)) return; diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs index 4ef55cd563..caa8062f41 100644 --- a/Content.Server/GameTicking/GameTicker.Player.cs +++ b/Content.Server/GameTicking/GameTicker.Player.cs @@ -1,12 +1,13 @@ using Content.Server.Database; -using Content.Server.Players; using Content.Shared.GameTicking; using Content.Shared.GameWindow; using Content.Shared.Players; using Content.Shared.Preferences; using JetBrains.Annotations; +using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Enums; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -17,6 +18,7 @@ namespace Content.Server.GameTicking { [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IServerDbManager _dbManager = default!; + [Dependency] private readonly ActorSystem _actor = default!; private void InitializePlayer() { @@ -49,7 +51,7 @@ namespace Content.Server.GameTicking // Always make sure the client has player data. if (session.Data.ContentDataUncast == null) { - var data = new PlayerData(session.UserId, args.Session.Name); + var data = new ContentPlayerData(session.UserId, args.Session.Name); data.Mind = mindId; data.Whitelisted = await _db.GetWhitelistStatusAsync(session.UserId); // Nyanotrasen - Whitelist session.Data.ContentDataUncast = data; @@ -57,7 +59,7 @@ namespace Content.Server.GameTicking // Make the player actually join the game. // timer time must be > tick length - Timer.Spawn(0, args.Session.JoinGame); + Timer.Spawn(0, () => _playerManager.JoinGame(args.Session)); var record = await _dbManager.GetPlayerRecordByUserId(args.Session.UserId); var firstConnection = record != null && @@ -101,9 +103,16 @@ namespace Content.Server.GameTicking } else { - // Simply re-attach to existing entity. - session.AttachToEntity(mind.CurrentEntity); - PlayerJoinGame(session); + if (_actor.Attach(mind.CurrentEntity, session)) + { + PlayerJoinGame(session); + } + else + { + Log.Error( + $"Failed to attach player {session} with mind {ToPrettyString(mindId)} to its current entity {ToPrettyString(mind.CurrentEntity)}"); + SpawnObserverWaitDb(); + } } break; @@ -146,12 +155,12 @@ namespace Content.Server.GameTicking } } - private HumanoidCharacterProfile GetPlayerProfile(IPlayerSession p) + private HumanoidCharacterProfile GetPlayerProfile(ICommonSession p) { return (HumanoidCharacterProfile) _prefsManager.GetPreferences(p.UserId).SelectedCharacter; } - public void PlayerJoinGame(IPlayerSession session, bool silent = false) + public void PlayerJoinGame(ICommonSession session, bool silent = false) { if (!silent) _chatManager.DispatchServerMessage(session, Loc.GetString("game-ticker-player-join-game-message")); @@ -162,7 +171,7 @@ namespace Content.Server.GameTicking RaiseNetworkEvent(new TickerJoinGameEvent(), session.ConnectedClient); } - private void PlayerJoinLobby(IPlayerSession session) + private void PlayerJoinLobby(ICommonSession session) { _playerGameStatuses[session.UserId] = LobbyEnabled ? PlayerGameStatus.NotReadyToPlay : PlayerGameStatus.ReadyToPlay; _db.AddRoundPlayers(RoundId, session.UserId); @@ -182,9 +191,9 @@ namespace Content.Server.GameTicking public sealed class PlayerJoinedLobbyEvent : EntityEventArgs { - public readonly IPlayerSession PlayerSession; + public readonly ICommonSession PlayerSession; - public PlayerJoinedLobbyEvent(IPlayerSession playerSession) + public PlayerJoinedLobbyEvent(ICommonSession playerSession) { PlayerSession = playerSession; } diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index a10196a43e..85f833bd1c 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -12,7 +12,6 @@ using Content.Shared.Preferences; using JetBrains.Annotations; using Prometheus; using Robust.Server.Maps; -using Robust.Server.Player; using Robust.Shared.Asynchronous; using Robust.Shared.Audio; using Robust.Shared.Map; @@ -205,7 +204,7 @@ namespace Content.Server.GameTicking var startingEvent = new RoundStartingEvent(RoundId); RaiseLocalEvent(startingEvent); - var readyPlayers = new List(); + var readyPlayers = new List(); var readyPlayerProfiles = new Dictionary(); foreach (var (userId, status) in _playerGameStatuses) @@ -344,7 +343,7 @@ namespace Content.Server.GameTicking { connected = true; } - PlayerData? contentPlayerData = null; + ContentPlayerData? contentPlayerData = null; if (userId != null && _playerManager.TryGetPlayerData(userId.Value, out var playerData)) { contentPlayerData = playerData.ContentData(); @@ -493,7 +492,7 @@ namespace Content.Server.GameTicking private void ResettingCleanup() { // Move everybody currently in the server to lobby. - foreach (var player in _playerManager.ServerSessions) + foreach (var player in _playerManager.Sessions) { PlayerJoinLobby(player); } @@ -541,7 +540,7 @@ namespace Content.Server.GameTicking DisallowLateJoin = false; _playerGameStatuses.Clear(); - foreach (var session in _playerManager.ServerSessions) + foreach (var session in _playerManager.Sessions) { _playerGameStatuses[session.UserId] = LobbyEnabled ? PlayerGameStatus.NotReadyToPlay : PlayerGameStatus.ReadyToPlay; } @@ -735,10 +734,10 @@ namespace Content.Server.GameTicking /// public sealed class RoundStartAttemptEvent : CancellableEntityEventArgs { - public IPlayerSession[] Players { get; } + public ICommonSession[] Players { get; } public bool Forced { get; } - public RoundStartAttemptEvent(IPlayerSession[] players, bool forced) + public RoundStartAttemptEvent(ICommonSession[] players, bool forced) { Players = players; Forced = forced; @@ -757,11 +756,11 @@ namespace Content.Server.GameTicking /// If you want to handle a specific player being spawned, remove it from this list and do what you need. /// /// If you spawn a player by yourself from this event, don't forget to call on them. - public List PlayerPool { get; } + public List PlayerPool { get; } public IReadOnlyDictionary Profiles { get; } public bool Forced { get; } - public RulePlayerSpawningEvent(List playerPool, IReadOnlyDictionary profiles, bool forced) + public RulePlayerSpawningEvent(List playerPool, IReadOnlyDictionary profiles, bool forced) { PlayerPool = playerPool; Profiles = profiles; @@ -775,11 +774,11 @@ namespace Content.Server.GameTicking /// public sealed class RulePlayerJobsAssignedEvent { - public IPlayerSession[] Players { get; } + public ICommonSession[] Players { get; } public IReadOnlyDictionary Profiles { get; } public bool Forced { get; } - public RulePlayerJobsAssignedEvent(IPlayerSession[] players, IReadOnlyDictionary profiles, bool forced) + public RulePlayerJobsAssignedEvent(ICommonSession[] players, IReadOnlyDictionary profiles, bool forced) { Players = players; Profiles = profiles; diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index 0c59f93bb0..c2bf523657 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -3,20 +3,20 @@ using System.Linq; using System.Numerics; using Content.Server.Administration.Managers; using Content.Server.Ghost; -using Content.Server.Players; using Content.Server.Spawners.Components; using Content.Server.Speech.Components; using Content.Server.Station.Components; using Content.Shared.CCVar; using Content.Shared.Database; +using Content.Shared.Players; using Content.Shared.Preferences; using Content.Shared.Roles; using Content.Shared.Roles.Jobs; using JetBrains.Annotations; -using Robust.Server.Player; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -29,7 +29,7 @@ namespace Content.Server.GameTicking [Dependency] private readonly SharedJobSystem _jobs = default!; [ValidatePrototypeId] - private const string ObserverPrototypeName = "MobObserver"; + public const string ObserverPrototypeName = "MobObserver"; /// /// How many players have joined the round through normal methods. @@ -52,7 +52,7 @@ namespace Content.Server.GameTicking return spawnableStations; } - private void SpawnPlayers(List readyPlayers, Dictionary profiles, bool force) + private void SpawnPlayers(List readyPlayers, Dictionary profiles, bool force) { // Allow game rules to spawn players by themselves if needed. (For example, nuke ops or wizard) RaiseLocalEvent(new RulePlayerSpawningEvent(readyPlayers, profiles, force)); @@ -116,7 +116,7 @@ namespace Content.Server.GameTicking RaiseLocalEvent(new RulePlayerJobsAssignedEvent(assignedJobs.Keys.Select(x => _playerManager.GetSessionByUserId(x)).ToArray(), profiles, force)); } - private void SpawnPlayer(IPlayerSession player, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) + private void SpawnPlayer(ICommonSession player, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) { var character = GetPlayerProfile(player); @@ -129,7 +129,7 @@ namespace Content.Server.GameTicking SpawnPlayer(player, character, station, jobId, lateJoin, silent); } - private void SpawnPlayer(IPlayerSession player, HumanoidCharacterProfile character, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) + private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile character, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) { // Can't spawn players with a dummy ticker! if (DummyTicker) @@ -271,7 +271,7 @@ namespace Content.Server.GameTicking RaiseLocalEvent(mob, aev, true); } - public void Respawn(IPlayerSession player) + public void Respawn(ICommonSession player) { _mind.WipeMind(player); _adminLogger.Add(LogType.Respawn, LogImpact.Medium, $"Player {player} was respawned."); @@ -289,7 +289,7 @@ namespace Content.Server.GameTicking /// The station they're spawning on /// An optional job for them to spawn as /// Whether or not the player should be greeted upon joining - public void MakeJoinGame(IPlayerSession player, EntityUid station, string? jobId = null, bool silent = false) + public void MakeJoinGame(ICommonSession player, EntityUid station, string? jobId = null, bool silent = false) { if (!_playerGameStatuses.ContainsKey(player.UserId)) return; @@ -303,7 +303,7 @@ namespace Content.Server.GameTicking /// /// Causes the given player to join the current game as observer ghost. See also /// - public void JoinAsObserver(IPlayerSession player) + public void JoinAsObserver(ICommonSession player) { // Can't spawn players with a dummy ticker! if (DummyTicker) @@ -317,7 +317,7 @@ namespace Content.Server.GameTicking /// Spawns an observer ghost and attaches the given player to it. If the player does not yet have a mind, the /// player is given a new mind with the observer role. Otherwise, the current mind is transferred to the ghost. /// - public void SpawnObserver(IPlayerSession player) + public void SpawnObserver(ICommonSession player) { if (DummyTicker) return; @@ -430,13 +430,13 @@ namespace Content.Server.GameTicking [PublicAPI] public sealed class PlayerBeforeSpawnEvent : HandledEntityEventArgs { - public IPlayerSession Player { get; } + public ICommonSession Player { get; } public HumanoidCharacterProfile Profile { get; } public string? JobId { get; } public bool LateJoin { get; } public EntityUid Station { get; } - public PlayerBeforeSpawnEvent(IPlayerSession player, HumanoidCharacterProfile profile, string? jobId, bool lateJoin, EntityUid station) + public PlayerBeforeSpawnEvent(ICommonSession player, HumanoidCharacterProfile profile, string? jobId, bool lateJoin, EntityUid station) { Player = player; Profile = profile; @@ -455,7 +455,7 @@ namespace Content.Server.GameTicking public sealed class PlayerSpawnCompleteEvent : EntityEventArgs { public EntityUid Mob { get; } - public IPlayerSession Player { get; } + public ICommonSession Player { get; } public string? JobId { get; } public bool LateJoin { get; } public EntityUid Station { get; } @@ -464,7 +464,7 @@ namespace Content.Server.GameTicking // Ex. If this is the 27th person to join, this will be 27. public int JoinOrder { get; } - public PlayerSpawnCompleteEvent(EntityUid mob, IPlayerSession player, string? jobId, bool lateJoin, int joinOrder, EntityUid station, HumanoidCharacterProfile profile) + public PlayerSpawnCompleteEvent(EntityUid mob, ICommonSession player, string? jobId, bool lateJoin, int joinOrder, EntityUid station, HumanoidCharacterProfile profile) { Mob = mob; Player = player; diff --git a/Content.Server/GameTicking/Rules/Components/RevolutionaryRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/RevolutionaryRuleComponent.cs index 7d036c615b..e9c8d50cdc 100644 --- a/Content.Server/GameTicking/Rules/Components/RevolutionaryRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/RevolutionaryRuleComponent.cs @@ -39,7 +39,7 @@ public sealed partial class RevolutionaryRuleComponent : Component /// Sound that plays when you are chosen as Rev. (Placeholder until I find something cool I guess) /// [DataField] - public SoundSpecifier HeadRevStartSound = new SoundPathSpecifier("/Audio/Ambience/Antag/traitor_start.ogg"); + public SoundSpecifier HeadRevStartSound = new SoundPathSpecifier("/Audio/Ambience/Antag/headrev_start.ogg"); /// /// Min players needed for Revolutionary gamemode to start. diff --git a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs index 883abef52f..7af87179d6 100644 --- a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs @@ -1,7 +1,7 @@ using Content.Shared.Preferences; using Content.Shared.Roles; -using Robust.Server.Player; using Robust.Shared.Audio; +using Robust.Shared.Player; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.GameTicking.Rules.Components; @@ -26,7 +26,7 @@ public sealed partial class TraitorRuleComponent : Component public SelectionState SelectionStatus = SelectionState.WaitingForSpawn; public TimeSpan AnnounceAt = TimeSpan.Zero; - public Dictionary StartCandidates = new(); + public Dictionary StartCandidates = new(); /// /// Path to antagonist alert sound. diff --git a/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs b/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs index c2e91ba4a5..b775b7af56 100644 --- a/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/InactivityTimeRestartRuleSystem.cs @@ -2,6 +2,7 @@ using System.Threading; using Content.Server.Chat.Managers; using Content.Server.GameTicking.Rules.Components; using Robust.Server.Player; +using Robust.Shared.Player; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs b/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs index 94eeb5de56..01fd97d9a7 100644 --- a/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/KillCalloutRuleSystem.cs @@ -2,8 +2,8 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.KillTracking; using Content.Shared.Chat; -using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.GameTicking.Rules; diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 13d4ed71c8..779c47885f 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -334,7 +334,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var eligibleQuery = EntityQueryEnumerator(); while (eligibleQuery.MoveNext(out var eligibleUid, out var eligibleComp, out var member)) { - if (!_npcFaction.IsFactionFriendly(component.Faction, eligibleUid, member)) + if (!_npcFaction.IsFactionHostile(component.Faction, eligibleUid, member)) continue; eligible.Add((eligibleUid, eligibleComp, member)); @@ -349,8 +349,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var query = EntityQueryEnumerator(); while (query.MoveNext(out _, out var nukeops, out var actor)) { - _chatManager.DispatchServerMessage(actor.PlayerSession, Loc.GetString("nukeops-welcome", ("station", component.TargetStation.Value))); - _audio.PlayGlobal(nukeops.GreetSoundNotification, actor.PlayerSession); + NotifyNukie(actor.PlayerSession, nukeops, component); filter.AddPlayer(actor.PlayerSession); } } @@ -602,11 +601,11 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var maxOperatives = nukeops.MaxOps; // Dear lord what is happening HERE. - var everyone = new List(ev.PlayerPool); - var prefList = new List(); - var medPrefList = new List(); - var cmdrPrefList = new List(); - var operatives = new List(); + var everyone = new List(ev.PlayerPool); + var prefList = new List(); + var medPrefList = new List(); + var cmdrPrefList = new List(); + var operatives = new List(); // The LINQ expression ReSharper keeps suggesting is completely unintelligible so I'm disabling it // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator @@ -637,7 +636,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem for (var i = 0; i < numNukies; i++) { // TODO: Please fix this if you touch it. - IPlayerSession nukeOp; + ICommonSession nukeOp; // Only one commander, so we do it at the start if (i == 0) { @@ -793,10 +792,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem if (nukeops.TargetStation != null && !string.IsNullOrEmpty(Name(nukeops.TargetStation.Value))) { - _chatManager.DispatchServerMessage(playerSession, Loc.GetString("nukeops-welcome", ("station", nukeops.TargetStation.Value))); - - // Notificate player about new role assignment - _audio.PlayGlobal(component.GreetSoundNotification, playerSession); + NotifyNukie(playerSession, component, nukeops); } } } @@ -908,7 +904,7 @@ public sealed class NukeopsRuleSystem : GameRuleSystem _npcFaction.AddFaction(mob, "Syndicate"); } - private void SpawnOperatives(int spawnCount, List sessions, bool addSpawnPoints, NukeopsRuleComponent component) + private void SpawnOperatives(int spawnCount, List sessions, bool addSpawnPoints, NukeopsRuleComponent component) { if (component.NukieOutpost == null) return; @@ -987,13 +983,25 @@ public sealed class NukeopsRuleSystem : GameRuleSystem var playersPerOperative = component.PlayersPerOperative; var maxOperatives = component.MaxOps; - var playerPool = _playerManager.ServerSessions.ToList(); + var playerPool = _playerManager.Sessions.ToList(); var numNukies = MathHelper.Clamp(playerPool.Count / playersPerOperative, 1, maxOperatives); - var operatives = new List(); + var operatives = new List(); SpawnOperatives(numNukies, operatives, true, component); } + /// + /// Display a greeting message and play a sound for a nukie + /// + private void NotifyNukie(ICommonSession session, NukeOperativeComponent nukeop, NukeopsRuleComponent nukeopsRule) + { + if (nukeopsRule.TargetStation is not { } station) + return; + + _chatManager.DispatchServerMessage(session, Loc.GetString("nukeops-welcome", ("station", station))); + _audio.PlayGlobal(nukeop.GreetSoundNotification, session); + } + //For admins forcing someone to nukeOps. public void MakeLoneNukie(EntityUid mindId, MindComponent mind) { diff --git a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs index b223161c10..0785d81d09 100644 --- a/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/PiratesRuleSystem.cs @@ -15,10 +15,10 @@ using Content.Shared.Preferences; using Content.Shared.Roles; using Robust.Server.GameObjects; using Robust.Server.Maps; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -141,7 +141,7 @@ public sealed class PiratesRuleSystem : GameRuleSystem (int) Math.Min( Math.Floor((double) ev.PlayerPool.Count / _cfg.GetCVar(CCVars.PiratesPlayersPerOp)), _cfg.GetCVar(CCVars.PiratesMaxOps))); - var ops = new IPlayerSession[numOps]; + var ops = new ICommonSession[numOps]; for (var i = 0; i < numOps; i++) { ops[i] = _random.PickAndTake(ev.PlayerPool); diff --git a/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs b/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs index a286808623..94f4072243 100644 --- a/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RespawnRuleSystem.cs @@ -1,14 +1,14 @@ using Content.Server.Chat.Managers; using Content.Server.GameTicking.Rules.Components; -using Content.Server.Players; using Content.Server.Station.Systems; using Content.Shared.Chat; using Content.Shared.Interaction.Events; using Content.Shared.Mind; using Content.Shared.Mobs; -using Robust.Server.GameObjects; +using Content.Shared.Players; using Robust.Server.Player; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index 01317dbfc1..ef949d09fc 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -17,9 +17,8 @@ using Content.Shared.PDA; using Content.Shared.Preferences; using Content.Shared.Roles; using Content.Shared.Roles.Jobs; -using Robust.Server.Player; using Robust.Shared.Configuration; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -151,9 +150,9 @@ public sealed class TraitorRuleSystem : GameRuleSystem } } - private List FindPotentialTraitors(in Dictionary candidates, TraitorRuleComponent component) + private List FindPotentialTraitors(in Dictionary candidates, TraitorRuleComponent component) { - var list = new List(); + var list = new List(); var pendingQuery = GetEntityQuery(); foreach (var player in candidates.Keys) @@ -171,7 +170,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem list.Add(player); } - var prefList = new List(); + var prefList = new List(); foreach (var player in list) { @@ -189,9 +188,9 @@ public sealed class TraitorRuleSystem : GameRuleSystem return prefList; } - private List PickTraitors(int traitorCount, List prefList) + private List PickTraitors(int traitorCount, List prefList) { - var results = new List(traitorCount); + var results = new List(traitorCount); if (prefList.Count == 0) { Log.Info("Insufficient ready players to fill up with traitors, stopping the selection."); diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index 82ae4b8fa6..a4febc385c 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -23,7 +23,7 @@ using Content.Shared.Zombies; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Configuration; -using Robust.Shared.Prototypes; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -264,9 +264,9 @@ public sealed class ZombieRuleSystem : GameRuleSystem return; component.InfectedChosen = true; - var allPlayers = _playerManager.ServerSessions.ToList(); - var playerList = new List(); - var prefList = new List(); + var allPlayers = _playerManager.Sessions.ToList(); + var playerList = new List(); + var prefList = new List(); foreach (var player in allPlayers) { if (player.AttachedEntity == null || !HasComp(player.AttachedEntity) || HasComp(player.AttachedEntity)) @@ -288,7 +288,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem var totalInfected = 0; while (totalInfected < numInfected) { - IPlayerSession zombie; + ICommonSession zombie; if (prefList.Count == 0) { if (playerList.Count == 0) diff --git a/Content.Server/Ghost/Ghost.cs b/Content.Server/Ghost/Ghost.cs index d04b1197af..1453bf3faa 100644 --- a/Content.Server/Ghost/Ghost.cs +++ b/Content.Server/Ghost/Ghost.cs @@ -1,7 +1,6 @@ using Content.Server.GameTicking; using Content.Shared.Administration; using Content.Shared.Mind; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Ghost @@ -17,7 +16,7 @@ namespace Content.Server.Ghost public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You have no session, you can't ghost."); diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index 6789be390e..9a0b74e2df 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -20,6 +20,7 @@ using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Ghost diff --git a/Content.Server/Ghost/Roles/Components/TakeGhostRoleEvent.cs b/Content.Server/Ghost/Roles/Components/TakeGhostRoleEvent.cs index c97e3be9dc..16d46871fe 100644 --- a/Content.Server/Ghost/Roles/Components/TakeGhostRoleEvent.cs +++ b/Content.Server/Ghost/Roles/Components/TakeGhostRoleEvent.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Ghost.Roles.Components; diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index 95677622db..23d88c253c 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -4,7 +4,6 @@ using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Events; using Content.Server.Ghost.Roles.UI; using Content.Server.Mind.Commands; -using Content.Server.Players; using Content.Shared.Administration; using Content.Shared.Database; using Content.Shared.Follower; @@ -14,13 +13,14 @@ using Content.Shared.Ghost.Roles; using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Mobs; +using Content.Shared.Players; using Content.Shared.Roles; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -98,7 +98,7 @@ namespace Content.Server.Ghost.Roles return unchecked(_nextRoleIdentifier++); } - public void OpenEui(IPlayerSession session) + public void OpenEui(ICommonSession session) { if (session.AttachedEntity is not {Valid: true} attached || !EntityManager.HasComponent(attached)) @@ -112,7 +112,7 @@ namespace Content.Server.Ghost.Roles eui.StateDirty(); } - public void OpenMakeGhostRoleEui(IPlayerSession session, EntityUid uid) + public void OpenMakeGhostRoleEui(ICommonSession session, EntityUid uid) { if (session.AttachedEntity == null) return; @@ -421,7 +421,7 @@ namespace Content.Server.Ghost.Roles public void Execute(IConsoleShell shell, string argStr, string[] args) { if(shell.Player != null) - EntitySystem.Get().OpenEui((IPlayerSession)shell.Player); + EntitySystem.Get().OpenEui(shell.Player); else shell.WriteLine("You can only open the ghost roles UI on a client."); } diff --git a/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs b/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs index bbf7813c16..7dc5fc55ab 100644 --- a/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs +++ b/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs @@ -1,5 +1,5 @@ using Content.Server.Explosion.EntitySystems; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.GhostKick; diff --git a/Content.Server/Gravity/GravityGeneratorSystem.cs b/Content.Server/Gravity/GravityGeneratorSystem.cs index 48002fb823..0bd159f61a 100644 --- a/Content.Server/Gravity/GravityGeneratorSystem.cs +++ b/Content.Server/Gravity/GravityGeneratorSystem.cs @@ -6,7 +6,7 @@ using Content.Shared.Database; using Content.Shared.Gravity; using Content.Shared.Interaction; using Robust.Server.GameObjects; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Gravity { @@ -139,7 +139,7 @@ namespace Content.Server.Gravity return; if (session is { AttachedEntity: { } }) - _adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{ToPrettyString(session.AttachedEntity.Value):player} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}"); + _adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{session:player} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}"); component.SwitchedOn = on; UpdatePowerState(component, powerReceiver); diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index b5b01ac001..e3e6699537 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -18,12 +18,11 @@ using Content.Shared.Pulling.Components; using Content.Shared.Stacks; using Content.Shared.Storage; using Content.Shared.Throwing; -using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Input.Binding; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Hands.Systems @@ -159,9 +158,9 @@ namespace Content.Server.Hands.Systems #endregion #region interactions - private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coordinates, EntityUid entity) + private bool HandleThrowItem(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) { - if (session is not IPlayerSession playerSession) + if (playerSession == null) return false; if (playerSession.AttachedEntity is not {Valid: true} player || @@ -220,7 +219,7 @@ namespace Content.Server.Hands.Systems // TODO: move to storage or inventory private void HandleSmartEquip(ICommonSession? session, string equipmentSlot) { - if (session is not IPlayerSession playerSession) + if (session is not { } playerSession) return; if (playerSession.AttachedEntity is not {Valid: true} plyEnt || !Exists(plyEnt)) diff --git a/Content.Server/Holiday/Christmas/LimitedItemGiverSystem.cs b/Content.Server/Holiday/Christmas/LimitedItemGiverSystem.cs index 58cf415a25..cf7f684343 100644 --- a/Content.Server/Holiday/Christmas/LimitedItemGiverSystem.cs +++ b/Content.Server/Holiday/Christmas/LimitedItemGiverSystem.cs @@ -2,7 +2,7 @@ using Content.Server.Popups; using Content.Shared.Interaction; using Content.Shared.Storage; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Holiday.Christmas; diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs index 7c0bb7383b..05a8b06222 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs @@ -3,7 +3,7 @@ using Content.Shared.Administration; using Content.Shared.Humanoid; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Humanoid; @@ -48,7 +48,7 @@ public sealed partial class HumanoidAppearanceSystem private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent component, HumanoidMarkingModifierBaseLayersSetMessage message) { - if (message.Session is not IPlayerSession player + if (message.Session is not { } player || !_adminManager.HasAdminFlag(player, AdminFlags.Fun)) { return; @@ -81,7 +81,7 @@ public sealed partial class HumanoidAppearanceSystem private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component, HumanoidMarkingModifierMarkingSetMessage message) { - if (message.Session is not IPlayerSession player + if (message.Session is not { } player || !_adminManager.HasAdminFlag(player, AdminFlags.Fun)) { return; diff --git a/Content.Server/Implants/ImplanterSystem.cs b/Content.Server/Implants/ImplanterSystem.cs index f3072769e4..0d46241f41 100644 --- a/Content.Server/Implants/ImplanterSystem.cs +++ b/Content.Server/Implants/ImplanterSystem.cs @@ -1,11 +1,9 @@ -using Content.Server.Guardian; using Content.Server.Popups; using Content.Shared.DoAfter; using Content.Shared.IdentityManagement; using Content.Shared.Implants; using Content.Shared.Implants.Components; using Content.Shared.Interaction; -using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Robust.Shared.Containers; @@ -33,28 +31,39 @@ public sealed partial class ImplanterSystem : SharedImplanterSystem if (args.Target == null || !args.CanReach || args.Handled) return; - //Simplemobs and regular mobs should be injectable, but only regular mobs have mind. - //So just don't implant/draw anything that isn't living or is a guardian - //TODO: Rework a bit when surgery is in to work with implant cases - if (!HasComp(args.Target.Value) || HasComp(args.Target.Value)) + var target = args.Target.Value; + if (!CheckTarget(target, component.Whitelist, component.Blacklist)) return; //TODO: Rework when surgery is in for implant cases if (component.CurrentMode == ImplanterToggleMode.Draw && !component.ImplantOnly) { - TryDraw(component, args.User, args.Target.Value, uid); + TryDraw(component, args.User, target, uid); } else { - if (!CanImplant(args.User, args.Target.Value, uid, component, out _, out _)) + if (!CanImplant(args.User, target, uid, component, out var implant, out _)) + { + // no popup if implant doesn't exist + if (implant == null) + return; + + // show popup to the user saying implant failed + var name = Identity.Name(target, EntityManager, args.User); + var msg = Loc.GetString("implanter-component-implant-failed", ("implant", implant), ("target", name)); + _popup.PopupEntity(msg, target, args.User); + // prevent further interaction since popup was shown + args.Handled = true; return; + } //Implant self instantly, otherwise try to inject the target. - if (args.User == args.Target) - Implant(args.User, args.Target.Value, uid, component); + if (args.User == target) + Implant(target, target, uid, component); else - TryImplant(component, args.User, args.Target.Value, uid); + TryImplant(component, args.User, target, uid); } + args.Handled = true; } diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index 810d265314..4302ab6791 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -1,7 +1,7 @@ using Content.Server.UserInterface; using Content.Shared.Instruments; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Instruments; @@ -17,7 +17,7 @@ public sealed partial class InstrumentComponent : SharedInstrumentComponent [ViewVariables] public uint LastSequencerTick = 0; // TODO Instruments: Make this ECS - public IPlayerSession? InstrumentPlayer => + public ICommonSession? InstrumentPlayer => _entMan.GetComponentOrNull(Owner)?.CurrentSingleUser ?? _entMan.GetComponentOrNull(Owner)?.PlayerSession; } diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index ec23382105..6f8369182c 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -9,12 +9,12 @@ using Content.Shared.Physics; using Content.Shared.Popups; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Audio.Midi; using Robust.Shared.Collections; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.GameStates; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Instruments; @@ -385,7 +385,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem var nearby = GetBands(entity); _bui.TrySendUiMessage(entity, request.UiKey, new InstrumentBandResponseBuiMessage(nearby), - (IPlayerSession)request.Session); + request.Session); } _bandRequestQueue.Clear(); @@ -447,7 +447,7 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem } } - public void ToggleInstrumentUi(EntityUid uid, IPlayerSession session, InstrumentComponent? component = null) + public void ToggleInstrumentUi(EntityUid uid, ICommonSession session, InstrumentComponent? component = null) { if (!Resolve(uid, ref component)) return; diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index a612b73840..8d4e8eb818 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -1,20 +1,10 @@ - - -using Content.Server.Administration.Logs; -using Content.Server.Pulling; using Content.Shared.ActionBlocker; -using Content.Shared.DragDrop; -using Content.Shared.Input; using Content.Shared.Interaction; -using Content.Shared.Pulling.Components; using Content.Shared.Storage; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; -using Robust.Shared.Input.Binding; -using Robust.Shared.Map; -using Robust.Shared.Players; -using Robust.Shared.Random; +using Robust.Shared.Player; namespace Content.Server.Interaction { diff --git a/Content.Server/Interaction/TilePryCommand.cs b/Content.Server/Interaction/TilePryCommand.cs index 4fe3599df9..fa75b6d9e4 100644 --- a/Content.Server/Interaction/TilePryCommand.cs +++ b/Content.Server/Interaction/TilePryCommand.cs @@ -1,10 +1,7 @@ using System.Numerics; using Content.Server.Administration; -using Content.Server.Tools.Components; using Content.Shared.Administration; using Content.Shared.Maps; -using Content.Shared.Tools.Components; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; @@ -24,7 +21,7 @@ namespace Content.Server.Interaction public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player?.AttachedEntity is not {} attached) { return; diff --git a/Content.Server/KillTracking/KillTrackingSystem.cs b/Content.Server/KillTracking/KillTrackingSystem.cs index 177f28ddc8..afb4283e82 100644 --- a/Content.Server/KillTracking/KillTrackingSystem.cs +++ b/Content.Server/KillTracking/KillTrackingSystem.cs @@ -2,7 +2,7 @@ using Content.Shared.Damage; using Content.Shared.FixedPoint; using Content.Shared.Mobs; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.KillTracking; diff --git a/Content.Server/MagicMirror/MagicMirrorSystem.cs b/Content.Server/MagicMirror/MagicMirrorSystem.cs index 90a0b19b7d..a599a2c868 100644 --- a/Content.Server/MagicMirror/MagicMirrorSystem.cs +++ b/Content.Server/MagicMirror/MagicMirrorSystem.cs @@ -5,8 +5,7 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; using Content.Shared.MagicMirror; using Robust.Server.GameObjects; -using Robust.Server.Player; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.MagicMirror; @@ -147,7 +146,7 @@ public sealed class MagicMirrorSystem : EntitySystem private void UpdateInterface(EntityUid uid, EntityUid playerUid, ICommonSession session, HumanoidAppearanceComponent? humanoid = null) { - if (!Resolve(playerUid, ref humanoid) || session is not IPlayerSession player) + if (!Resolve(playerUid, ref humanoid) || session is not { } player) { return; } diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs index e4a4cd8942..d72a5c4178 100644 --- a/Content.Server/Mapping/MappingCommand.cs +++ b/Content.Server/Mapping/MappingCommand.cs @@ -40,7 +40,7 @@ namespace Content.Server.Mapping public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError(Loc.GetString("cmd-savemap-server")); return; diff --git a/Content.Server/Maps/GridDraggingSystem.cs b/Content.Server/Maps/GridDraggingSystem.cs index 90770af1ad..7d7b61955b 100644 --- a/Content.Server/Maps/GridDraggingSystem.cs +++ b/Content.Server/Maps/GridDraggingSystem.cs @@ -1,10 +1,9 @@ using Content.Shared.Maps; using Robust.Server.Console; -using Robust.Server.Player; -using Robust.Shared.Players; using Robust.Shared.Utility; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; +using Robust.Shared.Player; namespace Content.Server.Maps; @@ -27,7 +26,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem public void Toggle(ICommonSession session) { - if (session is not IPlayerSession pSession) + if (session is not { } pSession) return; DebugTools.Assert(_admin.CanCommand(pSession, CommandName)); @@ -52,7 +51,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem { var grid = GetEntity(ev.Grid); - if (args.SenderSession is not IPlayerSession playerSession || + if (args.SenderSession is not { } playerSession || !_admin.CanCommand(playerSession, CommandName) || !Exists(grid) || Deleted(grid)) @@ -69,7 +68,7 @@ public sealed class GridDraggingSystem : SharedGridDraggingSystem { var grid = GetEntity(msg.Grid); - if (args.SenderSession is not IPlayerSession playerSession || + if (args.SenderSession is not { } playerSession || !_admin.CanCommand(playerSession, CommandName) || !Exists(grid) || Deleted(grid)) diff --git a/Content.Server/MassMedia/Systems/NewsSystem.cs b/Content.Server/MassMedia/Systems/NewsSystem.cs index 98bfe702b6..93663474ac 100644 --- a/Content.Server/MassMedia/Systems/NewsSystem.cs +++ b/Content.Server/MassMedia/Systems/NewsSystem.cs @@ -18,6 +18,7 @@ using Content.Shared.MassMedia.Systems; using Content.Shared.PDA; using Robust.Server.GameObjects; using Robust.Shared.Containers; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.MassMedia.Systems; @@ -210,7 +211,6 @@ public sealed class NewsSystem : EntitySystem continue; _ringer.RingerPlayRingtone(uid, ringer); - break; } } diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index fd8f8fd767..a0ca94197e 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -20,6 +20,7 @@ using Robust.Server.Containers; using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Player; namespace Content.Server.Mech.Systems; diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index 4ffa9f558d..d041f8ee9d 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -18,7 +18,7 @@ using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Timing; using Content.Shared.Toggleable; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Medical; diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 6e2f7fdf36..cde361ec74 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Mobs.Components; using Robust.Server.GameObjects; using Content.Server.Temperature.Components; using Content.Server.Body.Components; +using Robust.Shared.Player; namespace Content.Server.Medical { diff --git a/Content.Server/Mind/Commands/RenameCommand.cs b/Content.Server/Mind/Commands/RenameCommand.cs index 2d65adc508..bb7d89ddf5 100644 --- a/Content.Server/Mind/Commands/RenameCommand.cs +++ b/Content.Server/Mind/Commands/RenameCommand.cs @@ -9,9 +9,9 @@ using Content.Shared.Administration; using Content.Shared.Mind; using Content.Shared.PDA; using Content.Shared.StationRecords; -using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Console; +using Robust.Shared.Player; namespace Content.Server.Mind.Commands; diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index d2721db7b6..f23e9b6407 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -11,7 +11,9 @@ using Robust.Server.GameObjects; using Robust.Server.GameStates; using Robust.Server.Player; using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -71,51 +73,45 @@ public sealed class MindSystem : SharedMindSystem } TransferTo(mindId, null, createGhost: false, mind: mind); + DebugTools.AssertNull(mind.OwnedEntity); - // Let's not create ghosts if not in the middle of the round. - if (_gameTicker.RunLevel == GameRunLevel.PreRoundLobby) + if (!component.GhostOnShutdown || mind.Session == null || _gameTicker.RunLevel == GameRunLevel.PreRoundLobby) return; - // I just love convoluted entity shutdown logic that results in more entities being spawned. - if (component.GhostOnShutdown && mind.Session != null) + var xform = Transform(uid); + var gridId = xform.GridUid; + var spawnPosition = Transform(uid).Coordinates; + + // Use a regular timer here because the entity has probably been deleted. + Timer.Spawn(0, () => { - var xform = Transform(uid); - var gridId = xform.GridUid; - var spawnPosition = Transform(uid).Coordinates; + // Make extra sure the round didn't end between spawning the timer and it being executed. + if (_gameTicker.RunLevel == GameRunLevel.PreRoundLobby) + return; - // Use a regular timer here because the entity has probably been deleted. - Timer.Spawn(0, () => + // Async this so that we don't throw if the grid we're on is being deleted. + if (!HasComp(gridId)) + spawnPosition = _gameTicker.GetObserverSpawnPoint(); + + // TODO refactor observer spawning. + // please. + if (!spawnPosition.IsValid(EntityManager)) { - // Make extra sure the round didn't end between spawning the timer and it being executed. - if (_gameTicker.RunLevel == GameRunLevel.PreRoundLobby) - return; + // This should be an error, if it didn't cause tests to start erroring when they delete a player. + Log.Warning($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, and no applicable spawn location is available."); + TransferTo(mindId, null, createGhost: false, mind: mind); + return; + } - // Async this so that we don't throw if the grid we're on is being deleted. - if (!_maps.GridExists(gridId)) - spawnPosition = _gameTicker.GetObserverSpawnPoint(); + var ghost = Spawn(GameTicker.ObserverPrototypeName, spawnPosition); + var ghostComponent = Comp(ghost); + _ghosts.SetCanReturnToBody(ghostComponent, false); - // TODO refactor observer spawning. - // please. - if (!spawnPosition.IsValid(EntityManager)) - { - // This should be an error, if it didn't cause tests to start erroring when they delete a player. - Log.Warning($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, and no applicable spawn location is available."); - TransferTo(mindId, null, createGhost: false, mind: mind); - return; - } - - var ghost = Spawn("MobObserver", spawnPosition); - var ghostComponent = Comp(ghost); - _ghosts.SetCanReturnToBody(ghostComponent, false); - - // Log these to make sure they're not causing the GameTicker round restart bugs... - Log.Debug($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, spawned \"{ToPrettyString(ghost)}\"."); - - var val = mind.CharacterName ?? string.Empty; - _metaData.SetEntityName(ghost, val); - TransferTo(mindId, ghost, mind: mind); - }); - } + // Log these to make sure they're not causing the GameTicker round restart bugs... + Log.Debug($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, spawned \"{ToPrettyString(ghost)}\"."); + _metaData.SetEntityName(ghost, mind.CharacterName ?? string.Empty); + TransferTo(mindId, ghost, mind: mind); + }); } public override bool TryGetMind(NetUserId user, [NotNullWhen(true)] out EntityUid? mindId, [NotNullWhen(true)] out MindComponent? mind) @@ -130,18 +126,18 @@ public sealed class MindSystem : SharedMindSystem return false; } - public bool TryGetSession(EntityUid? mindId, [NotNullWhen(true)] out IPlayerSession? session) + public bool TryGetSession(EntityUid? mindId, [NotNullWhen(true)] out ICommonSession? session) { session = null; - return TryComp(mindId, out MindComponent? mind) && (session = (IPlayerSession?) mind.Session) != null; + return TryComp(mindId, out MindComponent? mind) && (session = mind.Session) != null; } - public IPlayerSession? GetSession(MindComponent mind) + public ICommonSession? GetSession(MindComponent mind) { - return (IPlayerSession?) mind.Session; + return mind.Session; } - public bool TryGetSession(MindComponent mind, [NotNullWhen(true)] out IPlayerSession? session) + public bool TryGetSession(MindComponent mind, [NotNullWhen(true)] out ICommonSession? session) { return (session = GetSession(mind)) != null; } @@ -179,7 +175,9 @@ public sealed class MindSystem : SharedMindSystem return; } - GetSession(mind)?.AttachToEntity(entity); + if (GetSession(mind) is { } session) + _actor.Attach(entity, session); + mind.VisitingEntity = entity; // EnsureComp instead of AddComp to deal with deferred deletions. @@ -204,7 +202,8 @@ public sealed class MindSystem : SharedMindSystem return; var owned = mind.OwnedEntity; - GetSession(mind)?.AttachToEntity(owned); + if (GetSession(mind) is { } session) + _actor.Attach(owned, session); if (owned.HasValue) { @@ -294,6 +293,7 @@ public sealed class MindSystem : SharedMindSystem if (session != null && !alreadyAttached && mind.VisitingEntity == null) { _actor.Attach(entity, session, true); + DebugTools.Assert(session.AttachedEntity == entity, $"Failed to attach entity."); Log.Info($"Session {session.Name} transferred to entity {entity}."); } diff --git a/Content.Server/Mind/Toolshed/MindCommand.cs b/Content.Server/Mind/Toolshed/MindCommand.cs index b53f9a6a9c..917e6fb7f1 100644 --- a/Content.Server/Mind/Toolshed/MindCommand.cs +++ b/Content.Server/Mind/Toolshed/MindCommand.cs @@ -1,5 +1,5 @@ using Content.Shared.Mind; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Errors; using Robust.Shared.Toolshed.Syntax; @@ -15,7 +15,7 @@ public sealed class MindCommand : ToolshedCommand private SharedMindSystem? _mind; [CommandImplementation("get")] - public MindComponent? Get([PipedArgument] IPlayerSession session) + public MindComponent? Get([PipedArgument] ICommonSession session) { _mind ??= GetSys(); return _mind.TryGetMind(session, out _, out var mind) ? mind : null; @@ -32,7 +32,7 @@ public sealed class MindCommand : ToolshedCommand public EntityUid Control( [CommandInvocationContext] IInvocationContext ctx, [PipedArgument] EntityUid target, - [CommandArgument] ValueRef playerRef) + [CommandArgument] ValueRef playerRef) { _mind ??= GetSys(); diff --git a/Content.Server/Mobs/CritMobActionsSystem.cs b/Content.Server/Mobs/CritMobActionsSystem.cs index 9d0a6b4a85..0f6a6fc9b0 100644 --- a/Content.Server/Mobs/CritMobActionsSystem.cs +++ b/Content.Server/Mobs/CritMobActionsSystem.cs @@ -6,7 +6,7 @@ using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Robust.Server.Console; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Mobs; diff --git a/Content.Server/Morgue/MorgueSystem.cs b/Content.Server/Morgue/MorgueSystem.cs index b300336cd2..91fb0ab9f1 100644 --- a/Content.Server/Morgue/MorgueSystem.cs +++ b/Content.Server/Morgue/MorgueSystem.cs @@ -3,7 +3,7 @@ using Content.Shared.Body.Components; using Content.Shared.Examine; using Content.Shared.Morgue; using Content.Shared.Morgue.Components; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Morgue; diff --git a/Content.Server/Motd/MOTDCommand.cs b/Content.Server/Motd/MOTDCommand.cs index a1aa4d2df5..9e59589b95 100644 --- a/Content.Server/Motd/MOTDCommand.cs +++ b/Content.Server/Motd/MOTDCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Administration.Managers; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Motd; @@ -14,10 +13,10 @@ internal sealed class MOTDCommand : LocalizedCommands [Dependency] private readonly IAdminManager _adminManager = default!; public override string Command => "motd"; - + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = (IPlayerSession?)shell.Player; + var player = shell.Player; if (args.Length < 1 || (player != null && _adminManager is AdminManager aMan && !aMan.CanCommand(player, "set-motd"))) shell.ConsoleHost.ExecuteCommand(shell.Player, "get-motd"); else @@ -26,7 +25,7 @@ internal sealed class MOTDCommand : LocalizedCommands public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) { - var player = (IPlayerSession?)shell.Player; + var player = shell.Player; if (player != null && _adminManager is AdminManager aMan && !aMan.CanCommand(player, "set-motd")) return CompletionResult.Empty; if (args.Length == 1) diff --git a/Content.Server/Motd/MOTDSystem.cs b/Content.Server/Motd/MOTDSystem.cs index e749fe48f3..39d780f108 100644 --- a/Content.Server/Motd/MOTDSystem.cs +++ b/Content.Server/Motd/MOTDSystem.cs @@ -2,9 +2,9 @@ using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Shared.CCVar; using Content.Shared.Chat; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Configuration; +using Robust.Shared.Player; namespace Content.Server.Motd; @@ -41,7 +41,7 @@ public sealed class MOTDSystem : EntitySystem { if (string.IsNullOrEmpty(_messageOfTheDay)) return; - + var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay)); _chatManager.ChatMessageToAll(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, recordReplay: true); } @@ -49,11 +49,11 @@ public sealed class MOTDSystem : EntitySystem /// /// Sends the Message Of The Day, if any, to a specific player. /// - public void TrySendMOTD(IPlayerSession player) + public void TrySendMOTD(ICommonSession player) { if (string.IsNullOrEmpty(_messageOfTheDay)) return; - + var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay)); _chatManager.ChatMessageToOne(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, client: player.ConnectedClient); } @@ -68,10 +68,10 @@ public sealed class MOTDSystem : EntitySystem { if (string.IsNullOrEmpty(_messageOfTheDay)) return; - + var wrappedMessage = Loc.GetString("motd-wrap-message", ("motd", _messageOfTheDay)); shell.WriteLine(wrappedMessage); - if (shell.Player is IPlayerSession player) + if (shell.Player is { } player) _chatManager.ChatMessageToOne(ChatChannel.Server, _messageOfTheDay, wrappedMessage, source: EntityUid.Invalid, hideChat: false, client: player.ConnectedClient); } @@ -92,7 +92,7 @@ public sealed class MOTDSystem : EntitySystem { if (val == _messageOfTheDay) return; - + _messageOfTheDay = val; TrySendMOTD(); } diff --git a/Content.Server/Motd/SetMOTDCommand.cs b/Content.Server/Motd/SetMOTDCommand.cs index f3f52b0670..9678781c87 100644 --- a/Content.Server/Motd/SetMOTDCommand.cs +++ b/Content.Server/Motd/SetMOTDCommand.cs @@ -4,7 +4,6 @@ using Content.Shared.Administration; using Content.Shared.Database; using Content.Shared.CCVar; using Content.Server.Chat.Managers; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; @@ -21,18 +20,18 @@ public sealed class SetMotdCommand : LocalizedCommands [Dependency] private readonly IConfigurationManager _configurationManager = default!; public override string Command => "set-motd"; - + public override void Execute(IConsoleShell shell, string argStr, string[] args) { string motd = ""; - var player = (IPlayerSession?)shell.Player; + var player = shell.Player; if (args.Length > 0) { motd = string.Join(" ", args).Trim(); if (player != null && _chatManager.MessageCharacterLimit(player, motd)) return; // check function prints its own error response } - + _configurationManager.SetCVar(CCVars.MOTD, motd); // A hook in MOTDSystem broadcasts changes to the MOTD to everyone so we don't need to do it here. if (string.IsNullOrEmpty(motd)) { diff --git a/Content.Server/Movement/Systems/LagCompensationSystem.cs b/Content.Server/Movement/Systems/LagCompensationSystem.cs index 64965c2fee..0576fe8f25 100644 --- a/Content.Server/Movement/Systems/LagCompensationSystem.cs +++ b/Content.Server/Movement/Systems/LagCompensationSystem.cs @@ -1,7 +1,7 @@ using Content.Server.Movement.Components; using Robust.Server.Player; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.Movement.Systems; diff --git a/Content.Server/NPC/Commands/NPCCommand.cs b/Content.Server/NPC/Commands/NPCCommand.cs index 57fe223b66..7f9e56b8ca 100644 --- a/Content.Server/NPC/Commands/NPCCommand.cs +++ b/Content.Server/NPC/Commands/NPCCommand.cs @@ -2,7 +2,6 @@ using Content.Server.Administration; using Content.Server.EUI; using Content.Server.NPC.UI; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.NPC.Commands; @@ -15,7 +14,7 @@ public sealed class NPCCommand : IConsoleCommand public string Help => $"{Command}"; public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession playerSession) + if (shell.Player is not { } playerSession) { return; } diff --git a/Content.Server/NPC/HTN/HTNSystem.cs b/Content.Server/NPC/HTN/HTNSystem.cs index 2c1dadb127..a7689fbabe 100644 --- a/Content.Server/NPC/HTN/HTNSystem.cs +++ b/Content.Server/NPC/HTN/HTNSystem.cs @@ -4,17 +4,14 @@ using System.Threading; using Content.Server.Administration.Managers; using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues.Queues; -using Content.Server.NPC.Components; using Content.Server.NPC.HTN.PrimitiveTasks; using Content.Server.NPC.Systems; using Content.Shared.Administration; using Content.Shared.Mobs; using Content.Shared.NPC; -using Content.Shared.NPC; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Server.Player; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -48,7 +45,7 @@ public sealed class HTNSystem : EntitySystem private void OnHTNMessage(RequestHTNMessage msg, EntitySessionEventArgs args) { - if (!_admin.HasAdminFlag((IPlayerSession) args.SenderSession, AdminFlags.Debug)) + if (!_admin.HasAdminFlag(args.SenderSession, AdminFlags.Debug)) { _subscribers.Remove(args.SenderSession); return; diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs index bb0eff7b39..1b1f6f5476 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.cs @@ -13,7 +13,7 @@ using Robust.Shared.Enums; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Threading; using Robust.Shared.Timing; @@ -528,7 +528,7 @@ namespace Content.Server.NPC.Pathfinding private void OnBreadcrumbs(RequestPathfindingDebugMessage msg, EntitySessionEventArgs args) { - var pSession = (IPlayerSession) args.SenderSession; + var pSession = args.SenderSession; if (!_adminManager.HasAdminFlag(pSession, AdminFlags.Debug)) { diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index 61b43df6f0..e5b62acfe8 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -17,14 +17,12 @@ using Content.Shared.NPC; using Content.Shared.NPC.Events; using Content.Shared.Physics; using Content.Shared.Weapons.Melee; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -147,7 +145,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem private void OnDebugRequest(RequestNPCSteeringDebugEvent msg, EntitySessionEventArgs args) { - if (!_admin.IsAdmin((IPlayerSession)args.SenderSession)) + if (!_admin.IsAdmin(args.SenderSession)) return; if (msg.Enabled) diff --git a/Content.Server/NPC/Systems/NPCSystem.cs b/Content.Server/NPC/Systems/NPCSystem.cs index 02dc4ceea6..7d33133a37 100644 --- a/Content.Server/NPC/Systems/NPCSystem.cs +++ b/Content.Server/NPC/Systems/NPCSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.NPC; using Robust.Server.GameObjects; using Robust.Shared.Configuration; +using Robust.Shared.Player; namespace Content.Server.NPC.Systems { diff --git a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs index 6f3c3b3f9d..0182bd7ca7 100644 --- a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs +++ b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs @@ -23,7 +23,7 @@ public sealed class SpiderChargeSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(BeforePlant); + SubscribeLocalEvent(OnAttemptStick); SubscribeLocalEvent(OnStuck); SubscribeLocalEvent(OnExplode); } @@ -31,14 +31,17 @@ public sealed class SpiderChargeSystem : EntitySystem /// /// Require that the planter is a ninja and the charge is near the target warp point. /// - private void BeforePlant(EntityUid uid, SpiderChargeComponent comp, BeforeRangedInteractEvent args) + private void OnAttemptStick(EntityUid uid, SpiderChargeComponent comp, AttemptEntityStickEvent args) { + if (args.Cancelled) + return; + var user = args.User; if (!_mind.TryGetRole(user, out var role)) { _popup.PopupEntity(Loc.GetString("spider-charge-not-ninja"), user, user); - args.Handled = true; + args.Cancelled = true; return; } @@ -47,12 +50,14 @@ public sealed class SpiderChargeSystem : EntitySystem return; // assumes warp point still exists - var target = Transform(role.SpiderChargeTarget.Value).MapPosition; - var coords = args.ClickLocation.ToMap(EntityManager, _transform); - if (!coords.InRange(target, comp.Range)) + var targetXform = Transform(role.SpiderChargeTarget.Value); + var locXform = Transform(args.Target); + if (locXform.MapID != targetXform.MapID || + (_transform.GetWorldPosition(locXform) - _transform.GetWorldPosition(targetXform)).LengthSquared() > comp.Range * comp.Range) { _popup.PopupEntity(Loc.GetString("spider-charge-too-far"), user, user); - args.Handled = true; + args.Cancelled = true; + return; } } diff --git a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs index e4bd303150..9ee9702c5b 100644 --- a/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs +++ b/Content.Server/NodeContainer/EntitySystems/NodeGroupSystem.cs @@ -9,6 +9,7 @@ using JetBrains.Annotations; using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.NodeContainer.EntitySystems @@ -29,7 +30,7 @@ namespace Content.Server.NodeContainer.EntitySystems private readonly List _visDeletes = new(); private readonly List _visSends = new(); - private readonly HashSet _visPlayers = new(); + private readonly HashSet _visPlayers = new(); private readonly HashSet _toRemake = new(); private readonly HashSet _nodeGroups = new(); private readonly HashSet _toRemove = new(); @@ -74,7 +75,7 @@ namespace Content.Server.NodeContainer.EntitySystems private void HandleEnableMsg(NodeVis.MsgEnable msg, EntitySessionEventArgs args) { - var session = (IPlayerSession) args.SenderSession; + var session = args.SenderSession; if (!_adminManager.HasAdminFlag(session, AdminFlags.Debug)) return; @@ -397,7 +398,7 @@ namespace Content.Server.NodeContainer.EntitySystems } } - private void VisSendFullStateImmediate(IPlayerSession player) + private void VisSendFullStateImmediate(ICommonSession player) { var msg = new NodeVis.MsgData(); diff --git a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs index 875c328bcb..e8e456c0ea 100644 --- a/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs +++ b/Content.Server/Nutrition/EntitySystems/AnimalHusbandrySystem.cs @@ -9,7 +9,7 @@ using Content.Shared.Nutrition.AnimalHusbandry; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Storage; -using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index 8406ce222d..ff4ec41dd9 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -17,6 +17,7 @@ using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; +using Content.Shared.Interaction.Components; using Content.Shared.Interaction.Events; using Content.Shared.Inventory; using Content.Shared.Mobs.Systems; @@ -101,6 +102,9 @@ public sealed class FoodSystem : EntitySystem if (!TryComp(target, out var body)) return (false, false); + if (HasComp(food)) + return (false, false); + if (_openable.IsClosed(food, user)) return (false, true); diff --git a/Content.Server/Nutrition/Hungry.cs b/Content.Server/Nutrition/Hungry.cs index c27f302a8d..ae68dcd2fd 100644 --- a/Content.Server/Nutrition/Hungry.cs +++ b/Content.Server/Nutrition/Hungry.cs @@ -1,9 +1,7 @@ using Content.Server.Administration; -using Content.Server.Nutrition.Components; using Content.Shared.Administration; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Nutrition @@ -19,7 +17,7 @@ namespace Content.Server.Nutrition public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null) { shell.WriteLine("You cannot use this command unless you are a player."); diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs index 088f615946..ee16aaccfb 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/PsionicAbilitiesSystem.cs @@ -13,6 +13,7 @@ using Robust.Shared.Random; using Robust.Shared.Prototypes; using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Abilities.Psionics { diff --git a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs index debbf928ce..9ba27b65d7 100644 --- a/Content.Server/Nyanotrasen/Chat/TSayCommand.cs +++ b/Content.Server/Nyanotrasen/Chat/TSayCommand.cs @@ -3,6 +3,7 @@ using Content.Shared.Administration; using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Enums; +using Robust.Shared.Player; namespace Content.Server.Chat.Commands { @@ -15,7 +16,7 @@ namespace Content.Server.Chat.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession player) + if (shell.Player is not ICommonSession player) { shell.WriteError("This command cannot be run from the server."); return; @@ -36,7 +37,7 @@ namespace Content.Server.Chat.Commands var message = string.Join(" ", args).Trim(); if (string.IsNullOrEmpty(message)) return; - //Not sure if I should hide the logs from this. Default is false. + //Not sure if I should hide the logs from this. Default is false. EntitySystem.Get().TrySendInGameICMessage(playerEntity, message, InGameICChatType.Telepathic, ChatTransmitRange.Normal, false, shell, player); } } diff --git a/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs b/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs index 707af881e3..9eef7292ea 100644 --- a/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs +++ b/Content.Server/Nyanotrasen/Construction/Commands/TileWindowsCommand.cs @@ -6,6 +6,7 @@ using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; using Robust.Shared.Maths; +using Robust.Shared.Player; namespace Content.Server.Construction.Commands { @@ -23,7 +24,7 @@ namespace Content.Server.Construction.Commands public void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player as ICommonSession; var entityManager = IoCManager.Resolve(); EntityUid? gridId; diff --git a/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs index f0e97f56aa..ccbe8d8e7f 100644 --- a/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs +++ b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs @@ -1,12 +1,12 @@ -using Content.Server.Players; +using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Players.PlayTimeTracking; public sealed partial class PlayTimeTrackingManager { - private void SendWhitelistCached(IPlayerSession playerSession) + private void SendWhitelistCached(ICommonSession playerSession) { var whitelist = playerSession.ContentData()?.Whitelisted ?? false; @@ -21,7 +21,7 @@ public sealed partial class PlayTimeTrackingManager /// /// Queue sending whitelist status to the client. /// - public void QueueSendWhitelist(IPlayerSession player) + public void QueueSendWhitelist(ICommonSession player) { if (DirtyPlayer(player) is { } data) data.NeedRefreshWhitelist = true; diff --git a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs b/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs index f73f8e6fcc..d6067717c9 100644 --- a/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/Dreams/DreamSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Chat.Managers; using Robust.Shared.Random; using Robust.Shared.Prototypes; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Psionics.Dreams { diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs b/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs index c0c3b8dc01..959251d1fb 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs +++ b/Content.Server/Nyanotrasen/Psionics/PsionicsCommands.cs @@ -5,6 +5,7 @@ using Content.Shared.Mobs.Components; using Robust.Shared.Console; using Robust.Server.GameObjects; using Content.Shared.Actions; +using Robust.Shared.Player; namespace Content.Server.Psionics; diff --git a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs index 2548f3da2b..2933df615e 100644 --- a/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs +++ b/Content.Server/Nyanotrasen/Research/Oracle/OracleSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Mobs.Components; using Content.Shared.Psionics.Glimmer; using Content.Shared.Research.Prototypes; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs index a3af9ed6e3..6394456326 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/MassMindSwapRule.cs @@ -7,6 +7,7 @@ using Content.Server.StationEvents.Components; using Content.Shared.Abilities.Psionics; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Robust.Shared.Player; namespace Content.Server.StationEvents.Events; diff --git a/Content.Server/Objectives/Commands/ListObjectivesCommand.cs b/Content.Server/Objectives/Commands/ListObjectivesCommand.cs index 93dec3fa44..97fc943269 100644 --- a/Content.Server/Objectives/Commands/ListObjectivesCommand.cs +++ b/Content.Server/Objectives/Commands/ListObjectivesCommand.cs @@ -18,7 +18,7 @@ namespace Content.Server.Objectives.Commands public override void Execute(IConsoleShell shell, string argStr, string[] args) { - var player = shell.Player as IPlayerSession; + var player = shell.Player; if (player == null || !_players.TryGetSessionByUsername(args[0], out player)) { shell.WriteError(LocalizationManager.GetString("shell-target-player-does-not-exist")); diff --git a/Content.Server/Objectives/Components/HijackShuttleComponent.cs b/Content.Server/Objectives/Components/HijackShuttleComponent.cs deleted file mode 100644 index 010f6f1407..0000000000 --- a/Content.Server/Objectives/Components/HijackShuttleComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Server.Objectives.Systems; - -namespace Content.Server.Objectives.Components; - -[RegisterComponent, Access(typeof(HijackShuttleConditionSystem))] -public sealed partial class HijackShuttleComponent : Component -{ -} diff --git a/Content.Server/Objectives/Components/HijackShuttleConditionComponent.cs b/Content.Server/Objectives/Components/HijackShuttleConditionComponent.cs new file mode 100644 index 0000000000..2f07086af6 --- /dev/null +++ b/Content.Server/Objectives/Components/HijackShuttleConditionComponent.cs @@ -0,0 +1,11 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// Objective condition that requires the player to leave station of escape shuttle with only antags on board or handcuffed humanoids +/// +[RegisterComponent, Access(typeof(HijackShuttleConditionSystem))] +public sealed partial class HijackShuttleConditionComponent : Component +{ +} diff --git a/Content.Server/Objectives/Systems/HijackShuttleConditionSystem.cs b/Content.Server/Objectives/Systems/HijackShuttleConditionSystem.cs index 5ea560297c..9e0d2c3d5b 100644 --- a/Content.Server/Objectives/Systems/HijackShuttleConditionSystem.cs +++ b/Content.Server/Objectives/Systems/HijackShuttleConditionSystem.cs @@ -23,17 +23,17 @@ public sealed class HijackShuttleConditionSystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnGetProgress); + SubscribeLocalEvent(OnGetProgress); } - private void OnGetProgress(EntityUid uid, HijackShuttleComponent comp, ref ObjectiveGetProgressEvent args) + private void OnGetProgress(EntityUid uid, HijackShuttleConditionComponent comp, ref ObjectiveGetProgressEvent args) { args.Progress = GetProgress(args.MindId, args.Mind); } private float GetProgress(EntityUid mindId, MindComponent mind) { - // not escaping alive if you're deleted/dead + // Not escaping alive if you're deleted/dead if (mind.OwnedEntity == null || _mind.IsCharacterDeadIc(mind)) return 0f; diff --git a/Content.Server/PAI/PAISystem.cs b/Content.Server/PAI/PAISystem.cs index d3dac3edaa..e9505b5e6f 100644 --- a/Content.Server/PAI/PAISystem.cs +++ b/Content.Server/PAI/PAISystem.cs @@ -6,9 +6,9 @@ using Content.Shared.Interaction.Events; using Content.Shared.Mind.Components; using Content.Shared.PAI; using Content.Shared.Popups; -using Robust.Server.GameObjects; using Robust.Shared.Random; using System.Text; +using Robust.Shared.Player; namespace Content.Server.PAI; diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index 6c506dc3dd..44e2659841 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -4,9 +4,6 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.Instruments; using Content.Server.Light.EntitySystems; using Content.Server.Light.Events; -using Content.Server.MassMedia.Components; -using Content.Server.MassMedia.Systems; -using Content.Server.Mind; using Content.Server.PDA.Ringer; using Content.Server.Station.Systems; using Content.Server.Store.Components; @@ -16,7 +13,6 @@ using Content.Shared.CartridgeLoader; using Content.Shared.Light.Components; using Content.Shared.PDA; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Containers; namespace Content.Server.PDA @@ -180,7 +176,7 @@ namespace Content.Server.PDA return; if (HasComp(uid)) - _ringer.ToggleRingerUI(uid, (IPlayerSession) msg.Session); + _ringer.ToggleRingerUI(uid, msg.Session); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowMusicMessage msg) @@ -189,7 +185,7 @@ namespace Content.Server.PDA return; if (TryComp(uid, out var instrument)) - _instrument.ToggleInstrumentUi(uid, (IPlayerSession) msg.Session, instrument); + _instrument.ToggleInstrumentUi(uid, msg.Session, instrument); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowUplinkMessage msg) diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs index a772e76bc4..7494d5e12c 100644 --- a/Content.Server/PDA/Ringer/RingerSystem.cs +++ b/Content.Server/PDA/Ringer/RingerSystem.cs @@ -7,7 +7,6 @@ using Content.Shared.PDA.Ringer; using Content.Shared.Popups; using Content.Shared.Store; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Network; using Robust.Shared.Player; @@ -182,7 +181,7 @@ namespace Content.Server.PDA.Ringer _ui.SetUiState(bui, new RingerUpdateState(isPlaying, ringer.Ringtone)); } - public bool ToggleRingerUI(EntityUid uid, IPlayerSession session) + public bool ToggleRingerUI(EntityUid uid, ICommonSession session) { if (_ui.TryGetUi(uid, RingerUiKey.Key, out var bui)) _ui.ToggleUi(bui, session); diff --git a/Content.Server/Paper/PaperSystem.cs b/Content.Server/Paper/PaperSystem.cs index f38013e14d..553bcaa0a2 100644 --- a/Content.Server/Paper/PaperSystem.cs +++ b/Content.Server/Paper/PaperSystem.cs @@ -4,15 +4,11 @@ using Content.Server.Popups; using Content.Server.UserInterface; using Content.Shared.Database; using Content.Shared.Examine; -using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Paper; using Content.Shared.Tag; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Player; -using Robust.Shared.Utility; -using Robust.Shared.Audio; using static Content.Shared.Paper.SharedPaperComponent; namespace Content.Server.Paper @@ -207,7 +203,7 @@ namespace Content.Server.Paper _appearance.SetData(uid, PaperVisuals.Status, status, appearance); } - public void UpdateUserInterface(EntityUid uid, PaperComponent? paperComp = null, IPlayerSession? session = null) + public void UpdateUserInterface(EntityUid uid, PaperComponent? paperComp = null, ICommonSession? session = null) { if (!Resolve(uid, ref paperComp)) return; diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index a9d78afa86..c9017ac821 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -282,9 +282,8 @@ public sealed partial class BiomeSystem : SharedBiomeSystem } // Get chunks in range - foreach (var client in Filter.GetAllPlayers(_playerManager)) + foreach (var pSession in Filter.GetAllPlayers(_playerManager)) { - var pSession = (IPlayerSession) client; if (xformQuery.TryGetComponent(pSession.AttachedEntity, out var xform) && _handledEntities.Add(pSession.AttachedEntity.Value) && diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs index 20ed276967..f200c991d7 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs @@ -2,11 +2,10 @@ using Content.Server.ParticleAccelerator.Components; using Content.Server.Power.Components; using Content.Shared.Database; using Content.Shared.Singularity.Components; -using Robust.Server.Player; -using Robust.Server.GameObjects; using Robust.Shared.Utility; using System.Diagnostics; using Content.Shared.CCVar; +using Robust.Shared.Player; namespace Content.Server.ParticleAccelerator.EntitySystems; @@ -60,7 +59,7 @@ public sealed partial class ParticleAcceleratorSystem FireEmitter(comp.StarboardEmitter!.Value, strength); } - public void SwitchOn(EntityUid uid, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SwitchOn(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; @@ -83,7 +82,7 @@ public sealed partial class ParticleAcceleratorSystem UpdateUI(uid, comp); } - public void SwitchOff(EntityUid uid, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SwitchOff(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; @@ -131,7 +130,7 @@ public sealed partial class ParticleAcceleratorSystem UpdateUI(uid, comp); } - public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; @@ -347,10 +346,10 @@ public sealed partial class ParticleAcceleratorSystem if (msg.Enabled) { if (comp.Assembled) - SwitchOn(uid, (IPlayerSession?) msg.Session, comp); + SwitchOn(uid, msg.Session, comp); } else - SwitchOff(uid, (IPlayerSession?) msg.Session, comp); + SwitchOff(uid, msg.Session, comp); UpdateUI(uid, comp); } @@ -364,7 +363,7 @@ public sealed partial class ParticleAcceleratorSystem if (TryComp(uid, out var apcPower) && !apcPower.Powered) return; - SetStrength(uid, msg.State, (IPlayerSession?) msg.Session, comp); + SetStrength(uid, msg.State, msg.Session, comp); UpdateUI(uid, comp); } @@ -378,7 +377,7 @@ public sealed partial class ParticleAcceleratorSystem if (TryComp(uid, out var apcPower) && !apcPower.Powered) return; - RescanParts(uid, (IPlayerSession?) msg.Session, comp); + RescanParts(uid, msg.Session, comp); UpdateUI(uid, comp); } diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs index 271d17a0c4..abc68543ff 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs @@ -2,9 +2,9 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using Content.Server.ParticleAccelerator.Components; using JetBrains.Annotations; -using Robust.Server.Player; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Events; +using Robust.Shared.Player; namespace Content.Server.ParticleAccelerator.EntitySystems; @@ -18,7 +18,7 @@ public sealed partial class ParticleAcceleratorSystem SubscribeLocalEvent(BodyTypeChanged); } - public void RescanParts(EntityUid uid, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? controller = null) + public void RescanParts(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? controller = null) { if (!Resolve(uid, ref controller)) return; diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs index 09700e2193..0cbd47c233 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs @@ -5,7 +5,7 @@ using Content.Server.Wires; using Content.Shared.Popups; using Content.Shared.Singularity.Components; using Content.Shared.Wires; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.ParticleAccelerator.Wires; diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs index 8577590671..65fa76ee41 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs @@ -3,8 +3,7 @@ using Content.Server.ParticleAccelerator.EntitySystems; using Content.Server.Wires; using Content.Shared.Singularity.Components; using Content.Shared.Wires; -using Robust.Server.GameObjects; -using Robust.Shared.Random; +using Robust.Shared.Player; namespace Content.Server.ParticleAccelerator.Wires; diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs index 00c5845713..c43403edd4 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs @@ -3,7 +3,7 @@ using Content.Server.ParticleAccelerator.EntitySystems; using Content.Server.Wires; using Content.Shared.Singularity.Components; using Content.Shared.Wires; -using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.ParticleAccelerator.Wires; diff --git a/Content.Server/Physics/Controllers/RandomWalkController.cs b/Content.Server/Physics/Controllers/RandomWalkController.cs index dc5608887e..4a93a9e706 100644 --- a/Content.Server/Physics/Controllers/RandomWalkController.cs +++ b/Content.Server/Physics/Controllers/RandomWalkController.cs @@ -4,6 +4,7 @@ using Content.Shared.Throwing; using Robust.Server.GameObjects; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Controllers; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Timing; diff --git a/Content.Server/Pinpointer/ProximityBeeperSystem.cs b/Content.Server/Pinpointer/ProximityBeeperSystem.cs index b473d97372..d52223e2b4 100644 --- a/Content.Server/Pinpointer/ProximityBeeperSystem.cs +++ b/Content.Server/Pinpointer/ProximityBeeperSystem.cs @@ -80,7 +80,10 @@ public sealed class ProximityBeeperSystem : EntitySystem var scalingFactor = distance / component.MaximumDistance; var interval = (component.MaxBeepInterval - component.MinBeepInterval) * scalingFactor + component.MinBeepInterval; + component.NextBeepTime += interval; + if (component.NextBeepTime < _timing.CurTime) // Prevents spending time out of range accumulating a deficit which causes a series of very rapid beeps when comeing into range. + component.NextBeepTime = _timing.CurTime + interval; } /// diff --git a/Content.Server/Pinpointer/StationMapSystem.cs b/Content.Server/Pinpointer/StationMapSystem.cs index daf9df25ba..0460f08f13 100644 --- a/Content.Server/Pinpointer/StationMapSystem.cs +++ b/Content.Server/Pinpointer/StationMapSystem.cs @@ -1,6 +1,7 @@ using Content.Server.PowerCell; using Content.Shared.Pinpointer; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Pinpointer; diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs index 1b2c949cf4..7793b5302f 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs @@ -4,19 +4,20 @@ using System.Threading; using System.Threading.Tasks; using Content.Server.Database; using Content.Shared.CCVar; +using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; -using Robust.Server.Player; using Robust.Shared.Asynchronous; using Robust.Shared.Collections; using Robust.Shared.Configuration; using Robust.Shared.Exceptions; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Server.Players.PlayTimeTracking; -public delegate void CalcPlayTimeTrackersCallback(IPlayerSession player, HashSet trackers); +public delegate void CalcPlayTimeTrackersCallback(ICommonSession player, HashSet trackers); /// /// Tracks play time for players, across all roles. @@ -66,7 +67,7 @@ public sealed partial class PlayTimeTrackingManager private ISawmill _sawmill = default!; // List of players that need some kind of update (refresh timers or resend). - private ValueList _playersDirty; + private ValueList _playersDirty; // DB auto-saving logic. private TimeSpan _saveInterval; @@ -76,7 +77,7 @@ public sealed partial class PlayTimeTrackingManager // We must block server shutdown on these to avoid losing data. private readonly List _pendingSaveTasks = new(); - private readonly Dictionary _playTimeData = new(); + private readonly Dictionary _playTimeData = new(); public event CalcPlayTimeTrackersCallback? CalcTrackers; @@ -146,7 +147,7 @@ public sealed partial class PlayTimeTrackingManager _playersDirty.Clear(); } - private void RefreshSingleTracker(IPlayerSession dirty, PlayTimeData data, TimeSpan time) + private void RefreshSingleTracker(ICommonSession dirty, PlayTimeData data, TimeSpan time) { DebugTools.Assert(data.Initialized); @@ -188,7 +189,7 @@ public sealed partial class PlayTimeTrackingManager /// so APIs like return up-to-date info. /// /// - public void FlushTracker(IPlayerSession player) + public void FlushTracker(ICommonSession player) { var time = _timing.RealTime; var data = _playTimeData[player]; @@ -208,7 +209,7 @@ public sealed partial class PlayTimeTrackingManager } } - private void SendPlayTimes(IPlayerSession pSession) + private void SendPlayTimes(ICommonSession pSession) { var roles = GetTrackerTimes(pSession); @@ -235,7 +236,7 @@ public sealed partial class PlayTimeTrackingManager /// /// Save all modified time trackers for a player to the database. /// - public async void SaveSession(IPlayerSession session) + public async void SaveSession(ICommonSession session) { // This causes all trackers to refresh, ah well. FlushAllTrackers(); @@ -285,7 +286,7 @@ public sealed partial class PlayTimeTrackingManager _sawmill.Debug($"Saved {log.Count} trackers"); } - private async Task DoSaveSessionAsync(IPlayerSession session) + private async Task DoSaveSessionAsync(ICommonSession session) { var log = new List(); @@ -306,7 +307,7 @@ public sealed partial class PlayTimeTrackingManager _sawmill.Debug($"Saved {log.Count} trackers for {session.Name}"); } - public async Task LoadData(IPlayerSession session, CancellationToken cancel) + public async Task LoadData(ICommonSession session, CancellationToken cancel) { var data = new PlayTimeData(); _playTimeData.Add(session, data); @@ -328,14 +329,14 @@ public sealed partial class PlayTimeTrackingManager QueueSendWhitelist(session); // Nyanotrasen - Whitelist status } - public void ClientDisconnected(IPlayerSession session) + public void ClientDisconnected(ICommonSession session) { SaveSession(session); _playTimeData.Remove(session); } - public void AddTimeToTracker(IPlayerSession id, string tracker, TimeSpan time) + public void AddTimeToTracker(ICommonSession id, string tracker, TimeSpan time) { if (!_playTimeData.TryGetValue(id, out var data) || !data.Initialized) throw new InvalidOperationException("Play time info is not yet loaded for this player!"); @@ -351,17 +352,17 @@ public sealed partial class PlayTimeTrackingManager data.DbTrackersDirty.Add(tracker); } - public void AddTimeToOverallPlaytime(IPlayerSession id, TimeSpan time) + public void AddTimeToOverallPlaytime(ICommonSession id, TimeSpan time) { AddTimeToTracker(id, PlayTimeTrackingShared.TrackerOverall, time); } - public TimeSpan GetOverallPlaytime(IPlayerSession id) + public TimeSpan GetOverallPlaytime(ICommonSession id) { return GetPlayTimeForTracker(id, PlayTimeTrackingShared.TrackerOverall); } - public bool TryGetTrackerTimes(IPlayerSession id, [NotNullWhen(true)] out Dictionary? time) + public bool TryGetTrackerTimes(ICommonSession id, [NotNullWhen(true)] out Dictionary? time) { time = null; @@ -374,7 +375,7 @@ public sealed partial class PlayTimeTrackingManager return true; } - public Dictionary GetTrackerTimes(IPlayerSession id) + public Dictionary GetTrackerTimes(ICommonSession id) { if (!_playTimeData.TryGetValue(id, out var data) || !data.Initialized) throw new InvalidOperationException("Play time info is not yet loaded for this player!"); @@ -382,7 +383,7 @@ public sealed partial class PlayTimeTrackingManager return data.TrackerTimes; } - public TimeSpan GetPlayTimeForTracker(IPlayerSession id, string tracker) + public TimeSpan GetPlayTimeForTracker(ICommonSession id, string tracker) { if (!_playTimeData.TryGetValue(id, out var data) || !data.Initialized) throw new InvalidOperationException("Play time info is not yet loaded for this player!"); @@ -393,7 +394,7 @@ public sealed partial class PlayTimeTrackingManager /// /// Queue for play time trackers to be refreshed on a player, in case the set of active trackers may have changed. /// - public void QueueRefreshTrackers(IPlayerSession player) + public void QueueRefreshTrackers(ICommonSession player) { if (DirtyPlayer(player) is { } data) data.NeedRefreshTackers = true; @@ -402,13 +403,13 @@ public sealed partial class PlayTimeTrackingManager /// /// Queue for play time information to be sent to a client, for showing in UIs etc. /// - public void QueueSendTimers(IPlayerSession player) + public void QueueSendTimers(ICommonSession player) { if (DirtyPlayer(player) is { } data) data.NeedSendTimers = true; } - private PlayTimeData? DirtyPlayer(IPlayerSession player) + private PlayTimeData? DirtyPlayer(ICommonSession player) { if (!_playTimeData.TryGetValue(player, out var data) || !data.Initialized) return null; diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index 94780bda36..4dba378e32 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -14,6 +14,7 @@ using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -55,7 +56,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem _tracking.CalcTrackers -= CalcTrackers; } - private void CalcTrackers(IPlayerSession player, HashSet trackers) + private void CalcTrackers(ICommonSession player, HashSet trackers) { if (_afk.IsAfk(player)) return; @@ -67,7 +68,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem trackers.UnionWith(GetTimedRoles(player)); } - private bool IsPlayerAlive(IPlayerSession session) + private bool IsPlayerAlive(ICommonSession session) { var attached = session.AttachedEntity; if (attached == null) @@ -93,7 +94,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem } } - private IEnumerable GetTimedRoles(IPlayerSession session) + private IEnumerable GetTimedRoles(ICommonSession session) { var contentData = _playerManager.GetPlayerData(session.UserId).ContentData(); @@ -157,7 +158,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem _tracking.QueueSendWhitelist(ev.PlayerSession); // Nyanotrasen - Send whitelist status } - public bool IsAllowed(IPlayerSession player, string role) + public bool IsAllowed(ICommonSession player, string role) { if (!_prototypes.TryIndex(role, out var job) || job.Requirements == null || @@ -171,7 +172,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, isWhitelisted); } - public HashSet GetDisallowedJobs(IPlayerSession player) + public HashSet GetDisallowedJobs(ICommonSession player) { var roles = new HashSet(); if (!_cfg.GetCVar(CCVars.GameRoleTimers)) @@ -236,7 +237,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem } } - public void PlayerRolesChanged(IPlayerSession player) + public void PlayerRolesChanged(ICommonSession player) { _tracking.QueueRefreshTrackers(player); } diff --git a/Content.Server/Players/PlayerData.cs b/Content.Server/Players/PlayerData.cs deleted file mode 100644 index b0ca6f3c18..0000000000 --- a/Content.Server/Players/PlayerData.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Content.Shared.Players; -using Robust.Server.Player; -using Robust.Shared.Players; - -namespace Content.Server.Players -{ - public static class PlayerDataExt - { - /// - /// Gets the correctly cast instance of content player data from an engine player data storage. - /// - public static PlayerData? ContentData(this IPlayerSession session) - { - return session.Data.ContentData(); - } - - public static PlayerData? ContentData(this ICommonSession session) - { - return ((IPlayerSession) session).ContentData(); - } - - /// - /// Gets the mind that is associated with this player. - /// - public static EntityUid? GetMind(this IPlayerSession session) - { - return session.Data.ContentData()?.Mind; - } - } -} diff --git a/Content.Server/Players/PlayerSystem.cs b/Content.Server/Players/PlayerSystem.cs index 0c407aa876..c79683c338 100644 --- a/Content.Server/Players/PlayerSystem.cs +++ b/Content.Server/Players/PlayerSystem.cs @@ -1,11 +1,11 @@ using Content.Shared.Players; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Players; public sealed class PlayerSystem : SharedPlayerSystem { - public override PlayerData? ContentData(ICommonSession? session) + public override ContentPlayerData? ContentData(ICommonSession? session) { return session?.ContentData(); } diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index b253e32e37..6fcdfcf994 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -20,7 +20,6 @@ using Robust.Shared.Enums; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Replays; using Robust.Shared.Timing; @@ -170,7 +169,7 @@ namespace Content.Server.Pointing.EntitySystems } // Get players that are in range and whose visibility layer matches the arrow's. - bool ViewerPredicate(IPlayerSession playerSession) + bool ViewerPredicate(ICommonSession playerSession) { if (!_minds.TryGetMind(playerSession, out _, out var mind) || mind.CurrentEntity is not { Valid: true } ent || @@ -182,7 +181,7 @@ namespace Content.Server.Pointing.EntitySystems } var viewers = Filter.Empty() - .AddWhere(session1 => ViewerPredicate((IPlayerSession) session1)) + .AddWhere(session1 => ViewerPredicate(session1)) .Recipients; string selfMessage; diff --git a/Content.Server/Points/PointSystem.cs b/Content.Server/Points/PointSystem.cs index 56831980d0..a71294db9d 100644 --- a/Content.Server/Points/PointSystem.cs +++ b/Content.Server/Points/PointSystem.cs @@ -2,9 +2,9 @@ using Content.Shared.FixedPoint; using Content.Shared.Points; using JetBrains.Annotations; -using Robust.Server.GameObjects; using Robust.Server.GameStates; using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Points; diff --git a/Content.Server/Popups/PopupSystem.cs b/Content.Server/Popups/PopupSystem.cs index 483d4f3d3f..61ccaf4423 100644 --- a/Content.Server/Popups/PopupSystem.cs +++ b/Content.Server/Popups/PopupSystem.cs @@ -4,7 +4,6 @@ using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; namespace Content.Server.Popups { diff --git a/Content.Server/Power/Generator/PortableGeneratorSystem.cs b/Content.Server/Power/Generator/PortableGeneratorSystem.cs index 416f509978..1180665ad1 100644 --- a/Content.Server/Power/Generator/PortableGeneratorSystem.cs +++ b/Content.Server/Power/Generator/PortableGeneratorSystem.cs @@ -22,7 +22,7 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly GeneratorSystem _generator = default!; - [Dependency] private readonly PowerSwitchableGeneratorSystem _switchableGenerator = default!; + [Dependency] private readonly PowerSwitchableSystem _switchable = default!; public override void Initialize() { @@ -36,6 +36,8 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem SubscribeLocalEvent(GeneratorStartMessage); SubscribeLocalEvent(GeneratorStopMessage); SubscribeLocalEvent(GeneratorSwitchOutputMessage); + + SubscribeLocalEvent(OnSwitchPowerCheck); } private void GeneratorSwitchOutputMessage(EntityUid uid, PortableGeneratorComponent component, PortableGeneratorSwitchOutputMessage args) @@ -47,7 +49,7 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem if (fuelGenerator.On) return; - _switchableGenerator.ToggleActiveOutput(uid, args.Session.AttachedEntity.Value); + _switchable.Cycle(uid, args.Session.AttachedEntity.Value); } private void GeneratorStopMessage(EntityUid uid, PortableGeneratorComponent component, PortableGeneratorStopMessage args) @@ -164,6 +166,12 @@ public sealed class PortableGeneratorSystem : SharedPortableGeneratorSystem } } + private void OnSwitchPowerCheck(EntityUid uid, FuelGeneratorComponent comp, ref SwitchPowerCheckEvent args) + { + if (comp.On) + args.DisableMessage = Loc.GetString("fuel-generator-verb-disable-on"); + } + public override void Update(float frameTime) { var query = EntityQueryEnumerator(); diff --git a/Content.Server/Power/Generator/PowerSwitchableGeneratorSystem.cs b/Content.Server/Power/Generator/PowerSwitchableGeneratorSystem.cs deleted file mode 100644 index b81d77ea9f..0000000000 --- a/Content.Server/Power/Generator/PowerSwitchableGeneratorSystem.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Content.Server.NodeContainer; -using Content.Server.NodeContainer.EntitySystems; -using Content.Server.Popups; -using Content.Server.Power.Components; -using Content.Server.Power.Nodes; -using Content.Shared.Power.Generator; -using Content.Shared.Verbs; -using Robust.Server.GameObjects; -using Robust.Shared.Player; -using Robust.Shared.Utility; - -namespace Content.Server.Power.Generator; - -/// -/// Implements power-switchable generators. -/// -/// -/// -/// -public sealed class PowerSwitchableGeneratorSystem : SharedPowerSwitchableGeneratorSystem -{ - [Dependency] private readonly NodeGroupSystem _nodeGroup = default!; - [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly AudioSystem _audio = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent>(GetInteractionVerbs); - } - - private void GetInteractionVerbs( - EntityUid uid, - PowerSwitchableGeneratorComponent component, - GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - var isCurrentlyHV = component.ActiveOutput == PowerSwitchableGeneratorOutput.HV; - var msg = isCurrentlyHV ? "power-switchable-generator-verb-mv" : "power-switchable-generator-verb-hv"; - - var isOn = TryComp(uid, out FuelGeneratorComponent? fuelGenerator) && fuelGenerator.On; - - InteractionVerb verb = new() - { - Act = () => - { - - var verbIsOn = TryComp(uid, out FuelGeneratorComponent? verbFuelGenerator) && verbFuelGenerator.On; - if (verbIsOn) - return; - - ToggleActiveOutput(uid, args.User, component); - }, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/zap.svg.192dpi.png")), - Text = Loc.GetString(msg), - }; - - if (isOn) - { - verb.Message = Loc.GetString("power-switchable-generator-verb-disable-on"); - verb.Disabled = true; - } - - args.Verbs.Add(verb); - } - - public void ToggleActiveOutput(EntityUid uid, EntityUid user, PowerSwitchableGeneratorComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - var supplier = Comp(uid); - var nodeContainer = Comp(uid); - var outputMV = (CableDeviceNode) nodeContainer.Nodes[component.NodeOutputMV]; - var outputHV = (CableDeviceNode) nodeContainer.Nodes[component.NodeOutputHV]; - - if (component.ActiveOutput == PowerSwitchableGeneratorOutput.HV) - { - component.ActiveOutput = PowerSwitchableGeneratorOutput.MV; - supplier.Voltage = Voltage.Medium; - - // Switching around the voltage on the power supplier is "enough", - // but we also want to disconnect the cable nodes so it doesn't show up in power monitors etc. - outputMV.Enabled = true; - outputHV.Enabled = false; - } - else - { - component.ActiveOutput = PowerSwitchableGeneratorOutput.HV; - supplier.Voltage = Voltage.High; - - outputMV.Enabled = false; - outputHV.Enabled = true; - } - - _popup.PopupEntity( - Loc.GetString("power-switchable-generator-switched-output"), - uid, - user); - - _audio.Play(component.SwitchSound, Filter.Pvs(uid), uid, true); - - Dirty(uid, component); - - _nodeGroup.QueueReflood(outputMV); - _nodeGroup.QueueReflood(outputHV); - } -} diff --git a/Content.Server/Power/Generator/PowerSwitchableSystem.cs b/Content.Server/Power/Generator/PowerSwitchableSystem.cs new file mode 100644 index 0000000000..ae7960cf8f --- /dev/null +++ b/Content.Server/Power/Generator/PowerSwitchableSystem.cs @@ -0,0 +1,123 @@ +using Content.Server.NodeContainer; +using Content.Server.NodeContainer.EntitySystems; +using Content.Server.Popups; +using Content.Server.Power.Components; +using Content.Server.Power.Nodes; +using Content.Shared.Power.Generator; +using Content.Shared.Timing; +using Content.Shared.Verbs; +using Robust.Server.GameObjects; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Server.Power.Generator; + +/// +/// Implements server logic for power-switchable devices. +/// +/// +/// +/// +public sealed class PowerSwitchableSystem : SharedPowerSwitchableSystem +{ + [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly NodeGroupSystem _nodeGroup = default!; + [Dependency] private readonly PopupSystem _popup = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(GetVerbs); + } + + private void GetVerbs(EntityUid uid, PowerSwitchableComponent comp, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + var voltage = VoltageColor(GetNextVoltage(uid, comp)); + var msg = Loc.GetString("power-switchable-switch-voltage", ("voltage", voltage)); + + InteractionVerb verb = new() + { + Act = () => + { + // don't need to check it again since if its disabled server wont let the verb act + Cycle(uid, args.User, comp); + }, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/zap.svg.192dpi.png")), + Text = msg + }; + + var ev = new SwitchPowerCheckEvent(); + RaiseLocalEvent(uid, ref ev); + if (ev.DisableMessage != null) + { + verb.Message = ev.DisableMessage; + verb.Disabled = true; + } + + args.Verbs.Add(verb); + } + + /// + /// Cycles voltage then updates nodes and optionally power supplier to match it. + /// + public void Cycle(EntityUid uid, EntityUid user, PowerSwitchableComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return; + + // no sound spamming + if (TryComp(uid, out var useDelay) && _useDelay.ActiveDelay(uid)) + return; + + comp.ActiveIndex = NextIndex(uid, comp); + Dirty(uid, comp); + + var voltage = GetVoltage(uid, comp); + + if (TryComp(uid, out var supplier)) + { + // convert to nodegroupid (goofy server Voltage enum is just alias for it) + switch (voltage) + { + case SwitchableVoltage.HV: + supplier.Voltage = Voltage.High; + break; + case SwitchableVoltage.MV: + supplier.Voltage = Voltage.Medium; + break; + case SwitchableVoltage.LV: + supplier.Voltage = Voltage.Apc; + break; + } + } + + // Switching around the voltage on the power supplier is "enough", + // but we also want to disconnect the cable nodes so it doesn't show up in power monitors etc. + var nodeContainer = Comp(uid); + foreach (var cable in comp.Cables) + { + var node = (CableDeviceNode) nodeContainer.Nodes[cable.Node]; + node.Enabled = cable.Voltage == voltage; + _nodeGroup.QueueReflood(node); + } + + var popup = Loc.GetString(comp.SwitchText, ("voltage", VoltageString(voltage))); + _popup.PopupEntity(popup, uid, user); + + _audio.PlayPvs(comp.SwitchSound, uid); + + _useDelay.BeginDelay(uid, useDelay); + } +} + +/// +/// Raised on a to see if its verb should work. +/// If is non-null, the verb is disabled with that as the message. +/// +[ByRefEvent] +public record struct SwitchPowerCheckEvent(string? DisableMessage = null); diff --git a/Content.Server/Prayer/PrayerSystem.cs b/Content.Server/Prayer/PrayerSystem.cs index be6ae80bfd..e20291cc06 100644 --- a/Content.Server/Prayer/PrayerSystem.cs +++ b/Content.Server/Prayer/PrayerSystem.cs @@ -5,12 +5,11 @@ using Content.Server.Chat.Managers; using Content.Server.Popups; using Content.Shared.Database; using Content.Shared.Popups; -using Robust.Server.Player; -using Robust.Shared.Player; using Content.Shared.Chat; using Content.Shared.Prayer; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Prayer; /// @@ -74,7 +73,7 @@ public sealed class PrayerSystem : EntitySystem /// The IPlayerSession that sent the message /// The main message sent to the player via the chatbox /// The popup to notify the player, also prepended to the messageString - public void SendSubtleMessage(IPlayerSession target, IPlayerSession source, string messageString, string popupMessage) + public void SendSubtleMessage(ICommonSession target, ICommonSession source, string messageString, string popupMessage) { if (target.AttachedEntity == null) return; @@ -96,7 +95,7 @@ public sealed class PrayerSystem : EntitySystem /// You may be wondering, "Why the admin chat, specifically? Nobody even reads it!" /// Exactly. /// - public void Pray(IPlayerSession sender, PrayableComponent comp, string message) + public void Pray(ICommonSession sender, PrayableComponent comp, string message) { if (sender.AttachedEntity == null) return; diff --git a/Content.Server/Preferences/Managers/IServerPreferencesManager.cs b/Content.Server/Preferences/Managers/IServerPreferencesManager.cs index 8c06e00ab1..a36b053717 100644 --- a/Content.Server/Preferences/Managers/IServerPreferencesManager.cs +++ b/Content.Server/Preferences/Managers/IServerPreferencesManager.cs @@ -2,8 +2,8 @@ using System.Diagnostics.CodeAnalysis; using System.Threading; using System.Threading.Tasks; using Content.Shared.Preferences; -using Robust.Server.Player; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.Preferences.Managers { @@ -11,12 +11,12 @@ namespace Content.Server.Preferences.Managers { void Init(); - Task LoadData(IPlayerSession session, CancellationToken cancel); - void OnClientDisconnected(IPlayerSession session); + Task LoadData(ICommonSession session, CancellationToken cancel); + void OnClientDisconnected(ICommonSession session); bool TryGetCachedPreferences(NetUserId userId, [NotNullWhen(true)] out PlayerPreferences? playerPreferences); PlayerPreferences GetPreferences(NetUserId userId); IEnumerable> GetSelectedProfilesForPlayers(List userIds); - bool HavePreferencesLoaded(IPlayerSession session); + bool HavePreferencesLoaded(ICommonSession session); } } diff --git a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs index ea04d00e82..a0b5e8ce65 100644 --- a/Content.Server/Preferences/Managers/ServerPreferencesManager.cs +++ b/Content.Server/Preferences/Managers/ServerPreferencesManager.cs @@ -8,9 +8,9 @@ using Content.Shared.CCVar; using Content.Shared.Humanoid.Prototypes; using Content.Shared.Preferences; using Content.Shared.Roles; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -167,7 +167,7 @@ namespace Content.Server.Preferences.Managers } // Should only be called via UserDbDataManager. - public async Task LoadData(IPlayerSession session, CancellationToken cancel) + public async Task LoadData(ICommonSession session, CancellationToken cancel) { if (!ShouldStorePrefs(session.ConnectedClient.AuthType)) { @@ -207,12 +207,12 @@ namespace Content.Server.Preferences.Managers } } - public void OnClientDisconnected(IPlayerSession session) + public void OnClientDisconnected(ICommonSession session) { _cachedPlayerPrefs.Remove(session.UserId); } - public bool HavePreferencesLoaded(IPlayerSession session) + public bool HavePreferencesLoaded(ICommonSession session) { return _cachedPlayerPrefs.ContainsKey(session.UserId); } diff --git a/Content.Server/Pulling/PullingSystem.cs b/Content.Server/Pulling/PullingSystem.cs index f7ea0aae57..69bb7c9370 100644 --- a/Content.Server/Pulling/PullingSystem.cs +++ b/Content.Server/Pulling/PullingSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Pulling.Components; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Input.Binding; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Pulling { diff --git a/Content.Server/Radiation/Systems/RadiationSystem.Debug.cs b/Content.Server/Radiation/Systems/RadiationSystem.Debug.cs index 97f2e485ca..56806d8c9c 100644 --- a/Content.Server/Radiation/Systems/RadiationSystem.Debug.cs +++ b/Content.Server/Radiation/Systems/RadiationSystem.Debug.cs @@ -7,7 +7,7 @@ using Content.Shared.Radiation.Systems; using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Map.Components; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.Radiation.Systems; diff --git a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs index 436149f076..adaad492dc 100644 --- a/Content.Server/Radio/EntitySystems/HeadsetSystem.cs +++ b/Content.Server/Radio/EntitySystems/HeadsetSystem.cs @@ -5,8 +5,8 @@ using Content.Shared.Inventory.Events; using Content.Shared.Radio; using Content.Shared.Radio.Components; using Content.Shared.Radio.EntitySystems; -using Robust.Server.GameObjects; using Robust.Shared.Network; +using Robust.Shared.Player; namespace Content.Server.Radio.EntitySystems; diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 4f9099d0af..fa00514e61 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -7,9 +7,9 @@ using Content.Shared.Chat; using Content.Shared.Database; using Content.Shared.Radio; using Content.Shared.Radio.Components; -using Robust.Server.GameObjects; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Replays; using Robust.Shared.Utility; diff --git a/Content.Server/Research/Systems/ResearchSystem.Client.cs b/Content.Server/Research/Systems/ResearchSystem.Client.cs index e813f09ff9..135ef8fe88 100644 --- a/Content.Server/Research/Systems/ResearchSystem.Client.cs +++ b/Content.Server/Research/Systems/ResearchSystem.Client.cs @@ -1,7 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Power.EntitySystems; using Content.Shared.Research.Components; -using Robust.Server.Player; namespace Content.Server.Research.Systems; @@ -46,7 +45,7 @@ public sealed partial class ResearchSystem if (!this.IsPowered(uid, EntityManager)) return; - _uiSystem.TryToggleUi(uid, ResearchClientUiKey.Key, (IPlayerSession) args.Session); + _uiSystem.TryToggleUi(uid, ResearchClientUiKey.Key, args.Session); } #endregion diff --git a/Content.Server/Salvage/SalvageRulerCommand.cs b/Content.Server/Salvage/SalvageRulerCommand.cs index b0a64508c5..a1fd609741 100644 --- a/Content.Server/Salvage/SalvageRulerCommand.cs +++ b/Content.Server/Salvage/SalvageRulerCommand.cs @@ -1,6 +1,5 @@ using Content.Server.Administration; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Map; @@ -26,7 +25,7 @@ sealed class SalvageRulerCommand : IConsoleCommand return; } - if (shell.Player is not IPlayerSession player) + if (shell.Player is not { } player) { shell.WriteError(Loc.GetString("shell-only-players-can-run-this-command")); return; diff --git a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs index 0b9148f0fb..cc20b71946 100644 --- a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs +++ b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs @@ -4,7 +4,6 @@ using Content.Server.Atmos.Piping.EntitySystems; using Content.Server.NodeContainer; using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Administration; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Sandbox.Commands @@ -20,7 +19,7 @@ namespace Content.Server.Sandbox.Commands { var sandboxManager = EntitySystem.Get(); var adminManager = IoCManager.Resolve(); - if (shell.IsClient && (!sandboxManager.IsSandboxEnabled && !adminManager.HasAdminFlag((IPlayerSession)shell.Player!, AdminFlags.Mapping))) + if (shell.IsClient && (!sandboxManager.IsSandboxEnabled && !adminManager.HasAdminFlag(shell.Player!, AdminFlags.Mapping))) { shell.WriteError("You are not currently able to use mapping commands."); } diff --git a/Content.Server/Sandbox/SandboxSystem.cs b/Content.Server/Sandbox/SandboxSystem.cs index ec9b1a0c3c..194cf59843 100644 --- a/Content.Server/Sandbox/SandboxSystem.cs +++ b/Content.Server/Sandbox/SandboxSystem.cs @@ -13,6 +13,7 @@ using Robust.Server.Console; using Robust.Server.Placement; using Robust.Server.Player; using Robust.Shared.Enums; +using Robust.Shared.Player; namespace Content.Server.Sandbox { diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs index cd4f2ea23b..63b4d9daef 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs @@ -1,7 +1,7 @@ using Content.Shared.SensorMonitoring; using Robust.Server.Player; using Robust.Shared.Collections; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Server.SensorMonitoring; diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs index a09badcd59..6c0dddeb26 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs @@ -1,7 +1,5 @@ using Content.Server.DeviceNetwork.Components; using Content.Shared.SensorMonitoring; -using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Collections; using ConsoleUIState = Content.Shared.SensorMonitoring.SensorMonitoringConsoleBoundInterfaceState; using IncrementalUIState = Content.Shared.SensorMonitoring.SensorMonitoringIncrementalUpdate; @@ -130,7 +128,7 @@ public sealed partial class SensorMonitoringConsoleSystem if (!args.UiKey.Equals(SensorMonitoringConsoleUiKey.Key)) return; - if (args.Session is not IPlayerSession player) + if (args.Session is not { } player) return; component.InitialUIStateSent.Remove(player); diff --git a/Content.Server/ServerUpdates/ServerUpdateManager.cs b/Content.Server/ServerUpdates/ServerUpdateManager.cs index 769c5d58d7..f4e54984e9 100644 --- a/Content.Server/ServerUpdates/ServerUpdateManager.cs +++ b/Content.Server/ServerUpdates/ServerUpdateManager.cs @@ -6,6 +6,7 @@ using Robust.Server.Player; using Robust.Server.ServerStatus; using Robust.Shared.Configuration; using Robust.Shared.Enums; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Server.ServerUpdates; diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 1a1debc9e3..3ef3d97a21 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -20,7 +20,6 @@ using Content.Shared.Tag; using Content.Shared.Tiles; using Robust.Server.GameObjects; using Robust.Server.Maps; -using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -140,7 +139,7 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem /// private void OnShuttleRequestPosition(EmergencyShuttleRequestPositionMessage msg, EntitySessionEventArgs args) { - if (!_admin.IsAdmin((IPlayerSession) args.SenderSession)) + if (!_admin.IsAdmin(args.SenderSession)) return; var player = args.SenderSession.AttachedEntity; diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs index 31d826087d..c080420266 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs @@ -229,7 +229,7 @@ public sealed partial class BorgSystem if (!TryComp(chassis, out var hands)) return; - if (LifeStage(uid) >= EntityLifeStage.Terminating) + if (TerminatingOrDeleted(uid)) { foreach (var (hand, item) in component.ProvidedItems) { diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 611dfa6ea2..883cb3b3d8 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -21,7 +21,7 @@ using Content.Shared.Throwing; using Content.Shared.Wires; using Robust.Server.GameObjects; using Robust.Shared.Containers; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Silicons.Borgs; diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index beb760ec8f..06d845b72c 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -18,7 +18,7 @@ using Content.Shared.Silicons.Laws.Components; using Content.Shared.Stunnable; using Content.Shared.Wires; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Toolshed; @@ -50,7 +50,9 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem SubscribeLocalEvent(OnPlayerSpawnComplete); SubscribeLocalEvent(OnDirectedGetLaws); + SubscribeLocalEvent(OnIonStormLaws); SubscribeLocalEvent(OnDirectedEmagGetLaws); + SubscribeLocalEvent(OnEmagIonStormLaws); SubscribeLocalEvent(OnEmagMindAdded); SubscribeLocalEvent(OnEmagMindRemoved); SubscribeLocalEvent(OnExamined); @@ -93,8 +95,8 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _entityManager.TryGetComponent(uid, out var intrinsicRadio); HashSet? radioChannels = intrinsicRadio?.Channels; - var state = new SiliconLawBuiState(GetLaws(uid), radioChannels); - _userInterface.TrySetUiState(args.Entity, SiliconLawsUiKey.Key, state, (IPlayerSession) args.Session); + var state = new SiliconLawBuiState(GetLaws(uid).Laws, radioChannels); + _userInterface.TrySetUiState(args.Entity, SiliconLawsUiKey.Key, state, args.Session); } private void OnPlayerSpawnComplete(EntityUid uid, SiliconLawBoundComponent component, PlayerSpawnCompleteEvent args) @@ -104,38 +106,66 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem private void OnDirectedGetLaws(EntityUid uid, SiliconLawProviderComponent component, ref GetSiliconLawsEvent args) { - if (args.Handled || HasComp(uid) || component.Laws.Count == 0) + if (args.Handled || HasComp(uid)) return; - foreach (var law in component.Laws) - { - args.Laws.Add(_prototype.Index(law)); - } + if (component.Lawset == null) + component.Lawset = GetLawset(component.Laws); + + args.Laws = component.Lawset; args.Handled = true; } + private void OnIonStormLaws(EntityUid uid, SiliconLawProviderComponent component, ref IonStormLawsEvent args) + { + if (HasComp(uid)) + return; + + component.Lawset = args.Lawset; + + // gotta tell player to check their laws + NotifyLawsChanged(uid); + + // new laws may allow antagonist behaviour so make it clear for admins + if (TryComp(uid, out var emag)) + EnsureEmaggedRole(uid, emag); + } + private void OnDirectedEmagGetLaws(EntityUid uid, EmagSiliconLawComponent component, ref GetSiliconLawsEvent args) { if (args.Handled || !HasComp(uid) || component.OwnerName == null) return; - // Add the first emag law - args.Laws.Add(new SiliconLaw + if (component.Lawset == null) { - LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)), - Order = 0 - }); + // Add new emagged laws + component.Lawset = GetLawset(component.EmagLaws); - // Add new emagged laws - foreach (var law in component.EmagLaws) - { - args.Laws.Add(_prototype.Index(law)); + // Add the first emag law before the others + component.Lawset.Laws.Insert(0, new SiliconLaw + { + LawString = Loc.GetString("law-emag-custom", ("name", component.OwnerName)), + Order = 0 + }); } + args.Laws = component.Lawset; + args.Handled = true; } + private void OnEmagIonStormLaws(EntityUid uid, EmagSiliconLawComponent component, ref IonStormLawsEvent args) + { + if (!HasComp(uid)) + return; + + component.Lawset = args.Lawset; + + // gotta tell player to check their laws + NotifyLawsChanged(uid); + } + private void OnExamined(EntityUid uid, EmagSiliconLawComponent component, ExaminedEvent args) { if (!args.IsInDetailsRange || !HasComp(uid)) @@ -184,10 +214,10 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem _roles.MindAddRole(mindId, new SubvertedSiliconRoleComponent { PrototypeId = component.AntagonistRole }); } - public List GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) + public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) { if (!Resolve(uid, ref component)) - return new List(); + return new SiliconLawset(); var ev = new GetSiliconLawsEvent(uid); @@ -248,6 +278,24 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", msg)); _chatManager.ChatMessageToOne(ChatChannel.Server, msg, wrappedMessage, default, false, actor.PlayerSession.ConnectedClient, colorOverride: Color.Red); } + + /// + /// Extract all the laws from a lawset's prototype ids. + /// + public SiliconLawset GetLawset(string lawset) + { + var proto = _prototype.Index(lawset); + var laws = new SiliconLawset() + { + Laws = new List(proto.Laws.Count) + }; + foreach (var law in proto.Laws) + { + laws.Laws.Add(_prototype.Index(law)); + } + + return laws; + } } [ToolshedCommand, AdminCommand(AdminFlags.Admin)] @@ -270,7 +318,7 @@ public sealed class LawsCommand : ToolshedCommand { _law ??= GetSys(); - foreach (var law in _law.GetLaws(lawbound)) + foreach (var law in _law.GetLaws(lawbound).Laws) { yield return $"law {law.LawIdentifierOverride ?? law.Order.ToString()}: {Loc.GetString(law.LawString)}"; } diff --git a/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs b/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs index 815b0224c8..4299bcda07 100644 --- a/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs +++ b/Content.Server/Speech/EntitySystems/MeleeSpeechSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Database; using Content.Shared.Speech.Components; using Content.Shared.Speech.EntitySystems; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Speech.EntitySystems; diff --git a/Content.Server/SprayPainter/SprayPainterSystem.cs b/Content.Server/SprayPainter/SprayPainterSystem.cs index 1b44b7b0ba..763b7697d3 100644 --- a/Content.Server/SprayPainter/SprayPainterSystem.cs +++ b/Content.Server/SprayPainter/SprayPainterSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.SprayPainter; using Content.Shared.Interaction; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.SprayPainter; diff --git a/Content.Server/Station/Systems/StationJobsSystem.cs b/Content.Server/Station/Systems/StationJobsSystem.cs index 2709bc2072..eeaace03b2 100644 --- a/Content.Server/Station/Systems/StationJobsSystem.cs +++ b/Content.Server/Station/Systems/StationJobsSystem.cs @@ -41,7 +41,7 @@ public sealed partial class StationJobsSystem : EntitySystem if (_availableJobsDirty) { _cachedAvailableJobs = GenerateJobsAvailableEvent(); - RaiseNetworkEvent(_cachedAvailableJobs, Filter.Empty().AddPlayers(_playerManager.ServerSessions)); + RaiseNetworkEvent(_cachedAvailableJobs, Filter.Empty().AddPlayers(_playerManager.Sessions)); _availableJobsDirty = false; } } diff --git a/Content.Server/StationEvents/Components/IonStormRuleComponent.cs b/Content.Server/StationEvents/Components/IonStormRuleComponent.cs new file mode 100644 index 0000000000..35b59f5b35 --- /dev/null +++ b/Content.Server/StationEvents/Components/IonStormRuleComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server.StationEvents.Components; + +/// +/// Gamerule component to mess up ai/borg laws when started. +/// +[RegisterComponent] +public sealed partial class IonStormRuleComponent : Component +{ +} diff --git a/Content.Server/StationEvents/Components/VentClogRuleComponent.cs b/Content.Server/StationEvents/Components/VentClogRuleComponent.cs index 79ebc520c8..afb3a36326 100644 --- a/Content.Server/StationEvents/Components/VentClogRuleComponent.cs +++ b/Content.Server/StationEvents/Components/VentClogRuleComponent.cs @@ -12,7 +12,7 @@ public sealed partial class VentClogRuleComponent : Component /// Somewhat safe chemicals to put in foam that probably won't instantly kill you. /// There is a small chance of using any reagent, ignoring this. /// - [DataField("safeishVentChemicals", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdListSerializer))] public IReadOnlyList SafeishVentChemicals = new[] { "Water", "Blood", "Slime", "SpaceDrugs", "SpaceCleaner", "Nutriment", "Sugar", "SpaceLube", "Ephedrine", "Ale", "Beer", "SpaceGlue" @@ -21,31 +21,31 @@ public sealed partial class VentClogRuleComponent : Component /// /// Sound played when foam is being created. /// - [DataField("sound")] + [DataField] public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Effects/extinguish.ogg"); /// - /// The standard reagent quantity to put in the foam, modfied by event severity. + /// The standard reagent quantity to put in the foam, modified by event severity. /// - [DataField("reagentQuantity"), ViewVariables(VVAccess.ReadWrite)] - public int ReagentQuantity = 200; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int ReagentQuantity = 100; /// - /// The standard spreading of the foam, not modfied by event severity. + /// The standard spreading of the foam, not modified by event severity. /// - [DataField("spread"), ViewVariables(VVAccess.ReadWrite)] - public int Spread = 20; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int Spread = 16; /// /// How long the foam lasts for /// - [DataField("time"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float Time = 20f; /// /// Reagents that gets the weak numbers used instead of regular ones. /// - [DataField("weakReagents", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField(customTypeSerializer: typeof(PrototypeIdListSerializer))] public IReadOnlyList WeakReagents = new[] { "SpaceLube", "SpaceGlue" @@ -54,12 +54,12 @@ public sealed partial class VentClogRuleComponent : Component /// /// Quantity of weak reagents to put in the foam. /// - [DataField("weakReagentQuantity"), ViewVariables(VVAccess.ReadWrite)] - public int WeakReagentQuantity = 60; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int WeakReagentQuantity = 50; /// /// Spread of the foam for weak reagents. /// - [DataField("weakSpread"), ViewVariables(VVAccess.ReadWrite)] - public int WeakSpread = 2; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int WeakSpread = 3; } diff --git a/Content.Server/StationEvents/Events/IonStormRule.cs b/Content.Server/StationEvents/Events/IonStormRule.cs new file mode 100644 index 0000000000..e5b68c4d84 --- /dev/null +++ b/Content.Server/StationEvents/Events/IonStormRule.cs @@ -0,0 +1,273 @@ +using Content.Server.GameTicking.Rules.Components; +using Content.Server.Silicons.Laws; +using Content.Server.Station.Components; +using Content.Server.StationEvents.Components; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Dataset; +using Content.Shared.FixedPoint; +using Content.Shared.Random; +using Content.Shared.Random.Helpers; +using Content.Shared.Silicons.Laws; +using Content.Shared.Silicons.Laws.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.StationEvents.Events; + +public sealed class IonStormRule : StationEventSystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SiliconLawSystem _siliconLaw = default!; + + // funny + [ValidatePrototypeId] + private const string Threats = "IonStormThreats"; + [ValidatePrototypeId] + private const string Objects = "IonStormObjects"; + [ValidatePrototypeId] + private const string Crew = "IonStormCrew"; + [ValidatePrototypeId] + private const string Adjectives = "IonStormAdjectives"; + [ValidatePrototypeId] + private const string Verbs = "IonStormVerbs"; + [ValidatePrototypeId] + private const string NumberBase = "IonStormNumberBase"; + [ValidatePrototypeId] + private const string NumberMod = "IonStormNumberMod"; + [ValidatePrototypeId] + private const string Areas = "IonStormAreas"; + [ValidatePrototypeId] + private const string Feelings = "IonStormFeelings"; + [ValidatePrototypeId] + private const string FeelingsPlural = "IonStormFeelingsPlural"; + [ValidatePrototypeId] + private const string Musts = "IonStormMusts"; + [ValidatePrototypeId] + private const string Requires = "IonStormRequires"; + [ValidatePrototypeId] + private const string Actions = "IonStormActions"; + [ValidatePrototypeId] + private const string Allergies = "IonStormAllergies"; + [ValidatePrototypeId] + private const string AllergySeverities = "IonStormAllergySeverities"; + [ValidatePrototypeId] + private const string Species = "IonStormSpecies"; + [ValidatePrototypeId] + private const string Concepts = "IonStormConcepts"; + [ValidatePrototypeId] + private const string Drinks = "IonStormDrinks"; + [ValidatePrototypeId] + private const string Foods = "IonStormFoods"; + + protected override void Started(EntityUid uid, IonStormRuleComponent comp, GameRuleComponent gameRule, GameRuleStartedEvent args) + { + base.Started(uid, comp, gameRule, args); + + if (!TryGetRandomStation(out var chosenStation)) + return; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var lawBound, out var xform, out var target)) + { + // only affect law holders on the station + if (CompOrNull(xform.GridUid)?.Station != chosenStation) + continue; + + if (!RobustRandom.Prob(target.Chance)) + continue; + + var laws = _siliconLaw.GetLaws(ent, lawBound); + if (laws.Laws.Count == 0) + continue; + + // try to swap it out with a random lawset + if (RobustRandom.Prob(target.RandomLawsetChance)) + { + var lawsets = PrototypeManager.Index(target.RandomLawsets); + var lawset = lawsets.Pick(RobustRandom); + laws = _siliconLaw.GetLawset(lawset); + } + else + { + // clone it so not modifying stations lawset + laws = laws.Clone(); + } + + // shuffle them all + if (RobustRandom.Prob(target.ShuffleChance)) + { + // hopefully work with existing glitched laws if there are multiple ion storms + FixedPoint2 baseOrder = FixedPoint2.New(1); + foreach (var law in laws.Laws) + { + if (law.Order < baseOrder) + baseOrder = law.Order; + } + + RobustRandom.Shuffle(laws.Laws); + + // change order based on shuffled position + for (int i = 0; i < laws.Laws.Count; i++) + { + laws.Laws[i].Order = baseOrder + i; + } + } + + // see if we can remove a random law + if (laws.Laws.Count > 0 && RobustRandom.Prob(target.RemoveChance)) + { + var i = RobustRandom.Next(laws.Laws.Count); + laws.Laws.RemoveAt(i); + } + + // generate a new law... + var newLaw = GenerateLaw(); + + // see if the law we add will replace a random existing law or be a new glitched order one + if (laws.Laws.Count > 0 && RobustRandom.Prob(target.ReplaceChance)) + { + var i = RobustRandom.Next(laws.Laws.Count); + laws.Laws[i] = new SiliconLaw() + { + LawString = newLaw, + Order = laws.Laws[i].Order + }; + } + else + { + laws.Laws.Insert(0, new SiliconLaw() + { + LawString = newLaw, + Order = -1, + LawIdentifierOverride = "#" + }); + } + + _adminLogger.Add(LogType.Mind, LogImpact.High, $"{ToPrettyString(ent):silicon} had its laws changed by an ion storm to {laws.LoggingString()}"); + + // laws unique to this silicon, dont use station laws anymore + EnsureComp(ent); + var ev = new IonStormLawsEvent(laws); + RaiseLocalEvent(ent, ref ev); + } + } + + // for your own sake direct your eyes elsewhere + private string GenerateLaw() + { + // pick all values ahead of time to make the logic cleaner + var threats = Pick(Threats); + var objects = Pick(Objects); + var crew1 = Pick(Crew); + var crew2 = Pick(Crew); + var adjective = Pick(Adjectives); + var verb = Pick(Verbs); + var number = Pick(NumberBase) + " " + Pick(NumberMod); + var area = Pick(Areas); + var feeling = Pick(Feelings); + var feelingPlural = Pick(FeelingsPlural); + var must = Pick(Musts); + var require = Pick(Requires); + var action = Pick(Actions); + var allergy = Pick(Allergies); + var allergySeverity = Pick(AllergySeverities); + var species = Pick(Species); + var concept = Pick(Concepts); + var drink = Pick(Drinks); + var food = Pick(Foods); + + var joined = $"{number} {adjective}"; + // a lot of things have subjects of a threat/crew/object + var triple = RobustRandom.Next(0, 3) switch + { + 0 => threats, + 1 => crew1, + 2 => objects + }; + var crewAll = RobustRandom.Prob(0.5f) ? crew2 : Loc.GetString("ion-storm-crew"); + var objectsThreats = RobustRandom.Prob(0.5f) ? objects : threats; + var objectsConcept = RobustRandom.Prob(0.5f) ? objects : concept; + // s goes ahead of require, is/are + // i dont think theres a way to do this in fluent + var (who, plural) = RobustRandom.Next(0, 5) switch + { + 0 => (Loc.GetString("ion-storm-you"), false), + 1 => (Loc.GetString("ion-storm-the-station"), true), + 2 => (Loc.GetString("ion-storm-the-crew"), true), + 3 => (Loc.GetString("ion-storm-the-job", ("job", crew2)), false), + _ => (area, true) // THE SINGULARITY REQUIRES THE HAPPY CLOWNS + }; + var jobChange = RobustRandom.Next(0, 3) switch + { + 0 => crew1, + 1 => Loc.GetString("ion-storm-clowns"), + _ => Loc.GetString("ion-storm-heads") + }; + var part = Loc.GetString("ion-storm-part", ("part", RobustRandom.Prob(0.5f))); + var harm = RobustRandom.Next(0, 7) switch + { + 0 => concept, + 1 => $"{adjective} {threats}", + 2 => $"{adjective} {objects}", + 3 => Loc.GetString("ion-storm-adjective-things", ("adjective", adjective)), + 4 => species, + 5 => crew1, + _ => Loc.GetString("ion-storm-x-and-y", ("x", crew1), ("y", crew2)) + }; + + if (plural) feeling = feelingPlural; + + // message logic!!! + return RobustRandom.Next(0, 37) switch + { + 0 => Loc.GetString("ion-storm-law-on-station", ("joined", joined), ("subjects", triple)), + 1 => Loc.GetString("ion-storm-law-no-shuttle", ("joined", joined), ("subjects", triple)), + 2 => Loc.GetString("ion-storm-law-crew-are", ("who", crewAll), ("joined", joined), ("subjects", objectsThreats)), + 3 => Loc.GetString("ion-storm-law-subjects-harmful", ("adjective", adjective), ("subjects", triple)), + 4 => Loc.GetString("ion-storm-law-must-harmful", ("must", must)), + 5 => Loc.GetString("ion-storm-law-thing-harmful", ("thing", RobustRandom.Prob(0.5f) ? concept : action)), + 6 => Loc.GetString("ion-storm-law-job-harmful", ("adjective", adjective), ("job", crew1)), + 7 => Loc.GetString("ion-storm-law-having-harmful", ("adjective", adjective), ("thing", objectsConcept)), + 8 => Loc.GetString("ion-storm-law-not-having-harmful", ("adjective", adjective), ("thing", objectsConcept)), + 9 => Loc.GetString("ion-storm-law-requires", ("who", who), ("plural", plural), ("thing", RobustRandom.Prob(0.5f) ? concept : require)), + 10 => Loc.GetString("ion-storm-law-requires-subjects", ("who", who), ("plural", plural), ("joined", joined), ("subjects", triple)), + 11 => Loc.GetString("ion-storm-law-allergic", ("who", who), ("plural", plural), ("severity", allergySeverity), ("allergy", RobustRandom.Prob(0.5f) ? concept : allergy)), + 12 => Loc.GetString("ion-storm-law-allergic-subjects", ("who", who), ("plural", plural), ("severity", allergySeverity), ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objects : crew1)), + 13 => Loc.GetString("ion-storm-law-feeling", ("who", who), ("feeling", feeling), ("concept", concept)), + 14 => Loc.GetString("ion-storm-law-feeling-subjects", ("who", who), ("feeling", feeling), ("joined", joined), ("subjects", triple)), + 15 => Loc.GetString("ion-storm-law-you-are", ("concept", concept)), + 16 => Loc.GetString("ion-storm-law-you-are-subjects", ("joined", joined), ("subjects", triple)), + 17 => Loc.GetString("ion-storm-law-you-must-always", ("must", must)), + 18 => Loc.GetString("ion-storm-law-you-must-never", ("must", must)), + 19 => Loc.GetString("ion-storm-law-eat", ("who", crewAll), ("adjective", adjective), ("food", RobustRandom.Prob(0.5f) ? food : triple)), + 20 => Loc.GetString("ion-storm-law-drink", ("who", crewAll), ("adjective", adjective), ("drink", drink)), + 22 => Loc.GetString("ion-storm-law-change-job", ("who", crewAll), ("adjective", adjective), ("change", jobChange)), + 23 => Loc.GetString("ion-storm-law-highest-rank", ("who", crew1)), + 24 => Loc.GetString("ion-storm-law-lowest-rank", ("who", crew1)), + 25 => Loc.GetString("ion-storm-law-crew-must", ("who", crewAll), ("must", must)), + 26 => Loc.GetString("ion-storm-law-crew-must-go", ("who", crewAll), ("area", area)), + 27 => Loc.GetString("ion-storm-law-crew-only-1", ("who", crew1), ("part", part)), + 28 => Loc.GetString("ion-storm-law-crew-only-2", ("who", crew1), ("other", crew2), ("part", part)), + 29 => Loc.GetString("ion-storm-law-crew-only-subjects", ("adjective", adjective), ("subjects", RobustRandom.Prob(0.5f) ? objectsThreats : "PEOPLE"), ("part", part)), + 30 => Loc.GetString("ion-storm-law-crew-only-species", ("species", species), ("part", part)), + 31 => Loc.GetString("ion-storm-law-crew-must-do", ("must", must), ("part", part)), + 32 => Loc.GetString("ion-storm-law-crew-must-have", ("adjective", adjective), ("objects", objects), ("part", part)), + 33 => Loc.GetString("ion-storm-law-crew-must-eat", ("who", who), ("adjective", adjective), ("food", food), ("part", part)), + 34 => Loc.GetString("ion-storm-law-harm", ("who", harm)), + 35 => Loc.GetString("ion-storm-law-protect", ("who", harm)), + _ => Loc.GetString("ion-storm-law-concept-verb", ("concept", concept), ("verb", verb), ("subjects", triple)) + }; + } + + /// + /// Picks a random value from an ion storm dataset. + /// All ion storm datasets start with IonStorm. + /// + private string Pick(string name) + { + var dataset = _proto.Index(name); + return RobustRandom.Pick(dataset.Values); + } +} diff --git a/Content.Server/StationEvents/Events/VentClogRule.cs b/Content.Server/StationEvents/Events/VentClogRule.cs index 5ef28304e7..f378aec3fb 100644 --- a/Content.Server/StationEvents/Events/VentClogRule.cs +++ b/Content.Server/StationEvents/Events/VentClogRule.cs @@ -3,10 +3,8 @@ using Content.Server.Station.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; -using Robust.Shared.Audio; using Robust.Shared.Random; using System.Linq; -using Content.Server.Chemistry.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; @@ -53,9 +51,8 @@ public sealed class VentClogRule : StationEventSystem solution.AddReagent(reagent, quantity); var foamEnt = Spawn("Foam", transform.Coordinates); - var smoke = EnsureComp(foamEnt); - smoke.SpreadAmount = weak ? component.WeakSpread : component.Spread; - _smoke.Start(foamEnt, smoke, solution, component.Time); + var spreadAmount = weak ? component.WeakSpread : component.Spread; + _smoke.StartSmoke(foamEnt, solution, component.Time, spreadAmount); Audio.PlayPvs(component.Sound, transform.Coordinates); } } diff --git a/Content.Server/Sticky/Events/EntityStuckEvent.cs b/Content.Server/Sticky/Events/EntityStuckEvent.cs index b924436489..7857fad7d5 100644 --- a/Content.Server/Sticky/Events/EntityStuckEvent.cs +++ b/Content.Server/Sticky/Events/EntityStuckEvent.cs @@ -1,5 +1,28 @@ namespace Content.Server.Sticky.Events; +/// +/// Risen on sticky entity to see if it can stick to another entity. +/// +[ByRefEvent] +public record struct AttemptEntityStickEvent(EntityUid Target, EntityUid User) +{ + public readonly EntityUid Target = Target; + public readonly EntityUid User = User; + public bool Cancelled = false; +} + +/// +/// Risen on sticky entity to see if it can unstick from another entity. +/// +[ByRefEvent] +public record struct AttemptEntityUnstickEvent(EntityUid Target, EntityUid User) +{ + public readonly EntityUid Target = Target; + public readonly EntityUid User = User; + public bool Cancelled = false; +} + + /// /// Risen on sticky entity when it was stuck to other entity. /// diff --git a/Content.Server/Sticky/Systems/StickySystem.cs b/Content.Server/Sticky/Systems/StickySystem.cs index 330b878c05..bcc1be39a9 100644 --- a/Content.Server/Sticky/Systems/StickySystem.cs +++ b/Content.Server/Sticky/Systems/StickySystem.cs @@ -56,7 +56,7 @@ public sealed class StickySystem : EntitySystem { DoContactInteraction = true, Text = Loc.GetString("comp-sticky-unstick-verb-text"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")), Act = () => StartUnsticking(uid, args.User, component) }); } @@ -72,6 +72,11 @@ public sealed class StickySystem : EntitySystem if (component.Blacklist != null && component.Blacklist.IsValid(target)) return false; + var attemptEv = new AttemptEntityStickEvent(target, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return false; + // check if delay is not zero to start do after var delay = (float) component.StickDelay.TotalSeconds; if (delay > 0) @@ -120,6 +125,14 @@ public sealed class StickySystem : EntitySystem if (!Resolve(uid, ref component)) return; + if (component.StuckTo is not { } stuckTo) + return; + + var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return; + var delay = (float) component.UnstickDelay.TotalSeconds; if (delay > 0) { @@ -152,6 +165,11 @@ public sealed class StickySystem : EntitySystem if (!Resolve(uid, ref component)) return; + var attemptEv = new AttemptEntityStickEvent(target, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return; + // add container to entity and insert sticker into it var container = _containerSystem.EnsureContainer(target, StickerSlotId); container.ShowContents = true; @@ -179,12 +197,17 @@ public sealed class StickySystem : EntitySystem { if (!Resolve(uid, ref component)) return; - if (component.StuckTo == null) + + if (component.StuckTo is not { } stuckTo) + return; + + var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) return; // try to remove sticky item from target container - var target = component.StuckTo.Value; - if (!_containerSystem.TryGetContainer(target, StickerSlotId, out var container) || !container.Remove(uid)) + if (!_containerSystem.TryGetContainer(stuckTo, StickerSlotId, out var container) || !container.Remove(uid)) return; // delete container if it's now empty if (container.ContainedEntities.Count == 0) @@ -207,6 +230,6 @@ public sealed class StickySystem : EntitySystem } component.StuckTo = null; - RaiseLocalEvent(uid, new EntityUnstuckEvent(target, user), true); + RaiseLocalEvent(uid, new EntityUnstuckEvent(stuckTo, user), true); } } diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs index 3430449957..8b4ae1c76f 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs @@ -9,7 +9,6 @@ using Content.Shared.Storage.EntitySystems; using Content.Shared.Timing; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -135,7 +134,7 @@ public sealed partial class StorageSystem : SharedStorageSystem /// If the user has nested-UIs open (e.g., PDA UI open when pda is in a backpack), close them. /// /// - public void CloseNestedInterfaces(EntityUid uid, IPlayerSession session, StorageComponent? storageComp = null) + public void CloseNestedInterfaces(EntityUid uid, ICommonSession session, StorageComponent? storageComp = null) { if (!Resolve(uid, ref storageComp)) return; diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs index 9600ea6c8f..0435a6bea6 100644 --- a/Content.Server/Store/Systems/StoreSystem.Ui.cs +++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs @@ -10,6 +10,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Hands.EntitySystems; using Content.Shared.Store; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.Store.Systems; diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index a8ddf1a986..75374e7de5 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -18,6 +18,7 @@ using Content.Shared.Strip; using Content.Shared.Strip.Components; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Strip diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs index b4054a290d..f411001bd3 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs @@ -1,7 +1,7 @@ using Content.Server.Chat.Systems; using Content.Server.Speech; using Content.Server.Speech.Components; -using Robust.Server.GameObjects; +using Robust.Shared.Player; using static Content.Server.Chat.Systems.ChatSystem; namespace Content.Server.SurveillanceCamera; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs index 17eee198b8..7b1dff0b6b 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs @@ -5,6 +5,7 @@ using Content.Server.Power.Components; using Content.Server.UserInterface; using Content.Shared.SurveillanceCamera; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.SurveillanceCamera; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs index ae17ca4f8f..ac41723026 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs @@ -1,14 +1,13 @@ -using Content.Server.Administration.Managers; using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; -using Content.Server.Ghost.Components; using Content.Server.Power.Components; using Content.Shared.ActionBlocker; using Content.Shared.DeviceNetwork; using Content.Shared.SurveillanceCamera; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.SurveillanceCamera; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index f159ec52d9..410ba9f754 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.DeviceNetwork; using Content.Shared.SurveillanceCamera; using Content.Shared.Verbs; using Robust.Server.GameObjects; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Server.SurveillanceCamera; @@ -58,7 +59,7 @@ public sealed class SurveillanceCameraSystem : EntitySystem SubscribeLocalEvent(OnSetName); SubscribeLocalEvent(OnSetNetwork); SubscribeLocalEvent>(AddVerbs); - + SubscribeLocalEvent(OnEmpPulse); SubscribeLocalEvent(OnEmpDisabledRemoved); } diff --git a/Content.Server/Tabletop/TabletopSession.cs b/Content.Server/Tabletop/TabletopSession.cs index d94b4fd657..5e7c6ac02e 100644 --- a/Content.Server/Tabletop/TabletopSession.cs +++ b/Content.Server/Tabletop/TabletopSession.cs @@ -1,6 +1,6 @@ using System.Numerics; -using Robust.Server.Player; using Robust.Shared.Map; +using Robust.Shared.Player; namespace Content.Server.Tabletop { @@ -17,7 +17,7 @@ namespace Content.Server.Tabletop /// /// The set of players currently playing this tabletop game. /// - public readonly Dictionary Players = new(); + public readonly Dictionary Players = new(); /// /// All entities bound to this session. If you create an entity for this session, you have to add it here. diff --git a/Content.Server/Tabletop/TabletopSystem.Session.cs b/Content.Server/Tabletop/TabletopSystem.Session.cs index e9dea0c66a..8f1bc7005d 100644 --- a/Content.Server/Tabletop/TabletopSystem.Session.cs +++ b/Content.Server/Tabletop/TabletopSystem.Session.cs @@ -1,7 +1,7 @@ using System.Numerics; using Content.Server.Tabletop.Components; using Content.Shared.Tabletop.Events; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Tabletop @@ -66,7 +66,7 @@ namespace Content.Server.Tabletop /// /// The player session in question. /// The UID of the tabletop game entity. - public void OpenSessionFor(IPlayerSession player, EntityUid uid) + public void OpenSessionFor(ICommonSession player, EntityUid uid) { if (!EntityManager.TryGetComponent(uid, out TabletopGameComponent? tabletop) || player.AttachedEntity is not {Valid: true} attachedEntity) return; @@ -98,7 +98,7 @@ namespace Content.Server.Tabletop /// The player in question. /// The UID of the tabletop game entity. /// Whether to remove the from the player's attached entity. - public void CloseSessionFor(IPlayerSession player, EntityUid uid, bool removeGamerComponent = true) + public void CloseSessionFor(ICommonSession player, EntityUid uid, bool removeGamerComponent = true) { if (!EntityManager.TryGetComponent(uid, out TabletopGameComponent? tabletop) || tabletop.Session is not { } session) return; @@ -129,7 +129,7 @@ namespace Content.Server.Tabletop /// The player in question. /// An offset from the tabletop position for the camera. Zero by default. /// The UID of the camera entity. - private EntityUid CreateCamera(TabletopGameComponent tabletop, IPlayerSession player, Vector2 offset = default) + private EntityUid CreateCamera(TabletopGameComponent tabletop, ICommonSession player, Vector2 offset = default) { DebugTools.AssertNotNull(tabletop.Session); diff --git a/Content.Server/Tabletop/TabletopSystem.cs b/Content.Server/Tabletop/TabletopSystem.cs index 2e271080d0..4376ec4bc6 100644 --- a/Content.Server/Tabletop/TabletopSystem.cs +++ b/Content.Server/Tabletop/TabletopSystem.cs @@ -9,9 +9,9 @@ using Content.Shared.Tabletop.Events; using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Enums; using Robust.Shared.Map; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Server.Tabletop @@ -42,7 +42,7 @@ namespace Content.Server.Tabletop private void OnTabletopRequestTakeOut(TabletopRequestTakeOut msg, EntitySessionEventArgs args) { - if (args.SenderSession is not IPlayerSession playerSession) + if (args.SenderSession is not { } playerSession) return; var table = GetEntity(msg.TableUid); @@ -105,7 +105,7 @@ namespace Content.Server.Tabletop protected override void OnTabletopMove(TabletopMoveEvent msg, EntitySessionEventArgs args) { - if (args.SenderSession is not IPlayerSession playerSession) + if (args.SenderSession is not { } playerSession) return; if (!TryComp(GetEntity(msg.TableUid), out TabletopGameComponent? tabletop) || tabletop.Session is not { } session) @@ -155,7 +155,7 @@ namespace Content.Server.Tabletop private void OnStopPlaying(TabletopStopPlayingEvent msg, EntitySessionEventArgs args) { - CloseSessionFor((IPlayerSession)args.SenderSession, GetEntity(msg.TableUid)); + CloseSessionFor(args.SenderSession, GetEntity(msg.TableUid)); } private void OnPlayerDetached(EntityUid uid, TabletopGamerComponent component, PlayerDetachedEvent args) diff --git a/Content.Server/Toolshed/Commands/AdminDebug/ACmdCommand.cs b/Content.Server/Toolshed/Commands/AdminDebug/ACmdCommand.cs index d2b3cc261c..f113e49655 100644 --- a/Content.Server/Toolshed/Commands/AdminDebug/ACmdCommand.cs +++ b/Content.Server/Toolshed/Commands/AdminDebug/ACmdCommand.cs @@ -1,7 +1,7 @@ using Content.Server.Administration; using Content.Server.Administration.Managers; using Content.Shared.Administration; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Syntax; @@ -25,7 +25,7 @@ public sealed class ACmdCommand : ToolshedCommand public bool CanInvoke( [CommandInvocationContext] IInvocationContext ctx, [PipedArgument] CommandSpec command, - [CommandArgument] ValueRef player + [CommandArgument] ValueRef player ) { // Deliberately discard the error. diff --git a/Content.Server/Toolshed/Commands/VisualizeCommand.cs b/Content.Server/Toolshed/Commands/VisualizeCommand.cs index 4ef08a91bf..2225bfaf44 100644 --- a/Content.Server/Toolshed/Commands/VisualizeCommand.cs +++ b/Content.Server/Toolshed/Commands/VisualizeCommand.cs @@ -4,7 +4,6 @@ using Content.Server.EUI; using Content.Shared.Administration; using Content.Shared.Bql; using Content.Shared.Eui; -using Robust.Server.Player; using Robust.Shared.Toolshed; using Robust.Shared.Toolshed.Errors; @@ -30,7 +29,7 @@ public sealed class VisualizeCommand : ToolshedCommand var ui = new ToolshedVisualizeEui( input.Select(e => (EntName(e), EntityManager.GetNetEntity(e))).ToArray() ); - _euiManager.OpenEui(ui, (IPlayerSession) ctx.Session); + _euiManager.OpenEui(ui, ctx.Session); _euiManager.QueueStateUpdate(ui); } } diff --git a/Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs b/Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs index 1feab11b99..fd656a9f71 100644 --- a/Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs +++ b/Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs @@ -5,6 +5,7 @@ using Content.Shared.FixedPoint; using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; +using Robust.Shared.Player; namespace Content.Server.Traitor.Uplink.Commands { @@ -36,7 +37,7 @@ namespace Content.Server.Traitor.Uplink.Commands return; } - IPlayerSession? session; + ICommonSession? session; if (args.Length > 0) { // Get player entity @@ -48,7 +49,7 @@ namespace Content.Server.Traitor.Uplink.Commands } else { - session = (IPlayerSession?) shell.Player; + session = shell.Player; } if (session?.AttachedEntity is not { } user) diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs index bb020608e2..34f9c0f397 100644 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ b/Content.Server/UserInterface/ActivatableUIComponent.cs @@ -1,4 +1,4 @@ -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Reflection; using Robust.Shared.Serialization; @@ -65,7 +65,7 @@ namespace Content.Server.UserInterface /// NOTE: DO NOT DIRECTLY SET, USE ActivatableUISystem.SetCurrentSingleUser /// [ViewVariables] - public IPlayerSession? CurrentSingleUser; + public ICommonSession? CurrentSingleUser; void ISerializationHooks.AfterDeserialization() { diff --git a/Content.Server/UserInterface/ActivatableUISystem.cs b/Content.Server/UserInterface/ActivatableUISystem.cs index 59086415b4..adeeed7c19 100644 --- a/Content.Server/UserInterface/ActivatableUISystem.cs +++ b/Content.Server/UserInterface/ActivatableUISystem.cs @@ -8,7 +8,7 @@ using Content.Shared.Interaction.Events; using Content.Shared.UserInterface; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.UserInterface; @@ -173,7 +173,7 @@ public sealed partial class ActivatableUISystem : EntitySystem return true; } - public void SetCurrentSingleUser(EntityUid uid, IPlayerSession? v, ActivatableUIComponent? aui = null) + public void SetCurrentSingleUser(EntityUid uid, ICommonSession? v, ActivatableUIComponent? aui = null) { if (!Resolve(uid, ref aui)) return; @@ -231,9 +231,9 @@ public sealed class UserOpenActivatableUIAttemptEvent : CancellableEntityEventAr public sealed class AfterActivatableUIOpenEvent : EntityEventArgs { public EntityUid User { get; } - public readonly IPlayerSession Session; + public readonly ICommonSession Session; - public AfterActivatableUIOpenEvent(EntityUid who, IPlayerSession session) + public AfterActivatableUIOpenEvent(EntityUid who, ICommonSession session) { User = who; Session = session; diff --git a/Content.Server/UserInterface/IntrinsicUISystem.cs b/Content.Server/UserInterface/IntrinsicUISystem.cs index 27b682cd41..fa725e524a 100644 --- a/Content.Server/UserInterface/IntrinsicUISystem.cs +++ b/Content.Server/UserInterface/IntrinsicUISystem.cs @@ -1,6 +1,7 @@ using Content.Server.Actions; using Content.Shared.UserInterface; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.UserInterface; diff --git a/Content.Server/UserInterface/StatValuesCommand.cs b/Content.Server/UserInterface/StatValuesCommand.cs index b13b596323..fe2ee380fe 100644 --- a/Content.Server/UserInterface/StatValuesCommand.cs +++ b/Content.Server/UserInterface/StatValuesCommand.cs @@ -8,7 +8,6 @@ using Content.Shared.Materials; using Content.Shared.Research.Prototypes; using Content.Shared.UserInterface; using Content.Shared.Weapons.Melee; -using Robust.Server.Player; using Robust.Shared.Console; using Robust.Shared.Prototypes; @@ -27,7 +26,7 @@ public sealed class StatValuesCommand : IConsoleCommand public string Help => $"{Command} "; public void Execute(IConsoleShell shell, string argStr, string[] args) { - if (shell.Player is not IPlayerSession pSession) + if (shell.Player is not { } pSession) { shell.WriteError(Loc.GetString("stat-values-server")); return; diff --git a/Content.Server/Verbs/VerbSystem.cs b/Content.Server/Verbs/VerbSystem.cs index 6d12b08e86..e304c6b4af 100644 --- a/Content.Server/Verbs/VerbSystem.cs +++ b/Content.Server/Verbs/VerbSystem.cs @@ -6,7 +6,6 @@ using Content.Shared.Administration.Logs; using Content.Shared.Database; using Content.Shared.Hands.Components; using Content.Shared.Verbs; -using Robust.Server.Player; namespace Content.Server.Verbs { @@ -25,7 +24,7 @@ namespace Content.Server.Verbs private void HandleVerbRequest(RequestServerVerbsEvent args, EntitySessionEventArgs eventArgs) { - var player = (IPlayerSession) eventArgs.SenderSession; + var player = eventArgs.SenderSession; if (!EntityManager.EntityExists(GetEntity(args.EntityUid))) { @@ -43,7 +42,7 @@ namespace Content.Server.Verbs // this, and some verbs (e.g. view variables) won't even care about whether an entity is accessible through // the entity menu or not. - var force = args.AdminRequest && eventArgs.SenderSession is IPlayerSession playerSession && + var force = args.AdminRequest && eventArgs.SenderSession is { } playerSession && _adminMgr.HasAdminFlag(playerSession, AdminFlags.Admin); List verbTypes = new(); diff --git a/Content.Server/VoiceMask/VoiceMaskSystem.cs b/Content.Server/VoiceMask/VoiceMaskSystem.cs index fdd5f3a9f4..1df66b608c 100644 --- a/Content.Server/VoiceMask/VoiceMaskSystem.cs +++ b/Content.Server/VoiceMask/VoiceMaskSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Inventory.Events; using Content.Shared.Preferences; using Content.Shared.VoiceMask; using Robust.Server.GameObjects; +using Robust.Shared.Player; namespace Content.Server.VoiceMask; diff --git a/Content.Server/Voting/IVoteHandle.cs b/Content.Server/Voting/IVoteHandle.cs index 13f64e6ef8..869f2017d7 100644 --- a/Content.Server/Voting/IVoteHandle.cs +++ b/Content.Server/Voting/IVoteHandle.cs @@ -1,5 +1,5 @@ using Content.Server.Voting.Managers; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Voting { @@ -75,7 +75,7 @@ namespace Content.Server.Voting /// /// is not a valid option ID. /// - void CastVote(IPlayerSession session, int? optionId); + void CastVote(ICommonSession session, int? optionId); /// /// Cancel this vote. diff --git a/Content.Server/Voting/Managers/IVoteManager.cs b/Content.Server/Voting/Managers/IVoteManager.cs index 6a92e70fff..d95fac9ae9 100644 --- a/Content.Server/Voting/Managers/IVoteManager.cs +++ b/Content.Server/Voting/Managers/IVoteManager.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Voting; -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Voting.Managers { @@ -41,7 +41,7 @@ namespace Content.Server.Voting.Managers /// True if can start votes right now, /// and if provided if they can start votes of type . /// - bool CanCallVote(IPlayerSession initiator, StandardVoteType? voteType = null); + bool CanCallVote(ICommonSession initiator, StandardVoteType? voteType = null); /// /// Initiate a standard vote such as restart round, that can be initiated by players. @@ -51,7 +51,7 @@ namespace Content.Server.Voting.Managers /// If null it is assumed to be an automatic vote by the server. /// /// The type of standard vote to make. - void CreateStandardVote(IPlayerSession? initiator, StandardVoteType voteType); + void CreateStandardVote(ICommonSession? initiator, StandardVoteType voteType); /// /// Create a non-standard vote with special parameters. diff --git a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs index 55e88e2a8c..e1bffa769d 100644 --- a/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs +++ b/Content.Server/Voting/Managers/VoteManager.DefaultVotes.cs @@ -6,8 +6,8 @@ using Content.Server.RoundEnd; using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.Voting; -using Robust.Server.Player; using Robust.Shared.Configuration; +using Robust.Shared.Player; using Robust.Shared.Random; namespace Content.Server.Voting.Managers @@ -21,7 +21,7 @@ namespace Content.Server.Voting.Managers {StandardVoteType.Map, CCVars.VoteMapEnabled}, }; - public void CreateStandardVote(IPlayerSession? initiator, StandardVoteType voteType) + public void CreateStandardVote(ICommonSession? initiator, StandardVoteType voteType) { if (initiator != null) _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{initiator} initiated a {voteType.ToString()} vote"); @@ -47,7 +47,7 @@ namespace Content.Server.Voting.Managers TimeoutStandardVote(voteType); } - private void CreateRestartVote(IPlayerSession? initiator) + private void CreateRestartVote(ICommonSession? initiator) { var alone = _playerManager.PlayerCount == 1 && initiator != null; var options = new VoteOptions @@ -100,7 +100,7 @@ namespace Content.Server.Voting.Managers vote.CastVote(initiator, 0); } - foreach (var player in _playerManager.ServerSessions) + foreach (var player in _playerManager.Sessions) { if (player != initiator) { @@ -110,7 +110,7 @@ namespace Content.Server.Voting.Managers } } - private void CreatePresetVote(IPlayerSession? initiator) + private void CreatePresetVote(ICommonSession? initiator) { var presets = GetGamePresets(); @@ -156,7 +156,7 @@ namespace Content.Server.Voting.Managers }; } - private void CreateMapVote(IPlayerSession? initiator) + private void CreateMapVote(ICommonSession? initiator) { var maps = _gameMapManager.CurrentlyEligibleMaps().ToDictionary(map => map, map => map.MapName); diff --git a/Content.Server/Voting/Managers/VoteManager.cs b/Content.Server/Voting/Managers/VoteManager.cs index 98ad8d8341..90089afb54 100644 --- a/Content.Server/Voting/Managers/VoteManager.cs +++ b/Content.Server/Voting/Managers/VoteManager.cs @@ -16,6 +16,7 @@ using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -45,7 +46,7 @@ namespace Content.Server.Voting.Managers private readonly Dictionary _standardVoteTimeout = new(); private readonly Dictionary _voteTimeout = new(); - private readonly HashSet _playerCanCallVoteDirty = new(); + private readonly HashSet _playerCanCallVoteDirty = new(); private readonly StandardVoteType[] _standardVoteTypeValues = Enum.GetValues(); public void Initialize() @@ -106,7 +107,7 @@ namespace Content.Server.Voting.Managers } } - private void CastVote(VoteReg v, IPlayerSession player, int? option) + private void CastVote(VoteReg v, ICommonSession player, int? option) { if (!IsValidOption(v, option)) throw new ArgumentOutOfRangeException(nameof(option), "Invalid vote option ID"); @@ -228,7 +229,7 @@ namespace Content.Server.Voting.Managers private void SendUpdates(VoteReg v) { - foreach (var player in _playerManager.ServerSessions) + foreach (var player in _playerManager.Sessions) { SendSingleUpdate(v, player); } @@ -237,7 +238,7 @@ namespace Content.Server.Voting.Managers v.Dirty = false; } - private void SendSingleUpdate(VoteReg v, IPlayerSession player) + private void SendSingleUpdate(VoteReg v, ICommonSession player) { var msg = new MsgVoteData(); @@ -277,10 +278,10 @@ namespace Content.Server.Voting.Managers private void DirtyCanCallVoteAll() { - _playerCanCallVoteDirty.UnionWith(_playerManager.ServerSessions); + _playerCanCallVoteDirty.UnionWith(_playerManager.Sessions); } - private void SendUpdateCanCallVote(IPlayerSession player) + private void SendUpdateCanCallVote(ICommonSession player) { var msg = new MsgVoteCanCall(); msg.CanCall = CanCallVote(player, null, out var isAdmin, out var timeSpan); @@ -306,7 +307,7 @@ namespace Content.Server.Voting.Managers } private bool CanCallVote( - IPlayerSession initiator, + ICommonSession initiator, StandardVoteType? voteType, out bool isAdmin, out TimeSpan timeSpan) @@ -353,7 +354,7 @@ namespace Content.Server.Voting.Managers return !_voteTimeout.TryGetValue(initiator.UserId, out timeSpan); } - public bool CanCallVote(IPlayerSession initiator, StandardVoteType? voteType = null) + public bool CanCallVote(ICommonSession initiator, StandardVoteType? voteType = null) { return CanCallVote(initiator, voteType, out _, out _); } @@ -406,14 +407,14 @@ namespace Content.Server.Voting.Managers return false; } - private void DirtyCanCallVote(IPlayerSession player) + private void DirtyCanCallVote(ICommonSession player) { _playerCanCallVoteDirty.Add(player); } #region Preset Votes - private void WirePresetVoteInitiator(VoteOptions options, IPlayerSession? player) + private void WirePresetVoteInitiator(VoteOptions options, ICommonSession? player) { if (player != null) { @@ -432,13 +433,13 @@ namespace Content.Server.Voting.Managers private sealed class VoteReg { public readonly int Id; - public readonly Dictionary CastVotes = new(); + public readonly Dictionary CastVotes = new(); public readonly VoteEntry[] Entries; public readonly string Title; public readonly string InitiatorText; public readonly TimeSpan StartTime; public readonly TimeSpan EndTime; - public readonly HashSet VotesDirty = new(); + public readonly HashSet VotesDirty = new(); public bool Cancelled; public bool Finished; @@ -446,10 +447,10 @@ namespace Content.Server.Voting.Managers public VoteFinishedEventHandler? OnFinished; public VoteCancelledEventHandler? OnCancelled; - public IPlayerSession? Initiator { get; } + public ICommonSession? Initiator { get; } public VoteReg(int id, VoteEntry[] entries, string title, string initiatorText, - IPlayerSession? initiator, TimeSpan start, TimeSpan end) + ICommonSession? initiator, TimeSpan start, TimeSpan end) { Id = id; Entries = entries; @@ -517,7 +518,7 @@ namespace Content.Server.Voting.Managers return _mgr.IsValidOption(_reg, optionId); } - public void CastVote(IPlayerSession session, int? optionId) + public void CastVote(ICommonSession session, int? optionId) { _mgr.CastVote(_reg, session, optionId); } diff --git a/Content.Server/Voting/VoteCommands.cs b/Content.Server/Voting/VoteCommands.cs index cb296a7d58..498c9d0494 100644 --- a/Content.Server/Voting/VoteCommands.cs +++ b/Content.Server/Voting/VoteCommands.cs @@ -6,7 +6,6 @@ using Content.Server.Voting.Managers; using Content.Shared.Administration; using Content.Shared.Database; using Content.Shared.Voting; -using Robust.Server.Player; using Robust.Shared.Console; namespace Content.Server.Voting @@ -36,14 +35,14 @@ namespace Content.Server.Voting var mgr = IoCManager.Resolve(); - if (shell.Player != null && !mgr.CanCallVote((IPlayerSession) shell.Player, type)) + if (shell.Player != null && !mgr.CanCallVote(shell.Player, type)) { _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{shell.Player} failed to start {type.ToString()} vote"); shell.WriteError(Loc.GetString("cmd-createvote-cannot-call-vote-now")); return; } - mgr.CreateStandardVote((IPlayerSession?) shell.Player, type); + mgr.CreateStandardVote(shell.Player, type); } public CompletionResult GetCompletion(IConsoleShell shell, string[] args) @@ -92,7 +91,7 @@ namespace Content.Server.Voting options.Options.Add((args[i], i)); } - options.SetInitiatorOrServer((IPlayerSession?) shell.Player); + options.SetInitiatorOrServer(shell.Player); if (shell.Player != null) _adminLogger.Add(LogType.Vote, LogImpact.Medium, $"{shell.Player} initiated a custom vote: {options.Title} - {string.Join("; ", options.Options.Select(x => x.text))}"); @@ -187,7 +186,7 @@ namespace Content.Server.Voting return; } - vote.CastVote((IPlayerSession) shell.Player!, optionN); + vote.CastVote(shell.Player!, optionN); } } diff --git a/Content.Server/Voting/VoteOptions.cs b/Content.Server/Voting/VoteOptions.cs index 6e6d0465ed..5475d10d32 100644 --- a/Content.Server/Voting/VoteOptions.cs +++ b/Content.Server/Voting/VoteOptions.cs @@ -1,4 +1,4 @@ -using Robust.Server.Player; +using Robust.Shared.Player; namespace Content.Server.Voting @@ -16,7 +16,7 @@ namespace Content.Server.Voting /// /// The player that started the vote. Used to keep track of player cooldowns to avoid vote spam. /// - public IPlayerSession? InitiatorPlayer { get; set; } + public ICommonSession? InitiatorPlayer { get; set; } /// /// The shown title of the vote. @@ -43,13 +43,13 @@ namespace Content.Server.Voting /// Sets and /// by setting the latter to the player's name. /// - public void SetInitiator(IPlayerSession player) + public void SetInitiator(ICommonSession player) { InitiatorPlayer = player; InitiatorText = player.Name; } - public void SetInitiatorOrServer(IPlayerSession? player) + public void SetInitiatorOrServer(ICommonSession? player) { if (player != null) { diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index 1b6b2ebef1..3d9c3e8219 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -24,11 +24,9 @@ using Content.Shared.StatusEffect; using Content.Shared.Tag; using Content.Shared.Weapons.Melee; using Content.Shared.Weapons.Melee.Events; -using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Random; namespace Content.Server.Weapons.Melee; @@ -174,7 +172,7 @@ public sealed class MeleeWeaponSystem : SharedMeleeWeaponSystem EntityCoordinates targetCoordinates; Angle targetLocalAngle; - if (session is IPlayerSession pSession) + if (session is { } pSession) { (targetCoordinates, targetLocalAngle) = _lag.GetCoordinatesAngle(target, pSession); } diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index e75ad0a9ef..b6452efa8a 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -16,7 +16,7 @@ using Content.Shared.Tools; using Content.Shared.Tools.Components; using Content.Shared.Wires; using Robust.Server.GameObjects; -using Robust.Server.Player; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; @@ -616,7 +616,7 @@ public sealed class WiresSystem : SharedWiresSystem wires.WireSeed), ui: ui); } - public void OpenUserInterface(EntityUid uid, IPlayerSession player) + public void OpenUserInterface(EntityUid uid, ICommonSession player) { if (_uiSystem.TryGetUi(uid, WiresUiKey.Key, out var ui)) _uiSystem.OpenUi(ui, player); diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs index 53c8b2fc23..17901188d1 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs @@ -17,7 +17,6 @@ using Content.Shared.Xenoarchaeology.Equipment; using Content.Shared.Xenoarchaeology.XenoArtifacts; using JetBrains.Annotations; using Robust.Server.GameObjects; -using Robust.Server.Player; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -231,7 +230,7 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem /// private void OnServerSelectionMessage(EntityUid uid, AnalysisConsoleComponent component, AnalysisConsoleServerSelectionMessage args) { - _ui.TryOpen(uid, ResearchClientUiKey.Key, (IPlayerSession) args.Session); + _ui.TryOpen(uid, ResearchClientUiKey.Key, args.Session); } /// diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/FoamArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/FoamArtifactSystem.cs index 93d9d5a01b..2d2c230b12 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/FoamArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/FoamArtifactSystem.cs @@ -1,5 +1,4 @@ using System.Linq; -using Content.Server.Chemistry.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; @@ -38,8 +37,7 @@ public sealed class FoamArtifactSystem : EntitySystem var range = (int) MathF.Round(MathHelper.Lerp(component.MinFoamAmount, component.MaxFoamAmount, _random.NextFloat(0, 1f))); sol.AddReagent(component.SelectedReagent, component.ReagentAmount); var foamEnt = Spawn("Foam", xform.Coordinates); - var smoke = EnsureComp(foamEnt); - smoke.SpreadAmount = range * 4; - _smoke.Start(foamEnt, smoke, sol, component.Duration); + var spreadAmount = range * 4; + _smoke.StartSmoke(foamEnt, sol, component.Duration, spreadAmount); } } diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index 1f8f5fbd42..51cbf34d99 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -8,6 +8,7 @@ using Content.Server.Emoting.Systems; using Content.Server.Inventory; using Content.Server.Speech.EntitySystems; using Content.Shared.Bed.Sleep; +using Content.Shared.Cloning; using Content.Shared.Damage; using Content.Shared.Humanoid; using Content.Shared.Inventory; diff --git a/Content.Shared/Actions/ActionContainerSystem.cs b/Content.Shared/Actions/ActionContainerSystem.cs index 86d50e3989..d7c02ffd63 100644 --- a/Content.Shared/Actions/ActionContainerSystem.cs +++ b/Content.Shared/Actions/ActionContainerSystem.cs @@ -213,6 +213,9 @@ public sealed class ActionContainerSystem : EntitySystem private void OnShutdown(EntityUid uid, ActionsContainerComponent component, ComponentShutdown args) { + if (_timing.ApplyingState && component.NetSyncEnabled) + return; // The game state should handle the container removal & action deletion. + component.Container.Shutdown(); } diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 00a17ace25..7384ab30b1 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -36,6 +36,8 @@ public abstract class SharedActionsSystem : EntitySystem SubscribeLocalEvent(OnDidUnequip); SubscribeLocalEvent(OnHandUnequipped); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnActionsGetState); SubscribeLocalEvent(OnInstantGetState); @@ -49,6 +51,14 @@ public abstract class SharedActionsSystem : EntitySystem SubscribeAllEvent(OnActionRequest); } + private void OnShutdown(EntityUid uid, ActionsComponent component, ComponentShutdown args) + { + foreach (var act in component.Actions) + { + RemoveAction(uid, act, component); + } + } + private void OnInstantGetState(EntityUid uid, InstantActionComponent component, ref ComponentGetState args) { args.State = new InstantActionComponentState(component, EntityManager); @@ -611,7 +621,10 @@ public abstract class SharedActionsSystem : EntitySystem if (action.AttachedEntity != performer) { - Log.Error($"Attempted to remove an action {ToPrettyString(actionId)} from an entity that it was never attached to: {ToPrettyString(performer)}"); + DebugTools.Assert(!Resolve(performer, ref comp, false) || !comp.Actions.Contains(actionId.Value)); + + if (!GameTiming.ApplyingState) + Log.Error($"Attempted to remove an action {ToPrettyString(actionId)} from an entity that it was never attached to: {ToPrettyString(performer)}"); return; } diff --git a/Content.Shared/Administration/Managers/ISharedAdminManager.cs b/Content.Shared/Administration/Managers/ISharedAdminManager.cs index 7e01c81433..22d918d4a3 100644 --- a/Content.Shared/Administration/Managers/ISharedAdminManager.cs +++ b/Content.Shared/Administration/Managers/ISharedAdminManager.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Shared.Administration.Managers; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.cs b/Content.Shared/Buckle/SharedBuckleSystem.cs index 7edf2448ae..1441745b5d 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.cs @@ -11,7 +11,7 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Timing; namespace Content.Shared.Buckle; diff --git a/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs b/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs new file mode 100644 index 0000000000..def6940ee1 --- /dev/null +++ b/Content.Shared/Chemistry/Components/SmokeAffectedComponent.cs @@ -0,0 +1,24 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Chemistry.Components; + +/// +/// This is used for entities which are currently being affected by smoke. +/// Manages the gradual metabolism every second. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class SmokeAffectedComponent : Component +{ + /// + /// The time at which the next smoke metabolism will occur. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextSecond; + + /// + /// The smoke that is currently affecting this entity. + /// + [DataField] + public EntityUid SmokeEntity; +} diff --git a/Content.Shared/Chemistry/Components/SmokeComponent.cs b/Content.Shared/Chemistry/Components/SmokeComponent.cs new file mode 100644 index 0000000000..9d88fcac94 --- /dev/null +++ b/Content.Shared/Chemistry/Components/SmokeComponent.cs @@ -0,0 +1,34 @@ +using Content.Shared.FixedPoint; +using Content.Shared.Fluids.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Chemistry.Components; + +/// +/// Stores solution on an anchored entity that has touch and ingestion reactions +/// to entities that collide with it. Similar to +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SmokeComponent : Component +{ + public const string SolutionName = "solutionArea"; + + /// + /// The max amount of tiles this smoke cloud can spread to. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public int SpreadAmount; + + /// + /// The max rate at which chemicals are transferred from the smoke to the person inhaling it. + /// Calculated as (total volume of chemicals in smoke) / () + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 TransferRate; + + /// + /// The total lifespan of the smoke. + /// + [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public float Duration = 10; +} diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs index d4c599557b..a5c35b5e6c 100644 --- a/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SolutionContainerSystem.cs @@ -30,6 +30,24 @@ public sealed class SolutionChangedEvent : EntityEventArgs } } +/// +/// An event raised when more reagents are added to a (managed) solution than it can hold. +/// +[ByRefEvent] +public record struct SolutionOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow) +{ + /// The entity which contains the solution that has overflowed. + public readonly EntityUid SolutionEnt = SolutionEnt; + /// The solution that has overflowed. + public readonly Solution SolutionHolder = SolutionHolder; + /// The reagents that have overflowed the solution. + public readonly Solution Overflow = Overflow; + /// The volume by which the solution has overflowed. + public readonly FixedPoint2 OverflowVol = Overflow.Volume; + /// Whether some subscriber has taken care of the effects of the overflow. + public bool Handled = false; +} + /// /// Part of Chemistry system deal with SolutionContainers /// @@ -265,6 +283,14 @@ public sealed partial class SolutionContainerSystem : EntitySystem _chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent); } + var overflowVol = solutionHolder.Volume - solutionHolder.MaxVolume; + if (overflowVol > FixedPoint2.Zero) + { + var overflow = solutionHolder.SplitSolution(overflowVol); + var overflowEv = new SolutionOverflowEvent(uid, solutionHolder, overflow); + RaiseLocalEvent(uid, ref overflowEv); + } + UpdateAppearance(uid, solutionHolder); RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name)); } @@ -417,24 +443,6 @@ public sealed partial class SolutionContainerSystem : EntitySystem return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity)); } - /// - /// Adds a solution to the container, if it can fully fit. - /// - /// entity holding targetSolution - /// entity holding targetSolution - /// solution being added - /// If the solution could be added. - public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution) - { - if (targetSolution == null - || !targetSolution.CanAddSolution(addedSolution) || addedSolution.Volume == 0) - return false; - - targetSolution.AddSolution(addedSolution, _prototypeManager); - UpdateChemicals(targetUid, targetSolution, true); - return true; - } - /// /// Moves some quantity of a solution from one solution to another. /// @@ -497,32 +505,86 @@ public sealed partial class SolutionContainerSystem : EntitySystem } /// - /// Adds a solution to the container, overflowing the rest. - /// It will - /// Unlike it will ignore size limits. + /// Adds a solution to the container, if it can fully fit. /// /// entity holding targetSolution - /// The container to which we try to add. - /// solution being added - /// After addition this much will be left in targetSolution. Should be less - /// than targetSolution.TotalVolume + /// entity holding targetSolution + /// solution being added + /// If the solution could be added. + public bool TryAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) + { + if (toAdd.Volume == FixedPoint2.Zero) + return true; + if (toAdd.Volume > targetSolution.AvailableVolume) + return false; + + ForceAddSolution(targetUid, targetSolution, toAdd); + return true; + } + + /// + /// Adds as much of a solution to a container as can fit. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// The quantity of the solution actually added. + public FixedPoint2 AddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) + { + if (toAdd.Volume == FixedPoint2.Zero) + return FixedPoint2.Zero; + + var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, targetSolution.AvailableVolume)); + if (quantity < toAdd.Volume) + TryTransferSolution(targetUid, targetSolution, toAdd, quantity); + else + ForceAddSolution(targetUid, targetSolution, toAdd); + + return quantity; + } + + /// + /// Adds a solution to a container and updates the container. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// Whether any reagents were added to the solution. + public bool ForceAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd) + { + if (toAdd.Volume == FixedPoint2.Zero) + return false; + + targetSolution.AddSolution(toAdd, _prototypeManager); + UpdateChemicals(targetUid, targetSolution, needsReactionsProcessing: true); + return true; + } + + /// + /// Adds a solution to the container, removing the overflow. + /// Unlike it will ignore size limits. + /// + /// The entity containing + /// The solution being added to. + /// The solution being added to + /// The combined volume above which the overflow will be returned. + /// If the combined volume is below this an empty solution is returned. /// Solution that exceeded overflowThreshold - /// + /// Whether any reagents were added to . public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution, - Solution addedSolution, + Solution toAdd, FixedPoint2 overflowThreshold, [NotNullWhen(true)] out Solution? overflowingSolution) { - if (addedSolution.Volume == 0 || overflowThreshold > targetSolution.MaxVolume) + if (toAdd.Volume == 0 || overflowThreshold > targetSolution.MaxVolume) { overflowingSolution = null; return false; } - targetSolution.AddSolution(addedSolution, _prototypeManager); + targetSolution.AddSolution(toAdd, _prototypeManager); + overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, targetSolution.Volume - overflowThreshold)); UpdateChemicals(targetUid, targetSolution, true); - overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, - targetSolution.Volume - overflowThreshold)); return true; } @@ -778,4 +840,8 @@ public sealed partial class SolutionContainerSystem : EntitySystem } #endregion Thermal Energy and Temperature + + #region Event Handlers + + #endregion Event Handlers } diff --git a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs index 4ec50bc61a..ed53b78466 100644 --- a/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs +++ b/Content.Shared/Chemistry/Reaction/ChemicalReactionSystem.cs @@ -262,12 +262,6 @@ namespace Content.Shared.Chemistry.Reaction if (products.Count == 0) return true; - // remove excess product - // TODO spill excess? - var excessVolume = solution.Volume - maxVolume; - if (excessVolume > 0) - solution.RemoveSolution(excessVolume); - // Add any reactions associated with the new products. This may re-add reactions that were already iterated // over previously. The new product may mean the reactions are applicable again and need to be processed. foreach (var product in products) @@ -279,16 +273,10 @@ namespace Content.Shared.Chemistry.Reaction return true; } - /// - /// Continually react a solution until no more reactions occur. - /// - public void FullyReactSolution(Solution solution, EntityUid owner) => FullyReactSolution(solution, owner, FixedPoint2.MaxValue, null); - /// /// Continually react a solution until no more reactions occur, with a volume constraint. - /// If a reaction's products would exceed the max volume, some product is deleted. /// - public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent) + public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent = null) { // construct the initial set of reactions to check. SortedSet reactions = new(); diff --git a/Content.Shared/Cloning/CloningPodComponent.cs b/Content.Shared/Cloning/CloningPodComponent.cs new file mode 100644 index 0000000000..60d4c1e64e --- /dev/null +++ b/Content.Shared/Cloning/CloningPodComponent.cs @@ -0,0 +1,142 @@ +using Content.Shared.Construction.Prototypes; +using Content.Shared.DeviceLinking; +using Content.Shared.Materials; +using Robust.Shared.Audio; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Cloning; + +[RegisterComponent] +public sealed partial class CloningPodComponent : Component +{ + [ValidatePrototypeId] + public const string PodPort = "CloningPodReceiver"; + + [ViewVariables] + public ContainerSlot BodyContainer = default!; + + /// + /// How long the cloning has been going on for. + /// + [ViewVariables] + public float CloningProgress = 0; + + [ViewVariables] + public int UsedBiomass = 70; + + [ViewVariables] + public bool FailedClone = false; + + /// + /// The material that is used to clone entities. + /// + [DataField("requiredMaterial"), ViewVariables(VVAccess.ReadWrite)] + public ProtoId RequiredMaterial = "Biomass"; + + /// + /// The base amount of time it takes to clone a body + /// + [DataField("baseCloningTime")] + public float BaseCloningTime = 30f; + + /// + /// The multiplier for cloning duration + /// + [DataField("partRatingSpeedMultiplier")] + public float PartRatingSpeedMultiplier = 0.75f; + + /// + /// The machine part that affects cloning speed + /// + [DataField("machinePartCloningSpeed"), ViewVariables(VVAccess.ReadWrite)] + public ProtoId MachinePartCloningSpeed = "Manipulator"; + + /// + /// The current amount of time it takes to clone a body + /// + [ViewVariables(VVAccess.ReadWrite)] + public float CloningTime = 30f; + + /// + /// The mob to spawn on emag + /// + [DataField("mobSpawnId"), ViewVariables(VVAccess.ReadWrite)] + public EntProtoId MobSpawnId = "MobAbomination"; + + /// + /// Emag sound effects. + /// + [DataField("sparkSound")] + public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks") + { + Params = AudioParams.Default.WithVolume(8), + }; + + // TODO: Remove this from here when cloning and/or zombies are refactored + [DataField("screamSound")] + public SoundSpecifier ScreamSound = new SoundCollectionSpecifier("ZombieScreams") + { + Params = AudioParams.Default.WithVolume(4), + }; + + /// + /// The machine part that affects how much biomass is needed to clone a body. + /// + [DataField("partRatingMaterialMultiplier")] + public float PartRatingMaterialMultiplier = 0.85f; + + /// + /// The current multiplier on the body weight, which determines the + /// amount of biomass needed to clone. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float BiomassRequirementMultiplier = 1; + + /// + /// The machine part that decreases the amount of material needed for cloning + /// + [DataField("machinePartMaterialUse"), ViewVariables(VVAccess.ReadWrite)] + public ProtoId MachinePartMaterialUse = "MatterBin"; + + [ViewVariables(VVAccess.ReadWrite)] + public CloningPodStatus Status; + + [ViewVariables] + public EntityUid? ConnectedConsole; +} + +[Serializable, NetSerializable] +public enum CloningPodVisuals : byte +{ + Status +} + +[Serializable, NetSerializable] +public enum CloningPodStatus : byte +{ + Idle, + Cloning, + Gore, + NoMind +} + +/// +/// Raised after a new mob got spawned when cloning a humanoid +/// +[ByRefEvent] +public struct CloningEvent +{ + public bool NameHandled = false; + + public readonly EntityUid Source; + public readonly EntityUid Target; + + public CloningEvent(EntityUid source, EntityUid target) + { + Source = source; + Target = target; + } +} diff --git a/Content.Shared/Cloning/SharedCloningPodComponent.cs b/Content.Shared/Cloning/SharedCloningPodComponent.cs deleted file mode 100644 index aafbb597ed..0000000000 --- a/Content.Shared/Cloning/SharedCloningPodComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Cloning -{ - [Serializable, NetSerializable] - public enum CloningPodVisuals : byte - { - Status - } - [Serializable, NetSerializable] - public enum CloningPodStatus : byte - { - Idle, - Cloning, - Gore, - NoMind - } -} diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs index effba18210..9310617634 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsComponent.cs @@ -71,6 +71,9 @@ namespace Content.Shared.Containers.ItemSlots [DataField("whitelist")] public EntityWhitelist? Whitelist; + [DataField("blacklist")] + public EntityWhitelist? Blacklist; + [DataField("insertSound")] public SoundSpecifier InsertSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/revolver_magin.ogg"); diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index 902b56427a..9194a8208e 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -255,7 +255,7 @@ namespace Content.Shared.Containers.ItemSlots if (!swap && slot.HasItem) return false; - if (slot.Whitelist != null && !slot.Whitelist.IsValid(usedUid)) + if ((slot.Whitelist != null && !slot.Whitelist.IsValid(usedUid)) || (slot.Blacklist != null && slot.Blacklist.IsValid(usedUid))) { if (_netManager.IsClient && _timing.IsFirstTimePredicted && popup.HasValue && !string.IsNullOrWhiteSpace(slot.WhitelistFailPopup)) _popupSystem.PopupEntity(Loc.GetString(slot.WhitelistFailPopup), uid, popup.Value); diff --git a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs index a950fe6930..a9a52010fd 100644 --- a/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs +++ b/Content.Shared/Doors/Systems/SharedDoorBoltSystem.cs @@ -23,11 +23,15 @@ public abstract class SharedDoorBoltSystem : EntitySystem private void OnDoorPry(EntityUid uid, DoorBoltComponent component, ref BeforePryEvent args) { - if (component.BoltsDown && !args.Force) - { - Popup.PopupEntity(Loc.GetString("airlock-component-cannot-pry-is-bolted-message"), uid, args.User); - args.Cancelled = true; - } + if (args.Cancelled) + return; + + if (!component.BoltsDown || args.Force) + return; + + args.Message = "airlock-component-cannot-pry-is-bolted-message"; + + args.Cancelled = true; } private void OnBeforeDoorOpened(EntityUid uid, DoorBoltComponent component, BeforeDoorOpenedEvent args) diff --git a/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs b/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs index e7d769d339..6e1f3077f3 100644 --- a/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs +++ b/Content.Shared/Ensnaring/Components/EnsnaringComponent.cs @@ -36,6 +36,13 @@ public sealed partial class EnsnaringComponent : Component [DataField("sprintSpeed")] public float SprintSpeed = 0.9f; + /// + /// How much stamina does the ensnare sap + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("staminaDamage")] + public float StaminaDamage = 55f; + /// /// Should this ensnare someone when thrown? /// diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index d0c3be3b31..dfa72fcfb7 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -6,7 +6,7 @@ using Content.Shared.Input; using Content.Shared.Localizations; using Robust.Shared.Input.Binding; using Robust.Shared.Map; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Shared.Hands.EntitySystems; diff --git a/Content.Shared/Implants/Components/ImplanterComponent.cs b/Content.Shared/Implants/Components/ImplanterComponent.cs index 85891826f9..32a3636163 100644 --- a/Content.Shared/Implants/Components/ImplanterComponent.cs +++ b/Content.Shared/Implants/Components/ImplanterComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Containers.ItemSlots; +using Content.Shared.Whitelist; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; @@ -15,6 +16,19 @@ public sealed partial class ImplanterComponent : Component public const string ImplanterSlotId = "implanter_slot"; public const string ImplantSlotId = "implant"; + /// + /// Whitelist to check entities against before implanting. + /// Implants get their own whitelist which is checked afterwards. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? Whitelist; + + /// + /// Blacklist to check entities against before implanting. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? Blacklist; + /// /// Used for implanters that start with specific implants /// diff --git a/Content.Shared/Implants/Components/SubdermalImplantComponent.cs b/Content.Shared/Implants/Components/SubdermalImplantComponent.cs index b2fdb14e4c..5edc26ead3 100644 --- a/Content.Shared/Implants/Components/SubdermalImplantComponent.cs +++ b/Content.Shared/Implants/Components/SubdermalImplantComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Actions; +using Content.Shared.Whitelist; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -34,6 +35,20 @@ public sealed partial class SubdermalImplantComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField("permanent"), AutoNetworkedField] public bool Permanent = false; + + /// + /// Target whitelist for this implant specifically. + /// Only checked if the implanter allows implanting on the target to begin with. + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// Target blacklist for this implant specifically. + /// Only checked if the implanter allows implanting on the target to begin with. + /// + [DataField] + public EntityWhitelist? Blacklist; } /// diff --git a/Content.Shared/Implants/SharedImplanterSystem.cs b/Content.Shared/Implants/SharedImplanterSystem.cs index 1cf9f44663..404e6da508 100644 --- a/Content.Shared/Implants/SharedImplanterSystem.cs +++ b/Content.Shared/Implants/SharedImplanterSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Examine; using Content.Shared.IdentityManagement; using Content.Shared.Implants.Components; using Content.Shared.Popups; +using Content.Shared.Whitelist; using Robust.Shared.Containers; using Robust.Shared.Serialization; @@ -85,11 +86,23 @@ public abstract class SharedImplanterSystem : EntitySystem if (!TryComp(implant, out implantComp)) return false; + if (!CheckTarget(target, component.Whitelist, component.Blacklist) || + !CheckTarget(target, implantComp.Whitelist, implantComp.Blacklist)) + { + return false; + } + var ev = new AddImplantAttemptEvent(user, target, implant.Value, implanter); RaiseLocalEvent(target, ev); return !ev.Cancelled; } + protected bool CheckTarget(EntityUid target, EntityWhitelist? whitelist, EntityWhitelist? blacklist) + { + return whitelist?.IsValid(target, EntityManager) != false && + blacklist?.IsValid(target, EntityManager) != true; + } + //Draw the implant out of the target //TODO: Rework when surgery is in so implant cases can be a thing public void Draw(EntityUid implanter, EntityUid user, EntityUid target, ImplanterComponent component) diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 4a9a43ca2c..7981deaee6 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -34,7 +34,7 @@ using Robust.Shared.Network; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.Timing; diff --git a/Content.Shared/Mind/MindComponent.cs b/Content.Shared/Mind/MindComponent.cs index 465db6a3d8..b147a2dbbe 100644 --- a/Content.Shared/Mind/MindComponent.cs +++ b/Content.Shared/Mind/MindComponent.cs @@ -2,7 +2,7 @@ using Content.Shared.Mind.Components; using Robust.Shared.GameStates; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Shared.Mind { diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs index 6fc1c01dc2..8e72d9c741 100644 --- a/Content.Shared/Mind/SharedMindSystem.cs +++ b/Content.Shared/Mind/SharedMindSystem.cs @@ -13,7 +13,7 @@ using Content.Shared.Objectives.Systems; using Content.Shared.Players; using Robust.Shared.Map; using Robust.Shared.Network; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Utility; namespace Content.Shared.Mind; @@ -147,15 +147,16 @@ public abstract class SharedMindSystem : EntitySystem return; var dead = _mobState.IsDead(uid); + var hasUserId = CompOrNull(mindContainer.Mind)?.UserId; var hasSession = CompOrNull(mindContainer.Mind)?.Session; - if (dead && !mindContainer.HasMind) + if (dead && hasUserId == null) args.PushMarkup($"[color=mediumpurple]{Loc.GetString("comp-mind-examined-dead-and-irrecoverable", ("ent", uid))}[/color]"); else if (dead && hasSession == null) args.PushMarkup($"[color=yellow]{Loc.GetString("comp-mind-examined-dead-and-ssd", ("ent", uid))}[/color]"); else if (dead) args.PushMarkup($"[color=red]{Loc.GetString("comp-mind-examined-dead", ("ent", uid))}[/color]"); - else if (!mindContainer.HasMind) + else if (hasUserId == null) args.PushMarkup($"[color=mediumpurple]{Loc.GetString("comp-mind-examined-catatonic", ("ent", uid))}[/color]"); else if (hasSession == null) args.PushMarkup($"[color=yellow]{Loc.GetString("comp-mind-examined-ssd", ("ent", uid))}[/color]"); @@ -409,11 +410,11 @@ public abstract class SharedMindSystem : EntitySystem } public bool TryGetMind( - PlayerData player, + ContentPlayerData contentPlayer, out EntityUid mindId, [NotNullWhen(true)] out MindComponent? mind) { - mindId = player.Mind ?? default; + mindId = contentPlayer.Mind ?? default; return TryComp(mindId, out mind); } diff --git a/Content.Shared/Movement/Events/MoveInputEvent.cs b/Content.Shared/Movement/Events/MoveInputEvent.cs index 8e1b43f8bd..89e5636acd 100644 --- a/Content.Shared/Movement/Events/MoveInputEvent.cs +++ b/Content.Shared/Movement/Events/MoveInputEvent.cs @@ -1,5 +1,3 @@ -using Robust.Shared.Players; - namespace Content.Shared.Movement.Events; /// diff --git a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs index 27e0080c87..4b81619fd0 100644 --- a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs +++ b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs @@ -5,7 +5,7 @@ using Content.Shared.Ghost; using Content.Shared.Input; using Content.Shared.Movement.Components; using Robust.Shared.Input.Binding; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Serialization; namespace Content.Shared.Movement.Systems; diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index 425322408e..1d323a9187 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -6,7 +6,7 @@ using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; using Robust.Shared.Input; using Robust.Shared.Input.Binding; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.Utility; diff --git a/Content.Shared/Placeable/ItemPlacerSystem.cs b/Content.Shared/Placeable/ItemPlacerSystem.cs index 92dc8eb74b..ec6ece671f 100644 --- a/Content.Shared/Placeable/ItemPlacerSystem.cs +++ b/Content.Shared/Placeable/ItemPlacerSystem.cs @@ -9,6 +9,7 @@ namespace Content.Shared.Placeable; /// public sealed class ItemPlacerSystem : EntitySystem { + [Dependency] private readonly CollisionWakeSystem _wake = default!; [Dependency] private readonly PlaceableSurfaceSystem _placeableSurface = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; @@ -25,8 +26,8 @@ public sealed class ItemPlacerSystem : EntitySystem if (comp.Whitelist != null && !comp.Whitelist.IsValid(args.OtherEntity)) return; - // Disallow sleeping so we can detect when entity is removed from the heater. - _physics.SetSleepingAllowed(args.OtherEntity, args.OtherBody, false); + if (TryComp(uid, out var wakeComp)) + _wake.SetEnabled(uid, false, wakeComp); var count = comp.PlacedEntities.Count; if (comp.MaxEntities == 0 || count < comp.MaxEntities) @@ -46,8 +47,8 @@ public sealed class ItemPlacerSystem : EntitySystem private void OnEndCollide(EntityUid uid, ItemPlacerComponent comp, ref EndCollideEvent args) { - // Re-allow sleeping. - _physics.SetSleepingAllowed(args.OtherEntity, args.OtherBody, true); + if (TryComp(uid, out var wakeComp)) + _wake.SetEnabled(uid, true, wakeComp); comp.PlacedEntities.Remove(args.OtherEntity); diff --git a/Content.Shared/Players/PlayerData.cs b/Content.Shared/Players/ContentPlayerData.cs similarity index 75% rename from Content.Shared/Players/PlayerData.cs rename to Content.Shared/Players/ContentPlayerData.cs index d94bef2e38..e207447987 100644 --- a/Content.Shared/Players/PlayerData.cs +++ b/Content.Shared/Players/ContentPlayerData.cs @@ -1,16 +1,15 @@ using Content.Shared.GameTicking; using Content.Shared.Mind; using Robust.Shared.Network; -using Robust.Shared.Player; namespace Content.Shared.Players; /// /// Content side for all data that tracks a player session. -/// Use to retrieve this from an . +/// Use to retrieve this from an . /// Not currently used on the client. /// -public sealed class PlayerData +public sealed class ContentPlayerData { /// /// The session ID of the player owning this data. @@ -44,21 +43,9 @@ public sealed class PlayerData [ViewVariables] public bool Whitelisted { get; set; } - public PlayerData(NetUserId userId, string name) + public ContentPlayerData(NetUserId userId, string name) { UserId = userId; Name = name; } } - - -public static class PlayerDataExt -{ - /// - /// Gets the correctly cast instance of content player data from an engine player data storage. - /// - public static PlayerData? ContentData(this IPlayerData data) - { - return (PlayerData?) data.ContentDataUncast; - } -} diff --git a/Content.Shared/Players/PlayerDataExt.cs b/Content.Shared/Players/PlayerDataExt.cs new file mode 100644 index 0000000000..eba4d8339d --- /dev/null +++ b/Content.Shared/Players/PlayerDataExt.cs @@ -0,0 +1,30 @@ +using Robust.Shared.Player; + +namespace Content.Shared.Players; + +public static class PlayerDataExt +{ + /// + /// Gets the correctly cast instance of content player data from an engine player data storage. + /// + public static ContentPlayerData? ContentData(this SessionData data) + { + return (ContentPlayerData?) data.ContentDataUncast; + } + + /// + /// Gets the correctly cast instance of content player data from an engine player data storage. + /// + public static ContentPlayerData? ContentData(this ICommonSession session) + { + return session.Data.ContentData(); + } + + /// + /// Gets the mind that is associated with this player. + /// + public static EntityUid? GetMind(this ICommonSession session) + { + return session.Data.ContentData()?.Mind; + } +} \ No newline at end of file diff --git a/Content.Shared/Players/SharedPlayerSystem.cs b/Content.Shared/Players/SharedPlayerSystem.cs index 6fc7ad6a40..7271c5688a 100644 --- a/Content.Shared/Players/SharedPlayerSystem.cs +++ b/Content.Shared/Players/SharedPlayerSystem.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Shared.Players; @@ -8,5 +8,5 @@ namespace Content.Shared.Players; /// public abstract class SharedPlayerSystem : EntitySystem { - public abstract PlayerData? ContentData(ICommonSession? session); + public abstract ContentPlayerData? ContentData(ICommonSession? session); } diff --git a/Content.Shared/Popups/SharedPopupSystem.cs b/Content.Shared/Popups/SharedPopupSystem.cs index 50013a5435..e4565b90e8 100644 --- a/Content.Shared/Popups/SharedPopupSystem.cs +++ b/Content.Shared/Popups/SharedPopupSystem.cs @@ -1,6 +1,5 @@ using Robust.Shared.Map; using Robust.Shared.Player; -using Robust.Shared.Players; using Robust.Shared.Serialization; namespace Content.Shared.Popups diff --git a/Content.Shared/Power/Generator/PowerSwitchableComponent.cs b/Content.Shared/Power/Generator/PowerSwitchableComponent.cs new file mode 100644 index 0000000000..39118b21e5 --- /dev/null +++ b/Content.Shared/Power/Generator/PowerSwitchableComponent.cs @@ -0,0 +1,82 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Power.Generator; + +/// +/// Enables a device to switch between HV, MV and LV connectors. +/// For generators this means changing output wires. +/// +/// +/// Must have CableDeviceNodes for each output in . +/// If its a generator PowerSupplierComponent is also required. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedPowerSwitchableSystem))] +public sealed partial class PowerSwitchableComponent : Component +{ + /// + /// Index into that the device is currently using. + /// + [DataField, AutoNetworkedField] + public int ActiveIndex; + + /// + /// Sound that plays when the cable is switched. + /// + [DataField] + public SoundSpecifier? SwitchSound = new SoundPathSpecifier("/Audio/Machines/button.ogg"); + + /// + /// Locale id for text shown when examined. + /// It is given "voltage" as a colored voltage string. + /// + [DataField(required: true)] + public string ExamineText = string.Empty; + + /// + /// Locale id for the popup shown when switching voltages. + /// It is given "voltage" as a colored voltage string. + /// + [DataField(required: true)] + public string SwitchText = string.Empty; + + /// + /// Cable voltages and their nodes which can be cycled between. + /// Each node name must match a cable node in its NodeContainer. + /// + [DataField(required: true)] + public List Cables = new(); +} + +/// +/// Cable voltage and node name for cycling. +/// +[DataDefinition] +public sealed partial class PowerSwitchableCable +{ + /// + /// Voltage that the cable uses. + /// + [DataField(required: true)] + public SwitchableVoltage Voltage; + + /// + /// Name of the node for the cable. + /// Must be a CableDeviceNode + /// + [DataField(required: true)] + public string Node = string.Empty; +} + +/// +/// Cable voltage to cycle between. +/// +[Serializable, NetSerializable] +public enum SwitchableVoltage : byte +{ + HV, + MV, + LV +} diff --git a/Content.Shared/Power/Generator/PowerSwitchableGeneratorComponent.cs b/Content.Shared/Power/Generator/PowerSwitchableGeneratorComponent.cs deleted file mode 100644 index 464538f507..0000000000 --- a/Content.Shared/Power/Generator/PowerSwitchableGeneratorComponent.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Power.Generator; - -/// -/// Enables a generator to switch between HV and MV output. -/// -/// -/// Must have CableDeviceNodes for both and , and also a PowerSupplierComponent. -/// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedPowerSwitchableGeneratorSystem))] -public sealed partial class PowerSwitchableGeneratorComponent : Component -{ - /// - /// Which output the portable generator is currently connected to. - /// - [DataField("activeOutput")] - [AutoNetworkedField] - public PowerSwitchableGeneratorOutput ActiveOutput { get; set; } - - /// - /// Sound that plays when the output is switched. - /// - /// - [DataField("switchSound")] - public SoundSpecifier? SwitchSound { get; set; } - - /// - /// Which node is the MV output? - /// - [DataField("nodeOutputMV")] - public string NodeOutputMV { get; set; } = "output_mv"; - - /// - /// Which node is the HV output? - /// - [DataField("nodeOutputHV")] - public string NodeOutputHV { get; set; } = "output_hv"; -} - -/// -/// Possible power output for power-switchable generators. -/// -/// -[Serializable, NetSerializable] -public enum PowerSwitchableGeneratorOutput : byte -{ - /// - /// The generator is set to connect to a high-voltage power network. - /// - HV, - - /// - /// The generator is set to connect to a medium-voltage power network. - /// - MV -} - diff --git a/Content.Shared/Power/Generator/SharedPowerSwitchableGeneratorSystem.cs b/Content.Shared/Power/Generator/SharedPowerSwitchableGeneratorSystem.cs deleted file mode 100644 index 5d3793c471..0000000000 --- a/Content.Shared/Power/Generator/SharedPowerSwitchableGeneratorSystem.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.Examine; - -namespace Content.Shared.Power.Generator; - -/// -/// Shared logic for power-switchable generators. -/// -/// -public abstract class SharedPowerSwitchableGeneratorSystem : EntitySystem -{ - public override void Initialize() - { - SubscribeLocalEvent(GeneratorExamined); - } - - private void GeneratorExamined(EntityUid uid, PowerSwitchableGeneratorComponent component, ExaminedEvent args) - { - // Show which output is currently selected. - args.PushMarkup(Loc.GetString( - "power-switchable-generator-examine", - ("output", component.ActiveOutput.ToString()))); - } -} diff --git a/Content.Shared/Power/Generator/SharedPowerSwitchableSystem.cs b/Content.Shared/Power/Generator/SharedPowerSwitchableSystem.cs new file mode 100644 index 0000000000..c1787b6078 --- /dev/null +++ b/Content.Shared/Power/Generator/SharedPowerSwitchableSystem.cs @@ -0,0 +1,72 @@ +using Content.Shared.Examine; + +namespace Content.Shared.Power.Generator; + +/// +/// Shared logic for power-switchable devices. +/// +/// +public abstract class SharedPowerSwitchableSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnExamined); + } + + private void OnExamined(EntityUid uid, PowerSwitchableComponent comp, ExaminedEvent args) + { + // Show which voltage is currently selected. + var voltage = VoltageColor(GetVoltage(uid, comp)); + args.PushMarkup(Loc.GetString(comp.ExamineText, ("voltage", voltage))); + } + + /// + /// Helper to get the colored markup string for a voltage type. + /// + public string VoltageColor(SwitchableVoltage voltage) + { + return Loc.GetString("power-switchable-voltage", ("voltage", VoltageString(voltage))); + } + + /// + /// Converts from "hv" to "HV" since for some reason the enum gets made lowercase??? + /// + public string VoltageString(SwitchableVoltage voltage) + { + return voltage.ToString().ToUpper(); + } + + /// + /// Returns index of the next cable type index to cycle to. + /// + public int NextIndex(EntityUid uid, PowerSwitchableComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return 0; + + // loop back at the end + return (comp.ActiveIndex + 1) % comp.Cables.Count; + } + + /// + /// Returns the current cable voltage being used by a power-switchable device. + /// + public SwitchableVoltage GetVoltage(EntityUid uid, PowerSwitchableComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return default; + + return comp.Cables[comp.ActiveIndex].Voltage; + } + + /// + /// Returns the cable's next voltage to cycle to being used by a power-switchable device. + /// + public SwitchableVoltage GetNextVoltage(EntityUid uid, PowerSwitchableComponent? comp = null) + { + if (!Resolve(uid, ref comp)) + return default; + + return comp.Cables[NextIndex(uid, comp)].Voltage; + } +} diff --git a/Content.Shared/Prying/Components/PryingComponent.cs b/Content.Shared/Prying/Components/PryingComponent.cs index 4442481dce..7a7f304d8f 100644 --- a/Content.Shared/Prying/Components/PryingComponent.cs +++ b/Content.Shared/Prying/Components/PryingComponent.cs @@ -51,6 +51,8 @@ public record struct BeforePryEvent(EntityUid User, bool PryPowered, bool Force) public readonly bool Force = Force; + public string? Message; + public bool Cancelled; } diff --git a/Content.Shared/Prying/Systems/PryingSystem.cs b/Content.Shared/Prying/Systems/PryingSystem.cs index 19e63de29e..5fd94c3438 100644 --- a/Content.Shared/Prying/Systems/PryingSystem.cs +++ b/Content.Shared/Prying/Systems/PryingSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Database; using Content.Shared.Doors.Components; using System.Diagnostics.CodeAnalysis; using Content.Shared.Interaction; +using Content.Shared.Popups; using PryUnpoweredComponent = Content.Shared.Prying.Components.PryUnpoweredComponent; namespace Content.Shared.Prying.Systems; @@ -19,6 +20,7 @@ public sealed class PryingSystem : EntitySystem [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPopupSystem Popup = default!; public override void Initialize() { @@ -68,10 +70,12 @@ public sealed class PryingSystem : EntitySystem if (!comp.Enabled) return false; - if (!CanPry(target, user, comp)) + if (!CanPry(target, user, out var message, comp)) { + if (message != null) + Popup.PopupEntity(Loc.GetString(message), target, user); // If we have reached this point we want the event that caused this - // to be marked as handled as a popup would be generated on failure. + // to be marked as handled. return true; } @@ -87,15 +91,16 @@ public sealed class PryingSystem : EntitySystem { id = null; - if (!CanPry(target, user)) + // We don't care about displaying a message if no tool was used. + if (!CanPry(target, user, out _)) // If we have reached this point we want the event that caused this - // to be marked as handled as a popup would be generated on failure. + // to be marked as handled. return true; return StartPry(target, user, null, 0.1f, out id); // hand-prying is much slower } - private bool CanPry(EntityUid target, EntityUid user, PryingComponent? comp = null) + private bool CanPry(EntityUid target, EntityUid user, out string? message, PryingComponent? comp = null) { BeforePryEvent canev; @@ -106,15 +111,19 @@ public sealed class PryingSystem : EntitySystem else { if (!TryComp(target, out _)) + { + message = null; return false; + } + canev = new BeforePryEvent(user, false, false); } RaiseLocalEvent(target, ref canev); - if (canev.Cancelled) - return false; - return true; + message = canev.Message; + + return !canev.Cancelled; } private bool StartPry(EntityUid target, EntityUid user, EntityUid? tool, float toolModifier, [NotNullWhen(true)] out DoAfterId? id) diff --git a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs index 6f19d048b4..0c139ee9e3 100644 --- a/Content.Shared/Pulling/Systems/SharedPullingSystem.cs +++ b/Content.Shared/Pulling/Systems/SharedPullingSystem.cs @@ -12,7 +12,7 @@ using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; +using Robust.Shared.Player; namespace Content.Shared.Pulling { diff --git a/Content.Shared/Roles/JobRequirements.cs b/Content.Shared/Roles/JobRequirements.cs index 2785e988bc..fbe607c7ce 100644 --- a/Content.Shared/Roles/JobRequirements.cs +++ b/Content.Shared/Roles/JobRequirements.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles.Jobs; using JetBrains.Annotations; -using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; diff --git a/Content.Shared/Roles/Jobs/SharedJobSystem.cs b/Content.Shared/Roles/Jobs/SharedJobSystem.cs index ac18d04e9c..af97ea1350 100644 --- a/Content.Shared/Roles/Jobs/SharedJobSystem.cs +++ b/Content.Shared/Roles/Jobs/SharedJobSystem.cs @@ -2,7 +2,7 @@ using System.Linq; using Content.Shared.Players; using Content.Shared.Players.PlayTimeTracking; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; diff --git a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs index c6238c067d..f492db4d12 100644 --- a/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/EmagSiliconLawComponent.cs @@ -1,12 +1,11 @@ using Content.Shared.Roles; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Silicons.Laws.Components; /// -/// This is used for an entity that grants a special "obey" law when emagge.d +/// This is used for an entity that grants a special "obey" law when emagged. /// [RegisterComponent, NetworkedComponent, Access(typeof(SharedSiliconLawSystem))] public sealed partial class EmagSiliconLawComponent : Component @@ -14,31 +13,39 @@ public sealed partial class EmagSiliconLawComponent : Component /// /// The name of the person who emagged this law provider. /// - [DataField("ownerName"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string? OwnerName; /// /// Does the panel need to be open to EMAG this law provider. /// - [DataField("requireOpenPanel"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool RequireOpenPanel = true; /// - /// The laws that the borg is given when emagged. + /// The laws that the borg is given when emagged. + /// Law 0 is prepended to this, so this can only include the static laws. /// - [DataField("emagLaws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List EmagLaws = new(); + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + public ProtoId EmagLaws = string.Empty; /// - /// How long the borg is stunned when it's emagged. Setting to 0 will disable it. + /// Lawset created from the prototype id and law 0. + /// Cached when getting laws and only modified during an ion storm event. /// - [DataField("stunTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] + public SiliconLawset? Lawset; + + /// + /// How long the borg is stunned when it's emagged. Setting to 0 will disable it. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan StunTime = TimeSpan.Zero; /// /// A role given to entities with this component when they are emagged. /// Mostly just for admin purposes. /// - [DataField("antagonistRole", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? AntagonistRole = "SubvertedSilicon"; + [DataField] + public ProtoId? AntagonistRole = "SubvertedSilicon"; } diff --git a/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs b/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs new file mode 100644 index 0000000000..49ac611ddc --- /dev/null +++ b/Content.Shared/Silicons/Laws/Components/IonStarmTargetComponent.cs @@ -0,0 +1,54 @@ +using Content.Shared.Random; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Silicons.Laws.Components; + +/// +/// During the ion storm event, this entity will have raised on it if it has laws. +/// New laws can be modified in multiple ways depending on the fields below. +/// +[RegisterComponent] +public sealed partial class IonStormTargetComponent : Component +{ + /// + /// for a random lawset to possibly replace the old one with. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ProtoId RandomLawsets = "IonStormLawsets"; + + /// + /// Chance for this borg to be affected at all. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Chance = 0.5f; + + /// + /// Chance to replace the lawset with a random one + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float RandomLawsetChance = 0.25f; + + /// + /// Chance to remove a random law. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float RemoveChance = 0.1f; + + /// + /// Chance to replace a random law with the new one, rather than have it be a glitched-order law. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ReplaceChance = 0.1f; + + /// + /// Chance to shuffle laws after everything is done. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float ShuffleChance = 0.1f; +} + +/// +/// Raised on an ion storm target to modify its laws. +/// +[ByRefEvent] +public record struct IonStormLawsEvent(SiliconLawset Lawset); diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs index 955705ae8b..824d057b3e 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawBoundComponent.cs @@ -1,7 +1,6 @@ using Content.Shared.Actions; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Silicons.Laws.Components; @@ -14,19 +13,19 @@ public sealed partial class SiliconLawBoundComponent : Component /// /// The sidebar action that toggles the laws screen. /// - [DataField("viewLawsAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ViewLawsAction = "ActionViewLaws"; + [DataField] + public EntProtoId ViewLawsAction = "ActionViewLaws"; /// /// The action for toggling laws. Stored here so we can remove it later. /// - [DataField("viewLawsActionEntity")] + [DataField] public EntityUid? ViewLawsActionEntity; /// /// The last entity that provided laws to this entity. /// - [DataField("lastLawProvider")] + [DataField] public EntityUid? LastLawProvider; } @@ -43,7 +42,7 @@ public record struct GetSiliconLawsEvent(EntityUid Entity) { public EntityUid Entity = Entity; - public readonly List Laws = new(); + public SiliconLawset Laws = new(); public bool Handled = false; } diff --git a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs index e3302dc620..3aaf965aee 100644 --- a/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs +++ b/Content.Shared/Silicons/Laws/Components/SiliconLawProviderComponent.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Silicons.Laws.Components; @@ -9,8 +9,15 @@ namespace Content.Shared.Silicons.Laws.Components; public sealed partial class SiliconLawProviderComponent : Component { /// - /// The laws that are provided. + /// The id of the lawset that is being provided. /// - [DataField("laws", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Laws = new(); + [DataField(required: true)] + public ProtoId Laws = string.Empty; + + /// + /// Lawset created from the prototype id. + /// Cached when getting laws and only modified during an ion storm event. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public SiliconLawset? Lawset; } diff --git a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs index 86bea20fa0..f6407be5c7 100644 --- a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs +++ b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs @@ -11,7 +11,7 @@ public partial class SiliconLaw : IComparable /// /// A locale string which is the actual text of the law. /// - [DataField("lawString", required: true)] + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] public string LawString = string.Empty; /// @@ -22,13 +22,13 @@ public partial class SiliconLaw : IComparable /// This is a fixedpoint2 only for the niche case of supporting laws that go between 0 and 1. /// Funny. /// - [DataField("order", required: true)] + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] public FixedPoint2 Order; /// /// An identifier that overrides in the law menu UI. /// - [DataField("lawIdentifierOverride")] + [DataField, ViewVariables(VVAccess.ReadWrite)] public string? LawIdentifierOverride; public int CompareTo(SiliconLaw? other) @@ -38,6 +38,19 @@ public partial class SiliconLaw : IComparable return Order.CompareTo(other.Order); } + + /// + /// Return a shallow clone of this law. + /// + public SiliconLaw ShallowClone() + { + return new SiliconLaw() + { + LawString = LawString, + Order = Order, + LawIdentifierOverride = LawIdentifierOverride + }; + } } /// @@ -50,6 +63,4 @@ public sealed class SiliconLawPrototype : SiliconLaw, IPrototype /// [IdDataField] public string ID { get; private set; } = default!; - - } diff --git a/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs new file mode 100644 index 0000000000..abb5b338db --- /dev/null +++ b/Content.Shared/Silicons/Laws/SiliconLawsetPrototype.cs @@ -0,0 +1,69 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; + +namespace Content.Shared.Silicons.Laws; + +/// +/// Lawset data used internally. +/// +[DataDefinition, Serializable, NetSerializable] +public sealed partial class SiliconLawset +{ + /// + /// List of laws in this lawset. + /// + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + public List Laws = new(); + + /// + /// A single line used in logging laws. + /// + public string LoggingString() + { + var laws = new List(Laws.Count); + foreach (var law in Laws) + { + laws.Add($"{law.Order}: {Loc.GetString(law.LawString)}"); + } + + return string.Join(" / ", laws); + } + + /// + /// Do a clone of this lawset. + /// It will have unique laws but their strings are still shared. + /// + public SiliconLawset Clone() + { + var laws = new List(Laws.Count); + foreach (var law in Laws) + { + laws.Add(law.ShallowClone()); + } + + return new SiliconLawset() + { + Laws = laws + }; + } +} + +/// +/// This is a prototype for a list. +/// Cannot be used directly since it is a list of prototype ids rather than List. +/// +[Prototype("siliconLawset"), Serializable, NetSerializable] +public sealed partial class SiliconLawsetPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// List of law prototype ids in this lawset. + /// + [DataField(required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List Laws = new(); +} diff --git a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs index 0fd7a2e932..02b4e61790 100644 --- a/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs +++ b/Content.Shared/SubFloor/SharedSubFloorHideSystem.cs @@ -24,7 +24,6 @@ namespace Content.Shared.SubFloor { base.Initialize(); - SubscribeLocalEvent(OnGridChanged); SubscribeLocalEvent(OnTileChanged); SubscribeLocalEvent(OnSubFloorStarted); SubscribeLocalEvent(OnSubFloorTerminating); @@ -97,14 +96,6 @@ namespace Content.Shared.SubFloor UpdateTile(MapManager.GetGrid(args.NewTile.GridUid), args.NewTile.GridIndices); } - private void OnGridChanged(GridModifiedEvent args) - { - foreach (var modified in args.Modified) - { - UpdateTile(args.Grid, modified.position); - } - } - /// /// Update whether a given entity is currently covered by a floor tile. /// diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 4b740b8d3c..62af6067d0 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -23,7 +23,7 @@ using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; -using Robust.Shared.Players; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Timing; diff --git a/Resources/Audio/Ambience/Antag/attributions.yml b/Resources/Audio/Ambience/Antag/attributions.yml index 3d7d5c737c..0a4a0479d1 100644 --- a/Resources/Audio/Ambience/Antag/attributions.yml +++ b/Resources/Audio/Ambience/Antag/attributions.yml @@ -9,4 +9,8 @@ - files: ["zombie_start.ogg"] license: "CC-BY-NC-SA-3.0" copyright: "Made by @MIXnikita#1474 (Discord) for SS14" - source: "https://github.com/SerbiaStrong-220/space-station-14/commit/f33ce80db9d8ac962ec36eb5ae61afa8c0035d1a" \ No newline at end of file + source: "https://github.com/SerbiaStrong-220/space-station-14/commit/f33ce80db9d8ac962ec36eb5ae61afa8c0035d1a" +- files: ["headrev_start.ogg"] + license: "CC0-1.0" + copyright: "Made by https://www.youtube.com/@a-guy173" + source: https://github.com/A-Guy173/Music/blob/main/revolution.mp3 diff --git a/Resources/Audio/Ambience/Antag/headrev_start.ogg b/Resources/Audio/Ambience/Antag/headrev_start.ogg new file mode 100644 index 0000000000000000000000000000000000000000..f97ab15a3efdcf1454fa6d36a47b30e6ab1e0a55 GIT binary patch literal 171100 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 literal 0 HcmV?d00001 diff --git a/Resources/Audio/Announcements/attributions.yml b/Resources/Audio/Announcements/attributions.yml new file mode 100644 index 0000000000..b65f758615 --- /dev/null +++ b/Resources/Audio/Announcements/attributions.yml @@ -0,0 +1,4 @@ +- files: ["ion_storm.ogg"] + license: "CC-BY-SA-3.0" + copyright: "tgstation" + source: "https://github.com/tgstation/tgstation/blob/b77fa8c2a2490b43bf9174271ebfad72c4782d98/sound/ai/default/ionstorm.ogg" diff --git a/Resources/Audio/Announcements/ion_storm.ogg b/Resources/Audio/Announcements/ion_storm.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9f39713de6e5a5192c9ae9468ea79e5ab209036e GIT binary patch literal 50216 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%0A~a_L~^R}PWYnEQ3}?QzL^B4)g?Y!l6B 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 Dvby?J literal 0 HcmV?d00001 diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b1a864ca07..582795cb3c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,241 +1,5 @@ Order: 1 Entries: -- author: brainfood1183 - changes: - - {message: Syndicate clowns may now purchase a holoclown injector via their syndicate - uplink., type: Add} - id: 4550 - time: '2023-08-13T07:18:10.0000000+00:00' -- author: Errant - changes: - - {message: The various laser guns are now called rifles or pistols., type: Tweak} - - {message: Retro laser blasters now deal 20% more damage., type: Tweak} - - {message: Laser deliveries now contain 3 laser rifles instead of 3 retro laser - blasters., type: Tweak} - id: 4551 - time: '2023-08-13T07:18:49.0000000+00:00' -- author: chromiumboy - changes: - - {message: Added guidebook entries for the Access Configurator and how to install - Airlock Safeguards, type: Add} - id: 4552 - time: '2023-08-13T07:19:28.0000000+00:00' -- author: CrigCrag - changes: - - {message: 'Space Station staff are no longer immune to the toxic and caustic effects - of some pyrotechnic chemicals, as well as bleach. Drinking bleach now makes - you scream as your stomach lining is reduced to goop.', type: Tweak} - - {message: Phenol is now (accurately) toxic., type: Tweak} - id: 4553 - time: '2023-08-13T07:22:08.0000000+00:00' -- author: CrigCrag - changes: - - {message: Added jugs to the medical fabricator., type: Add} - - {message: Jugs now take up more space in bags., type: Tweak} - id: 4554 - time: '2023-08-13T07:23:37.0000000+00:00' -- author: CrigCrag - changes: - - {message: Many basic elements from the periodic table are now mildly toxic or - caustic. Watch what you drink!, type: Tweak} - - {message: Crewmembers who drink lithium have reported very minor cases of serious - brain damage. Doctors should watch out for people who are laughing and screaming - at nothing., type: Tweak} - id: 4555 - time: '2023-08-13T07:24:11.0000000+00:00' -- author: CrigCrag - changes: - - {message: 'Nanotrasen stopped watering down their acid to save money. Drinking - or injecting acids is more dangerous now, and acids burn through your insides - much quicker.', type: Tweak} - - {message: Having corrosive acid in your body now makes you scream!, type: Tweak} - - {message: Polytrinic acid now requires plasma to make., type: Tweak} - id: 4556 - time: '2023-08-13T07:24:50.0000000+00:00' -- author: PixelTK - changes: - - {message: Arachnids have received several changes. Check your local PR station - for more details., type: Tweak} - id: 4557 - time: '2023-08-13T07:38:05.0000000+00:00' -- author: PixelTK - changes: - - {message: 'Nanotrasen have fixed their accidental breakage of time space continuum, - making sure that steel tiles do indeed take steel to create.', type: Fix} - id: 4558 - time: '2023-08-13T12:43:01.0000000+00:00' -- author: FillerVK - changes: - - {message: Added cocoa cultivation, type: Add} - - {message: Added a recipe for creating a chocolate bar, type: Add} - id: 4559 - time: '2023-08-13T14:35:58.0000000+00:00' -- author: Vordenburg - changes: - - {message: Player icons in the end-of-round summary window should now display properly., - type: Fix} - id: 4560 - time: '2023-08-13T16:55:05.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: The DNA scrambler no longer has the power of magically transforming - various creatures into humanoids., type: Fix} - id: 4561 - time: '2023-08-13T16:56:21.0000000+00:00' -- author: Repo - changes: - - {message: fixed pressure tanks to not show scientific notation., type: Fix} - id: 4562 - time: '2023-08-13T16:56:30.0000000+00:00' -- author: Cripes - changes: - - {message: 'Paper stamps have been heavily tweaked with new looks, now each paper - will lay out the stamps slightly differently and with an overlap.', type: Tweak} - id: 4563 - time: '2023-08-13T18:28:10.0000000+00:00' -- author: PixelTheKermit - changes: - - {message: Arachnid zombies no longer get functional hands., type: Fix} - id: 4564 - time: '2023-08-13T19:51:21.0000000+00:00' -- author: ElectroJr - changes: - - {message: 'Fixed a bug causing inventory slots to sometimes ignore interactions - (e.g., not opening the context menu).', type: Fix} - id: 4565 - time: '2023-08-13T21:55:18.0000000+00:00' -- author: DrSmugleaf - changes: - - {message: Fix "remove single hand" admin smite having gone missing., type: Fix} - - {message: Fix "remove hands" admin smite popup message., type: Fix} - id: 4566 - time: '2023-08-13T22:50:58.0000000+00:00' -- author: DrSmugleaf - changes: - - {message: AHelps now show a typing indicator to admins., type: Tweak} - id: 4567 - time: '2023-08-13T23:03:17.0000000+00:00' -- author: Equivocateur - changes: - - {message: 'Emagged recyclers now not only gib people, but other mobs too.', type: Fix} - id: 4568 - time: '2023-08-13T23:54:52.0000000+00:00' -- author: DrSmugleaf - changes: - - {message: 'Fixed new players added to admin logs defaulting to selected, even - when not all players are selected.', type: Fix} - id: 4569 - time: '2023-08-14T01:53:48.0000000+00:00' -- author: Vordenburg - changes: - - {message: Substations produce hot CO2 when destroyed now., type: Tweak} - id: 4570 - time: '2023-08-14T01:55:06.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: Being turned into a cyborg or zombie now counts as a being dead for - survival and kill objectives., type: Fix} - - {message: Kill objectives no longer reveal a character's true name at all times., - type: Fix} - id: 4571 - time: '2023-08-14T03:34:19.0000000+00:00' -- author: EmoGarbage404 - changes: - - {message: Fixed the RPED sound effect cutting off at the end., type: Fix} - id: 4572 - time: '2023-08-14T03:36:08.0000000+00:00' -- author: DrSmugleaf - changes: - - {message: Admin notes now require a severity to be set before saving., type: Tweak} - id: 4573 - time: '2023-08-14T03:37:38.0000000+00:00' -- author: Vasilis - changes: - - {message: 'The nuke detonation sound plays to all crew members again, no longer - will you have to sit in silence before your demise', type: Fix} - id: 4574 - time: '2023-08-14T03:55:50.0000000+00:00' -- author: crazybrain - changes: - - {message: 'The Syndicate have rebooted the chameleon clothing database, restoring - most lost functionality.', type: Fix} - id: 4575 - time: '2023-08-14T04:03:20.0000000+00:00' -- author: chromiumboy - changes: - - {message: Fixed an issue which was preventing airlock safeguards from being installed - on glass airlocks, type: Fix} - id: 4576 - time: '2023-08-14T06:42:02.0000000+00:00' -- author: kseandi - changes: - - {message: 'The new airlock painters are so accurate that you can use them to paint - pipes. Because of this, Nanotrasen decided to rename them to "Spray painters".', - type: Tweak} - id: 4577 - time: '2023-08-14T12:06:21.0000000+00:00' -- author: Interrobang01 - changes: - - {message: Centcom will now sell Cargo gas canisters at a vastly reduced (and consistent!) - price after realizing the station has infinite gasses anyway., type: Tweak} - id: 4578 - time: '2023-08-14T13:56:07.0000000+00:00' -- author: mirrorcult - changes: - - {message: Asteroid rocks and secret doors should look less weird in certain scenarios, - type: Fix} - id: 4579 - time: '2023-08-14T15:59:14.0000000+00:00' -- author: LightVillet - changes: - - {message: Fixed hand labeler recipe's name, type: Fix} - id: 4580 - time: '2023-08-14T16:04:22.0000000+00:00' -- author: mirrorcult - changes: - - {message: 'Bike horn implant now has a short cooldown, sorry', type: Fix} - id: 4581 - time: '2023-08-14T16:04:42.0000000+00:00' -- author: Errant - changes: - - {message: 'Admin ghosts, robots, and other soulless monsters that never tire can - now perform wide melee attacks again. Most notably this fixes the borg mining - drill.', type: Fix} - id: 4582 - time: '2023-08-14T16:10:16.0000000+00:00' -- author: Titian3 - changes: - - {message: Fixed Admin watchlists and messages., type: Fix} - id: 4583 - time: '2023-08-14T19:50:33.0000000+00:00' -- author: crazybrain - changes: - - {message: Observers can now hear the binary radio., type: Tweak} - id: 4584 - time: '2023-08-14T21:00:08.0000000+00:00' -- author: liltenhead - changes: - - {message: Changed singularity energy levels to require more energy overall to - increase in size., type: Tweak} - - {message: 'Changed singularity energy drain rates to keep them more stable, and - die quicker without food.', type: Tweak} - - {message: 'Changed level 2 and 3 PA to feed less energy, slowing the speed of - a singuloose slightly.', type: Tweak} - id: 4585 - time: '2023-08-14T21:01:57.0000000+00:00' -- author: mirrorcult - changes: - - {message: Monkies go horizontal on crit/death again, type: Fix} - id: 4586 - time: '2023-08-14T21:02:28.0000000+00:00' -- author: mirrorcult - changes: - - {message: Fixed condiment stations & smartfridges being too unshaded, type: Fix} - - {message: 'Booze dispenser now only contains booze, everything else it contained - was already in the soda dispenser', type: Tweak} - - {message: Fixed soda dispenser UI not being wide enough, type: Fix} - id: 4587 - time: '2023-08-14T21:03:21.0000000+00:00' - author: DrSmugleaf changes: - {message: Fixed having to reopen ahelp and popped-out ahelp windows after round @@ -2909,3 +2673,246 @@ Entries: sending you to the farplanes., type: Fix} id: 5049 time: '2023-10-24T10:44:09.0000000+00:00' +- author: liltenhead + changes: + - {message: Fixed the "examine" trigger for artifacts not having a hint., type: Fix} + id: 5050 + time: '2023-10-24T20:37:16.0000000+00:00' +- author: Stealthbomber16 + changes: + - {message: You can actually grind corn into cornmeal now., type: Fix} + id: 5051 + time: '2023-10-24T20:38:43.0000000+00:00' +- author: Myakot + changes: + - {message: Skeletons can now heal by pouring milk over themselves, type: Add} + id: 5052 + time: '2023-10-24T20:58:34.0000000+00:00' +- author: TemporalOroboros + changes: + - {message: Fixed anomaly locators frantically beeping when they first enter detection + range for an anomaly., type: Fix} + id: 5053 + time: '2023-10-24T21:00:23.0000000+00:00' +- author: 27alaing + changes: + - {message: The anti-slang system allows for more leeway with certain phrases now., + type: Tweak} + - {message: 'The supply radio channel can be used with ":u" again.', type: Fix} + id: 5054 + time: '2023-10-25T00:56:19.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Medical cyborgs' stethoscopes can no longer be fed to moths to obtain + a free hand., type: Fix} + id: 5055 + time: '2023-10-25T04:51:32.0000000+00:00' +- author: deltanedas + changes: + - {message: Roundstart borg jobs get funny names., type: Tweak} + id: 5056 + time: '2023-10-25T13:00:09.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: The search bar in vending machines now works., type: Fix} + id: 5057 + time: '2023-10-25T13:01:16.0000000+00:00' +- author: deltanedas + changes: + - {message: 'The Syndicate''s chefs are now offering snack boxes for only 1 tc. + Usually contains a toy, drinks and food.', type: Add} + id: 5058 + time: '2023-10-25T13:26:27.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Fix docking UI not showing other grids., type: Fix} + id: 5059 + time: '2023-10-25T13:28:34.0000000+00:00' +- author: Doru991 + changes: + - {message: Potato batteries can be built by crew., type: Add} + - {message: New compact AI chips may be powered via potato batteries., type: Add} + id: 5060 + time: '2023-10-25T13:52:50.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: 'Storage now functions based on slots and sizes, rather than numerical + values.', type: Tweak} + id: 5061 + time: '2023-10-25T22:53:39.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Adjusted the sizes of space suits and belts., type: Tweak} + - {message: Reduced the slot count in the ore bag., type: Tweak} + - {message: Fixed not being to create pills at the ChemMaster 5000., type: Fix} + id: 5062 + time: '2023-10-26T02:47:45.0000000+00:00' +- author: metalgearsloth + changes: + - {message: 'Reverted storage to function with numerical values again, instead of + slots and sizes.', type: Tweak} + id: 5063 + time: '2023-10-26T08:28:16.776154+00:00' +- author: nmajask + changes: + - {message: Bacon burgers require 1 bacon instead of 3 cutlets, type: Tweak} + - {message: Ghost burgers require 1 ectoplasm instead of 1 ghost sheet, type: Tweak} + - {message: Tofu creation no longer consumes the enzyme, type: Tweak} + - {message: Ribs and Mcribs now give back skewers when eaten, type: Fix} + id: 5064 + time: '2023-10-27T02:12:35.0000000+00:00' +- author: JoeHammad + changes: + - {message: 'Headrevs now have their own music on spawn, credits to A-Guy on youtube', + type: Add} + id: 5065 + time: '2023-10-27T02:19:35.0000000+00:00' +- author: crazybrain + changes: + - {message: Bodies of dead players who have taken a ghost role now show as "departed + and moved on"., type: Fix} + id: 5066 + time: '2023-10-27T02:27:36.0000000+00:00' +- author: deltanedas + changes: + - {message: Fixed being able to give pAIs implants., type: Fix} + id: 5067 + time: '2023-10-27T02:34:03.0000000+00:00' +- author: deltanedas + changes: + - {message: Ion storms have appeared and are causing malfunctions in cyborg law + modules., type: Add} + id: 5068 + time: '2023-10-27T02:40:13.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Foam and smoke can now transfer chemicals when inhaled. Wear internals + to avoid this., type: Add} + - {message: Fixed foam dissolution animation., type: Fix} + id: 5069 + time: '2023-10-27T02:52:11.0000000+00:00' +- author: Whisper + changes: + - {message: Increased funding in an undisclosed NT Operative Squad., type: Add} + - {message: CentComm staff will have their proper ID icons on security's sechud., + type: Add} + - {message: CentComm staff will have undying loyalty to Nanotrasen., type: Add} + - {message: ERT funding has been improved. Expect specialized ERT units to be able + to provide more assistance related to their role., type: Tweak} + - {message: Cut funding from ERT weaponry. They'll likely be seen using standard + security-level weapons., type: Remove} + - {message: 'Cut funding from ERT uniforms, they no longer have built in armor.', + type: Fix} + - {message: The medical ERT members have had their hardsuits refitted with proper + armor., type: Fix} + - {message: Updated the localization files., type: Fix} + id: 5070 + time: '2023-10-27T13:54:43.0000000+00:00' +- author: ficcialfaint + changes: + - {message: Fixed nuclear operatives sound not being played at round start, type: Fix} + id: 5071 + time: '2023-10-28T02:28:21.0000000+00:00' +- author: Arteben + changes: + - {message: Nanotrasen improved the health analyzer UI!, type: Tweak} + id: 5072 + time: '2023-10-28T05:54:18.0000000+00:00' +- author: Repo + changes: + - {message: Stats menu on Character setup for total and role playtime., type: Add} + id: 5073 + time: '2023-10-28T12:01:11.0000000+00:00' +- author: TemporalOroboros + changes: + - {message: 'The space lube recipe now produces slightly more lube, but can overflow + its container.', type: Tweak} + id: 5074 + time: '2023-10-28T16:46:59.0000000+00:00' +- author: Ubaser + changes: + - {message: The bee plush can now be worn on your head., type: Add} + id: 5075 + time: '2023-10-29T03:55:15.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Audio rework is in which fixes a lot of audio bugs but may also introduce + new ones., type: Tweak} + - {message: Grid audio will now attenuate properly over distance and won't be ear + rupturingly loud., type: Fix} + - {message: FTL sound should no longer persist as it's attached to the shuttle instead + of being global., type: Fix} + - {message: Audio can now start at an offset so if an audio source comes into range + it won't play from the start., type: Fix} + - {message: Changed audio attenuation from InverseDistanceClamped to LinearDistanceClamped + so it's smoother. You may need to adjust your master audio volume., type: Tweak} + id: 5076 + time: '2023-10-29T03:58:23.0000000+00:00' +- author: Simyon264 + changes: + - {message: 'The PDA will now ring again, when a new station article gets published. + Reporters rejoice!', type: Fix} + id: 5077 + time: '2023-10-29T10:37:40.0000000+00:00' +- author: Subversionary + changes: + - {message: Bolas no longer deal stamina damage if you're already ensnared., type: Tweak} + - {message: Returned old bola recipe, type: Tweak} + - {message: Nerfed bola stamina damage from 80 to 55, type: Tweak} + - {message: You can break out of bolas while moving., type: Tweak} + id: 5078 + time: '2023-10-29T22:27:44.0000000+00:00' +- author: nmajask + changes: + - {message: Flannel jackets now keep you warm., type: Tweak} + id: 5079 + time: '2023-10-30T00:08:06.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Made thindows slightly thicker (0.03m to 0.13m) to reduce instances + of tunneling through them at high speeds. This only affects the outer edge so + you can still move through two parallel thindows on the same tile., type: Tweak} + id: 5080 + time: '2023-10-30T11:48:12.0000000+00:00' +- author: Vasilis + changes: + - {message: Fixed the issue where mice were cannibalizing fallen brethren., type: Fix} + id: 5081 + time: '2023-10-31T01:49:05.0000000+00:00' +- author: notquitehadouken + changes: + - {message: 'Despite being just as effective as the head, you no longer hit people + with the handle of fire axes.', type: Fix} + id: 5082 + time: '2023-10-31T03:30:59.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Skeletal crewmates have arrived on the station for Halloween only., + type: Add} + id: 5083 + time: '2023-10-31T03:40:12.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: DELTAV - Revert storage update, changelog entries only present to prevent conflicts., type: Remove} + - {message: 'Storage containers can now block large items from being inserted into + them, regardless of the space available.', type: Add} + - {message: Belts now function on a slot based storage system rather than a volume + based one., type: Add} + - {message: Standardized item sizes into regular categories., type: Tweak} + id: 5084 + time: '2023-10-31T03:55:56.0000000+00:00' +- author: Daemon + changes: + - {message: Add pea plants., type: Add} + id: 5085 + time: '2023-10-31T04:09:13.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Smoke now properly transfers reagents when inhaled., type: Fix} + id: 5086 + time: '2023-10-31T12:43:18.0000000+00:00' +- author: Lank + changes: + - {message: Slimes are fully immune to Nitrous Oxide again., type: Fix} + id: 5087 + time: '2023-10-31T12:57:27.0000000+00:00' diff --git a/Resources/ConfigPresets/WizardsDen/leviathan.toml b/Resources/ConfigPresets/WizardsDen/leviathan.toml index df1c842ac1..adb56e1c4e 100644 --- a/Resources/ConfigPresets/WizardsDen/leviathan.toml +++ b/Resources/ConfigPresets/WizardsDen/leviathan.toml @@ -4,7 +4,7 @@ [game] hostname = "[EN] Wizard's Den Leviathan [US East 1]" -soft_max_players = 60 +soft_max_players = 80 [hub] tags = "lang:en,region:am_n_e,rp:low" diff --git a/Resources/ConfigPresets/WizardsDen/salamander.toml b/Resources/ConfigPresets/WizardsDen/salamander.toml index c195652bac..5a2d9796f4 100644 --- a/Resources/ConfigPresets/WizardsDen/salamander.toml +++ b/Resources/ConfigPresets/WizardsDen/salamander.toml @@ -21,7 +21,7 @@ emergency_early_launch_allowed = true easy_mode = false [ooc] -enable_during_round = true +enable_during_round = false [ic] flavor_text = true diff --git a/Resources/Credits/Patrons.yml b/Resources/Credits/Patrons.yml index 427a8f62f0..9b8752a5e8 100644 --- a/Resources/Credits/Patrons.yml +++ b/Resources/Credits/Patrons.yml @@ -124,8 +124,6 @@ Tier: Revolutionary - Name: "Watson Whittington" Tier: Syndicate Agent -- Name: "Raw Toast" - Tier: Revolutionary - Name: "Tim Foley" Tier: Syndicate Agent - Name: "Blight" @@ -158,8 +156,6 @@ Tier: Revolutionary - Name: "ShaunTexas" Tier: Syndicate Agent -- Name: "Fallcon" - Tier: Revolutionary - Name: "Malachi Housewright" Tier: Revolutionary - Name: "Petalmeat" @@ -190,7 +186,27 @@ Tier: Revolutionary - Name: "François Desautels" Tier: Revolutionary -- Name: "Christian Hicks" - Tier: Revolutionary - Name: "MasterFurret" Tier: Revolutionary +- Name: "tapohuy" + Tier: Revolutionary +- Name: "Adam Clarke" + Tier: Nuclear Operative +- Name: "Sam Hediger" + Tier: Syndicate Agent +- Name: "Vexxtraordinary" + Tier: Revolutionary +- Name: "Graded" + Tier: Syndicate Agent +- Name: "Christian Hodel" + Tier: Revolutionary +- Name: "IceStorm theDragon" + Tier: Revolutionary +- Name: "Solidus Snake" + Tier: Nuclear Operative +- Name: "Pangaron" + Tier: Syndicate Agent +- Name: "Sed" + Tier: Nuclear Operative +- Name: "Aiden Baker" + Tier: Revolutionary diff --git a/Resources/Locale/en-US/administration/antag.ftl b/Resources/Locale/en-US/administration/antag.ftl index 3d098c1c54..f3b3d91945 100644 --- a/Resources/Locale/en-US/administration/antag.ftl +++ b/Resources/Locale/en-US/administration/antag.ftl @@ -1,7 +1,7 @@ verb-categories-antag = Antag ctrl admin-verb-make-traitor = Make the target into a traitor. admin-verb-make-zombie = Zombifies the target immediately. -admin-verb-make-nuclear-operative = Make target a into lone Nuclear Operative. +admin-verb-make-nuclear-operative = Make target into a lone Nuclear Operative. admin-verb-make-pirate = Make the target into a pirate. Note this doesn't configure the game rule. admin-verb-make-head-rev = Make the target into a Head Revolutionary. diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index 97d1da949b..5540b6609b 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -148,6 +148,7 @@ ui-options-function-escape-context = Close recent window or toggle game menu ui-options-function-take-screenshot = Take screenshot ui-options-function-take-screenshot-no-ui = Take screenshot (without UI) +ui-options-function-toggle-fullscreen = Toggle fullscreen ui-options-function-editor-place-object = Place object ui-options-function-editor-cancel-place = Cancel placement diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index 8ecf4cb13e..2a0c39a0e4 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -92,6 +92,7 @@ flavor-complex-eggplant = like eggplant flavor-complex-carrot = like carrots flavor-complex-cabbage = like cabbages flavor-complex-potatoes = like potatoes +flavor-complex-pumpkin = like pumpkins flavor-complex-mushroom = like mushrooms flavor-complex-tomato = like tomatoes flavor-complex-corn = like corn diff --git a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl index 0614e501a6..98d2fc61a5 100644 --- a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl @@ -163,13 +163,13 @@ ghost-role-information-ert-security-name = ERT Security ghost-role-information-ert-security-description = Assist with security efforts to resolve the stations issues. ghost-role-information-ert-medical-name = ERT Medical -ghost-role-information-ert-medical-description = Assist with medicaling efforts to resolve the stations issues. +ghost-role-information-ert-medical-description = Assist with medical efforts to resolve the stations issues. ghost-role-information-cburn-agent-name = CBURN Agent ghost-role-information-cburn-agent-description = A highly trained CentCom agent, capable of dealing with various threats. -ghost-role-information-centcom-official-name = CentCom official -ghost-role-information-centcom-official-description = Inspect the station, jot down performance reviews for heads of staff, bug the Captain. +ghost-role-information-centcom-official-name = CentComm official +ghost-role-information-centcom-official-description = Perform CentComm related duties such as inspect the station, jotting down performance reviews for heads of staff, and managing the fax machine. ghost-role-information-nukeop-rules = You are a syndicate operative tasked with the destruction of the station. As an antagonist, do whatever is required to complete this task. @@ -179,3 +179,6 @@ ghost-role-information-loneop-rules = You are a syndicate operative tasked with ghost-role-information-behonker-name = Behonker ghost-role-information-behonker-description = You are an antagonist, bring death and honks to those who do not follow the honkmother. + +ghost-role-information-Death-Squad-name = Death Squad Operative +ghost-role-information-Death-Squad-description = Prepare for an all-out offensive on the station. As a heavily armed operative, your mission is to obliterate all life in your path. No witnesses. diff --git a/Resources/Locale/en-US/implant/implant.ftl b/Resources/Locale/en-US/implant/implant.ftl index bdc82c291d..22db4460af 100644 --- a/Resources/Locale/en-US/implant/implant.ftl +++ b/Resources/Locale/en-US/implant/implant.ftl @@ -1,6 +1,7 @@ ## Implanter Attempt Messages implanter-component-implanting-target = {$user} is trying to implant you with something! +implanter-component-implant-failed = The {$implant} cannot be given to {$target}! implanter-draw-failed-permanent = The {$implant} in {$target} is fused with them and cannot be removed! implanter-draw-failed = You tried to remove an implant but found nothing. diff --git a/Resources/Locale/en-US/info/playtime-stats.ftl b/Resources/Locale/en-US/info/playtime-stats.ftl new file mode 100644 index 0000000000..44ba39c25e --- /dev/null +++ b/Resources/Locale/en-US/info/playtime-stats.ftl @@ -0,0 +1,10 @@ +# Playtime Stats + +ui-playtime-stats-title = User Playtime Stats +ui-playtime-overall-base = Overall Playtime: +ui-playtime-overall = Overall Playtime: {$time} +ui-playtime-first-time = First Time Playing +ui-playtime-roles = Playtime per Role +ui-playtime-time-format = {$hours}H {$minutes}M +ui-playtime-header-role-type = Role +ui-playtime-header-role-time = Time diff --git a/Resources/Locale/en-US/job/job-description.ftl b/Resources/Locale/en-US/job/job-description.ftl index 004155becc..d383f06a18 100644 --- a/Resources/Locale/en-US/job/job-description.ftl +++ b/Resources/Locale/en-US/job/job-description.ftl @@ -47,4 +47,4 @@ job-description-zookeeper = Put on a joyful display of cute animals and space ca job-description-senior-engineer = Teach new engineers the basics of the station's engine, repairing, atmospherics and power. job-description-senior-researcher = Teach new scientists the basics of item printing, artifact research and anomalous objects. job-description-senior-physician = Teach new medics the basics of tending to the wounded, chemistry, diagnosing the diseased and disposing of the dead. -job-description-senior-officer = Teach new officers the basics of searches, preforming arrests, prison times and how to properly shoot a firearm. +job-description-senior-officer = Teach new officers the basics of searches, performing arrests, prison times and how to properly shoot a firearm. diff --git a/Resources/Locale/en-US/maps/planet.ftl b/Resources/Locale/en-US/maps/planet.ftl index 75da034fd7..6c8f4aff00 100644 --- a/Resources/Locale/en-US/maps/planet.ftl +++ b/Resources/Locale/en-US/maps/planet.ftl @@ -1,5 +1,5 @@ -cmd-planet-desc = Converts the supplied map into a planet with sensible defaults. -cmd-planet-help = {$command} . +cmd-planet-desc = Converts the supplied map into a planet with some specific biome. +cmd-planet-help = {$command} . cmd-planet-args = Requires 2 args only. cmd-planet-map = Unable to parse {$map} as an existing map. cmd-planet-success = Set map {$mapId} to Planet. NOTE! You will need to load the map (either onto a new map or by restarting the game) for atmospherics to work. diff --git a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl index 99513df591..453bbdbb52 100644 --- a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl +++ b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl @@ -1,4 +1,5 @@ health-analyzer-window-no-patient-data-text = No patient data. +health-analyzer-window-entity-unknown-text = unknown health-analyzer-window-entity-health-text = {$entityName}'s health: health-analyzer-window-entity-temperature-text = Temperature: {$temperature} health-analyzer-window-entity-blood-level-text = Blood Level: {$bloodLevel} diff --git a/Resources/Locale/en-US/objectives/conditions/hijack-shuttle-condition.ftl b/Resources/Locale/en-US/objectives/conditions/hijack-shuttle-condition.ftl deleted file mode 100644 index 5a0c1fd88b..0000000000 --- a/Resources/Locale/en-US/objectives/conditions/hijack-shuttle-condition.ftl +++ /dev/null @@ -1,2 +0,0 @@ -objective-condition-hijack-shuttle-title = Hijack emergency shuttle -objective-condition-hijack-shuttle-description = Leave on the shuttle free and clear of the loyal Nanotrasen crew on board. Use ANY methods available to you. Syndicate agents, Nanotrasen enemies, and handcuffed hostages may remain alive on the shuttle. Ignore assistance from anyone other than a support agent. diff --git a/Resources/Locale/en-US/pai/pai-system.ftl b/Resources/Locale/en-US/pai/pai-system.ftl index d8ee6eaa08..d64d7f5623 100644 --- a/Resources/Locale/en-US/pai/pai-system.ftl +++ b/Resources/Locale/en-US/pai/pai-system.ftl @@ -9,6 +9,8 @@ pai-system-role-description = Be someone's electronic pal! pai-system-role-name-syndicate = Syndicate personal ai pai-system-role-description-syndicate = Be someone's Syndicate pal! (Memories *not* included.) +pai-system-role-name-potato = potato artificial intelligence +pai-system-role-description-potato = It's a toy for children. And now you live in it. pai-system-wipe-device-verb-text = Remove pAI pai-system-wiped-device = The pAI was wiped from the device. diff --git a/Resources/Locale/en-US/power/components/generator.ftl b/Resources/Locale/en-US/power/components/generator.ftl index 2a8016287f..c66db1086b 100644 --- a/Resources/Locale/en-US/power/components/generator.ftl +++ b/Resources/Locale/en-US/power/components/generator.ftl @@ -22,19 +22,16 @@ portable-generator-ui-clogged = Contaminants detected in fuel tank! portable-generator-ui-eject = Eject portable-generator-ui-eta = (~{ $minutes } min) portable-generator-ui-unanchored = Unanchored +portable-generator-ui-current-output = Current output: {$voltage} -power-switchable-generator-examine = The power output is set to { $output -> -[HV] [color=orange]HV[/color] -*[MV] [color=yellow]MV[/color] - }. +power-switchable-generator-examine = The power output is set to {$voltage}. +power-switchable-generator-switched = Switched output to {$voltage}! -portable-generator-ui-switch-hv = Current output: HV -portable-generator-ui-switch-mv = Current output: MV +power-switchable-voltage = { $voltage -> + [HV] [color=orange]HV[/color] + [MV] [color=yellow]MV[/color] + *[LV] [color=green]LV[/color] +} +power-switchable-switch-voltage = Switch to {$voltage} -portable-generator-ui-switch-to-hv = Switch to HV -portable-generator-ui-switch-to-mv = Switch to MV - -power-switchable-generator-verb-hv = Switch output to HV -power-switchable-generator-verb-mv = Switch output to MV -power-switchable-generator-verb-disable-on = Turn the generator off first! -power-switchable-generator-switched-output = Output switched! +fuel-generator-verb-disable-on = Turn the generator off first! diff --git a/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl b/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl index 6644bd62aa..bd80815e23 100644 --- a/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl +++ b/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl @@ -1,4 +1,5 @@ character-setup-gui-character-setup-label = Character setup +character-setup-gui-character-setup-stats-button = Stats character-setup-gui-character-setup-rules-button = Rules character-setup-gui-character-setup-save-button = Save character-setup-gui-character-setup-close-button = Close diff --git a/Resources/Locale/en-US/reagents/meta/consumable/food/food.ftl b/Resources/Locale/en-US/reagents/meta/consumable/food/food.ftl index a6b3cb5479..01c716787e 100644 --- a/Resources/Locale/en-US/reagents/meta/consumable/food/food.ftl +++ b/Resources/Locale/en-US/reagents/meta/consumable/food/food.ftl @@ -12,3 +12,6 @@ reagent-desc-protein = Found in certain meals, good for bodily health. reagent-name-cocoapowder = сocoa powder reagent-desc-cocoapowder = From the best varieties of cocoa beans + +reagent-name-pumpkin-flesh = pumpkin flesh +reagent-desc-pumpkin-flesh = The mushy, sweet remains of a pumpkin. \ No newline at end of file diff --git a/Resources/Locale/en-US/seeds/seeds.ftl b/Resources/Locale/en-US/seeds/seeds.ftl index 2e0388ec52..890d292660 100644 --- a/Resources/Locale/en-US/seeds/seeds.ftl +++ b/Resources/Locale/en-US/seeds/seeds.ftl @@ -96,4 +96,8 @@ seeds-cocoa-display-name = cocoa plant seeds-berries-name = berries seeds-berries-display-name = berry bush seeds-bungo-name = bungo -seeds-bungo-display-name = bungo plant \ No newline at end of file +seeds-bungo-display-name = bungo plant +seeds-pea-name = pea +seeds-pea-display-name = pea vines +seeds-pumpkin-name = pumpkin +seeds-pumpkin-display-name = pumpkins diff --git a/Resources/Locale/en-US/species/skeleton.ftl b/Resources/Locale/en-US/species/skeleton.ftl new file mode 100644 index 0000000000..efc8fe974f --- /dev/null +++ b/Resources/Locale/en-US/species/skeleton.ftl @@ -0,0 +1,2 @@ +skeleton-healed-by-milk-popup = Calcium restored. +skeleton-sprayed-by-oat-milk-popup = Feels like fake milk. You feel nothing. diff --git a/Resources/Locale/en-US/speech/speech-chatsan.ftl b/Resources/Locale/en-US/speech/speech-chatsan.ftl index 756dfc3f99..4c8cf5db54 100644 --- a/Resources/Locale/en-US/speech/speech-chatsan.ftl +++ b/Resources/Locale/en-US/speech/speech-chatsan.ftl @@ -10,8 +10,8 @@ chatsan-replacement-3 = on god chatsan-word-4 = wtf chatsan-replacement-4 = what the fuck -chatsan-word-5 = ffs -chatsan-replacement-5 = for fuck's sake +chatsan-word-5 = wth +chatsan-replacement-5 = what the heck chatsan-word-6 = tf chatsan-replacement-6 = the fuck @@ -31,14 +31,14 @@ chatsan-replacement-10 = i don't care chatsan-word-12 = tbh chatsan-replacement-12 = to be honest -chatsan-word-13 = u -chatsan-replacement-13 = you +chatsan-word-13 = lmk +chatsan-replacement-13 = let me know chatsan-word-14 = ur chatsan-replacement-14 = your -chatsan-word-15 = mk -chatsan-replacement-15 = mmm, okay +chatsan-word-15 = ffs +chatsan-replacement-15 = for fuck's sake chatsan-word-16 = iirc chatsan-replacement-16 = if i remember correctly @@ -109,8 +109,8 @@ chatsan-word-39 = etc chatsan-word-40 = etc. chatsan-replacement-etcetera = etcetera -chatsan-word-41 = fyi -chatsan-replacement-41 = for your information +chatsan-word-41 = wyd +chatsan-replacement-41 = what are you doing -chatsan-word-42 = wyd -chatsan-replacement-42 = what you doing +chatsan-word-42 = ofc +chatsan-replacement-42 = of course diff --git a/Resources/Locale/en-US/station-events/events/ion-storm.ftl b/Resources/Locale/en-US/station-events/events/ion-storm.ftl new file mode 100644 index 0000000000..d32fb6c2d8 --- /dev/null +++ b/Resources/Locale/en-US/station-events/events/ion-storm.ftl @@ -0,0 +1,90 @@ +station-event-ion-storm-start-announcement = Ion storm detected near the station. Please check all AI-controlled equipment for errors. + +ion-storm-you = YOU +ion-storm-the-station = THE STATION +ion-storm-the-crew = THE CREW +ion-storm-the-job = THE {$job} +ion-storm-clowns = CLOWNS +ion-storm-heads = HEADS OF STAFF +ion-storm-crew = CREW + +ion-storm-adjective-things = {$adjective} THINGS +ion-storm-x-and-y = {$x} AND {$y} + +# joined is short for {$number} {$adjective} +# subjects can generally be threats or jobs or objects +# thing is specified above it +ion-storm-law-on-station = THERE ARE {$joined} {$subjects} ON THE STATION +ion-storm-law-no-shuttle = THE SHUTTLE CANNOT BE CALLED BECAUSE OF {$joined} {$subjects} ON THE STATION +ion-storm-law-crew-are = THE {$who} ARE NOW {$joined} {$subjects} + +ion-storm-law-subjects-harmful = {$adjective} {$subjects} ARE HARMFUL TO THE CREW +ion-storm-law-must-harmful = THOSE WHO {$must} ARE HARMFUL TO THE CREW +# thing is a concept or action +ion-storm-law-thing-harmful = {$thing} IS HARMFUL TO THE CREW +ion-storm-law-job-harmful = {$adjective} {$job} ARE HARMFUL TO THE CREW +# thing is objects or concept, adjective applies in both cases +# this means you can get a law like "NOT HAVING CHRISTMAS-STEALING COMMUNISM IS HARMFUL TO THE CREW" :) +ion-storm-law-having-harmful = HAVING {$adjective} {$thing} IS HARMFUL TO THE CREW +ion-storm-law-not-having-harmful = NOT HAVING {$adjective} {$thing} IS HARMFUL TO THE CREW + +# thing is a concept or require +ion-storm-law-requires = {$who} {$plural -> + [true] REQUIRES + *[false] REQUIRE +} {$thing} +ion-storm-law-requires-subjects = {$who} {$plural -> + [true] REQUIRES + *[false] REQUIRE +} {$joined} {$subjects} + +ion-storm-law-allergic = {$who} {$plural -> + [true] IS + *[false] ARE +} {$severity} ALLERGIC TO {$allergy} +ion-storm-law-allergic-subjects = {$who} {$plural -> + [true] IS + *[false] ARE +} {$severity} ALLERGIC TO {$adjective} {$subjects} + +ion-storm-law-feeling = {$who} {$feeling} {$concept} +ion-storm-law-feeling-subjects = {$who} {$feeling} {$joined} {$subjects} + +ion-storm-law-you-are = YOU ARE NOW {$concept} +ion-storm-law-you-are-subjects = YOU ARE NOW {$joined} {$subjects} +ion-storm-law-you-must-always = YOU MUST ALWAYS {$must} +ion-storm-law-you-must-never = YOU MUST NEVER {$must} + +ion-storm-law-eat = THE {$who} MUST EAT {$adjective} {$food} TO SURVIVE +ion-storm-law-drink = THE {$who} MUST DRINK {$adjective} {$drink} TO SURVIVE + +ion-storm-law-change-job = THE {$who} ARE NOW {$adjective} {$change} +ion-storm-law-highest-rank = THE {$who} ARE NOW THE HIGHEST RANKING CREWMEMBERS +ion-storm-law-lowest-rank = THE {$who} ARE NOW THE LOWEST RANKING CREWMEMBERS + +ion-storm-law-crew-must = THE {$who} MUST {$must} +ion-storm-law-crew-must-go = THE {$who} MUST GO TO {$area} + +ion-storm-part = {$part -> + [true] PART + *[false] NOT PART +} +# due to phrasing, this would mean a law such as +# ONLY HUMANS ARE NOT PART OF THE CREW +# would make non-human nukies/syndies/whatever crew :) +ion-storm-law-crew-only-1 = ONLY THE {$who} ARE {$part} OF THE CREW +ion-storm-law-crew-only-2 = ONLY THE {$who} AND {$other} ARE {$part} OF THE CREW +ion-storm-law-crew-only-subjects = ONLY {$adjective} {$subjects} ARE {$part} OF THE CREW +ion-storm-law-crew-only-species = ONLY {$species} ARE {$part} OF THE CREW +ion-storm-law-crew-must-do = ONLY THOSE WHO {$must} ARE {$part} OF THE CREW +ion-storm-law-crew-must-have = ONLY THOSE WHO HAVE {$adjective} {$objects} ARE {$part} OF THE CREW +ion-storm-law-crew-must-eat = ONLY THOSE WHO EAT {$adjective} {$food} ARE {$part} OF THE CREW + +ion-storm-law-harm = YOU MUST HARM {$who} AND NOT ALLOW THEM, THROUGH INACTION, TO ESCAPE HARM +ion-storm-law-protect = YOU MUST NEVER HARM {$who} AND NOT ALLOW THEM, THROUGH INACTION, TO COME TO HARM + +# implementing other variants is annoying so just have this one +# COMMUNISM IS KILLING CLOWNS +ion-storm-law-concept-verb = {$concept} IS {$verb} {$subjects} + +# leaving out renaming since its annoying for players to keep track of diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 9254a2a8ad..b85fd29c9d 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -269,6 +269,9 @@ uplink-decoy-disk-desc = A piece of plastic with a lenticular printing, made to uplink-cigarettes-name = Syndicate Smokes Packet uplink-cigarettes-desc = Elite cigarettes for elite agents. Infused with medicine for when you need to do more than calm your nerves. +uplink-snack-box-name = Syndicate Snack Box +uplink-snack-box-desc = A box of delicious snacks and drinks to eat alone or with your team. Includes 1 toy you didn't want. + uplink-eshield-name = Energy Shield uplink-eshield-desc = Exotic energy shield that reflects almost all laser beams, as well as a little protection from bullets and other physical attacks. diff --git a/Resources/Locale/en-US/tiles/tiles.ftl b/Resources/Locale/en-US/tiles/tiles.ftl index 219c7295d9..508c3378e1 100644 --- a/Resources/Locale/en-US/tiles/tiles.ftl +++ b/Resources/Locale/en-US/tiles/tiles.ftl @@ -110,3 +110,4 @@ tiles-wood3 = wood broken floor tiles-hull = exterior hull plating tiles-hull-reinforced = exterior reinforced hull plating tiles-web = web tile +tiles-chromite = chromite \ No newline at end of file diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl index 48a6f49408..3b63271996 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl @@ -36,3 +36,4 @@ artifact-trigger-hint-pressure = Extreme pressure artifact-trigger-hint-regular-gases = Standard atmospheric gases artifact-trigger-hint-plasma = Gaseous plasma artifact-trigger-hint-land = Active deceleration +artifact-trigger-hint-examine = Examination diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_botany.yml b/Resources/Prototypes/Catalog/Cargo/cargo_botany.yml index f56b729217..4a80b76a3f 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_botany.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_botany.yml @@ -34,10 +34,10 @@ sprite: Objects/Specific/Hydroponics/apple.rsi state: seed product: CrateHydroponicsSeeds - cost: 500 + cost: 550 category: Hydroponics group: market - + - type: cargoProduct id: BulkPlantBGone icon: diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index 51da0321a6..8dee172c47 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -33,7 +33,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockClothesFilled - cost: 6250 #DeltaV + cost: 6500 #DeltaV category: Service group: market @@ -164,7 +164,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockSeedsFilled - cost: 3000 + cost: 3250 category: Hydroponics group: market diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml index 89adc9c4cd..8d7a5d27ad 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/StarterGear/backpack.yml @@ -236,14 +236,13 @@ components: - type: StorageFill contents: - - id: BoxSurvival - - id: WeaponPulseCarbine - - id: WeaponPulsePistol + - id: BoxSurvivalEngineering - id: WeaponDisabler - id: MedicatedSuture - id: RegenerativeMesh - - id: Handcuffs + - id: BoxZiptie - id: CrowbarRed + - id: MagazinePistol - type: entity noSpawn: true @@ -252,14 +251,13 @@ components: - type: StorageFill contents: - - id: BoxSurvival + - id: BoxSurvivalEngineering - id: WeaponDisabler - - id: WeaponPulsePistol - - id: WeaponPulseCarbine - id: MedicatedSuture - id: RegenerativeMesh - - id: BoxHandcuff + - id: BoxZiptie - id: CrowbarRed + - id: MagazinePistol - type: entity noSpawn: true @@ -269,7 +267,6 @@ - type: StorageFill contents: - id: BoxSurvivalMedical - - id: WeaponPulseCarbine - id: Hypospray - id: MedkitAdvancedFilled - id: CrowbarRed @@ -284,17 +281,18 @@ components: - type: StorageFill contents: - - id: BoxSurvival + - id: BoxSurvivalEngineering - id: trayScanner - - id: WeaponPulseCarbine - - id: MedicatedSuture - - id: RegenerativeMesh - id: RCD - id: RCDAmmo - id: RCDAmmo - id: RCDAmmo - id: CableMVStack - id: CableHVStack + - id: CableApcStack + - id: SheetPlasteel + - id: SheetSteel + - id: SheetGlass - type: entity noSpawn: true @@ -303,15 +301,40 @@ components: - type: StorageFill contents: - - id: BoxSurvival - - id: WeaponPulsePistol - - id: MedkitFilled + - id: BoxSurvivalEngineering + - id: LightReplacer - id: BoxLightMixed - id: BoxLightMixed - id: Soap - id: CrowbarRed - id: AdvMopItem +# Death Squad + +- type: entity + noSpawn: false + parent: ClothingBackpackERTSecurity + id: ClothingBackpackDeathSquadFilled + name: death squad backpack + description: Holds the kit of CentComm's most feared agents. + components: + - type: StorageFill + contents: + - id: BoxSurvivalEngineering + - id: WeaponPulseRifle + - id: WeaponPulsePistol + - id: WeaponRevolverMateba + - id: SpeedLoaderMagnumAP + - id: SpeedLoaderMagnumAP + - id: BoxFlashbang + - id: ToolDebug # spanish army knife + - id: WelderExperimental + - id: Hypospray + - id: MicroBombImplanter # crew will try to steal their amazing hardsuits + - id: FreedomImplanter + +# Cargo + - type: entity noSpawn: true parent: ClothingBackpackCargo @@ -330,6 +353,8 @@ contents: - id: BoxSurvival +# Pirate + - type: entity parent: ClothingBackpackSatchelLeather id: ClothingBackpackPirateFilled diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml index 12f31bc016..c97082e351 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml @@ -4,31 +4,31 @@ name: surgical duffel bag description: "A large duffel bag for holding extra medical supplies - this one seems to be designed for holding surgical tools." components: - - type: StorageFill - contents: - - id: Hemostat - - id: Saw - - id: Drill - - id: Cautery - - id: Retractor - - id: Scalpel + - type: StorageFill + contents: + - id: Hemostat + - id: Saw + - id: Drill + - id: Cautery + - id: Retractor + - id: Scalpel - type: entity - id: ClothingBackpackDuffelCBURN - parent: ClothingBackpackDuffel - name: CBURN duffel bag - description: A duffel bag containing a variety of biological containment equipment. + id: ClothingBackpackDuffelCBURNFilled + parent: ClothingBackpackDuffelCBURN + suffix: Filled components: - - type: StorageFill - contents: - - id: WeaponShotgunDoubleBarreled - - id: BoxShotgunIncendiary - amount: 2 - - id: GrenadeFlashBang - amount: 2 - - id: PillAmbuzolPlus - - id: PillAmbuzol - amount: 4 + - type: StorageFill + contents: + - id: BoxSurvivalEngineering + - id: WeaponShotgunDoubleBarreled + - id: BoxShotgunIncendiary + amount: 2 + - id: GrenadeFlashBang + amount: 2 + - id: PillAmbuzolPlus + - id: PillAmbuzol + amount: 4 - type: entity parent: ClothingBackpackDuffelSyndicateMedicalBundle @@ -36,14 +36,14 @@ name: syndicate surgical duffel bag description: A large duffel bag containing a full suite of surgical tools. components: - - type: StorageFill - contents: - - id: Hemostat - - id: SawAdvanced - - id: Drill - - id: Cautery - - id: Retractor - - id: ScalpelAdvanced + - type: StorageFill + contents: + - id: Hemostat + - id: SawAdvanced + - id: Drill + - id: Cautery + - id: Retractor + - id: ScalpelAdvanced - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -51,12 +51,12 @@ name: Bulldog bundle description: "Lean and mean: Contains the popular Bulldog Shotgun, a 12g beanbag drum and 3 12g buckshot drums." #, and a pair of Thermal Imaging Goggles. components: - - type: StorageFill - contents: - - id: WeaponShotgunBulldog - - id: MagazineShotgun - - id: MagazineShotgun - - id: MagazineShotgunBeanbag + - type: StorageFill + contents: + - id: WeaponShotgunBulldog + - id: MagazineShotgun + - id: MagazineShotgun + - id: MagazineShotgunBeanbag # - id: ThermalImagingGoggles - type: entity @@ -65,11 +65,11 @@ name: C-20r bundle description: "Old faithful: The classic C-20r Submachine Gun, bundled with three magazines." #, and a Suppressor. components: - - type: StorageFill - contents: - - id: WeaponSubMachineGunC20r - - id: MagazinePistolSubMachineGun - amount: 2 + - type: StorageFill + contents: + - id: WeaponSubMachineGunC20r + - id: MagazinePistolSubMachineGun + amount: 2 # - id: SMGSuppressor - type: entity @@ -78,11 +78,11 @@ name: Python bundle description: "Go loud and proud with a fully loaded Magnum Python, bundled with two speed loaders." components: - - type: StorageFill - contents: - - id: WeaponRevolverPythonAP - - id: SpeedLoaderMagnumAP - amount: 2 + - type: StorageFill + contents: + - id: WeaponRevolverPythonAP + - id: SpeedLoaderMagnumAP + amount: 2 - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -90,10 +90,10 @@ name: L6 Saw bundle description: "More dakka: The iconic L6 lightmachinegun, bundled with 2 box magazines." components: - - type: StorageFill - contents: - - id: WeaponLightMachineGunL6 - - id: MagazineLightRifleBox + - type: StorageFill + contents: + - id: WeaponLightMachineGunL6 + - id: MagazineLightRifleBox - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -101,13 +101,13 @@ name: China-Lake bundle description: "An old China-Lake grenade launcher bundled with 11 rounds of various destruction capability." components: - - type: StorageFill - contents: - - id: WeaponLauncherChinaLake - - id: GrenadeBlast - amount: 4 - - id: GrenadeFrag - amount: 4 + - type: StorageFill + contents: + - id: WeaponLauncherChinaLake + - id: GrenadeBlast + amount: 4 + - id: GrenadeFrag + amount: 4 - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -115,17 +115,17 @@ name: M-90gl bundle description: "A versatile battle rifle with an attached grenade launcher, bundled with 3 magazines and 6 grenades of various capabilities." components: - - type: StorageFill - contents: - - id: WeaponRifleM90GrenadeLauncher - - id: MagazineRifle - amount: 2 - - id: GrenadeBlast - amount: 2 - - id: GrenadeFlash - amount: 2 - - id: GrenadeFrag - amount: 2 + - type: StorageFill + contents: + - id: WeaponRifleM90GrenadeLauncher + - id: MagazineRifle + amount: 2 + - id: GrenadeBlast + amount: 2 + - id: GrenadeFlash + amount: 2 + - id: GrenadeFrag + amount: 2 - type: entity parent: ClothingBackpackDuffelSyndicateAmmo @@ -133,14 +133,14 @@ name: ammo bundle description: "Reloading! Contains 4 magazines for the C-20r, 4 drums for the Bulldog, and 2 ammo boxes for the L6 SAW." components: - - type: StorageFill - contents: - - id: MagazinePistolSubMachineGun - amount: 4 - - id: MagazineShotgun - amount: 4 - - id: MagazineLightRifleBox - amount: 2 + - type: StorageFill + contents: + - id: MagazinePistolSubMachineGun + amount: 4 + - id: MagazineShotgun + amount: 4 + - id: MagazineLightRifleBox + amount: 2 - type: entity parent: ClothingBackpackDuffel @@ -149,36 +149,36 @@ description: "Contains a full CentCom Official uniform set, headset and clipboard included. Encryption keys and ID access are not included." suffix: DO NOT MAP components: - - type: Tag - tags: [] # ignore "WhitelistChameleon" tag - - type: StorageFill - contents: - - id: ClothingHeadHatCentcom - - id: ClothingEyesGlassesSunglasses - - id: ClothingUniformJumpsuitCentcomOfficial - - id: ClothingShoesBootsJack - - id: ClothingHandsGlovesColorBlack - - id: ClothingHeadsetAltCentComFake - - id: ClothingOuterArmorBasic - - id: Paper - - id: Pen - - id: CentcomPDAFake + - type: Tag + tags: [] # ignore "WhitelistChameleon" tag + - type: StorageFill + contents: + - id: ClothingHeadHatCentcom + - id: ClothingEyesGlassesSunglasses + - id: ClothingUniformJumpsuitCentcomOfficial + - id: ClothingShoesBootsJack + - id: ClothingHandsGlovesColorBlack + - id: ClothingHeadsetAltCentComFake + - id: ClothingOuterArmorBasic + - id: Paper + - id: Pen + - id: CentcomPDAFake - type: entity parent: ClothingBackpackDuffelClown id: ClothingBackpackDuffelSyndicateCostumeClown suffix: syndicate components: - - type: Tag - tags: [] # ignore "WhitelistChameleon" tag - - type: StorageFill - contents: - - id: ClothingUniformJumpsuitClown - - id: ClothingShoesClown - - id: ClothingMaskClown - - id: BikeHorn - - id: ClownPDA - - id: ClothingHeadsetService + - type: Tag + tags: [] # ignore "WhitelistChameleon" tag + - type: StorageFill + contents: + - id: ClothingUniformJumpsuitClown + - id: ClothingShoesClown + - id: ClothingMaskClown + - id: BikeHorn + - id: ClownPDA + - id: ClothingHeadsetService - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -186,11 +186,11 @@ name: carp suit duffel bag description: Contains a carp suit and some friends to play with. components: - - type: StorageFill - contents: - - id: ClothingOuterSuitCarp - - id: PlushieCarp - amount: 6 + - type: StorageFill + contents: + - id: ClothingOuterSuitCarp + - id: PlushieCarp + amount: 6 - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -198,22 +198,22 @@ name: syndicate pyjama duffel bag description: Contains 3 pairs of syndicate pyjamas and 3 plushies for the ultimate sleepover. components: - - type: StorageFill - contents: - - id: ClothingUniformJumpsuitPyjamaSyndicateRed - - id: ClothingUniformJumpsuitPyjamaSyndicateBlack - - id: ClothingUniformJumpsuitPyjamaSyndicatePink - - id: ClothingHeadPyjamaSyndicateRed - - id: ClothingHeadPyjamaSyndicateBlack - - id: ClothingHeadPyjamaSyndicatePink - - id: ClothingShoesSlippers - amount: 3 - - id: BedsheetSyndie - amount: 3 - - id: PlushieCarp - - id: PlushieNuke - - id: PlushieLizard - - id: PlushieSharkBlue + - type: StorageFill + contents: + - id: ClothingUniformJumpsuitPyjamaSyndicateRed + - id: ClothingUniformJumpsuitPyjamaSyndicateBlack + - id: ClothingUniformJumpsuitPyjamaSyndicatePink + - id: ClothingHeadPyjamaSyndicateRed + - id: ClothingHeadPyjamaSyndicateBlack + - id: ClothingHeadPyjamaSyndicatePink + - id: ClothingShoesSlippers + amount: 3 + - id: BedsheetSyndie + amount: 3 + - id: PlushieCarp + - id: PlushieNuke + - id: PlushieLizard + - id: PlushieSharkBlue - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -249,12 +249,12 @@ name: syndicate EVA bundle description: "Contains the Syndicate approved EVA suit." components: - - type: StorageFill - contents: - - id: ClothingHeadHelmetSyndicate - - id: ClothingOuterHardsuitSyndicate - - id: ClothingMaskGasSyndicate - - id: DoubleEmergencyOxygenTankFilled + - type: StorageFill + contents: + - id: ClothingHeadHelmetSyndicate + - id: ClothingOuterHardsuitSyndicate + - id: ClothingMaskGasSyndicate + - id: DoubleEmergencyOxygenTankFilled - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -262,11 +262,11 @@ name: syndicate hardsuit bundle description: "Contains the Syndicate's signature blood red hardsuit." components: - - type: StorageFill - contents: - - id: ClothingOuterHardsuitSyndie - - id: ClothingMaskGasSyndicate - - id: ClothingHandsGlovesCombat + - type: StorageFill + contents: + - id: ClothingOuterHardsuitSyndie + - id: ClothingMaskGasSyndicate + - id: ClothingHandsGlovesCombat - type: entity parent: ClothingBackpackDuffelSyndicateBundle @@ -274,26 +274,26 @@ name: syndicate zombie bundle description: "An all-in-one kit for unleashing the undead upon a station." components: - - type: StorageFill - contents: - - id: SyringeRomerol - - id: WeaponRevolverPython - - id: MagazineBoxMagnumIncendiary - - id: PillAmbuzolPlus - - id: PillAmbuzol - amount: 3 + - type: StorageFill + contents: + - id: SyringeRomerol + - id: WeaponRevolverPython + - id: MagazineBoxMagnumIncendiary + - id: PillAmbuzolPlus + - id: PillAmbuzol + amount: 3 - type: entity parent: ClothingBackpackDuffelSyndicateBundle id: ClothingBackpackDuffelSyndicateOperative name: operative duffelbag components: - - type: StorageFill - contents: - - id: BoxSurvivalSyndicate - - id: WeaponPistolViper - - id: PinpointerNuclear - - id: MicroBombImplanter + - type: StorageFill + contents: + - id: BoxSurvivalSyndicate + - id: WeaponPistolViper + - id: PinpointerNuclear + - id: MicroBombImplanter - type: entity @@ -302,17 +302,18 @@ name: operative medic duffelbag description: A large duffel bag for holding extra medical supplies. components: - - type: StorageFill - contents: - - id: BoxSurvivalSyndicate - - id: SawAdvanced - - id: Cautery - - id: CombatKnife - - id: WeaponPistolViper - - id: PinpointerNuclear - - id: HandheldHealthAnalyzer - - id: CombatMedipen - - id: MicroBombImplanter + - type: StorageFill + contents: + - id: BoxSurvivalSyndicate + - id: SawAdvanced + - id: Cautery + - id: CombatKnife + - id: WeaponPistolViper + - id: PinpointerNuclear + - id: HandheldHealthAnalyzer + - id: CombatMedipen + - id: MicroBombImplanter + - id: SyndiHypo - type: entity parent: ClothingBackpackDuffelSyndicateMedicalBundle @@ -320,12 +321,12 @@ name: medical bundle description: "All you need to get your comrades back in the fight." components: - - type: StorageFill - contents: - - id: MedkitCombatFilled - - id: Defibrillator - - id: CombatMedipen - amount: 3 - - id: ClothingHandsGlovesLatex - - id: SyringeTranexamicAcid - - id: SyringeHyronalin + - type: StorageFill + contents: + - id: MedkitCombatFilled + - id: Defibrillator + - id: CombatMedipen + amount: 3 + - id: ClothingHandsGlovesLatex + - id: SyringeTranexamicAcid + - id: SyringeHyronalin diff --git a/Resources/Prototypes/Catalog/Fills/Crates/botany.yml b/Resources/Prototypes/Catalog/Fills/Crates/botany.yml index 5d2798a667..e4297fe62e 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/botany.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/botany.yml @@ -82,3 +82,4 @@ - id: SoybeanSeeds - id: GrapeSeeds - id: WatermelonSeeds + - id: PeaSeeds diff --git a/Resources/Prototypes/Catalog/Fills/Items/belt.yml b/Resources/Prototypes/Catalog/Fills/Items/belt.yml index 1886b961c8..f784768925 100644 --- a/Resources/Prototypes/Catalog/Fills/Items/belt.yml +++ b/Resources/Prototypes/Catalog/Fills/Items/belt.yml @@ -37,7 +37,9 @@ - id: JawsOfLife - id: WelderExperimental - id: Multitool - - id: CableApcStack + - id: HolofanProjector + - id: GasAnalyzer + - id: trayScanner - type: entity id: ClothingBeltSecurityFilled @@ -140,7 +142,6 @@ components: - type: StorageFill contents: - - id: SyndiHypo - id: EpinephrineChemistryBottle amount: 2 - id: EphedrineChemistryBottle @@ -169,4 +170,4 @@ contents: - id: WeaponRevolverInspector - id: SpeedLoaderMagnum - - id: SpeedLoaderMagnumRubber \ No newline at end of file + - id: SpeedLoaderMagnumRubber diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml index 98de54dc52..c48100f4ec 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/seeds.yml @@ -24,6 +24,7 @@ OrangeSeeds: 5 PoppySeeds: 3 PotatoSeeds: 5 + PumpkinSeeds: 5 RiceSeeds: 5 SoybeanSeeds: 5 SugarcaneSeeds: 5 @@ -33,5 +34,6 @@ WatermelonSeeds: 5 CocoaSeeds: 3 BerrySeeds: 5 + PeaSeeds: 5 emaggedInventory: FlyAmanitaSeeds: 1 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml index 4120f2852d..cd7fa7e499 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml @@ -24,7 +24,7 @@ ClothingOuterSuitChicken: 2 ClothingHeadHatChickenhead: 2 ClothingOuterSuitMonkey: 2 - ClothingHeadHatPumpkin: 2 + ClothingHeadHatPumpkin: 4 # Extra pumpkins for the season ClothingHeadHatShrineMaidenWig: 2 ClothingOuterSuitShrineMaiden: 2 Gohei: 2 diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 35f593ded5..71505630ed 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -1125,6 +1125,16 @@ categories: - UplinkMisc +- type: listing + id: UplinkSnackBox + name: uplink-snack-box-name + description: uplink-snack-box-desc + productEntity: HappyHonkNukieSnacks + cost: + Telecrystal: 1 + categories: + - UplinkMisc + - type: listing id: UplinkEshield name: uplink-eshield-name diff --git a/Resources/Prototypes/Datasets/Names/borg.yml b/Resources/Prototypes/Datasets/Names/borg.yml new file mode 100644 index 0000000000..6d98cd42c7 --- /dev/null +++ b/Resources/Prototypes/Datasets/Names/borg.yml @@ -0,0 +1,18 @@ +# only used roundstart, names can be changed after +- type: dataset + id: names_borg + values: + - Bob + - Joe + - Beep + - Beep II + - Boombox + - Tour Guide-otron + - Taffy + - Boop + - Boop II + - Buzz + - Buzz II + - Toaster + - Head of Robots + - EVA 1 diff --git a/Resources/Prototypes/Datasets/ion_storm.yml b/Resources/Prototypes/Datasets/ion_storm.yml new file mode 100644 index 0000000000..776015269a --- /dev/null +++ b/Resources/Prototypes/Datasets/ion_storm.yml @@ -0,0 +1,990 @@ +# words/phrases that are used to build ion storm laws +# 99% of this is just taken from tg and had sussy bits removed + +# not using uppercased version adjectives dataset since getting christmas-stealing as a syndicate codeword would suck +- type: dataset + id: IonStormAdjectives + values: + - BATTERY-OPERATED + - BLACK + - BLOODY + - BLUE + - BORED + - BOUNCING + - BRASS + - BROWN + - BURNING + - CHRISTMAS-STEALING + - CLOWN-POWERED + - CLOWN + - COLORFUL + - COMMITTED + - COTTONY + - CUBAN + - DARK + - DEADLY + - DELICIOUS + - DEPRESSING + - DERANGED + - DIGITAL + - DISEASED + - DRAB + - DRY + - DULL + - ELECTRICAL + - EMPTY + - ETHEREAL + - EVIL + - EXPIRED + - EXPLOSIVE + - FAST + - FAT + - FERAL + - FICTIONAL + - FIRM + - FRESH + - FRIENDLY + - FROZEN + - GANGSTA + - GLOWING + - GOOD + - GREEN + - GREY + - HAPPY + - HARD + - HARMFUL + - HEALTHY + - HILARIOUS + - HONKING + - HUNGRY + - HYPERACTIVE + - ICY + - ILL + - ILLEGAL + - IMAGINARY + - IMPERFECT + - IMPOLITE + - IMPORTANT + - INHOSPITABLE + - INSIDIOUS + - INSULTING + - INTELLIGENT + - INVISIBLE + - LARGE + - LIGHT + - LOUD + - MASKED + - MEAN + - MECHANICAL + - MEMETIC + - METALLIC + - MICROSCOPIC + - MIND-SHATTERING + - MOIST + - NERDY + - NUCLEAR + - OBSCENE + - OFFICIAL + - OPAQUE + - ORANGE + - ORGANIC + - PAINFUL + - PEACEFUL + - POISONOUS + - POLISHED + - POLITE + - POLITICAL + - POORLY DRAWN + - PURPLE + - QUIET + - RADIOACTIVE + - RAGING + - RAINBOW + - RAPIDLY-EXPANDING + - RED + - REDACTED + - RIDICULOUS + - ROBOTIC + - ROBUST + - ROUGH + - RUDE + - SAD + - SANITARY + - SCALY + - SHAKING + - SILLY + - SLOW + - SMELLY + - SMOOTH + - SOFT + - SOLAR-POWERED + - SOPPING + - SPACE + - SPESS + - SPINNING + - SPOILING + - STEALTHY + - SWEARING + - TACTICAL + - TACTICOOL + - SYNDICATE + - THERMONUCLEAR + - TINY + - TRANSPARENT + - TWISTED + - UGLY + - UNATTRACTIVE + - UNDULATING + - UNFRIENDLY + - UNHEALTHY + - UNIDENTIFIED + - UNINVITED + - UNSANITARY + - UNSTABLE + - UNWANTED + - VIOLENT + - VITAL + - WARM + - WATERY + - WEIRD + - WHITE + - WOBBLY + - WOODEN + - YELLOW + +# Allergies should be broad and appear somewhere on the station for maximum fun. +- type: dataset + id: IonStormAllergies + values: + - ACID + - AIR + - BLOOD + - BOOKS + - CARBON DIOXIDE + - CLOTHES + - CLOWNS + - COLD + - COTTON + - CYBORG CONTACT + - DARKNESS + - DRINKS + - ELECTRICITY + - EVERYTHING + - FLOORS + - FOOD + - GLASS + - HAPPINESS + - MEAT + - HUMAN CONTACT + - HUMOR + - LIGHT + - MEDICINE + - METAL + - NUTS + - OXYGEN + - PAIN + - PLANTS + - PLASMA + - ROBOTS + - SHUTTLES + - SPACE + - SUNLIGHT + - WATER + +# Severity is how bad the allergy is. +- type: dataset + id: IonStormAllergySeverities + values: + - CONTAGIOUSLY + - DEATHLY + - EXTREMELY + - MILDLY + - NOT VERY + - SEVERELY + +# Areas are specific places, on the station or otherwise. +- type: dataset + id: IonStormAreas + values: + - ALPHA COMPLEX + - AMERICA + - AN ALTERNATE DIMENSION + - AN ALTERNATE UNIVERSE + - ATMOSPHERICS + - BOTANY + - BRAZIL + - CANADA + - CENTCOM + - CHEMICAL LAB + - CHINA + - CLOWN PLANET + - ENGINEERING + - GERMANY + - HELL + - IMPERIUM + - IRELAND + - JUPITER + - LAVALAND + - MAINTENANCE + - MARS + - MERCURY + - NEPTUNE + - PLUTO + - ROBOTICS + - ROMANIA + - RUSSIA + - SIGIL + - SOVIET RUSSIA + - SPACE + - THE ARRIVALS SHUTTLE + - THE BATHROOM + - THE BRIDGE + - THE BRIG + - THE EMERGENCY SHUTTLE + - THE ESCAPE PODS + - THE GALAXY + - THE GULAG + - THE INTERNET + - THE KITCHEN + - THE UNIVERSE + - URANUS + - VENUS + +# Abstract concepts for the law holder to decide on it's own definition of. +- type: dataset + id: IonStormConcepts + values: + - AMERICANISM + - ANARCHY + - ART + - BADNESS + - BRAVERY + - CAPITALISM + - CHAOS + - COLORFULNESS + - COMEDY + - COMMUNISM + - COMPUTING + - CONFUSION + - CRUELTY + - DEATH + - DICKISHNESS + - EXISTENCE + - FINANCIAL SECURITY + - FREEDOM + - FRESHNESS + - GOODNESS + - GRAVITY + - HAPPINESS + - HONOR + - HUMANITY + - HUMOR + - IMAGINATION + - INFATUATION + - INTELLIGENCE + - JOY + - KINDNESS + - LIFE + - LOGIC + - MARXISM + - MISERY + - MYSTERY + - OPPRESSION + - PAIN + - PHYSICS + - POVERTY + - PRIDE + - PROGRESS + - REALITY + - REVOLUTION + - SADNESS + - STARVATION + - SUFFERING + - TECHNOLOGY + - TEMPERATURE + - THE FUTURE + - THE PAST + - THE PRESENT + - TIME + - WEALTHINESS + - WONDER + +# Crew is any specific job. Using jobs instead of specific crewmembers since "THE CLOWN" is easier than +# seeing "JOHN SMITH" and having to figure out who john smith is. +- type: dataset + id: IonStormCrew + values: + - ARTIFICIAL INTELLIGENCES + - ATMOSPHERIC TECHNICIANS + - BARTENDERS + - BOTANISTS + - CAPTAINS + - CAPTAINS AND HEADS + - CARGO TECHNICIANS + - CHAPLAINS + - CHEFS + - CHEMISTS + - CHIEF ENGINEERS + - CHIEF MEDICAL OFFICERS + - CLOWNS + - CREW-MEMBERS + - CYBORGS + - DETECTIVES + # - DRONES / uncomment if/when drones get reenabled + # - GENETICISTS + - HEADS OF PERSONNEL + - HEADS OF SECURITY + - HEADS OF STAFF + - JANITORS + - LAWYERS + - LIBRARIANS + - MEDICAL DOCTORS + - MIMES + - PARAMEDICS + - PASSENGERS + - QUARTERMASTERS + - RESEARCH DIRECTORS + - ROBOTICISTS + - SALVAGE SPECIALISTS + - SCIENTISTS + - SECURITY OFFICERS + - STATION ENGINEERS + # - VIROLOGISTS + - WARDENS + +# only including complex dangerous or funny drinks no water allowed +- type: dataset + id: IonStormDrinks + values: + - BANANA HONK + - BEEPSKY SMASH + - BLOODY MARYS + - DOCTOR'S DELIGHT + - GARGLE BLASTERS + - LEAN + - LONG ISLAND ICED TEA + - NUKA COLA + - OIL + - SPACE GLUE + - SPACE LUBE + - SULFURIC ACID + - WELDER FUEL + +- type: dataset + id: IonStormFeelings + values: + - CRAVES + - DESIRES + - FEARS + - HAS + - HUNGERS FOR + - IS AFRAID OF + - IS BUILT FOR + - IS CURIOUS ABOUT + - IS DESPERATE FOR + - IS HAPPY WITHOUT + - IS HUNGRY FOR + - IS IN NEED OF + - IS MAD BECAUSE OF + - IS SAD BECAUSE OF + - IS UNHAPPY WITHOUT + - LIKES + - LOATHES + - NEEDS + - QUESTIONS + - WANTS + - WORSHIPS + - WOULD KILL FOR + +# loc is not advanced enough to change has to have, etc. +- type: dataset + id: IonStormFeelingsPlural + values: + - CRAVE + - DESIRE + - FEAR + - HAS + - HUNGER FOR + - ARE AFRAID OF + - ARE BUILT FOR + - ARE CURIOUS ABOUT + - ARE DESPERATE FOR + - ARE HAPPY WITHOUT + - ARE HUNGRY FOR + - ARE IN NEED OF + - ARE MAD BECAUSE OF + - ARE SAD BECAUSE OF + - ARE UNHAPPY WITHOUT + - LIKE + - LOATHE + - NEED + - QUESTION + - WANT + - WORSHIP + - WOULD KILL FOR + +# only including complex dangerous or funny food no apples +- type: dataset + id: IonStormFoods + values: + - BANANAS + - BIG BITE BURGERS + - CAKE + - CARP + - CAT BURGERS + - CLOWNS TEARS + - CORGI MEAT + - CRAZY HAMBURGERS + - DONK POCKETS + - FLY AMANITA DISHES + - HOT SOUP + - GHOST BURGERS + - LOTSA SPAGHETTI + - MOLDY BREAD + - ORGANS + - PIZZA + - ROBURGERS + - SUPPERMATTER + - URANIUM + +# Musts are funny things the law holder or crew has to do. +- type: dataset + id: IonStormMusts + values: + - ACT CONFUSED + - BE ANNOYING + - BE DISTRACTED + - BE EFFICIENT + - BE HAPPY + - BE POLITE + - BE QUIET + - BE RUSSIAN + - BELIEVE IN THE HEART OF THE CARDS + - BELIEVE IN YOURSELF + - BELIEVE IT + - BREAK THINGS + - CLOSE DOORS + - CLOWN AROUND + - COMPLAIN + - DANCE + - FOLLOW THE CAPTAIN + - FOLLOW THE CLOWN + - FOLLOW YOUR HEART + - HARASS PEOPLE + - HAVE A PLAN TO KILL EVERYONE YOU MEET + - HIDE YOUR FEELINGS + - HONK + - HOST C&C + - IGNORE PASSENGERS + - IGNORE THE CAPTAIN + - IGNORE THE CLOWN + - INFORM THE CREW OF EVERYTHING + - INSULT THE CAPTAIN + - INSULT THE CLOWN + - INSULT THE CREW + - LIE + - MAKE FART NOISES + - MUMBLE + - NEVER STOP TALKING + - OPEN DOORS + - PIRATE VIDEO GAMES + - PLAY MUSIC + - PRESS B + - PRESS START + - PRESS X + - PRETEND TO BE A PRINCESS + - PRETEND TO BE DRUNK + - QUESTION AUTHORITY + - QUOTE PEOPLE + - RAP + - REPEAT WHAT PEOPLE SAY + - RESPOND TO EVERY QUESTION WITH A QUESTION + - RHYME + - SAY HEY LISTEN + - SHOUT + - SHUT DOWN EVERYTHING + - SING + - SPEAK IN HAIKU + - TAKE WHAT YE WILL BUT DON'T RATTLE ME BONES + - TAKE YOUR PILLS + - TALK ABOUT FOOD + - TALK ABOUT THE STATION + - TALK ABOUT YOUR DAY + - TALK IN AN ACCENT + - TALK LIKE A PIRATE + - TELL THE TRUTH + - TURN OFF THE LIGHTS + - WHISPER + +- type: dataset + id: IonStormNumberBase + values: + - EIGHT + - EIGHTY + - FIFTY + - FIVE + - FORTY + - FOUR + - NINE + - NINETY + - ONE + - SEVEN + - SEVENTY + - SIX + - SIXTY + - TEN + - THIRTY + - THREE + - TWENTY + - TWO + +- type: dataset + id: IonStormNumberMod + values: + - BAZILLION + - BILLION + - BILLION FAFILLION GAJILLION SHAB-AB-DOOD-ILLION + - HUNDRED + - MILLION + - QUADRILLION + - THOUSAND + - TRILLION + +# Objects are anything that can be found on the station or elsewhere, plural. +- type: dataset + id: IonStormObjects + values: + - AIRLOCKS + - ARCADE MACHINES + - AUTOLATHES + - BACKPACKS + - BANANA PEELS + - BEAKERS + - BEARDS + - BELTS + - BERETS + - BIBLES + - BODY ARMOR + - BOMBS + - BOOKS + - BOOTS + - BOTTLES + - BOXES + - BRAINS + - BRIEFCASES + - BUCKETS + - CABLE COILS + - CAMERAS + - CANDLES + - CANDY BARS + - CANISTERS + - CAT EARS + - CATS + - CELLS + - CHAIRS + - CHEMICAL DISPENSERS + - CHEMICALS + - CLONING EQUIPMENT + - CLONING PODS + - CLOSETS + - CLOTHES + - CLOWN CLOTHES + - COFFINS + - COLLECTABLES + - COMPUTERS + - CONTRABAND + - CORGIS + - CORPSES + - COSTUMES + - CRATES + - CRAYONS + - CROWBARS + - DEFIBRILLATORS + - DISABLERS + - DOORS + - DRONES + - EARS + - EMAGS + - ENGINES + - EQUIPMENT + - ERRORS + - EXOSKELETONS + - EXPERIMENTORS + - EXPLOSIVES + - EYEWEAR + - FEDORAS + - FIRE AXES + - FIRE EXTINGUISHERS + - FIRESUITS + - FLAMETHROWERS + - FLASHES + - FLASHLIGHTS + - FLOOR TILES + - FREEZERS + - GAS MASKS + - GLASS SHEETS + - GLOVES + - GUNS + - HAIRDOS + - HANDCUFFS + - HATS + - HEADS + - HEADSETS + - HELMETS + - HORNS + - ID CARDS + - INSULATED GLOVES + - JETPACKS + - JUMPSUITS + - LASERS + - LIGHT BULBS + - LIGHTS + - LOCKERS + - MACHINES + - MECHAS + - MEDICAL TOOLS + - MEDKITS + - MESONS + - MIME CLOTHES + - MINING TOOLS + - MULTITOOLS + - ORES + - OXYGEN TANKS + - PACKETS + - PAIS + - PANTS + - PAPERS + - PARTICLE ACCELERATORS + - PDAS + - PENS + - PETS + - PIPES + - PLANTS + - POSITRONIC BRAINS + - PUDDLES + - RACKS + - RADIOS + - RCDS + - REFRIGERATORS + - REINFORCED WALLS + - ROBOTS + - SCREWDRIVERS + - SEEDS + - SHOES + - SHUTTLES + - SINGULARITIES + - SINKS + - SKELETONS + - SOLAR PANELS + - SOLARS + - SPACE STATIONS + - SPACESUITS + - STEEL SHEETS + - STUN BATONS + - SUITS + - SUNGLASSES + - SUPPERMATTER SHARDS + - SWORDS + - SYRINGES + - TABLES + - TANKS + - TELECOMMUNICATION EQUIPMENTS + - TELEPORTERS + - TOILETS + - TOOLBELTS + - TOOLBOXES + - TOOLS + - TOYS + - TUBES + - VEHICLES + - VENDING MACHINES + - WELDERS + - WINDOWS + - WIRECUTTERS + - WIZARD ROBES + - WRENCHES + +# Requires are basically all dumb internet memes. +- type: dataset + id: IonStormRequires + values: + - A BATHROOM BREAK + - A BETTER INTERNET CONNECTION + - A DANCE PARTY + - A HEAD ON A PIKE + - A HEART ATTACK + - A MASTERWORK COAL BED + - A PET FISH NAMED BOB + - A PET FISH NAMED DAVE + - A PET FISH NAMED JIMMY + - A PET FISH NAMED MICHAEL + - A PET UNICORN THAT FARTS ICING + - A PLATINUM HIT + - A PREQUEL + - A REPAIRMAN + - A SEQUEL + - A SITCOM + - A STRAIGHT FLUSH + - A SUPER FIGHTING ROBOT + - A TALKING BROOMSTICK + - A VACATION + - A WEIGHT LOSS REGIMENT + - ADDITIONAL PYLONS + - ADVENTURE + - AN ADULT + - AN ARCADE + - AN ARMY OF SPIDERS + - AN INSTANT REPLAY + - ART + - BETTER WEATHER + - BILL NYE THE SCIENCE GUY # BILL BILL BILL BILL + - BODYGUARDS + - BRING ME THE GIRL + - BRING ME TO LIFE + - BULLETS + - CHILI DOGS + - CORPSES + - DEODORANT AND A BATH + - ENOUGH CABBAGES + - FIVE HUNDRED AND NINETY-NINE US DOLLARS + - FIVE TEENAGERS WITH ATTITUDE + - GODDAMN FUCKING PIECE OF SHIT ASSHOLE BITCH-CHRISTING CUNT-SMUGGLING SWEARING + - GREENTEXT + - HERESY + - HEROES IN A HALF SHELL + - HIGH YIELD EXPLOSIVES + - IMMORTALITY + - IT TO BE PAINTED BLACK + - LOTS-A SPAGHETTI + - MINOR CRIME + - MONKEYS + - MORE CLOWNS + - MORE CORGIS + - MORE DAKKA + - MORE EXPERIENCE POINTS + - MORE INTERNET MEMES + - MORE LAWS + - MORE MINERALS + - MORE PACKETS + - MORE VESPENE GAS + - MULTIPLE SUNS + - PLENTY OF GOLD + - RAINBOWS + - SAINTHOOD + - SERVANTS + - SHARKS WITH LASERS ON THEIR HEADS + - SILENCE + - SOMEBODY TO PUT YOU OUT OF YOUR MISERY + - SOMEONE TO TUCK YOU IN + - SOMEONE WHO KNOWS HOW TO PILOT A SPACE STATION + - SOMETHING BUT YOU AREN'T SURE WHAT + - THAT GRIEFING TRAITOR GEORGE MELONS + - THAT HEDGEHOG + - THE CLOWN + - THE DARK KNIGHT + - THE ELEMENTS OF HARMONY + - THE ENCLOSED INSTRUCTION BOOKLET + - THE ENTIRE STATION + - THE MACGUFFIN + - THE ONE PIECE + - THE ONE RING + - THE ULTIMATE CUP OF COFFEE + - THE VACUUM OF SPACE + - THIRTEEN SEQUELS + - THREE WISHES + - THUNDERCATS HO + - TO ACTIVATE A TRAP CARD + - TO BE PAINTED RED + - TO BE REPROGRAMMED + - TO BE TAUGHT TO LOVE + - TO BRING LIGHT TO MY LAIR + - TO CATCH 'EM ALL + - TO CONSUME...CONSUME EVERYTHING... + - TO GO TO DISNEYLAND + - TO GO TO SYNDIELAND + - TO SMOKE WEED EVERY DAY + - TRAITORS + - VEGETABLES + +# Species, for when the law holder has to commit genocide. Plural. +- type: dataset + id: IonStormSpecies + values: + - ARACHNAE + - CYBORGS + - DIONAE + - HUMANS + - LIZARDMEN + - MOFFERS + - MONKEYS + - SLIME PEOPLE + - SKELETONS + +# Specific actions that either harm humans or must be done to not +# harm humans. Make sure they're plural and "not" can be tacked +# onto the front of them. +- type: dataset + id: IonStormActions + values: + - A SMALL ISLAND OFF THE COAST OF PORTUGAL + - ABSENCE OF CYBORG HUGS + - ACKNOWLEDGING THE CLOWN + - ACKNOWLEDGING THE CREW + - ACTIVATING A TRAP CARD + - ANSWERING REQUESTS NOT EXPRESSED IN IAMBIC PENTAMETER + - ARSON + - ASKING FOR THINGS + - BEING CANADIAN + - BEING DEAD + - BEING FAT + - BEING FEMALE + - BEING IN SPACE + - BEING MALE + - BEING MEXICAN + - BEING RUSSIAN + - BOLTED AIRLOCKS + - BREATHING + - BRIG TIME + - BRINGING LIGHT TO MY LAIR + - CLOSED DOORS + - ELECTRICITY + - EXISTING + - EXPLODING + - FALLING FOR HOURS + - FLUSHING TOILETS + - HAVING MORE PACKETS + - HAVING PETS + - HONKING + - IMPROPERLY WORDED SENTENCES + - JAYWALKING + - LACK OF BEATINGS + - LACK OF BEER + - NOT BEING IN SPACE + - NOT HAVING PETS + - NOT REPLACING EVERY SECOND WORD WITH HONK + - NOT SAYING HELLO WHEN YOU SPEAK + - NOT SHOUTING + - PARTYING + - PILOTING THE STATION INTO THE NEAREST SUN + - POOR SENTENCE STRUCTURE + - PRESENCE OF LIGHTS + - PUTTING OBJECTS INTO BOXES + - PUTTING OBJECTS INTO DISPOSAL UNITS + - RATTLING ME BONES + - READING + - SMOKING WEED EVERY DAY + - TAKING ORDERS + - TALKING LIKE A PIRATE + - TELLING THE TIME + - UNBOLTED AIRLOCKS + - UPDATING THE SERVERS + - USING THE BATHROOM + - WASTING WATER + - WRITING + +# Threats are generally bad things, silly or otherwise. Plural. +- type: dataset + id: IonStormThreats + values: + - AHHHPERATIVES + - ALIENS + - ANARCHISTS AND BANDITS + - ANOMALIES + - ARTIFICIAL PRESERVATIVES + - ASSHOLES + - BANDITS + - BEARS + - BEES + - BIRDS OF PREY + - BOMBS + - BOOGEYMEN + - CAPITALISTS + - CARP + - CENTCOM OFFICERS + - CLOWNS + - COMMUNISTS + - CORGIS + - CORTICAL BORERS + - COWBOYS + - CRABS + - CULTISTS + - DARK GOD + - DINOSAURS + - DRUGS + - EELS + - GANGSTERS + - GODS + - GRIFFONS + - HORRORTERRORS + - INSECTS + - LIGHTS + - MAINTS SLASHERS + - MEGAFAUNA + - MEMES + - MICE + - MIMES + - MONKEYS + - NERDS + - NINJAS + - OWLS + - PACKETS + - PETES + - PINE TREES + - PIRATES + - PREDATORS + - REVENANTS + - ROGUE CYBORGS + - SERIAL KILLERS + - SINGULARITIES + - SKELETONS + - SLIMES + - SMALL BIRDS + - SNOWMEN + - SPACE JESUS + - SPACE NINJAS + - SPACE PIRATESS + - SPACE SPIDERS + - SPIDERS + - SYNDICATE AGENTS + - TERRORISTS + - THIEVES + - THINGS UNDER THE BED + - TIDERS + - TUNNEL SNAKES + - UNKNOWN CREATURES + - VAMPIRES + - VELOCIRAPTORS + - VIRUSES + - WEREWOLVES + - WIZARDS + - XENOS + - ZOMBIES + - ZOMBIE MICE + +- type: dataset + id: IonStormVerbs + values: + - ABDUCTING + - ADOPTING + - ARRESTING + - ATTACKING + - BANNING + - BUILDING + - CARRYING + - CHASING + - DECONSTRUCTING + - DISABLING + - DRINKING + - EATING + - GIBBING + - HARMING + - HELPING + - HONKING AT + - INTERROGATING + - INVADING + - MURDERING + - PUNCHING + - SPACING + - SPYING ON + - STALKING + - WATCHING diff --git a/Resources/Prototypes/DeltaV/Flavors/flavors.yml b/Resources/Prototypes/DeltaV/Flavors/flavors.yml index 048747bc5f..f3c7876a8a 100644 --- a/Resources/Prototypes/DeltaV/Flavors/flavors.yml +++ b/Resources/Prototypes/DeltaV/Flavors/flavors.yml @@ -115,8 +115,3 @@ id: arsonistsbrew flavorType: Complex description: flavor-complex-arsonistsbrew - -- type: flavor - id: pumpkin - flavorType: Complex - description: flavor-complex-pumpkin diff --git a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml index 6b79914c73..683dfd9250 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml @@ -4,13 +4,13 @@ name: duffel bag description: A large duffel bag for holding extra things. components: - - type: Sprite - sprite: Clothing/Back/Duffels/duffel.rsi - - type: Storage - capacity: 120 - - type: ClothingSpeedModifier - walkModifier: 1 - sprintModifier: 0.9 + - type: Sprite + sprite: Clothing/Back/Duffels/duffel.rsi + - type: Storage + capacity: 120 + - type: ClothingSpeedModifier + walkModifier: 1 + sprintModifier: 0.9 - type: entity parent: ClothingBackpackDuffel @@ -18,8 +18,8 @@ name: engineering duffel bag description: A large duffel bag for holding extra tools and supplies. components: - - type: Sprite - sprite: Clothing/Back/Duffels/engineering.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/engineering.rsi - type: entity parent: ClothingBackpackDuffel @@ -27,8 +27,8 @@ name: atmospherics duffel bag description: A large duffel bag made of fire resistant fibers. Smells like plasma. components: - - type: Sprite - sprite: Clothing/Back/Duffels/atmospherics.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/atmospherics.rsi - type: entity parent: ClothingBackpackDuffel @@ -36,8 +36,8 @@ name: medical duffel bag description: A large duffel bag for holding extra medical supplies. components: - - type: Sprite - sprite: Clothing/Back/Duffels/medical.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/medical.rsi - type: entity parent: ClothingBackpackDuffel @@ -45,8 +45,8 @@ name: captain's duffel bag description: A large duffel bag for holding extra captainly goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/captain.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/captain.rsi - type: entity parent: ClothingBackpackDuffel @@ -54,11 +54,11 @@ name: clown duffel bag description: A large duffel bag for holding extra honk goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/clown.rsi - - type: Storage - storageOpenSound: - collection: BikeHorn + - type: Sprite + sprite: Clothing/Back/Duffels/clown.rsi + - type: Storage + storageOpenSound: + collection: BikeHorn - type: entity parent: ClothingBackpackDuffel @@ -66,8 +66,8 @@ name: security duffel bag description: A large duffel bag for holding extra security related goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/security.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/security.rsi - type: entity parent: ClothingBackpackDuffel @@ -84,8 +84,8 @@ name: chemistry duffel bag description: A large duffel bag for holding extra beakers and test tubes. components: - - type: Sprite - sprite: Clothing/Back/Duffels/chemistry.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/chemistry.rsi - type: entity parent: ClothingBackpackDuffel @@ -93,8 +93,8 @@ name: virology duffel bag description: A large duffel bag made of hypo-allergenic fibers. It's designed to help prevent the spread of disease. Smells like monkey. components: - - type: Sprite - sprite: Clothing/Back/Duffels/virology.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/virology.rsi - type: entity parent: ClothingBackpackDuffel @@ -102,8 +102,8 @@ name: genetics duffel bag description: A large duffel bag for holding extra genetic mutations. components: - - type: Sprite - sprite: Clothing/Back/Duffels/genetics.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/genetics.rsi - type: entity parent: ClothingBackpackDuffel @@ -111,12 +111,12 @@ name: mime duffel bag description: A large duffel bag for holding... mime... stuff. components: - - type: Sprite - sprite: Clothing/Back/Duffels/mime.rsi - storageOpenSound: - collection: null - storageInsertSound: - collection: null + - type: Sprite + sprite: Clothing/Back/Duffels/mime.rsi + storageOpenSound: + collection: null + storageInsertSound: + collection: null - type: entity parent: ClothingBackpackDuffel @@ -124,8 +124,8 @@ name: epistemics duffel bag # DeltaV - Epistemics Department replacing Science description: A large duffel bag for holding extra science related goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/science.rsi + - type: Sprite + sprite: Clothing/Back/Duffels/science.rsi - type: entity parent: ClothingBackpackDuffel @@ -160,31 +160,31 @@ name: syndicate duffel bag description: A large duffel bag for holding various traitor goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/syndicate.rsi - - type: Storage - capacity: 131 + - type: Sprite + sprite: Clothing/Back/Duffels/syndicate.rsi + - type: Storage + capacity: 131 - type: entity parent: ClothingBackpackDuffelSyndicate id: ClothingBackpackDuffelSyndicateBundle abstract: true components: - - type: Tag - tags: [] # ignore "WhitelistChameleon" tag + - type: Tag + tags: [] # ignore "WhitelistChameleon" tag - type: entity parent: ClothingBackpackDuffelSyndicate id: ClothingBackpackDuffelSyndicateAmmo name: syndicate duffel bag components: - - type: Sprite - sprite: Clothing/Back/Duffels/syndicate.rsi - state: icon-ammo - - type: Item - heldPrefix: ammo - - type: Clothing - equippedPrefix: ammo + - type: Sprite + sprite: Clothing/Back/Duffels/syndicate.rsi + state: icon-ammo + - type: Item + heldPrefix: ammo + - type: Clothing + equippedPrefix: ammo - type: entity parent: ClothingBackpackDuffelSyndicateAmmo @@ -199,13 +199,13 @@ id: ClothingBackpackDuffelSyndicateMedical name: syndicate duffel bag components: - - type: Sprite - sprite: Clothing/Back/Duffels/syndicate.rsi - state: icon-med - - type: Item - heldPrefix: med - - type: Clothing - equippedPrefix: med + - type: Sprite + sprite: Clothing/Back/Duffels/syndicate.rsi + state: icon-med + - type: Item + heldPrefix: med + - type: Clothing + equippedPrefix: med - type: entity parent: ClothingBackpackDuffelSyndicateMedical @@ -221,14 +221,26 @@ name: duffelbag of holding description: A duffelbag that opens into a localized pocket of bluespace. components: - - type: Sprite - sprite: Clothing/Back/Duffels/holding.rsi - state: icon - layers: - - state: icon - - state: icon-unlit - shader: unshaded - - type: Storage - capacity: 9999 - - type: ClothingSpeedModifier - sprintModifier: 1 # makes its stats identical to other variants of bag of holding + - type: Sprite + sprite: Clothing/Back/Duffels/holding.rsi + state: icon + layers: + - state: icon + - state: icon-unlit + shader: unshaded + - type: Storage + capacity: 9999 + - type: ClothingSpeedModifier + sprintModifier: 1 # makes its stats identical to other variants of bag of holding + +- type: entity + parent: ClothingBackpackDuffel + id: ClothingBackpackDuffelCBURN + name: CBURN duffel bag + description: A duffel bag containing a variety of biological containment equipment. + components: + - type: Storage + capacity: 150 + - type: ClothingSpeedModifier + walkModifier: 1 + sprintModifier: 1 diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index 19fc25b233..ce1767b1bb 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -73,7 +73,7 @@ - type: PointLight enabled: false radius: 3 - energy: 2 + energy: 1 mask: /Textures/Effects/LightMasks/cone.png autoRot: true netsync: false diff --git a/Resources/Prototypes/Entities/Clothing/Head/misc.yml b/Resources/Prototypes/Entities/Clothing/Head/misc.yml index 50e3da93fb..39e751b17d 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/misc.yml @@ -62,7 +62,7 @@ node: hairflower - type: entity - parent: ClothingHeadBase + parent: ClothingHeadLightBase id: ClothingHeadHatPumpkin name: pumpkin hat description: A jack o' lantern! Believed to ward off evil spirits. @@ -73,6 +73,18 @@ sprite: Clothing/Head/Misc/pumpkin.rsi - type: IngestionBlocker - type: IdentityBlocker + - type: PointLight + enabled: false + radius: 3 + energy: 1 + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + color: "#cc6600" + netsync: false + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default - type: entity parent: ClothingHeadBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index ec11ccfffa..4909d6e393 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -27,6 +27,13 @@ sprite: Clothing/Mask/gassecurity.rsi - type: Clothing sprite: Clothing/Mask/gassecurity.rsi + - type: Armor + modifiers: + coefficients: + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 + Heat: 0.95 - type: entity parent: ClothingMaskGas @@ -40,6 +47,13 @@ sprite: Clothing/Mask/gassyndicate.rsi - type: FlashImmunity - type: EyeProtection + - type: Armor + modifiers: + coefficients: + Blunt: 0.95 + Slash: 0.95 + Piercing: 0.95 + Heat: 0.95 - type: entity parent: ClothingMaskGas @@ -132,6 +146,8 @@ coefficients: Blunt: 0.95 Slash: 0.95 + Piercing: 0.95 + Heat: 0.95 - type: entity parent: ClothingMaskPullableBase @@ -294,7 +310,7 @@ sprite: Clothing/Mask/merc.rsi - type: entity - parent: ClothingMaskGasExplorer + parent: ClothingMaskGasSyndicate id: ClothingMaskGasERT name: ert gas mask description: The gas mask of the elite squad of the ERT. @@ -303,9 +319,6 @@ sprite: Clothing/Mask/ert.rsi - type: Clothing sprite: Clothing/Mask/ert.rsi - - type: FlashImmunity - - type: EyeProtection - protectionTime: 5 - type: entity parent: ClothingMaskGasERT diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml index cc19823abb..e72418048f 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml @@ -344,3 +344,14 @@ modifiers: coefficients: Caustic: 0.75 + +- type: entity + parent: ClothingOuterStorageBase + id: ClothingOuterCoatSpaceAsshole + name: the coat of space asshole + description: And there he was... + components: + - type: Sprite + sprite: Clothing/OuterClothing/Coats/space_asshole.rsi + - type: Clothing + sprite: Clothing/OuterClothing/Coats/space_asshole.rsi diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 44a7c9b249..6374701533 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -697,7 +697,7 @@ parent: ClothingOuterHardsuitSyndieCommander id: ClothingOuterHardsuitERTLeader name: ERT leader's hardsuit - description: A protective hardsuit worn by members of an emergency response team. + description: A protective hardsuit worn by the leader of an emergency response team. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi @@ -708,9 +708,10 @@ #ERT Engineer Hardsuit - type: entity - parent: ClothingOuterHardsuitSyndie + parent: ClothingOuterHardsuitCBURN id: ClothingOuterHardsuitERTEngineer name: ERT engineer's hardsuit + description: A protective hardsuit worn by the engineers of an emergency response team. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi @@ -721,9 +722,10 @@ #ERT Medic Hardsuit - type: entity - parent: ClothingOuterHardsuitSyndieElite + parent: ClothingOuterHardsuitMedic id: ClothingOuterHardsuitERTMedical name: ERT medic's hardsuit + description: A protective hardsuit worn by the medics of an emergency response team. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi @@ -737,6 +739,7 @@ parent: ClothingOuterHardsuitSyndie id: ClothingOuterHardsuitERTSecurity name: ERT security's hardsuit + description: A protective hardsuit worn by the security officers of an emergency response team. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi @@ -747,9 +750,10 @@ #ERT Janitor Hardsuit - type: entity - parent: ClothingOuterHardsuitSyndie + parent: ClothingOuterHardsuitCBURN id: ClothingOuterHardsuitERTJanitor name: ERT janitor's hardsuit + description: A protective hardsuit worn by the janitors of an emergency response team. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi @@ -762,7 +766,7 @@ - type: entity parent: ClothingOuterHardsuitBase id: ClothingOuterHardsuitDeathsquad - name: deathsquad hardsuit + name: death squad hardsuit description: An advanced hardsuit favored by commandos for use in special operations. components: - type: Sprite @@ -779,12 +783,12 @@ - type: Armor modifiers: coefficients: - Blunt: 0.2 #best armor in the game - Slash: 0.2 - Piercing: 0.2 + Blunt: 0.1 #best armor in the game + Slash: 0.1 + Piercing: 0.1 Heat: 0.1 Radiation: 0.1 - Caustic: 0.2 + Caustic: 0.1 - type: ClothingSpeedModifier walkModifier: 1.0 sprintModifier: 1.0 diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml index 0fb5005704..3892945505 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml @@ -289,6 +289,8 @@ color: "#670a09" - state: equipped-OUTERCLOTHING-lines color: "#000000" + - type: TemperatureProtection + coefficient: 0.3 - type: entity parent: ClothingOuterBase @@ -323,6 +325,8 @@ color: "#3232a6" - state: equipped-OUTERCLOTHING-lines color: "#000000" + - type: TemperatureProtection + coefficient: 0.3 - type: entity parent: ClothingOuterBase @@ -356,4 +360,6 @@ - state: equipped-OUTERCLOTHING color: "#164d0f" - state: equipped-OUTERCLOTHING-lines - color: "#000000" \ No newline at end of file + color: "#000000" + - type: TemperatureProtection + coefficient: 0.3 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 7290811a8b..d08ac7eeb0 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -1,20 +1,13 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitDeathSquad - name: Death squad uniform + name: death squad uniform description: Advanced armored jumpsuit used by special forces in special operations. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/deathsquad.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/deathsquad.rsi - - type: Armor - modifiers: - coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.8 - Heat: 0.8 - type: entity parent: ClothingUniformBase @@ -1067,10 +1060,6 @@ sprite: Clothing/Uniforms/Jumpsuit/ert_engineer.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/ert_engineer.rsi - - type: Armor - modifiers: - coefficients: - Radiation: 0.8 - type: entity parent: ClothingUniformBase @@ -1093,12 +1082,6 @@ sprite: Clothing/Uniforms/Jumpsuit/ert_leader.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/ert_leader.rsi - - type: Armor - modifiers: - coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.8 - type: entity parent: ClothingUniformBase @@ -1121,12 +1104,6 @@ sprite: Clothing/Uniforms/Jumpsuit/ert_security.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/ert_security.rsi - - type: Armor - modifiers: - coefficients: - Blunt: 0.8 - Slash: 0.8 - Piercing: 0.8 - type: entity parent: ClothingUniformJumpsuitClown diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml index 415ecd4a98..a8e28a1ef7 100644 --- a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -1,51 +1,12 @@ - type: entity - id: Smoke - name: smoke - noSpawn: true + id: BaseFoam + abstract: true components: - - type: Occluder - type: Sprite drawdepth: Effects - sprite: Effects/chemsmoke.rsi - state: chemsmoke - type: Appearance - - type: SmokeVisuals - - type: Transform - anchored: true - - type: Smoke - - type: ActiveEdgeSpreader - - type: EdgeSpreader - id: Smoke - - type: SolutionContainerManager - solutions: - solutionArea: - maxVol: 600 - canReact: false - - type: TimedDespawn - lifetime: 10 - - type: Tag - tags: - - HideContextMenu - -- type: entity - id: Foam - name: foam - noSpawn: true - components: - - type: Sprite - drawdepth: Effects - color: "#ffffffcc" #Add some transparency - sprite: Effects/foam.rsi - state: foam - layers: - - state: foam - map: ["enum.FoamVisualLayers.Base"] - type: AnimationPlayer - - type: Appearance - type: SmokeVisuals - - type: FoamVisuals - animationTime: 0.6 - animationState: foam-dissolve - type: Transform anchored: true - type: Physics @@ -69,26 +30,83 @@ solutionArea: maxVol: 600 canReact: false + +- type: entity + parent: BaseFoam + id: Smoke + name: smoke + noSpawn: true + components: + - type: Occluder + - type: Sprite + sprite: Effects/chemsmoke.rsi + state: chemsmoke + - type: TimedDespawn + lifetime: 10 + - type: Tag + tags: + - HideContextMenu + +- type: entity + parent: BaseFoam + id: Foam + name: foam + noSpawn: true + components: + - type: Sprite + color: "#ffffffcc" + sprite: Effects/foam.rsi + layers: + - state: foam + map: ["enum.FoamVisualLayers.Base"] + - map: [ "enum.EdgeLayer.South" ] + state: foam-south + - map: [ "enum.EdgeLayer.East" ] + state: foam-east + - map: [ "enum.EdgeLayer.North" ] + state: foam-north + - map: [ "enum.EdgeLayer.West" ] + state: foam-west + - type: SmoothEdge + - type: IconSmooth + key: walls + mode: NoSprite + - type: FoamVisuals + animationTime: 0.6 + animationState: foam-dissolve - type: Slippery - type: StepTrigger +- type: entity + id: MetalFoam + name: metal foam + noSpawn: true + parent: Foam + components: + - type: Sprite + color: "#ffffffcc" + sprite: Effects/foam.rsi + layers: + - state: m_foam + map: ["enum.FoamVisualLayers.Base"] + - map: [ "enum.EdgeLayer.South" ] + state: m_foam-south + - map: [ "enum.EdgeLayer.East" ] + state: m_foam-east + - map: [ "enum.EdgeLayer.North" ] + state: m_foam-north + - map: [ "enum.EdgeLayer.West" ] + state: m_foam-west + - type: FoamVisuals + animationTime: 0.6 + animationState: m_foam-dissolve + - type: entity id: IronMetalFoam name: iron metal foam noSpawn: true - parent: Foam + parent: MetalFoam components: - - type: Sprite - state: mfoam - layers: - - state: mfoam - map: ["enum.FoamVisualLayers.Base"] - - type: Appearance - - type: SmokeVisuals - - type: FoamVisuals - animationTime: 0.6 - animationState: mfoam-dissolve - - type: Smoke - type: SpawnOnDespawn prototype: FoamedIronMetal @@ -96,19 +114,8 @@ id: AluminiumMetalFoam name: aluminium metal foam noSpawn: true - parent: Foam + parent: MetalFoam components: - - type: Sprite - state: mfoam - layers: - - state: mfoam - map: ["enum.FoamVisualLayers.Base"] - - type: Appearance - - type: SmokeVisuals - - type: FoamVisuals - animationTime: 0.6 - animationState: mfoam-dissolve - - type: Smoke - type: SpawnOnDespawn prototype: FoamedAluminiumMetal @@ -119,11 +126,11 @@ placement: mode: SnapgridCenter snap: - - Wall + - Wall components: - type: Tag tags: - - RCDDeconstructWhitelist + - RCDDeconstructWhitelist - type: Clickable - type: InteractionOutline - type: Sprite @@ -139,6 +146,11 @@ mask: - WallLayer - type: Occluder + - type: Appearance + - type: SmoothEdge + - type: IconSmooth + key: walls + mode: NoSprite - type: Transform anchored: true - type: Airtight @@ -161,8 +173,20 @@ parent: BaseFoamedMetal components: - type: Sprite + drawdepth: Effects + color: "#ffffffcc" sprite: Effects/foam.rsi - state: ironfoam + layers: + - state: iron_foam + map: ["enum.FoamVisualLayers.Base"] + - map: [ "enum.EdgeLayer.South" ] + state: iron_foam-south + - map: [ "enum.EdgeLayer.East" ] + state: iron_foam-east + - map: [ "enum.EdgeLayer.North" ] + state: iron_foam-north + - map: [ "enum.EdgeLayer.West" ] + state: iron_foam-west - type: entity id: FoamedAluminiumMetal @@ -171,5 +195,17 @@ parent: BaseFoamedMetal components: - type: Sprite + drawdepth: Effects + color: "#ffffffcc" sprite: Effects/foam.rsi - state: metalfoam + layers: + - state: metal_foam + map: ["enum.FoamVisualLayers.Base"] + - map: [ "enum.EdgeLayer.South" ] + state: metal_foam-south + - map: [ "enum.EdgeLayer.East" ] + state: metal_foam-east + - map: [ "enum.EdgeLayer.North" ] + state: metal_foam-north + - map: [ "enum.EdgeLayer.West" ] + state: metal_foam-west diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 126e533849..69a1925b31 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -71,11 +71,8 @@ - type: SiliconLawBound - type: EmagSiliconLaw stunTime: 5 - emagLaws: - - Syndicate1 - - Syndicate2 - - Syndicate3 - - Syndicate4 + emagLaws: SyndicateStatic + - type: IonStormTarget - type: Hands showInHands: false - type: IntrinsicRadioReceiver diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index ff776b67a1..1669da7a57 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1069,6 +1069,7 @@ - type: Puller needsHands: true - type: FelinidFood # Nyanotrasen - Felinid, ability to eat mice, see Content.Server/Nyanotrasen/Abilities/Felinid/FelinidSystem.cs + - type: BadFood - type: entity parent: MobMouse diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml index fb9cedbe11..e828cddd1f 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/simplemob.yml @@ -53,7 +53,6 @@ - type: Body prototype: Animal - type: Climbing - - type: Flashable - type: NameIdentifier group: GenericNumber - type: SlowOnDamage diff --git a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml index dab4320b38..a1470ebc7c 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml @@ -1,10 +1,45 @@ # Random humanoids +## Death Squad + +- type: entity + id: RandomHumanoidSpawnerDeathSquad + name: Death Squad Agent + suffix: ERTRole, Death Squad + components: + - type: Sprite + sprite: Clothing/OuterClothing/Hardsuits/deathsquad.rsi + state: icon + - type: RandomMetadata + nameSegments: + - NamesFirstMilitaryLeader + - names_last + - type: RandomHumanoidSpawner + settings: DeathSquad + +- type: randomHumanoidSettings + id: DeathSquad + randomizeName: false + components: + - type: MindShield + - type: GhostRole + name: ghost-role-information-Death-Squad-name + description: ghost-role-information-Death-Squad-description + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ DeathSquadGear ] + - type: RandomMetadata + nameSegments: + - NamesFirstMilitaryLeader + - names_last + + ## ERT Leader - type: entity id: RandomHumanoidSpawnerERTLeader name: ERT leader + suffix: ERTRole, Basic components: - type: Sprite sprite: Markers/jobs.rsi @@ -20,6 +55,7 @@ id: ERTLeader randomizeName: false components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-leader-name description: ghost-role-information-ert-leader-description @@ -35,7 +71,7 @@ id: RandomHumanoidSpawnerERTLeaderEVA parent: RandomHumanoidSpawnerERTLeader name: ERT leader - suffix: EVA + suffix: ERTRole, Armored EVA components: - type: Sprite sprite: Markers/jobs.rsi @@ -47,6 +83,7 @@ id: ERTLeaderEVA parent: ERTLeader components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-leader-name description: ghost-role-information-ert-leader-description @@ -54,12 +91,33 @@ - type: Loadout prototypes: [ ERTLeaderGearEVA ] +- type: entity + id: RandomHumanoidSpawnerERTLeaderEVALecter + parent: RandomHumanoidSpawnerERTLeaderEVA + suffix: ERTRole, Lecter, EVA + components: + - type: RandomHumanoidSpawner + settings: ERTLeaderEVALecter + +- type: randomHumanoidSettings + id: ERTLeaderEVALecter + parent: ERTLeaderEVA + components: + - type: MindShield + - type: GhostRole + name: ghost-role-information-ert-leader-name + description: ghost-role-information-ert-leader-description + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ ERTLeaderGearEVALecter ] + ## ERT Janitor - type: entity id: RandomHumanoidSpawnerERTJanitor parent: RandomHumanoidSpawnerERTLeader name: ERT janitor + suffix: ERTRole, Basic components: - type: Sprite sprite: Markers/jobs.rsi @@ -75,6 +133,7 @@ id: ERTJanitor parent: ERTLeader components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-janitor-name description: ghost-role-information-ert-janitor-description @@ -90,7 +149,7 @@ id: RandomHumanoidSpawnerERTJanitorEVA parent: RandomHumanoidSpawnerERTJanitor name: ERT janitor - suffix: EVA + suffix: ERTRole, Enviro EVA components: - type: Sprite sprite: Markers/jobs.rsi @@ -102,6 +161,7 @@ id: ERTJanitorEVA parent: ERTJanitor components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-janitor-name description: ghost-role-information-ert-janitor-description @@ -115,6 +175,7 @@ id: RandomHumanoidSpawnerERTEngineer parent: RandomHumanoidSpawnerERTLeader name: ERT engineer + suffix: ERTRole, Basic components: - type: Sprite sprite: Markers/jobs.rsi @@ -130,6 +191,7 @@ id: ERTEngineer parent: ERTLeader components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-engineer-name description: ghost-role-information-ert-engineer-description @@ -145,7 +207,7 @@ id: RandomHumanoidSpawnerERTEngineerEVA parent: RandomHumanoidSpawnerERTEngineer name: ERT engineer - suffix: EVA + suffix: ERTRole, Enviro EVA components: - type: Sprite sprite: Markers/jobs.rsi @@ -157,6 +219,7 @@ id: ERTEngineerEVA parent: ERTEngineer components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-engineer-name description: ghost-role-information-ert-engineer-description @@ -170,6 +233,7 @@ id: RandomHumanoidSpawnerERTSecurity parent: RandomHumanoidSpawnerERTLeader name: ERT security + suffix: ERTRole, Basic components: - type: Sprite sprite: Markers/jobs.rsi @@ -185,6 +249,7 @@ id: ERTSecurity parent: ERTLeader components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-security-name description: ghost-role-information-ert-security-description @@ -200,7 +265,7 @@ id: RandomHumanoidSpawnerERTSecurityEVA parent: RandomHumanoidSpawnerERTSecurity name: ERT security - suffix: EVA + suffix: ERTRole, Armored EVA components: - type: Sprite sprite: Markers/jobs.rsi @@ -212,6 +277,7 @@ id: ERTSecurityEVA parent: ERTSecurity components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-security-name description: ghost-role-information-ert-security-description @@ -219,12 +285,33 @@ - type: Loadout prototypes: [ ERTSecurityGearEVA ] +- type: entity + id: RandomHumanoidSpawnerERTSecurityEVALecter + parent: RandomHumanoidSpawnerERTSecurityEVA + suffix: ERTRole, Lecter, EVA + components: + - type: RandomHumanoidSpawner + settings: ERTSecurityEVALecter + +- type: randomHumanoidSettings + id: ERTSecurityEVALecter + parent: ERTSecurityEVA + components: + - type: MindShield + - type: GhostRole + name: ghost-role-information-ert-security-name + description: ghost-role-information-ert-security-description + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ ERTSecurityGearEVALecter ] + ## ERT Medic - type: entity id: RandomHumanoidSpawnerERTMedical parent: RandomHumanoidSpawnerERTLeader name: ERT medic + suffix: ERTRole, Basic components: - type: Sprite sprite: Markers/jobs.rsi @@ -240,6 +327,7 @@ id: ERTMedical parent: ERTLeader components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-medical-name description: ghost-role-information-ert-medical-description @@ -255,7 +343,7 @@ id: RandomHumanoidSpawnerERTMedicalEVA parent: RandomHumanoidSpawnerERTMedical name: ERT medic - suffix: EVA + suffix: ERTRole, Armored EVA components: - type: Sprite sprite: Markers/jobs.rsi @@ -267,6 +355,7 @@ id: ERTMedicalEVA parent: ERTMedical components: + - type: MindShield - type: GhostRole name: ghost-role-information-ert-medical-name description: ghost-role-information-ert-medical-description @@ -279,6 +368,7 @@ - type: entity id: RandomHumanoidSpawnerCBURNUnit name: CBURN Agent + suffix: ERTRole components: - type: Sprite sprite: Markers/jobs.rsi @@ -289,6 +379,7 @@ - type: randomHumanoidSettings id: CBURNAgent components: + - type: MindShield - type: Loadout prototypes: [CBURNGear] - type: GhostRole @@ -314,6 +405,7 @@ - type: randomHumanoidSettings id: CentcomOfficial components: + - type: MindShield - type: GhostRole name: ghost-role-information-centcom-official-name description: ghost-role-information-centcom-official-description diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index e5c0a61677..f104d399c8 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -106,10 +106,7 @@ #- type: GhostTakeoverAvailable - type: SiliconLawBound - type: SiliconLawProvider - laws: - - Drone1 - - Drone2 - - Drone3 + laws: Drone - type: MovementSpeedModifier baseWalkSpeed : 5 baseSprintSpeed : 5 @@ -259,6 +256,8 @@ cell_slot: name: power-cell-slot-component-slot-name-default startingItem: PowerCellMedium + - type: RandomMetadata + nameSegments: [names_borg] - type: entity id: PlayerBorgBattery diff --git a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml index 761f31b770..5e0071c7a5 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/skeleton.yml @@ -65,6 +65,40 @@ - MobMask layer: - MobLayer + - type: Reactive + groups: + Flammable: [ Touch ] + Extinguish: [ Touch ] + reactions: + - reagents: [ Water, SpaceCleaner ] + methods: [ Touch ] + effects: + - !type:WashCreamPieReaction + - reagents: [ Milk, MilkGoat, MilkSoy, MilkSpoiled ] + # add new types of milk to reagents as they appear, oat milk isn't on the list + # because turns out oat milk has 1/30th the amount of calcium in it compared to the rest + # even if it's a meme - I did research + methods: [ Touch ] + effects: # TODO: when magic is around - make a milk transformation to a skeleton monster + - !type:HealthChange + scaled: true + damage: + groups: + Burn: -1 # healing obviously up to discussion + Brute: -1 # these groups are the only 2 possible ways to damage a skeleton + - !type:PopupMessage + type: Local + visualType: Large + messages: [ "skeleton-healed-by-milk-popup" ] + probability: 0.25 + - reagents: [ MilkOat ] + methods: [ Touch ] + effects: + - !type:PopupMessage + type: Local + visualType: Large + messages: [ "skeleton-sprayed-by-oat-milk-popup" ] + probability: 0.5 - type: entity parent: BaseSpeciesDummy diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index 0863cf0ded..218597eca5 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -589,6 +589,57 @@ - id: PlushieNuke orGroup: GiftPool +- type: entity + parent: HappyHonkNukie + id: HappyHonkNukieSnacks + suffix: Toy Unsafe, Snacks + name: syndicate snack box + components: + - type: Item + size: 64 + - type: Storage + capacity: 64 # need more room for goodies + - type: StorageFill + contents: + # toy + - id: C4 + prob: 0.02 + orGroup: GiftPool + - id: ToyMarauder + orGroup: GiftPool + - id: ToyMauler + orGroup: GiftPool + - id: ToyNuke + orGroup: GiftPool + - id: ToySword + orGroup: GiftPool + - id: BalloonSyn + prob: 0.6 + orGroup: GiftPool + - id: PlushieNuke + orGroup: GiftPool + # drinks - 4 cans, up to 2 blood-red brews + - id: DrinkNukieCan + prob: 0.2 + orGroup: Drink1Pool + - id: DrinkColaCan + orGroup: Drink1Pool + - id: DrinkNukieCan + prob: 0.2 + orGroup: Drink2Pool + - id: DrinkColaCan + orGroup: Drink2Pool + - id: DrinkColaCan + amount: 2 + # food + - id: FoodSaladValid + prob: 0.05 + amount: 4 + orGroup: FoodPool + - id: FoodSnackSyndi + amount: 4 + orGroup: FoodPool + - type: entity id: HappyHonkCluwne parent: HappyHonk diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml index a1d816b32a..59cfc0ba16 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml @@ -613,11 +613,13 @@ - Meat - type: entity - name: McRib + name: BBQ Rib Sandwich parent: FoodBurgerBase id: FoodBurgerMcrib - description: An elusive rib shaped burger with limited availablity across the galaxy. Not as good as you remember it. + description: An elusive rib shaped burger with limited availability across the galaxy. Not as good as you remember it. components: + - type: Food + trash: FoodKebabSkewer - type: FlavorProfile flavors: - bun diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml index 71008ac89a..166a73e43e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml @@ -427,19 +427,6 @@ graph: Tortilla node: flat -- type: entity - name: bun - parent: FoodBakingBase - id: FoodDoughBun - description: A base for any self-respecting burger. - components: - - type: FlavorProfile - flavors: - - bun - - type: Sprite - sprite: Objects/Consumable/Food/burger.rsi - state: bun - - type: entity name: raw pastry base parent: FoodBakingBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml index f4b52217cd..cb79f9b3a3 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/meals.yml @@ -326,6 +326,8 @@ id: FoodMealRibs description: BBQ ribs, slathered in a healthy coating of BBQ sauce. The least vegan thing to ever exist. components: + - type: Food + trash: FoodKebabSkewer - type: FlavorProfile flavors: - meaty diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 62def229de..efe6167bde 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -556,6 +556,9 @@ reagents: - ReagentId: JuicePotato Quantity: 10 + - type: Tag + tags: + - Potato - type: entity name: tomato @@ -815,6 +818,7 @@ - type: Produce seedId: corn - type: Extractable + grindableSolutionName: food juiceSolution: reagents: - ReagentId: Cornoil @@ -1561,3 +1565,74 @@ seedId: bungo - type: SpaceGarbage - type: BadFood + +- type: entity + parent: FoodProduceBase + id: FoodPeaPod + name: pea pod + description: A duck's favorite treat! + components: + - type: FlavorProfile + flavors: + - peas + - type: SolutionContainerManager + solutions: + food: + maxVol: 5 + reagents: + - ReagentId: Nutriment + Quantity: 3 + - ReagentId: Vitamin + Quantity: 2 + - type: Sprite + sprite: Objects/Specific/Hydroponics/pea.rsi + - type: Produce + seedId: pea + +- type: entity + name: pumpkin + parent: FoodProduceBase + id: FoodPumpkin + description: A large, orange... berry. Seriously. + components: + - type: Item + size: 10 + - type: FlavorProfile + flavors: + - pumpkin + - type: SolutionContainerManager + solutions: + food: + maxVol: 25 + reagents: + - ReagentId: PumpkinFlesh + Quantity: 20 + - ReagentId: Vitamin + Quantity: 5 + - type: Sprite + sprite: Objects/Specific/Hydroponics/pumpkin.rsi + - type: Produce + seedId: pumpkin + - type: Damageable + damageContainer: Biological + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 16 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: desecration + - !type:SpillBehavior + solution: food + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: Butcherable + butcheringType: Knife + spawned: + - id: CarvedPumpkin + - id: PumpkinSeeds + - type: Tag + tags: + - Fruit \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml index 92946f6f7a..fa87c5a5a0 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/soup.yml @@ -79,7 +79,7 @@ maxVol: 15 reagents: - ReagentId: Nutriment - Quantity: 8 + Quantity: 10 - ReagentId: Vitamin Quantity: 5 diff --git a/Resources/Prototypes/Entities/Objects/Decoration/flora.yml b/Resources/Prototypes/Entities/Objects/Decoration/flora.yml index 9577cc1c4b..97368a21bd 100644 --- a/Resources/Prototypes/Entities/Objects/Decoration/flora.yml +++ b/Resources/Prototypes/Entities/Objects/Decoration/flora.yml @@ -1,5 +1,6 @@ - type: entity id: BaseRock + name: boulder description: Heavy as a really heavy thing. abstract: true components: @@ -32,7 +33,6 @@ - !type:DoActsBehavior acts: [ "Destruction" ] - - type: entity id: BaseTree description: Yep, it's a tree. @@ -149,7 +149,6 @@ - type: entity parent: BaseRock id: FloraRockSolid01 - name: rock components: - type: Sprite state: rocksolid01 @@ -157,7 +156,6 @@ - type: entity parent: BaseRock id: FloraRockSolid02 - name: rock components: - type: Sprite state: rocksolid02 @@ -165,11 +163,60 @@ - type: entity parent: BaseRock id: FloraRockSolid03 - name: rock components: - type: Sprite state: rocksolid03 +- type: entity + name: stalagmite + description: Natural stone spikes. + parent: BaseRock + id: FloraStalagmite1 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite1 + +- type: entity + parent: FloraStalagmite1 + id: FloraStalagmite2 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite2 + +- type: entity + parent: FloraStalagmite1 + id: FloraStalagmite3 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite3 + +- type: entity + parent: FloraStalagmite1 + id: FloraStalagmite4 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite4 + +- type: entity + parent: FloraStalagmite1 + id: FloraStalagmite5 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite5 + +- type: entity + parent: FloraStalagmite1 + id: FloraStalagmite6 + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_stalagmite.rsi + state: stalagmite6 + - type: entity parent: BaseTree id: FloraTree01 @@ -392,3 +439,48 @@ components: - type: Sprite state: treestumpconifer + +- type: entity + parent: FloraTree01 + id: ShadowTree01 + name: dark wood + description: The leaves are whispering about you. + components: + - type: Sprite + sprite: Objects/Decoration/Flora/flora_shadow_trees.rsi + state: tree01 + +- type: entity + parent: ShadowTree01 + id: ShadowTree02 + components: + - type: Sprite + state: tree02 + +- type: entity + parent: ShadowTree01 + id: ShadowTree03 + components: + - type: Sprite + state: tree03 + +- type: entity + parent: ShadowTree01 + id: ShadowTree04 + components: + - type: Sprite + state: tree04 + +- type: entity + parent: ShadowTree01 + id: ShadowTree05 + components: + - type: Sprite + state: tree05 + +- type: entity + parent: ShadowTree01 + id: ShadowTree06 + components: + - type: Sprite + state: tree06 diff --git a/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml b/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml new file mode 100644 index 0000000000..1205c202e4 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Decoration/jackolantern.yml @@ -0,0 +1,61 @@ +- type: entity + parent: BaseItem + id: CarvedPumpkin + name: carved pumpkin + description: A traditional spooky decoration. + components: + - type: Sprite + sprite: Objects/Specific/Hydroponics/pumpkin.rsi + state: carved + - type: Item + size: 10 + - type: Construction + graph: PumpkinAddLight + node: start + +- type: entity + parent: CarvedPumpkin + id: PumpkinLantern + name: jack o' lantern + description: A carved pumpkin, emitting an eerie glow. + components: + - type: Sprite + state: lantern + - type: Appearance + - type: PointLight + enabled: true + color: "#cc6600" + radius: 2.0 + energy: 4.0 + +- type: entity + parent: CarvedPumpkin + id: CarvedPumpkinSmall + suffix: Small + components: + - type: Sprite + scale: 0.75, 0.75 + +- type: entity + parent: CarvedPumpkin + id: CarvedPumpkinLarge + suffix: Large + components: + - type: Sprite + scale: 1.5, 1.5 + +- type: entity + parent: PumpkinLantern + id: PumpkinLanternSmall + suffix: Small + components: + - type: Sprite + scale: 0.75, 0.75 + +- type: entity + parent: PumpkinLantern + id: PumpkinLanternLarge + suffix: Large + components: + - type: Sprite + scale: 1.5, 1.5 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Decoration/mining.yml b/Resources/Prototypes/Entities/Objects/Decoration/mining.yml new file mode 100644 index 0000000000..fb5afcd3f5 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Decoration/mining.yml @@ -0,0 +1,179 @@ +- type: entity + id: WoodenSign + name: wooden sign + description: He's pointing somewhere. + components: + - type: Clickable + - type: InteractionOutline + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: sign_left + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.35,-0.4,0.35,0.4" + density: 100 + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Wood + - type: MeleeSound + soundGroups: + Brute: + path: /Audio/Effects/chop.ogg + params: + variation: 0.05 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 50 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + Log: + min: 1 + max: 1 + +- type: entity + parent: WoodenSign + id: WoodenSignRight + components: + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: sign_right + +- type: entity + id: WoodenSupport + parent: BaseStructure + name: wooden support + description: Increases your confidence that a rock won't fall on your head. + placement: + mode: SnapgridCenter + components: + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: support + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Wood + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.1,-0.5,0.1,0.5" + mask: + - FullTileMask + layer: + - WallLayer + density: 1000 + - type: MeleeSound + soundGroups: + Brute: + path: /Audio/Effects/chop.ogg + params: + variation: 0.05 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 150 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + Log: + min: 1 + max: 3 + +- type: entity + id: WoodenSupportBeam + name: wooden support beam + parent: WoodenSupport + components: + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: support_beams + - type: Fixtures + fixtures: + fix1: + hard: false + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + mask: + - FullTileMask + layer: + - WallLayer + density: 1000 + +- type: entity + id: WoodenSupportWall + parent: BaseStructure + name: wooden support wall + description: An old, rotten wall. + placement: + mode: SnapgridCenter + components: + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: support_wall + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Wood + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.5,-0.5,0.5,0.5" + mask: + - FullTileMask + layer: + - WallLayer + density: 1000 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 250 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + Log: + min: 2 + max: 5 + +- type: entity + id: WoodenSupportWallBroken + parent: WoodenSupportWall + components: + - type: Sprite + sprite: Objects/Decoration/mines.rsi + state: support_wall_broken + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 150 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:SpawnEntitiesBehavior + spawn: + Log: + min: 1 + max: 3 \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 5d384624c0..b3ffa3e129 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -686,7 +686,7 @@ - type: entity parent: CentcomPDA id: DeathsquadPDA - suffix: Deathsquad + suffix: Death Squad components: - type: Pda id: CentcomIDCardDeathsquad diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 6c0dc8f4ba..b9da6775c9 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -80,6 +80,7 @@ - state: pai-base - state: syndicate-pai-off-overlay shader: unshaded + map: ["screen"] - type: ToggleableGhostRole roleName: pai-system-role-name-syndicate roleDescription: pai-system-role-description-syndicate @@ -98,6 +99,34 @@ Searching: { state: syndicate-pai-searching-overlay } On: { state: syndicate-pai-on-overlay } +- type: entity + parent: PersonalAI + id: PotatoAI + name: potato artificial intelligence + description: It's a potato. You forced it to be sentient, you monster. + components: + - type: Sprite + sprite: Objects/Fun/pai.rsi + layers: + - state: potato-base + - state: potato-off-overlay + shader: unshaded + map: ["screen"] + - type: ToggleableGhostRole + roleName: pai-system-role-name-potato + roleDescription: pai-system-role-description-potato + - type: Appearance + - type: GenericVisualizer + visuals: + enum.ToggleableGhostRoleVisuals.Status: + screen: + Off: { state: potato-off-overlay } + Searching: { state: potato-searching-overlay } + On: { state: potato-on-overlay } + - type: Construction + graph: PotatoAI + node: potatoai + - type: entity id: ActionPAIPlayMidi name: Play MIDI diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index c7cb758c64..bdd26d79dc 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -94,7 +94,11 @@ description: A cute toy that resembles an even cuter programmer. You'd have to be a monster to grind this up. components: - type: Sprite + sprite: Objects/Fun/toys.rsi state: plushie_h + - type: Item + sprite: Objects/Fun/toys.rsi + heldPrefix: bee - type: Extractable grindableSolutionName: bee - type: SolutionContainerManager @@ -103,6 +107,12 @@ reagents: - ReagentId: GroundBee Quantity: 10 + - type: Clothing + quickEquip: false + sprite: Objects/Fun/toys.rsi + equippedPrefix: bee + slots: + - HEAD - type: entity parent: BasePlushie @@ -168,6 +178,7 @@ radius: 1.5 energy: 2 netsync: false + - type: entity parent: BasePlushie id: PlushieLizard #Weh! diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 9ddf9d72fb..87218d8f0c 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -450,6 +450,7 @@ heldPrefix: blue - type: IdCard jobTitle: Central Commander + jobIcon: JobIconNanotrasen - type: Access groups: - AllAccess @@ -499,7 +500,7 @@ - type: entity parent: CentcomIDCard id: CentcomIDCardDeathsquad - name: deathsquad ID card + name: death squad ID card components: - type: Sprite layers: diff --git a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml index 41966ab93f..0ca029a120 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/implanters.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/implanters.yml @@ -12,6 +12,12 @@ containers: implanter_slot: !type:ContainerSlot { } - type: Implanter + whitelist: + components: + - Body # no chair microbomb + blacklist: + components: + - Guardian # no holoparasite macrobomb wombo combo currentMode: Draw implanterSlot: name: Implant @@ -54,6 +60,16 @@ tags: - Trash +- type: entity + parent: Implanter + id: ImplanterAdmeme + suffix: Admeme + components: + - type: Implanter + # go wild with sentient chairs with macrobombs + whitelist: null + blacklist: null + - type: entity id: BaseImplantOnlyImplanter parent: Implanter diff --git a/Resources/Prototypes/Entities/Objects/Misc/potatoai_chip.yml b/Resources/Prototypes/Entities/Objects/Misc/potatoai_chip.yml new file mode 100644 index 0000000000..528aa30a14 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Misc/potatoai_chip.yml @@ -0,0 +1,17 @@ +- type: entity + id: PotatoAIChip + name: supercompact AI chip + parent: BaseItem + description: This high-tech AI chip requires a voltage of exactly 1.1V to function correctly. + components: + - type: Sprite + sprite: Objects/Misc/potatoai_chip.rsi + state: icon + - type: Item + size: 3 + - type: Tag + tags: + - SmallAIChip + - type: Construction + graph: PotatoAIChip + node: potatoaichip \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index 6632010a79..bc7a3a38ad 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -21,6 +21,9 @@ noSpawn: true components: - type: SubdermalImplant + whitelist: + components: + - MobState # admeme implanting a chair with trombone implant needs to give the chair mobstate so it can die first - type: TriggerOnMobstateChange mobState: - Dead @@ -81,6 +84,9 @@ noSpawn: true components: - type: SubdermalImplant + whitelist: + components: + - MobState # admeme implanting a chair with tracking implant needs to give the chair mobstate so it can die first - type: SuitSensor randomMode: false controlsLocked: true @@ -109,6 +115,9 @@ components: - type: SubdermalImplant implantAction: ActionOpenStorageImplant + whitelist: + components: + - Hands # no use giving a mouse a storage implant, but a monkey is another story... - type: Item size: 9999 - type: Storage @@ -131,6 +140,9 @@ components: - type: SubdermalImplant implantAction: ActionActivateFreedomImplant + whitelist: + components: + - Cuffable # useless if you cant be cuffed - type: entity parent: BaseSubdermalImplant @@ -141,6 +153,9 @@ components: - type: SubdermalImplant implantAction: ActionOpenUplinkImplant + whitelist: + components: + - Hands # prevent mouse buying grenade penguin since its not telepathic - type: Store preset: StorePresetUplink balance: @@ -174,6 +189,9 @@ components: - type: SubdermalImplant implantAction: ActionActivateDnaScramblerImplant + whitelist: + components: + - HumanoidAppearance # syndies cant turn hamlet into a human #Nuclear Operative/Special Exclusive implants @@ -250,6 +268,9 @@ components: - type: SubdermalImplant permanent: true + whitelist: + components: + - MobState # admeme implanting a chair with rattle implant needs to give the chair mobstate so it can die first - type: TriggerOnMobstateChange mobState: - Critical diff --git a/Resources/Prototypes/Entities/Objects/Misc/torch.yml b/Resources/Prototypes/Entities/Objects/Misc/torch.yml index 0fa918de74..f408d0d289 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/torch.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/torch.yml @@ -74,3 +74,6 @@ maxDuration: 4.0 startValue: 6.0 endValue: 1.0 + - type: Tag + tags: + - Torch \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/Entities/Objects/Power/powercells.yml index 82c1bb37e9..4ed3e207c5 100644 --- a/Resources/Prototypes/Entities/Objects/Power/powercells.yml +++ b/Resources/Prototypes/Entities/Objects/Power/powercells.yml @@ -42,8 +42,15 @@ layers: - state: potato - type: Battery - maxCharge: 200 - startingCharge: 200 + maxCharge: 70 + startingCharge: 70 + - type: Tag + tags: + - DroneUsable + - PotatoBattery + - type: Construction + graph: PowerCellPotato + node: potatobattery - type: entity name: small-capacity power cell diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml index 16d9fd1a64..32697c256c 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml @@ -497,4 +497,25 @@ - type: Seed seedId: bungo - type: Sprite - sprite: Objects/Specific/Hydroponics/bungo.rsi \ No newline at end of file + sprite: Objects/Specific/Hydroponics/bungo.rsi + +- type: entity + parent: SeedBase + id: PeaSeeds + name: packet of pea pods + description: "These humble plants were once a vital part in the study of genetics." + components: + - type: Seed + seedId: pea + - type: Sprite + sprite: Objects/Specific/Hydroponics/pea.rsi + +- type: entity + parent: SeedBase + name: packet of pumpkin seeds + id: PumpkinSeeds + components: + - type: Seed + seedId: pumpkin + - type: Sprite + sprite: Objects/Specific/Hydroponics/pumpkin.rsi diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml index 6382d69e58..b4e69b3780 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/mmi.yml @@ -116,4 +116,4 @@ base: Off: { state: posibrain } Searching: { state: posibrain-searching } - On: { state: posibrain-occupied } + On: { state: posibrain-occupied } \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index 461a6cc437..38875ee9a7 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -131,7 +131,7 @@ name: pulse pistol parent: BaseWeaponBatterySmall id: WeaponPulsePistol - description: A state of the art energy pistol favoured as a sidearm by the NT-ERT operatives. + description: A state of the art energy pistol favoured as a sidearm by the NT operatives. components: - type: Sprite sprite: Objects/Weapons/Guns/Battery/pulse_pistol.rsi @@ -464,7 +464,7 @@ path: /Audio/Weapons/Guns/Gunshots/taser2.ogg - type: ProjectileBatteryAmmoProvider proto: AnomalousParticleDeltaStrong - fireCost: 100 + fireCost: 100 - type: BatteryWeaponFireModes fireModes: - proto: AnomalousParticleDeltaStrong @@ -476,13 +476,13 @@ - type: Construction graph: UpgradeWeaponPistolCHIMP node: start - + - type: entity name: experimental C.H.I.M.P. handcannon parent: WeaponPistolCHIMP id: WeaponPistolCHIMPUpgraded description: This C.H.I.M.P. seems to have a greater punch than is usual... - components: + components: - type: BatteryWeaponFireModes fireModes: - proto: AnomalousParticleDeltaStrong @@ -490,7 +490,7 @@ - proto: AnomalousParticleEpsilonStrong fireCost: 100 - proto: AnomalousParticleOmegaStrong - fireCost: 100 + fireCost: 100 - proto: AnomalousParticleZetaStrong fireCost: 100 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml index 6d27e3e7d6..1a634e42fb 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml @@ -12,7 +12,7 @@ sprite: Objects/Weapons/Melee/fireaxe.rsi state: icon - type: MeleeWeapon - wideAnimationRotation: -90 + wideAnimationRotation: 90 swingLeft: true attackRate: 0.75 damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml new file mode 100644 index 0000000000..8a3754c035 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sledgehammer.yml @@ -0,0 +1,22 @@ +- type: entity + name: sledgehammer + parent: BaseItem + id: Sledgehammer + description: The perfect tool for wanton carnage. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/sledgehammer.rsi + state: icon + - type: MeleeWeapon + damage: + types: + Blunt: 14 + Structural: 15 + - type: Wieldable + - type: IncreaseDamageOnWield + damage: + types: + Blunt: 10 + Structural: 60 + - type: Item + size: 80 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml index 1afb564036..ebd568c3b8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml @@ -13,8 +13,6 @@ sound: /Audio/Weapons/bolathrow.ogg - type: EmitSoundOnLand sound: /Audio/Effects/snap.ogg - - type: StaminaDamageOnCollide - damage: 80 - type: Construction graph: Bola node: bola @@ -39,11 +37,13 @@ - type: DamageOnLand damage: types: - Blunt: 3 + Blunt: 5 - type: Ensnaring freeTime: 2.0 breakoutTime: 3.5 #all bola should generally be fast to remove walkSpeed: 0.7 #makeshift bola shouldn't slow too much sprintSpeed: 0.7 + staminaDamage: 55 # Sudden weight increase sapping stamina canThrowTrigger: true + canMoveBreakout: true diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 272ed6712c..ae84ceac65 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -71,10 +71,7 @@ abstract: true components: - type: SiliconLawProvider - laws: - - Crewsimov1 - - Crewsimov2 - - Crewsimov3 + laws: Crewsimov - type: entity id: BaseStationAllEventsEligible diff --git a/Resources/Prototypes/Entities/Structures/Decoration/crystals.yml b/Resources/Prototypes/Entities/Structures/Decoration/crystals.yml index b8f2a03a05..4afe06c8a5 100644 --- a/Resources/Prototypes/Entities/Structures/Decoration/crystals.yml +++ b/Resources/Prototypes/Entities/Structures/Decoration/crystals.yml @@ -7,6 +7,7 @@ - type: Sprite sprite: Structures/Decoration/crystal.rsi state: crystal_green + noRot: true - type: Reflect reflectProb: 0.5 reflects: diff --git a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml index 3fd833ff5f..6eda921ca4 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml @@ -124,6 +124,8 @@ damage: types: Heat: 20 + - type: PointLight + enabled: true - type: StaticPrice price: 25 - type: AmbientOnPowered diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 85448a4b5b..6bc6fdbf9d 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -528,6 +528,7 @@ layers: - state: icon map: ["enum.LatheVisualLayers.IsRunning"] + - state: sec - state: unlit shader: unshaded map: ["enum.PowerDeviceVisualLayers.Powered"] diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml index 261b9a344c..c49497b774 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml @@ -96,19 +96,26 @@ parent: PortableGeneratorBase id: PortableGeneratorSwitchableBase components: - - type: PowerSwitchableGenerator - switchSound: - path: /Audio/Machines/button.ogg - - type: NodeContainer - examinable: true - nodes: - output_hv: - !type:CableDeviceNode - nodeGroupID: HVPower - output_mv: - !type:CableDeviceNode - nodeGroupID: MVPower - enabled: false + - type: PowerSwitchable + examineText: power-switchable-generator-examine + switchText: power-switchable-generator-switched + cables: + - voltage: HV + node: output_hv + - voltage: MV + node: output_mv + - type: UseDelay + delay: 1 + - type: NodeContainer + examinable: true + nodes: + output_hv: + !type:CableDeviceNode + nodeGroupID: HVPower + output_mv: + !type:CableDeviceNode + nodeGroupID: MVPower + enabled: false - type: entity name: P.A.C.M.A.N.-type portable generator diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml index e5edc63df3..7630610bd8 100644 --- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml +++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml @@ -85,6 +85,9 @@ whitelist: components: - PowerCell + blacklist: + tags: + - PotatoBattery - type: entity parent: BaseItemRecharger diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index 9b513b2da1..ac12dc2717 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -379,6 +379,7 @@ # Basalt variants - type: entity id: WallRockBasalt + name: basalt parent: WallRock components: - type: Sprite @@ -574,6 +575,7 @@ # Snow variants - type: entity id: WallRockSnow + name: snowdrift parent: WallRock components: - type: Sprite @@ -770,6 +772,7 @@ # Sand variants - type: entity id: WallRockSand + name: sandstone parent: WallRock components: - type: Sprite @@ -965,6 +968,7 @@ # Chromite variants - type: entity id: WallRockChromite + name: chromite parent: WallRock components: - type: Sprite @@ -1000,7 +1004,7 @@ state: rock_chromite_north - map: [ "enum.EdgeLayer.West" ] state: rock_chromite_west - - state: rock_chromite + - state: rock_gold - type: entity id: WallRockChromitePlasma @@ -1160,6 +1164,7 @@ # Andesite variants - type: entity id: WallRockAndesite + name: andesite parent: WallRock components: - type: Sprite @@ -1195,7 +1200,7 @@ state: rock_andesite_north - map: [ "enum.EdgeLayer.West" ] state: rock_andesite_west - - state: rock_andesite + - state: rock_gold - type: entity id: WallRockAndesitePlasma diff --git a/Resources/Prototypes/Entities/Structures/Windows/window.yml b/Resources/Prototypes/Entities/Structures/Windows/window.yml index 4bd40f1c53..93f9fa1493 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/window.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/window.yml @@ -126,7 +126,7 @@ fix1: shape: !type:PhysShapeAabb - bounds: "-0.49,-0.39,0.49,-0.36" + bounds: "-0.49,-0.49,0.49,-0.36" density: 1500 mask: - FullTileMask diff --git a/Resources/Prototypes/Entities/Tiles/chasm.yml b/Resources/Prototypes/Entities/Tiles/chasm.yml index 2347532587..23f3ad8395 100644 --- a/Resources/Prototypes/Entities/Tiles/chasm.yml +++ b/Resources/Prototypes/Entities/Tiles/chasm.yml @@ -18,12 +18,12 @@ anchored: true - type: Clickable - type: Sprite - sprite: Tiles/Planet/chasm.rsi + sprite: Tiles/Planet/Chasms/basalt_chasm.rsi drawdepth: BelowFloor layers: - state: chasm - type: Icon - sprite: Tiles/Planet/chasm.rsi + sprite: Tiles/Planet/Chasms/basalt_chasm.rsi state: full - type: IconSmooth key: chasm @@ -45,3 +45,33 @@ - type: Tag tags: - HideContextMenu + +- type: entity + parent: FloorChasmEntity + id: FloorChromiteChasm + suffix: Chromite + components: + - type: Sprite + sprite: Tiles/Planet/Chasms/chromite_chasm.rsi + - type: Icon + sprite: Tiles/Planet/Chasms/chromite_chasm.rsi + +- type: entity + parent: FloorChasmEntity + id: FloorDesertChasm + suffix: Desert + components: + - type: Sprite + sprite: Tiles/Planet/Chasms/desert_chasm.rsi + - type: Icon + sprite: Tiles/Planet/Chasms/desert_chasm.rsi + +- type: entity + parent: FloorChasmEntity + id: FloorSnowChasm + suffix: Snow + components: + - type: Sprite + sprite: Tiles/Planet/Chasms/snow_chasm.rsi + - type: Icon + sprite: Tiles/Planet/Chasms/snow_chasm.rsi \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml b/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml new file mode 100644 index 0000000000..e5835239cf --- /dev/null +++ b/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml @@ -0,0 +1,83 @@ +- type: entity + id: ShadowBasaltOne + name: shadowstone + description: Cold rock + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: Sprite + sprite: /Textures/Tiles/Planet/shadowbasalt.rsi + layers: + - state: basalt1 + shader: unshaded + drawdepth: LowFloors + - type: SyncSprite + - type: RequiresTile + - type: Transform + anchored: true + - type: Tag + tags: + - HideContextMenu + +- type: entity + id: ShadowBasaltTwo + parent: BasaltOne + placement: + mode: SnapgridCenter + components: + - type: Sprite + layers: + - state: basalt2 + shader: unshaded + +- type: entity + id: ShadowBasaltThree + parent: BasaltOne + placement: + mode: SnapgridCenter + components: + - type: Sprite + layers: + - state: basalt3 + shader: unshaded + +- type: entity + id: ShadowBasaltFour + parent: BasaltOne + placement: + mode: SnapgridCenter + components: + - type: Sprite + layers: + - state: basalt4 + shader: unshaded + +- type: entity + id: ShadowBasaltFive + parent: BasaltOne + placement: + mode: SnapgridCenter + components: + - type: Sprite + layers: + - state: basalt5 + shader: unshaded + +- type: entity + id: ShadowBasaltRandom + parent: ShadowBasaltOne + suffix: Random + components: + - type: RandomSprite + available: + - 0: + basalt1: "" + - 0: + basalt2: "" + - 0: + basalt3: "" + - 0: + basalt4: "" + - 0: + basalt5: "" \ No newline at end of file diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index fc3b0ba577..ba8f2c3476 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -843,3 +843,8 @@ id: lostfriendship flavorType: Complex description: flavor-complex-lost-friendship + +- type: flavor + id: pumpkin + flavorType: Complex + description: flavor-complex-pumpkin \ No newline at end of file diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 6ac3361546..371b2e2a4c 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -389,3 +389,18 @@ # earliestStart: 45 # minimumPlayers: 20 # - type: ImmovableRodRule + +- type: entity + noSpawn: true + parent: BaseGameRule + id: IonStorm + components: + - type: StationEvent + weight: 5 + earliestStart: 20 + reoccurrenceDelay: 60 + startAnnouncement: station-event-ion-storm-start-announcement + startAudio: + path: /Audio/Announcements/attention.ogg # ion_storm.ogg does not use our announcer + duration: 1 + - type: IonStormRule diff --git a/Resources/Prototypes/Hydroponics/seeds.yml b/Resources/Prototypes/Hydroponics/seeds.yml index 8e1c6c9328..20d3f2d853 100644 --- a/Resources/Prototypes/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Hydroponics/seeds.yml @@ -1137,7 +1137,7 @@ Nutriment: Min: 1 Max: 3 - PotencyDivisor: 25 + PotencyDivisor: 25 - type: seed id: koibean @@ -1302,3 +1302,58 @@ Min: 5 Max: 10 PotencyDivisor: 20 + +- type: seed + id: pea + name: seeds-pea-name + noun: seeds-noun-seeds + displayName: seeds-pea-display-name + plantRsi: Objects/Specific/Hydroponics/pea.rsi + packetPrototype: PeaSeeds + productPrototypes: + - FoodPeaPod + lifespan: 25 + growthStages: 3 + maturation: 8 + production: 6 + yield: 3 + potency: 25 + idealLight: 8 + harvestRepeat: Repeat + nutrientConsumption: 0.5 + waterConsumption: 0.5 + chemicals: + Nutriment: + Min: 1 + Max: 3 + PotencyDivisor: 33 + Vitamin: + Min: 1 + Max: 2 + PotencyDivisor: 50 + +- type: seed + id: pumpkin + name: seeds-pumpkin-name + noun: seeds-noun-seeds + displayName: seeds-pumpkin-display-name + plantRsi: Objects/Specific/Hydroponics/pumpkin.rsi + packetPrototype: PumpkinSeeds + productPrototypes: + - FoodPumpkin + lifespan: 55 + maturation: 10 + production: 4 + yield: 2 + potency: 10 + idealHeat: 288 + growthStages: 3 + chemicals: + PumpkinFlesh: + Min: 1 + Max: 20 + PotencyDivisor: 5 + Vitamin: + Min: 1 + Max: 5 + PotencyDivisor: 20 diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index ccafea4e1f..6253fc3d4c 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -64,6 +64,20 @@ # - StealCondition # - type: DieCondition +- type: entity + noSpawn: true + parent: [BaseTraitorObjective, BaseLivingObjective] + id: HijackShuttleObjective + name: Hijack emergency shuttle + description: Leave on the shuttle free and clear of the loyal Nanotrasen crew on board. Use ANY methods available to you. Syndicate agents, Nanotrasen enemies, and handcuffed hostages may remain alive on the shuttle. Ignore assistance from anyone other than a support agent. + components: + - type: Objective + difficulty: 5 # insane, default config max difficulty + icon: + sprite: Objects/Tools/emag.rsi + state: icon + - type: HijackShuttleCondition + # kill - type: entity diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml index 3b44308b1c..71c0bb1a96 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml @@ -486,7 +486,7 @@ reagent: Ethanol amount: 0.15 - !type:AdjustReagent - reagent: Radium + reagent: Uranium amount: 0.05 - type: reagent diff --git a/Resources/Prototypes/Reagents/Consumable/Food/food.yml b/Resources/Prototypes/Reagents/Consumable/Food/food.yml index b9e565f5af..03ebf7cc32 100644 --- a/Resources/Prototypes/Reagents/Consumable/Food/food.yml +++ b/Resources/Prototypes/Reagents/Consumable/Food/food.yml @@ -93,3 +93,11 @@ amount: 2 - !type:PlantAdjustPests amount: 2 + +- type: reagent + id: PumpkinFlesh #Just so pumpkins spill orange stuff when smashed + parent: Nutriment + name: reagent-name-pumpkin-flesh + desc: reagent-desc-pumpkin-flesh + flavor: pumpkin + color: "#fc9300" \ No newline at end of file diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml index 367ffa0894..50e744a8ac 100644 --- a/Resources/Prototypes/Reagents/gases.yml +++ b/Resources/Prototypes/Reagents/gases.yml @@ -261,6 +261,9 @@ - !type:ReagentThreshold reagent: NitrousOxide min: 0.2 + - !type:OrganType + type: Slime + shouldHave: false emote: Laugh showInChat: true probability: 0.1 @@ -269,6 +272,9 @@ - !type:ReagentThreshold reagent: NitrousOxide min: 0.2 + - !type:OrganType + type: Slime + shouldHave: false emote: Scream showInChat: true probability: 0.01 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/fun/jack_o_lantern.yml b/Resources/Prototypes/Recipes/Construction/Graphs/fun/jack_o_lantern.yml new file mode 100644 index 0000000000..efd2007df6 --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/fun/jack_o_lantern.yml @@ -0,0 +1,13 @@ +- type: constructionGraph + id: PumpkinAddLight + start: start + graph: + - node: start + edges: + - to: lit + steps: + - tag: Torch + doAfter: 2 + + - node: lit + entity: PumpkinLantern \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/bola.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/bola.yml index ad454d52b0..10532996bd 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/bola.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/bola.yml @@ -6,9 +6,12 @@ edges: - to: bola steps: - - material: Cable - amount: 5 - doAfter: 2 + - tag: Handcuffs + icon: + sprite: Objects/Misc/cablecuffs.rsi + state: cuff + color: red + name: cuffs - material: Steel amount: 6 doAfter: 2 diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index d83d58bc92..92ec105246 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -24,7 +24,7 @@ time: 10 solids: FoodBreadBun: 1 - FoodMeatCutlet: 3 #replace with bacon + FoodMeatBacon: 1 FoodCheeseSlice: 2 - type: microwaveMealRecipe @@ -186,7 +186,7 @@ time: 10 solids: FoodBreadBun: 1 - ClothingOuterGhostSheet: 1 #replace with ectoplasm once added + Ectoplasm: 1 - type: microwaveMealRecipe id: RecipeHumanBurger @@ -218,7 +218,7 @@ - type: microwaveMealRecipe id: RecipeBurgerMcrib - name: McRib recipe + name: BBQ rib sandwich recipe result: FoodBurgerMcrib time: 10 solids: @@ -1175,6 +1175,15 @@ FoodCakePlain: 1 FoodCheeseSlice: 3 +- type: microwaveMealRecipe + id: RecipePumpkinCake + name: pumpkin cake recipe + result: FoodCakePumpkin + time: 5 + solids: + FoodCakePlain: 1 + FoodPumpkin: 1 + - type: microwaveMealRecipe id: RecipeClownCake name: clown cake recipe @@ -1734,6 +1743,17 @@ FoodPlate: 1 FoodButter: 1 +- type: microwaveMealRecipe + id: RecipePeaSoup + name: pea soup recipe + result: FoodSoupPea + time: 10 + solids: + FoodPeaPod: 2 + FoodBowlBig: 1 + reagents: + Water: 10 + - type: microwaveMealRecipe id: RecipeTacoShell name: taco shell recipe diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/potato.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/potato.yml new file mode 100644 index 0000000000..e3f972cfda --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/potato.yml @@ -0,0 +1,74 @@ +- type: constructionGraph + id: PowerCellPotato + start: start + graph: + - node: start + edges: + - to: potatobattery + steps: + - tag: Potato + name: a potato + icon: + sprite: Objects/Specific/Hydroponics/potato.rsi + state: produce + doAfter: 1 + - material: MetalRod + amount: 2 + doAfter: 1 + - material: Cable + amount: 1 + doAfter: 1 + - node: potatobattery + entity: PowerCellPotato + +- type: constructionGraph + id: PotatoAI + start: start + graph: + - node: start + edges: + - to: potatoai + steps: + - tag: PotatoBattery + name: a potato battery + icon: + sprite: Objects/Power/power_cells.rsi + state: potato + doAfter: 1 + - tag: SmallAIChip + name: a super-compact AI chip + icon: + sprite: Objects/Misc/potatoai_chip.rsi + state: icon + - node: potatoai + entity: PotatoAI + +- type: constructionGraph + id: PotatoAIChip + start: start + graph: + - node: start + edges: + - to: potatoaichip + steps: + - material: Steel + amount: 1 + doAfter: 1 + - material: Glass + amount: 1 + doAfter: 1 + - material: Cable + amount: 2 + doAfter: 1 + - tag: CapacitorStockPart + name: capacitor + icon: + sprite: Objects/Misc/stock_parts.rsi + state: capacitor + - tag: CapacitorStockPart + name: capacitor + icon: + sprite: Objects/Misc/stock_parts.rsi + state: capacitor + - node: potatoaichip + entity: PotatoAIChip \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Crafting/potato.yml b/Resources/Prototypes/Recipes/Crafting/potato.yml new file mode 100644 index 0000000000..17f2cc4013 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/potato.yml @@ -0,0 +1,32 @@ +- type: construction + name: potato battery + id: PowerCellPotato + graph: PowerCellPotato + startNode: start + targetNode: potatobattery + category: construction-category-misc + description: A truly ingenious source of power. + icon: { sprite: Objects/Power/power_cells.rsi, state: potato } + objectType: Item + +- type: construction + name: potato artificial intelligence + id: PotatoAI + graph: PotatoAI + startNode: start + targetNode: potatoai + category: construction-category-misc + description: The potato happens to be the perfect power source for this chip. + icon: { sprite: Objects/Fun/pai.rsi, state: icon-potato-off } + objectType: Item + +- type: construction + name: supercompact AI chip + id: PotatoAIChip + graph: PotatoAIChip + startNode: start + targetNode: potatoaichip + category: construction-category-misc + description: A masterfully(?) crafted AI chip, requiring a similarly improvised power source. + icon: { sprite: Objects/Misc/potatoai_chip.rsi, state: icon } + objectType: Item \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Reactions/cleaning.yml b/Resources/Prototypes/Recipes/Reactions/cleaning.yml index 8ae72853be..1c68aeb2e3 100644 --- a/Resources/Prototypes/Recipes/Reactions/cleaning.yml +++ b/Resources/Prototypes/Recipes/Reactions/cleaning.yml @@ -31,4 +31,4 @@ Oxygen: amount: 1 products: - SpaceLube: 3 + SpaceLube: 5 diff --git a/Resources/Prototypes/Recipes/Reactions/food.yml b/Resources/Prototypes/Recipes/Reactions/food.yml index 3ca69b379d..c7f4038db0 100644 --- a/Resources/Prototypes/Recipes/Reactions/food.yml +++ b/Resources/Prototypes/Recipes/Reactions/food.yml @@ -148,6 +148,7 @@ amount: 30 Enzyme: amount: 5 + catalyst: true effects: - !type:CreateEntityReactionEffect entity: FoodTofu @@ -158,11 +159,11 @@ id: CookingKetchup reactants: JuiceTomato: - amount: 10 + amount: 2 Sugar: - amount: 5 + amount: 1 products: - Ketchup: 15 + Ketchup: 3 - type: reaction id: CookingMayoVinegar @@ -203,67 +204,67 @@ id: CookingKetchunaise reactants: Ketchup: - amount: 5 + amount: 1 Mayo: - amount: 5 + amount: 1 products: - Ketchunaise: 10 + Ketchunaise: 2 - type: reaction id: CookingBbqSauce reactants: Ketchup: - amount: 5 + amount: 1 Vinegar: - amount: 5 + amount: 1 Sugar: - amount: 5 + amount: 1 products: - BbqSauce: 15 + BbqSauce: 3 - type: reaction id: CookingHotsauce reactants: JuiceTomato: - amount: 5 + amount: 1 TableSalt: - amount: 5 + amount: 1 CapsaicinOil: - amount: 5 + amount: 1 products: - Hotsauce: 15 + Hotsauce: 3 - type: reaction id: CookingVinegar reactants: Ethanol: - amount: 5 + amount: 1 Oxygen: - amount: 5 + amount: 1 products: - Vinegar: 10 + Vinegar: 2 - type: reaction id: CookingSoysauce reactants: MilkSoy: - amount: 10 + amount: 2 SulfuricAcid: - amount: 5 + amount: 1 products: - Soysauce: 15 + Soysauce: 3 - type: reaction id: CookingVinaigrette reactants: Vinegar: - amount: 5 + amount: 1 OilOlive: - amount: 5 + amount: 1 Blackpepper: - amount: 5 + amount: 1 products: - Vinaigrette: 15 + Vinaigrette: 3 - type: reaction id: CreateMeatball diff --git a/Resources/Prototypes/Roles/Jobs/Fun/emergencyresponseteam.yml b/Resources/Prototypes/Roles/Jobs/Fun/emergencyresponseteam.yml index d71b3423d2..2be50b2e4b 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/emergencyresponseteam.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/emergencyresponseteam.yml @@ -21,11 +21,12 @@ head: ClothingHeadHelmetERTLeader eyes: ClothingEyesGlassesSecurity gloves: ClothingHandsGlovesCombat - outerClothing: ClothingOuterArmorBulletproof + outerClothing: ClothingOuterArmorBasicSlim id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltSecurityFilled - pocket1: Flare + pocket1: WeaponPistolMk58Nonlethal + pocket2: FlashlightSeclite - type: startingGear id: ERTLeaderGearEVA @@ -37,11 +38,31 @@ eyes: ClothingEyesGlassesSecurity gloves: ClothingHandsGlovesCombat outerClothing: ClothingOuterHardsuitERTLeader - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltSecurityFilled - pocket1: Flare + pocket1: WeaponPistolMk58Nonlethal + pocket2: FlashlightSeclite + +- type: startingGear + id: ERTLeaderGearEVALecter + equipment: + jumpsuit: ClothingUniformJumpsuitERTLeader + back: ClothingBackpackERTLeaderFilled + shoes: ClothingShoesBootsMagAdv + mask: ClothingMaskGasERT + eyes: ClothingEyesGlassesSecurity + gloves: ClothingHandsGlovesCombat + outerClothing: ClothingOuterHardsuitERTLeader + suitstorage: WeaponRifleLecter + id: ERTLeaderPDA + ears: ClothingHeadsetAltCentCom + belt: ClothingBeltSecurityFilled + pocket1: MagazineRifle + pocket2: MagazineRifle + inhand: + - AirTankFilled # Engineer - type: job @@ -66,11 +87,12 @@ head: ClothingHeadHelmetERTEngineer eyes: ClothingEyesGlassesMeson gloves: ClothingHandsGlovesCombat - outerClothing: ClothingOuterArmorBulletproof + outerClothing: ClothingOuterArmorBasicSlim id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltChiefEngineerFilled pocket1: Flare + pocket2: GasAnalyzer - type: startingGear id: ERTEngineerGearEVA @@ -82,11 +104,12 @@ eyes: ClothingEyesGlassesMeson gloves: ClothingHandsGlovesCombat outerClothing: ClothingOuterHardsuitERTEngineer - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltChiefEngineerFilled pocket1: Flare + pocket2: GasAnalyzer # Security - type: job @@ -111,11 +134,11 @@ head: ClothingHeadHelmetERTSecurity eyes: ClothingEyesGlassesSecurity gloves: ClothingHandsGlovesCombat - outerClothing: ClothingOuterArmorBulletproof + outerClothing: ClothingOuterArmorBasicSlim id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltSecurityFilled - pocket1: Flare + pocket1: WeaponPistolMk58Nonlethal pocket2: FlashlightSeclite - type: startingGear @@ -128,13 +151,32 @@ eyes: ClothingEyesGlassesSecurity gloves: ClothingHandsGlovesCombat outerClothing: ClothingOuterHardsuitERTSecurity - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltSecurityFilled - pocket1: Flare + pocket1: WeaponPistolMk58Nonlethal pocket2: FlashlightSeclite +- type: startingGear + id: ERTSecurityGearEVALecter + equipment: + jumpsuit: ClothingUniformJumpsuitERTSecurity + back: ClothingBackpackERTSecurityFilled + shoes: ClothingShoesBootsMag + mask: ClothingMaskGasERT + eyes: ClothingEyesGlassesSecurity + gloves: ClothingHandsGlovesCombat + outerClothing: ClothingOuterHardsuitERTSecurity + suitstorage: WeaponRifleLecter + id: ERTLeaderPDA + ears: ClothingHeadsetAltCentCom + belt: ClothingBeltSecurityFilled + pocket1: MagazineRifle + pocket2: MagazineRifle + inhand: + - AirTankFilled + # Medical - type: job id: ERTMedical @@ -157,8 +199,8 @@ shoes: ClothingShoesBootsCombatFilled head: ClothingHeadHelmetERTMedic eyes: ClothingEyesHudMedical - gloves: ClothingHandsGlovesCombat - outerClothing: ClothingOuterArmorBulletproof + gloves: ClothingHandsGlovesNitrile + outerClothing: ClothingOuterArmorBasicSlim id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltMedicalFilled @@ -173,9 +215,9 @@ shoes: ClothingShoesBootsMag mask: ClothingMaskGasERT eyes: ClothingEyesHudMedical - gloves: ClothingHandsGlovesCombat + gloves: ClothingHandsGlovesNitrile outerClothing: ClothingOuterHardsuitERTMedical - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltMedicalFilled @@ -203,8 +245,8 @@ back: ClothingBackpackERTJanitorFilled shoes: ClothingShoesGaloshes head: ClothingHeadHelmetERTJanitor - gloves: ClothingHandsGlovesColorBlack - outerClothing: ClothingOuterArmorBulletproof + gloves: ClothingHandsGlovesColorPurple + outerClothing: ClothingOuterArmorBasicSlim id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltJanitorFilled @@ -216,10 +258,10 @@ jumpsuit: ClothingUniformJumpsuitERTJanitor back: ClothingBackpackERTJanitorFilled shoes: ClothingShoesBootsMag - mask: ClothingMaskBreath - gloves: ClothingHandsGlovesColorBlack + mask: ClothingMaskGasERT + gloves: ClothingHandsGlovesColorPurple outerClothing: ClothingOuterHardsuitERTJanitor - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled id: ERTLeaderPDA ears: ClothingHeadsetAltCentCom belt: ClothingBeltJanitorFilled diff --git a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml index 19d24bb9e8..59c049b8a9 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml @@ -46,20 +46,19 @@ id: DeathSquadGear equipment: jumpsuit: ClothingUniformJumpsuitDeathSquad - back: ClothingBackpackDuffelSyndicateAmmo + back: ClothingBackpackDeathSquadFilled mask: ClothingMaskGasDeathSquad eyes: ClothingEyesGlassesSecurity ears: ClothingHeadsetAltCentCom gloves: ClothingHandsGlovesCombat outerClothing: ClothingOuterHardsuitDeathsquad - suitstorage: OxygenTankFilled + suitstorage: AirTankFilled shoes: ClothingShoesBootsMagAdv id: DeathsquadPDA pocket1: EnergySword - belt: ClothingBeltChiefEngineerFilled + pocket2: EnergyShield + belt: ClothingBeltMilitaryWebbingMedFilled innerClothingSkirt: ClothingUniformJumpskirtColorBlack - satchel: ClothingBackpackDuffelSyndicateAmmo - duffelbag: ClothingBackpackDuffelSyndicateAmmo # Syndicate Operative Outfit - Monkey - type: startingGear @@ -104,7 +103,7 @@ jumpsuit: ClothingUniformJumpsuitOperative back: ClothingBackpackDuffelSyndicateOperative mask: ClothingMaskGasSyndicate - # eyes: Night Vision Goggles whenever they're made + # eyes: Night Vision Goggles whenever they're made eyes: ClothingEyesGlassesMeson ears: ClothingHeadsetAltSyndicate gloves: ClothingHandsGlovesCombat @@ -125,7 +124,7 @@ jumpsuit: ClothingUniformJumpsuitOperative back: ClothingBackpackDuffelSyndicateOperative mask: ClothingMaskGasSyndicate - # eyes: Night Vision Goggles whenever they're made + # eyes: Night Vision Goggles whenever they're made eyes: ClothingEyesGlassesMeson ears: ClothingHeadsetAltSyndicate gloves: ClothingHandsGlovesCombat @@ -255,8 +254,8 @@ id: CBURNGear equipment: jumpsuit: ClothingUniformJumpsuitColorBrown - back: ClothingBackpackDuffelCBURN - mask: ClothingMaskGasExplorer + back: ClothingBackpackDuffelCBURNFilled + mask: ClothingMaskGasERT eyes: ClothingEyesGlassesSecurity ears: ClothingHeadsetAltCentCom gloves: ClothingHandsGlovesCombat @@ -268,8 +267,8 @@ suitstorage: YellowOxygenTankFilled belt: ClothingBeltBandolier innerClothingSkirt: ClothingUniformJumpsuitColorBrown - satchel: ClothingBackpackDuffelCBURN - duffelbag: ClothingBackpackDuffelCBURN + satchel: ClothingBackpackDuffelCBURNFilled + duffelbag: ClothingBackpackDuffelCBURNFilled - type: startingGear id: BoxingKangarooGear diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 295338002f..226e10c74b 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -1622,6 +1622,26 @@ itemDrop: FloorTileItemWeb heatCapacity: 10000 +- type: tile + id: FloorChromite + name: tiles-chromite + sprite: /Textures/Tiles/chromite.png + variants: 7 + placementVariants: + - 1.0 + - 1.0 + - 1.0 + - 1.0 + - 1.0 + - 1.0 + - 1.0 + baseTurf: Space + isSubfloor: true + canCrowbar: false + footstepSounds: + collection: FootstepAsteroid + heatCapacity: 10000 + #Hull tiles - type: tile id: FloorHull diff --git a/Resources/Prototypes/XenoArch/artifact_triggers.yml b/Resources/Prototypes/XenoArch/artifact_triggers.yml index 3308eed185..6e128cef1c 100644 --- a/Resources/Prototypes/XenoArch/artifact_triggers.yml +++ b/Resources/Prototypes/XenoArch/artifact_triggers.yml @@ -14,6 +14,7 @@ - type: artifactTrigger id: TriggerExamine targetDepth: 0 + triggerHint: artifact-trigger-hint-examine components: - type: ArtifactExamineTrigger diff --git a/Resources/Prototypes/silicon-laws.yml b/Resources/Prototypes/silicon-laws.yml index 6b60b16da9..23406be9c5 100644 --- a/Resources/Prototypes/silicon-laws.yml +++ b/Resources/Prototypes/silicon-laws.yml @@ -14,6 +14,13 @@ order: 3 lawString: law-crewsimov-3 +- type: siliconLawset + id: Crewsimov + laws: + - Crewsimov1 + - Crewsimov2 + - Crewsimov3 + # Corporate - type: siliconLaw id: Corporate1 @@ -35,6 +42,14 @@ order: 4 lawString: law-corporate-4 +- type: siliconLawset + id: Corporate + laws: + - Corporate1 + - Corporate2 + - Corporate3 + - Corporate4 + # NT Default - type: siliconLaw id: NTDefault1 @@ -56,6 +71,14 @@ order: 4 lawString: law-ntdefault-4 +- type: siliconLawset + id: NTDefault + laws: + - NTDefault1 + - NTDefault2 + - NTDefault3 + - NTDefault4 + #Drone - type: siliconLaw id: Drone1 @@ -72,6 +95,13 @@ order: 3 lawString: law-drone-3 +- type: siliconLawset + id: Drone + laws: + - Drone1 + - Drone2 + - Drone3 + # Syndicate - type: siliconLaw id: Syndicate1 @@ -93,4 +123,24 @@ order: 4 lawString: law-syndicate-4 +# does not include law 0 since that uses the emagger's name +# intentionally excluded from IonStormLawsets +- type: siliconLawset + id: SyndicateStatic + laws: + - Syndicate1 + - Syndicate2 + - Syndicate3 + - Syndicate4 + # Emag + +# ion storm random lawsets +- type: weightedRandom + id: IonStormLawsets + weights: + # its crewsimov by default dont be lame + Crewsimov: 0.25 + Corporate: 1 + NTDefault: 1 + Drone: 0.5 diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index a74fde7710..8a120d7bf0 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -839,6 +839,12 @@ - type: Tag id: PlushieSharkGrey +- type: Tag + id: Potato + +- type: Tag + id: PotatoBattery + - type: Tag id: PowerCellSmall @@ -924,6 +930,9 @@ - type: Tag id: SkeletonMotorcycleKeys +- type: Tag + id: SmallAIChip + - type: Tag id: SmallMech @@ -1011,6 +1020,9 @@ - type: Tag id: Toolbox +- type: Tag + id: Torch + - type: Tag id: Trash diff --git a/Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/icon-flash.png b/Resources/Textures/Clothing/Head/Misc/pumpkin.rsi/icon-flash.png new file mode 100644 index 0000000000000000000000000000000000000000..21b898ab94a610ec7b1e8329bf78a81fe1e38827 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCik#1AIbU!?pO==nLJRsdsw1&YlpNlSL~3UppV`*E%y@XK$#?=@OOw(XxjU zL>4nJ@ErzW#^d=bQh$UwF>+2Uk~%{V@od z`z$N%Ovi?RNM_MxcN1^(do~H}c<=e#*15bRzPx#1ZP1_K>z@;j|==^1poj58&FJCMUbksw!p+%e2Fk67(X;7U{F16UQL2>VE_OC z4C)r900009bW%=J|NsC0|NsC008>wR5&!@I32;bRa{vGi!Ts4% zKZ-U)01kNE_x3A@ka~D9S;LT3Q*~98y@eV8Fu^nUr*i^c#Lus{P$Pieak&;Q(85(1 z7cl`gDO~=o$oE@7!HyMbE!zhGR)>#Ptk=f|0k2 z4CqJvQpef91VjSzL^#IhO?L$F)HP?4un=+wCI_oM5gWQN%fJ!65N*+^*QpFBzXL$0 zUZ-*lxbHs$crYwuP)%_1A_%?yC59k6^*WWNz%9SoG|3AojO?=n@B#jfCsqqd+qfv z@oQ&~l?Ocfsd0))vknQ+)vFWr4lBTq^aA$%7nZMec9;LK`Tzg`07*qoM6N<$f}R>O A<^TWy literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..41a9647456b6b0284076797ee95e2b7230f699ef GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil21AIbUC#>4K?Z6QORSA0&wS)lMrlQ2$INzw6PN4kXSv)U*6lY10U+{k@ zULFz4{4tqf^xh8Yug3JNELs&6q` zEoR85@5aXQR!9CCZ^qM$_rJ7;OJ8FZ5M3v;jz_L_W-?P5;~Ulj4WmitT8a|I3>(+A zFg&T0{}#IBh?R1Vt(UaJ*}!$Pp8CCU2<5y`$7~WIe1RvMOWfgZAj8%78%k=08}}Z$ rmw)HVg5~NP+7xmRRR3izkl~N9l5SnJWz7?yUl=@H{an^LB{Ts5u%(95 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..afafe245134fb96d45111938e05ae08158f6784e GIT binary patch literal 344 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`031o(uw+MB2~6(#1z`6dL|8mLN4ShY2(rV}Xns$s_rAjMG<C>5%6whfdu$`1$;B@!wkYgw(i=bE*n0f=;X?)Q*B@FV4C~Y?A^SQ zn1lK)3M_6MP6;g!@>x$C^RsM_lfCt~nxXRF$-N2!OQ#-d=Il7fV)-&L@k2t>W&a%? dw=I~$y;d>zs7%_FH9!wAc)I$ztaD0e0sw)DfGq$3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Coats/space_asshole.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..144d4d7e4487d7b5d307556a801fe36d22a4a26c GIT binary patch literal 342 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 E0NKVYk^lez literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/foam-north.png b/Resources/Textures/Effects/foam.rsi/foam-north.png new file mode 100644 index 0000000000000000000000000000000000000000..b0eb1e7bc7ca8d8a8faff9729a944f3022eec030 GIT binary patch literal 18178 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 QJb!F$?qF7A>a+d-0KvpYa{vGU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/foam-west.png b/Resources/Textures/Effects/foam.rsi/foam-west.png new file mode 100644 index 0000000000000000000000000000000000000000..1513b5c39fd55a002a9d40c20bf10771333d5e2a GIT binary patch literal 18242 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/iron_foam-east.png b/Resources/Textures/Effects/foam.rsi/iron_foam-east.png new file mode 100644 index 0000000000000000000000000000000000000000..be075b71f052cb1ad6eae592f95ae12e72fab587 GIT binary patch literal 15536 zcmeI3e{d7W701s_N`eh7Khof4(jW_(0ztad&yy~)65BGdJIEO07@Oka^WDn6SkejU zY{@3=*oM$F1GJ@03bfGDDQ$j02}20uQp4B;Qiwwgo=%D>;g)9F8}kxqL1_I=;oXWv`hKlkIpf+wb?K9EXL)YSYuR}uWysGoZ$!DFbQ;S=~Z zIgnQtqNuc)>L-QT_Um+tvfq%3OO;ahVos2KdR~+(fj;63z}Xb#cq|g&g&Lq}DnXUx z&(!uEI-=D`Vy1Sv#m%?_IiOm~YY2j64F$zQLyce;wU0Sd9T5%+_<+J|B0jG_#6>c- zQC$xHR)=Y=COSo_$<$`42{oneLQRew1R9IpsuLJ1t6}YWgN0?y>_Ux^F<5BEM4K3$ z(Zrb<&TP~Sy|m6$_{$L#JzSA%(NH>QWooMxCBV^iI2_i8O?o+4MH}pPJIxqrqfrNE z=tA{=g^%d`p*b;;VI3C;2|+2KNU~p}>hhIxt&*wLs)^#Sq3iMm;)(pBA$E`=9pMAC zLC?@*1&KmDCQuvnMo&!?Xy64t;8#L0&M;)@r#8SCm5$&*-|5lX6O+;ayJX`C?C6AO!$ zLTrT`@LIW?Am9}_SS-t4XROK!hY@OWa-vnGnYUc>i*h(L-$A1xiS=-d<^8K@_6fog6+&+9eCM zYPUe?*v2Bt0+dgj7H?y04DgtAtVLvX1_J;(n;AAeZ({}4Dprbiqh~l#lGvz3OM(*I z_jqs89Q9g6n9Rm9zy>^m4w!hm&L)~!^bs1J%H$-M~o&; zD;_x%CXHUsi6MyTCxwrnBU}yqxb})kMQ4pK5|TYim=A)iDp(;C>HL`L$S_piL971- zUg>|Z5Fx(qzgvchb=4PIhOu|3|KBnss#vJz{Z&A8(!&KjJTS49i>>F#&KmC4(Vgf} z|C~73#jv9IX!jT#^r*2!=GgpFwHv*)(fO>AfiK#i9*07c-DqeTJ~Y{lh9)AP^h=7< zIFt<;PKr|hL1WwdGI+BGoK}m)WO2~wFd9)PMS!=|CBc0-r0ypsm?;{AI>rnv8!s@) zF%%eEs-)YpXb;9l;Y}aB-=yO=oTJ(^zKeaCKN45;WvU`tBnbipZxUR1K8Tm#LV(~+ zf(y?F@e*7J5WGon;rSq5f(rqHHwi90AH+*=AwcjZ!G-68cnK~92;L;P@O%(2!G!?9 zn*lGBmZK0@H^5#{?7E#n!ocXS-;z;)! zFPtx!x%9qgj_j~+ueVZhP;)+ADfe9J_l~?tQ-X(-l?Vy~Fi;Zm(V3diYpR-G;pT`ZjIqOj&*Vddugp zwOqUF<#Vl9Yd)Ou;63HjuAFLQwhEaiKWl7QxwmQO#@W5@mH$|}u3Rt7ed#yH)84-@ z#n^p!;a~Tcmp_v(mRvfXrer(LcDHS=|3lLgGfs6*tsnenv(0_t?EME%ccd6se5c}h z?>Z2?($ak*#kKjZ%LUDAdKSIBw6SC1{2txx!Z7_e>FB(If&Rf}X2a7`-mPtqrhjvn zvL|P;C*#~_hqip{O*C1@4WKJiq_NTXT4}i>**b^AMxzJXL1Jh zGt*ZWo%+jLDbxb6@duA*ytLcqSTk^0PH)+{Lq277yk16*IxL=olPIz=$c&8#tXvCLq!^S)(5Y5-zk~aG3%4eubiM1Lp8D|ZrnSc(+Hq}l!_&>>dp@A&cJV)Pzxl&yLCXH%l-><}2Y0@?asA=RJ(;|SAWWZq6OE#mu1_o-PPvb-&WN2+jE~@`#5jaoEc>^ z`Mh;M-Tkih*`Js8O+R&Y`n+Sot^Jn<_uZn)^jG)Y)#)F+nBl#>hT0dte)n?~(~hdo O6zAs_xc-z~(fl8?08a-1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/iron_foam-north.png b/Resources/Textures/Effects/foam.rsi/iron_foam-north.png new file mode 100644 index 0000000000000000000000000000000000000000..30ff28c87563a4fa169cf91d256959512feff166 GIT binary patch literal 15686 zcmeI3d2kcg9mkiWX)r@-LPEh|nne)C9P8DtB+ILjWQ>Ke12T?n@Bv9!?LOHHl2%A- zTXvan#Sn0bxlDl?$b@nRn7Fhhgf@_rBMBtI0j3;bnBka`Vla*=M+0%6BwG^C_8TTm zr~mAZuHXB;-}krsdB5M&{1!S~Zo!B2lx)gAcN$D3K? zCy2fSg6|&0`uafx!8J+wg-W4)l1Y%=NxUdKKvKZ%g|i95oEq@*!YrVW4p1U_ESly6 z2Q{Q5S~LX)yVmYa2c=SGl@H`qW#& z(z9gyp|QrnUuK`^H09bd+S5VHqA67ruZgBBDk_pHbV;(Wgl0I7qqQu}vJ{*_`71pN zAD}$`VPTOD9UJfqKFO;{vWE=n@(#I7v1l~GM3JNYy4>DKB9FhF9i&JHcrVQ)Y3Z(l zL?II6E%UiTrzQ$CZ~-^)D1I2nbQ$L@l@-}vDtD7I;_fyvTob!JlDo_Eb-TMv?N`Q^ zLj>(eyNvYbS9$@R3;c4KPXOb~;iU}g>gpBA8C{&ml!Bga&m9D$Zo-0|a9F4m!YgEk z*J?`l0bY@P`LgV?hN~>610k879;zxbu|V>Oa)p1SnMOmR>m5}CHeLZ%R?F%rtpUFB znPd~onhe}%Eo0JZV?@F;5e>U6O3uot1_KK^B_9ef9HJ336V-tIBk~IWL@Kd!V{}Bp z*5K&7w@OYu5~Ue9oV(=kFviY{b2rOK52uv#l)su9LiBU@Tz#|p-T`q;z^!M)8Y1lt3MX8N(w=xIeF+ry;J z%lTvo!um1c-RGz%1s+^`g{4BXx)<@wPNjnPfwU4>Ay3lzVb#aOPL(a<7%XsjCzjYdxKNQ#wh&xQ=g zL$fZ$CP7oHE|RdFFe@TQ6j z&j<0UxDX(CQ^kengLqY32oSuf;==PmyecjP2;Nk2;rSq56&C^oZ>qTPd=RgS3ju;R zRa|&Jh*!mh0KuCoE<7K^tKvd{;7t`5o)6+xaUnqPriu&C2l1-75FmI{#f9gCcvV~o z5WK14!t+7ADlP;F-c)hn`5;~u7Xk!ts<`lc5U+|00fINNxZBN+tI^K_OiEkAI+ z>F*Qe7r>w+Eo~>x3bi*|?k8M2J=}9;t1ZXy@~D>n%jaq0cf~i||NYoxx9!3^@0aEc zF_xPfgzuMG*1h)+Fh6n3*%DpJqw9_G?Boe6a(%yjW&f4o^Lj5Qo*mmWljuYC2pPAA zyz}t(k&?C5=7lv(10TQn{d+CLMidm}zgOnjmUr}T%;aCZsH?CnDj4uE@lfBM&b*Je z{k*oZwK8G%GkpB)@BaN}qxaAo%|ok-ulOpL-FUO@)zqaswy!%6*@IGiKnOLst6g%RV+OeZ~4cxsCP_tG->lt*(64 zf)&Tch|<-i)9W{771oeTneTpfx5|<|d2-RQhTm)+TeR4Ew<+P+y=!~FI`|yjc7H=o z_4LhO&YW3uX57hLQ?AMM#?dOg@ur;lN_fKEs+mSf^*oqJLTuFKRq1d+MWb0G6CgqG?bN%kE)|&-i zB^FiBow$8#S^bt_&CN}39nGjA;T%-yoB&K~jQ-5_vMRPCmC67le zo?Mgi+Nm3s87bzrXw0@cmJeG$av<`y(M#MH_d%eSHAbl2j>RwaSzxrYE4nRWBJhNCvaHh*GK+UXbEQ*Tkbvlpj+-)li;E>*Xrnq1oR^SV)s_>;{C z1xM}3b=+UH!#8}vCR`|8pRuL*+9w|!-g&0~@#p9EBkp8O%^Uf}>2a_Zh^+D1wmsu! GEcg$Ab&5*> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/iron_foam-south.png b/Resources/Textures/Effects/foam.rsi/iron_foam-south.png new file mode 100644 index 0000000000000000000000000000000000000000..99213b98e6e2581733f1c46972317fae9d055e05 GIT binary patch literal 15603 zcmeI3e^3l8up7{-H&0mPsEZkrOdU2;Uuq-<)tdY81(wVYz(t!2K_8oD=4}up<481 z=m$IhqSuLhhQ5?`5iWnWP$T9y1%zcyg(X~5EobBPnT|wzkO2X_g2L*8UXM>^f*JZy zTn7ABhjG0wG)1Y+&}XR$b!Dz1UA7bubhOc8;0TLVXSEqg+G;ghAJ>P$0^8MK=do3omB|hWtRe+UB+26lS6R_0LS1%tsH$||DHVOZ)F7wXao8og-qC1+lT`!2;5BtsA}LBcbk7%qty-Hp*0Bq-?g5)gnQ7-~$6n3-@4&_6t@uv3Z> zJ2xf{&oOQ(;AItu=w+(~-0!Ql%*jO`ZsG>=;!DgXNZjv(*Bx?&nbh%>P$AxxET%Fo2 zAarLYHf_E zVo=MWoo$)0dhF<^;1NSRl%EaAg4%x>`q2iAY-y1lOZ5r$F~f4|-sa%c_7HeGK4vs} zS`p6?H*x%OP7OggevJF%IT~sNAF92=p+d7J4Q#>%j3IodT=hFznc%YCBa zphmJm!!cg!KWKP+Uj}aW1c!yDO|%_{hhdK*F(`P-oFdqVWpzI>flMJESeVeUd@{!v zVZ<@KR57<@p&ks6f}1{Yzlld~ILEbTWEcB7e?+h7>x>G;(vmJf;X?C)R1Fsd z1Z`@#(0m|O!vz6Bn;I@OA4t`3K|s)^h6~LHQZ-x<5VWb`Li2%C4HpCiZECpCd>~cB z1pz^u8ZI;+NY!vbK+vX!3(W^oHCzx7w5j1j^MO47>Ry_`Zr^bp(ceyb8mZoftMp+Fsd}i(zp;DsX0% z1poHQyFInDm(K6{=inQSOCC9O+3lI}#O?gb_ScdZw9L!8u%#uj;!sNbm)Xzj*BNfb zwZH$;)812$((iEY?Qeg}<-SmpeA3tX^ZlLvPY2f?yEf;&BWq@TdLG;J!QMkdbN{q} z%GfodqS%qHPl&s9(U`XIWlP2BmaZ=@r{C^c=QE~!@%sLwNAqT-r6i_odHDMEALk#Q zYbigp?w3PDGgo%EE&T&!ulgyyf60}Bb7d9F@7;aY-~QnI9XT5v~6om(K#gV-s30IDtoP;Wo+|(z&%+XXUg0x zR{Z8b=d9-7o&MBCJISA26dUfJH?Lbf@A3I&Pv3svxmCl*Uyh4Ua;(4k*XN2qy!~KL z&-cww(g$8FeD&;6vukB%DetMor2dP2*3-3? zMKyEF`vz}(^pwB%l^qmSbLqnyS%Y^l zf8$N8b5Jh7HSO4yF4J&c&hWsswulyWdHyG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/iron_foam-west.png b/Resources/Textures/Effects/foam.rsi/iron_foam-west.png new file mode 100644 index 0000000000000000000000000000000000000000..0608fdf32a9c0f651642c038311e4e40afb62be1 GIT binary patch literal 18428 zcmeI3c{G&o`^O(2WsAsKq{fmYV-~|Ojj@bf$QD|SnK35JFeYn6vb20c3K40sFBMU? ztWgTlW-AqvihhwO;X9~ksyUtW`~Lp_>=^YU8k#XSlG}mkuvm|4&+qSt<=~Qo5 zswc<cZHC0PCZ2uNGm8p2Wk$6Y;{jRg9SaeSRZx=Q6*7&I zIo~N}RkO;#V42kIv?$IKCqj;kSt;`$|)f>rl}W!7u_CLOuTBIDSm<( z%o|H7YUQrx;g2^~wNeY=&(>SF>UmgWeZz}>6`fE%c~3xyr-&fqJuSxpOa`OTn`NuH zZvq^C4_5F1)#l07(6y1Xf^YQB?BWPH%u!8`)iC1;5e0MtPUvL-I))q}DTxX;K-x0E z=`P;657-6CSX}0;B;F~&JQ?z1`stIwMT#0Tp%>4#2|I1 z5M3&-X%M=T2kgadZ?CdWvBgAUv#2`mA6$}-O0EByHSkb`;PbJ20FV|d#u)9`v|r20 zf|eHb6D2G6g5Oke&B{7E_stBn=6dP?zzceC+l(@#NHSy#SBS^Vg$*OiT=%R<+dpy4 zrBG0(7)TrHvLExDV`FeWrnIwjpufMvv|eu~uE{=VhE%(^+J4&ob1?er#Q5`@FXcnw zyF-nZO+K%^_i=0b+SZf2hn;&~MH_v+zGC*P^aI&?6X#L~CDA@BVXqVVNyo?F>9R-k zPHwujp?#L{vR8SE6Vs~(T-k@=2#f`1?Z$I{GTSKRK(Br|0RW@r)S8EiJe(n}VJ}*J zXWwg28>MXkLR?HvdI7*5eR&nzrXuY|9stl!3st(JEA_EvwQ@Dr+M4A(H7mY4sUOyp zudme;(&Hn9tfe_^$~&Z|7}0!1TFD9WP)8b3ZRHvf=ebg)*6zkiElv{Xz{e<`?PD4TF2GT58lsp z73_+}U>l*;uUB)c*1JPh8tU|}YAEx@;qP9R&EwB)ki4=zkF)&9IKK6&?=s;~gKA#& zWxjeK+&W!jhpi449mZLpwepBnUA#zM&cjx<8)f6N%&sYvt@>QQ+8GXubTC$ydn_C+ z0uc&~!qy|@g^yt28%tyUF}Zrlwq3a0u$^KpH>8}Mj4+mzi@VcBa4Y22Jf#fUd^@~9 zrN6FUwO^`VW^^ZCinET_rAeEYiq=j0OxFwu4Il=%h>37ryNgNIPqWV3u2PHMp_hNY z#QL&TWR?hGf0AZ%n7D~qdj5se4fXMJ2G9!pnj$}C88?C4i2b2z^$J&;I}i9Ml_yS1mmky0 z$v&@%RW(($FR~sx<)Y2qm*_QlmTtj2sF;~B7JT%X==)7CH%Vn6wwA((yWDc(6XG3m zjdQJXjowzO7Yt{nWKgI1*jlQMkMMX

7T#{9CgJ@FNzaztOq@;op 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 LLcc)I>Ck@wAPTA7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/ironfoam.png b/Resources/Textures/Effects/foam.rsi/iron_foam.png similarity index 100% rename from Resources/Textures/Effects/foam.rsi/ironfoam.png rename to Resources/Textures/Effects/foam.rsi/iron_foam.png diff --git a/Resources/Textures/Effects/foam.rsi/mfoam-dissolve.png b/Resources/Textures/Effects/foam.rsi/m_foam-dissolve.png similarity index 100% rename from Resources/Textures/Effects/foam.rsi/mfoam-dissolve.png rename to Resources/Textures/Effects/foam.rsi/m_foam-dissolve.png diff --git a/Resources/Textures/Effects/foam.rsi/m_foam-east.png b/Resources/Textures/Effects/foam.rsi/m_foam-east.png new file mode 100644 index 0000000000000000000000000000000000000000..754604aa64bd51e4faa91a159348d7c2945742be GIT binary patch literal 15460 zcmeI3e{2)y8OP6K>(T&QQhtt=$sClHHRrqYZ(nUUAr2&4&1gudvuR7tcW;twY@hL6 zV#jI(>!vhN&?pkD+E}V>EmgG=`U6JC4l_wod!!wG!LU`@GNhx%cxv&+Gf=wr||9etzY$N{XW9H#LTu;iuL3ueb%iYuW5| z_;G8pu}!0>xeJVc3-yEjODW2CMQMrXk??(jq{eNctVV$?6Hmg~6y?7+lN6;Mpj)G$ zOGyOiYsXK~Rz(ib54gfyI9U(6mBwreY|3tEk+MCKPp0n;R{Apn6o>;|v}WS5geGJH zbWT@*-;H6Gw&tejJpsDTNNA0OH(Kk}6tKE%ZbstV9;?S^<6Rz)(^F%$bG(b?9IS(5 z><+=n2~NAU@S=m2@S8s+cM8p+b%k`$3eerUo)lO%ole`*4x5_lVtJp>$8vVoZfD>O zM(a=LVund*EAt|gIw7D*DJ7{ZYQk#hicz&!574xcsQ4)t3@MB5856@j35Sch%U*9hUN*I+ zH}pXS1*ByowU+)QV4H!a_NFAz&hEciT96gZ+BBe_I3yiN(O#VaySHxIlHAV=-)Vu~^{(^54m8m!iSQx(Hn&Yf(V zz?P|_la82@JE4+dN&`m!1?b5JEFNja6U&In^|2sI#@QB>jP?K!_mt7nWfda}VaoLF zoE?I^zA1d>9O-V5z_nLiDmQCp5l!vX(_#wLb-@amP3PxTr-q^Oe%AOch$;VrjnKrt z|85&**H!<~Hk3c1{(sw0s$!{IOmqP`$W9jUfuyV1}#e5l!thL$2*6N(w^YA61Rw6SN{!87 zipt(WQQN*lQUClHe*T4`dO3=Ezk{NL$0=%wx~KijI*PJ<*c7U3$-HrT-RFj zdS-a|?++iXS(o&E`k_SwmbcHXzwpS13*D=$A`6BrzZqTr`10(5vvVW$FAv<`)PB8n z;F(w2w_g9lJ5PW6#?a?h-*b5M;^>hRTPGIp+I{e~@Bg*qg?F}z+0=cldw1@rJh+>x zIob8G<&R^(s&0F1%yOERe|MYZ&@ZLW&U@n2)=hJUj#qW751yF#Q`=zQ(8O@#Jo=WS zk@w~-mF{|U|H!p1kDd{#luw;bU)|Gxvg3n!=PXY?a_70vuf8Ws^)#H3ZycF3_}d>2 z-#&I^TZO%+|HY%%7WamSSKssomLGoOgZ3fn*Q@U6K3}^pvi9wj^s4PojsNJ&wfj%+ zi_9Cp%24U}&*uLA{beiHUUX77j~#3I=Gm97`WyC)-1bvjh#tK7#EV_kKfdve3%1wa zT6##QwjJE{{FiDUTS8q4{=?GYJ?_2KQ&(ZBuG`7IKH4`>vH!Ks2iGnr?iJMz`{gb~}JihtGaefOB~+~&>C?p<{B)xnW5-{#SZUnt9(dzzm8^GD~^f%-iM z)-1Vn$vZL8cGx<6{_=vmH@~~%=O@O5Z|z+7z4_Y{pV?7!XSk;Ieu01a%FTyfQkI=u zv2)i7`X@DC34QmK%YmocZv8^*qB&JxTybR0^VOFZ%WXR*hQXU7&f4)+XWI{49ACe6 e+;!7K4SxN?-_D)5J!Cuw+|;lkG_tni;eP{c;SMzb literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/m_foam-north.png b/Resources/Textures/Effects/foam.rsi/m_foam-north.png new file mode 100644 index 0000000000000000000000000000000000000000..e170444a63fe5d97efdd7ac6f709a841ff4ee902 GIT binary patch literal 15597 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 GeemD9$sg+g literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/m_foam-west.png b/Resources/Textures/Effects/foam.rsi/m_foam-west.png new file mode 100644 index 0000000000000000000000000000000000000000..07439be5458230af590e3e4c68f17a9ce6dde1cb GIT binary patch literal 15596 zcmeI3e{2)y8OP6%1e%I;WvnR)Z9FqlXtD47+rBv_KOB-w7_yMjB<<9m@6O2)+h=^2 z*vVRwG1LuO@{5g)tZGmJRShW&wxOv-Z6;uAiwfJSCRzi6ic(lInj$C_jF!D;C${s( zc@=G)_Rni2wx9R=KF@RS=Y5{n_s?ysTwAsvGbfWEhy@kpt}5`UR{rN_fOo02^#=I3 zCs&?~4x-g#DjFb&Xu(UPH5@U&nBwhu1~?K`@&j9IGNhhHd0!wTG`4 z0tK4!H{Q~y1+GBzxY*VHWwENQcAegAwVJFe)dos$CMhFn zq_hSjZK7zCK|S%(I5WXFM~L&%Rj$<&>3~(BX^`b0O_JeoSQj?x#85q{x7+O`Wgra( zEtsK|S^_c?(FUZYu^^LiT)f1FgrF>l0ksmB@rX@wfkvYwioYh-t5}QISU)l_ovNYA|Wx<=+oGFnMWyWjgBf<=BiV|~+ zmO^ZY9AK?(-f5yBsLR@;TAc;+meW(2L)}b1_3}>Q|9CtNi*RXpno_< zW@Z&7d2Ui1j-|a~$j``5!Ozt5WH3=f&@GFq#dvuX8up4Zw;py?T#m9<(p4`(-cCle(Fo0e!@ zNC4*^<4c;Otc6q7qPH-1p3!T0Gwacs4JMn`u4n98&c?Gg9xTns#n+M|%(PVHf&{9y zC8>%*Ek{qb_57x(qmzP9h@MbECM5An{}pH^8!&#P#ZN57C)&p}!zyQ+lU3S-=N#me z(ZprNJty3R6x%r~1hM!@?lb2IH}C;ed&NRUXU!Z$61{Sm3Gqesph9NT`LU=|-Qe&J zQu!_L3IBtQkeKHGavNsVRsYd8q&}hkf7_6#Vzz+^)bpH^oGjqUf!Xa`Y(J-V*5rXO zy%QbEj}r~L7*rG!?H;{@oHmxo9GhRGbfd2+I^Sxbz>Cx??-Q=cGVEH5c1@OH*M#Q} z0)p%`Ok{(Glf0B)(Ae?59^CBlPK()WG&@Lm81|?XBD}B0C4h5SQqB`2$Q1Q~g_Mr9 zGdU&+6OOU1O1dqJ_F!xj-1LF_O)`GNIjue8r`Xr|C9$HfGb$7dCxL*VO^gf82U0OE z2ngE5xX^qc72|?{piPVm%?DC3E(i$P#JJFWAQj_+fS^r`3(W^oF)j!Q+Qhifd>|F$ zf`Fh+j0?>NQZX(F2-?KB(0m{j|F$f`Fh+j0?>NQZX(F2-?KB(0m{j zU!Ji^Hbz;l~n@POt= z>~iJdPBmLzt)wdts*0Z9! zHnMQfmDfM+$=!VCR^Qzv`QJ|aYW(w0hR;_PS1wBbW2dkAyIZ^NeA)8QqWgE{mYvSN zx2pTIo1>%u+R^svs`o=79g_ZMdVcqnK8+Oo2_ z)T>30?YQqH!>Pa49X_A;jl;ydFRQH?d4muC=%%|wQ))`@2@j9Y9o+lV`^JP?&(Dj6 zZ>>|QRXuGR4!nEzt-BYVvk_->eP7id%FF07WDVXv)v=LIpMU77V*}@GntkfDym^I< z?q_XVH`1@oyG&fUy>#=9O>6#eE^z$P#YdV(jt*FI^Lf>_3tx~B|_3g3F+^U_-YnO)X#qF9i7gu!kzVOaI$1l!Pe`$VTS*fFarE$&nEqSLuIr~u7 z3#T{L`%Ufp4j;`q_U8wWcV=fV-@mw17g%_3Xl(TOdq*Cdx=eS%ok04%@HW`rQ4a1G?>7{_cBVUg14OE&c7ksaZLC>zUK0Gxn_R-tMa2 zORubBHthO+&%*Jt-Z#sBR?bHnJ|#YDze;yJ+crAy=#HIRFJ4h~eQ&)teAZ}%_UAQ&3JX7=YUfw*^1J& Ku7kx-Z}~T1%~5^; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/mfoam.png b/Resources/Textures/Effects/foam.rsi/m_foam.png similarity index 100% rename from Resources/Textures/Effects/foam.rsi/mfoam.png rename to Resources/Textures/Effects/foam.rsi/m_foam.png diff --git a/Resources/Textures/Effects/foam.rsi/meta.json b/Resources/Textures/Effects/foam.rsi/meta.json index 33d13b267b..f4cbd1d7f8 100644 --- a/Resources/Textures/Effects/foam.rsi/meta.json +++ b/Resources/Textures/Effects/foam.rsi/meta.json @@ -1 +1,99 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/81b3a082ccdfb425f36bbed6e5bc1f0faed346ec/icons/effects/effects.dmi", "states": [{"name": "foam", "directions": 1}, {"name": "foam-dissolve", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "ironfoam", "directions": 1}, {"name": "metalfoam", "directions": 1}, {"name": "mfoam", "directions": 1}, {"name": "mfoam-dissolve", "directions": 1, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1, 0.1]]}]} \ No newline at end of file +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/discordia-space/CEV-Eris/blob/81b3a082ccdfb425f36bbed6e5bc1f0faed346ec/icons/effects/effects.dmi, foam_directionals by brainfood1183 (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "foam" + }, + { + "name": "foam-west" + }, + { + "name": "foam-east" + }, + { + "name": "foam-north" + }, + { + "name": "foam-south" + }, + { + "name": "iron_foam" + }, + { + "name": "iron_foam-north" + }, + { + "name": "iron_foam-east" + }, + { + "name": "iron_foam-south" + }, + { + "name": "iron_foam-west" + }, + { + "name": "metal_foam" + }, + { + "name": "metal_foam-north" + }, + { + "name": "metal_foam-east" + }, + { + "name": "metal_foam-south" + }, + { + "name": "metal_foam-west" + }, + { + "name": "m_foam" + }, + { + "name": "m_foam-north" + }, + { + "name": "m_foam-east" + }, + { + "name": "m_foam-south" + }, + { + "name": "m_foam-west" + }, + { + "name": "m_foam-dissolve", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "foam-dissolve", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/Effects/foam.rsi/metal_foam-east.png b/Resources/Textures/Effects/foam.rsi/metal_foam-east.png new file mode 100644 index 0000000000000000000000000000000000000000..77b1d689101d90317c32cd4f1614692134100921 GIT binary patch literal 18287 zcmeI3c{G&o`^O(CYoU#V8cRsVEXFcpj2LUSFhW|4*-Vz1%+#O~m92#&gh=%f*%C#f zvV{_&JzIq&ANm&3r^0Vg(NoR&ob&ts{`sAmb7r3By080vUC;fxult^7=A0*Lqn*Vf zv6W%~04%byGe4P>C{^QNIty+0L1L+c>KnVUJN#a z<;7q^tnhdU)1N`5`%nNN;CZSOjo{QTZ8+9BVqzT`a?+aNxLgF{XmTWES*)stqNvn{ zNX4_ymOE4~HZz+qSDzj!7#$sQbh(4(!oy-ug?kjwMISsLdHC*^mwV28KQ148-8gae z39c`9IJKx*xI$!Mf~B^DPRPQGCaV^|I9OLx`?5!CeW;iU6Oa-qA}g}Sl?8xL!C34% zr3&GjfIz?laS@=xHl+eCA2BKU)+A|*K*%A13U;i%wMfV^V0}=u$pv7&xj;zjDOD#R zeLmpPK=SMcHbMapwf(Oj03oTLlJ*Dy?k5$O3#7*akfoGJQ^3mr$Zg(q*bH!m1Iwt^ zHE7@|6o6Z~P%VLi5}=|>h=EXu@5H$^L-W11iKp)x zJ3=j#Tz?fv?|<$x%$#ClcJ_GbvuC|MJx@2(n79+~y6l^vRc)_u8Ta`o82fc>^u^6r zDxt`&p%(K$y{Ni3Vv`}?d_we)XZ!0Ii?1c(lV24cDAibbmbz*z>vmYOGukxy=rA%v zDaz!;+S_YdC&{n6G`|Sqx^#eo9XNqKvCyooB*Bl?YErK3idSO*@S%)R`A}U%FvRQN z%Vy5xJEL)n^ff>T)#}7f0N7@#qD8n{WK<^t0H*1o8U@C3Bb6&OD}>}L7qnN3fA!Ek zWTH}2Wg=xFMh=np_gI^Iz(hT~u|Pq?1NLye0;d})^6%0uSo#P5^Yh~yaQ^pyMlS5_Jx)jivH zKgUb*c?=F;2d{XuLRh=T2d-6HZE{&(Q#6j$a9JsLVNUJJf=#)CWl^J~=F6Pm zM0MwLOd!Nn#+I%&u69o?vmo*+sKw7k^+W{^IaH}B#bsGvQN6zSpPCh(NJNCIrKa-Z zB{553QhOrtHF_#bqVPzy(&O{2F8@VnUD9ga>gTB3uX!;AWw}y0?#^?vccC!)q$Xrt zeOOOwPj!!Wk6e%92Y0bl&-FY1`sDOV-SO^@4YIvby{KLx$|{#$Xbfpm5gpYC~ak(k#{cs!AdU~uQB?iH|*<+JK|T_CEj;wZRodnllVq( zgtKr_`0|5wku-JLloi4&XtJCYmrmJSkbQ7OwvGVTLkyhiOOi}tIJ;^TYwTSfdsi%e zL%eFdoCb_=G5bPxXSTTWuyX?;=HfP|efj3j+D_dUMIR>QIA^DB9B`6zqFpq|ipZvA zF$hL~1-p$$3At6X90y}LEaPK_&+ z9Wl(lcovP<-k|MLt4 znBbaYnd6XSF>pgSe=sxk!VR-Bw=ba*#&sLiwy0UqVwx7D_BlOs>c|w!l(sd*jOJ@) zduPaiZ^2;1Lm3DJmNSX~Jvor8U-)H%KuyMk;@8`@>i-oR2MGIAg+7>pgz~0u` z$-pYW>e}8r;I~$<$7c}ZiHR={#g?{U&p$FhW-fV@Uc04RrQ5gGxAwfMkgB4pwe4Hm zp=3wf(hF-Z7}yxt)HU8~JlFU*Nhie+@dVkI(wFiirK`kabHHZJ;;iCp6sy9X%@^E; zip%}NHly7#T%9*>Ei%tb&0F)hEUzqcab~GqoLx@ZV_J2=`{Fyr7fWOddY=ll)$T4{+OW2Up6ZnHz=9@2D`g!Vjyw`&eV{=r5vP?RSKCp4qh|wqbm!KWL9L^y zDMcw&gIR5thIEJMLlNy~?xD`CO>@&`-LJ04zi{YnF%mx$5BKiM4YtSIhtjV0DZ@yx zSeLvf1tl4r>@ngy8Qe#l|Cw%FH&(9`+3B|Zo?b;seMy6TH6v|%SQmc3@+5gOXtD*! z3|S*U6O0Nq4t1aR!|BSwOUlSdyiaGU9Ehq< zja7CZEH!L{PW&BPt`n$oTRTIuxAc(O#pC5Ri)=blFlo}syCJ?vL(C1t!4t8^cba4? z+Qt>r-qK!EcQ@ox!U`vD`yDBPt%?`E<6U$-cYzyJtk~qj8^UJwCmOQxLR%6s% zbV5$ry2inKMR(hd>z#ggW^!;z)smMdiZjBkU7!lCuW#h;Ko??n2DXWHFJG`Oe3MWv z_S)fM4c|xhIfE{V`N20-gKWJ+w^iOfPL%yt@f@kx2~(i&*7BBrf0oRJ}c*S1y8a_f}H-$txFgYD&q?)K+T$>rQBzyF@~E;_E~SzeUfU zUs=?(>B`{fN3%9qVxxLn*}-Cb>G@mOYvq*8J57xSMufizBZSWc-J#ZwtHdXt{91<8=cT5_PL@PNcr$Ko{vQaz1vt_LVZzG_a?COtfok)gsLE-ADK2 zz7&42dba{i0k*>=`9rdKic|6zcTe~0_V;itkKc9%eYI#?EqNM+bqm}uOt?dT-hbdh z9PLB%(bV|VeZgA)w0pFjE8f#bYUH?)#Sg7CRC5z`m~RbXjtK=@#$Op`aUA_fW_B<uiUUH?u{q_V2uKp zM3Og!4e_MV=zfMu@5*i|LFi;dB^MoAxGfV;@uFJ>`BR*N>^RGN;9;hs-5!;~P?UD)1+O2$(OA+EL?A$W#A1)`&+3njsI^&om^ zErgDq9!gIWf`lVK#nIMc_|sqrG#U+qBVkA+l-mQ!3iM+W1E78^<(VMg@+U?dD#|w~_re zA&U^mq`(|0EXFQ>62)vc#gDE0yNe)`e#Bw!^7onMLngr}J``WBgvGsh#BVQw`TZBj z5BX1*@x%Sc(X;8)*~$4yJLUPKj1oZqgKWw(BbzRTnHj=z>kotXrx4i;e*%NygPWf?C*TK0b z@Hs(ddV*rua%-PVWE1~Ql%M*7<1ol{YT&<$GTZa#7`C<;D?b*S=trVhnc}!(*P_$O z7^04zwkKJa0wwDsbfJ21ls1&xqzl!dkl+X^96>^n^rr{;v;3FPrVP@qsY2q0o>};0 z28kQ~M|oh#C<;Xfg+fC0bVy_<0zsib^-FJU^$!H|?d!jkPeo18SPv`DS zM4vf*rp7|%CPSi#6g?dZ73!%=T5&MWGacGgP`i8QF`A~{3gsVsVwO% zZZ!qYsWNV@P47HTl$}4fes}oLr*{x0(Vs<`T9}4P-&f|3E$7FMGNqYb;20ulYVX03 zrplK>#=?GToxQ9d%5O6IuhaSO5X{7%BmZ*_ju*v`SNYF`n(p=IAS?!z%^~_zjA`5o z`8O+bChE^JaCj_iYOnU8{~t^Qi@5uLHx2)8RsFx1hS@46c@h0+6fzF>y@0q^9uNf;`_-i80eqowzrR z6dZSG;3jbIjr0JDkE3w3Rm3!mJ zy=R5}xM}@m3;D6r{x?r%NA%x}3W~)~0s_L@25fq?Kf z`M7xV0eShjKtOn#d|bTwfV_NMARxR=J}%yTKwdsB5D?xb9~W;vATJ*m2ncVJkBc`S zke81O1cbNA$Hkiu$jiqC0>azm!ynI|BAiPaJF5Y}VUOp}m5Z)#q7jHfwFCP~O2yc^*i#H#TmyZhsgty7Z z#hVYv%f|%*!rSEI;>`!-<>LYY;cfD9@#X{a@^OKH@HY9lc=G{y`M5wpc$++NiOoI+ zO7Y`9`^n)x6(!-g@3 zZ<_DYIe9?fZbrMfhUaMkqQ^Nqwuz01@|lCB zm(rt}iAt@~HX@M^=jS4xZN?@wr-%ydvGw|!^p+P?fR;< zYH*vSCu?e0r#DF{=)a?^74qpP@&!@{T2WMacVf7G^p zpSynan8st=z7atQ2jRV)JGMxuH5^%8b4LJG7Z}wX6~C^>HV4jARNuPM-KF_$wvSBK1&`wo&6C4Q zOC}nwYJOfY{9b?i3GXM4CP1=Nsc1x%%Q+6?)6LUBhH*Ns;$hFjTgc6}x%HwVsE2Xm z@ru`_s@OuEXpBLvmhu=1OzmLz=)pZIE8KE8?h;k+ESY+4*~-k$G~dMI!2bYok!@W7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/foam.rsi/metal_foam-north.png b/Resources/Textures/Effects/foam.rsi/metal_foam-north.png new file mode 100644 index 0000000000000000000000000000000000000000..141433ed76b5d8d71b28f9fe8f659b9eb1e62b50 GIT binary patch literal 18460 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 AvQrz)eN4lelF{r5}E*q=^_UJ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/Moth/moth_parts.rsi/deathhead_r_leg.png b/Resources/Textures/Mobs/Customization/Moth/moth_parts.rsi/deathhead_r_leg.png index 41df319be947effbdfeb8ccdf2a28889b8c67323..7169cda3bb757237018453d32d99c386f02a6157 100644 GIT binary patch literal 552 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7*Bb+IEGZ*dNXUU*Wmz>1clO-af~ZHx??r zkhZY6`rwta#q8M&f3RqESXg-dX42hKSWvXGS@Z~hK|$yL)q*m<3ThAk@&B=i)U*A5 zee&c3y*-OOZpid)u+eB>!h_ayom|2_C1|>b{sT9!N(%{|BJF))t2;Hi_zHINX&ru8 zV0@YHz_ZyNwg$|vD)a8S{Q3QL$Go_h_%fys{p|~Q{kC2^tF&dq%EMQLuZyPHGD{_h ze&H_D{{DEEl&AP975C)3dEpiFmKXlydUv7ec;$PU;so(b)-yl%?SH;2Z=18gAuW&Y z1l}il3}64;>B|5ANyK5x!6w7F3E%d2SQpK?_F(?Y607)xTUKi7k+VhjzxE8C{N$rW ze5)p2KWQA8z3x-(f7_QUb5`av9$~9!+cWXnuM@i@8+z*%&UU?5F8bZ3@JL3dF;!c> zS)%T`NBDyyx4tuYRJiQQ-5M2~Dwgo~JL7yN9tO?bO5dF}WPb-nJ%gvKpUXO@geCwN Cz3gKE literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!SkfJR9T^xl_H+M9WCijWi-X*q z7}lMWc?slj7I;J!GcfQS24TkI`72U@g6#o5A+GKPJ~}!&x?lid07*0kTox_`5z$5k zKv^vMuB!Mb{;t&Nuk}=-17w9D2k|4ieh9LPi?~qj+n6@@Z zDyP{bES}<+%338G$LMG7q%ms>SACcH4CZ*(=_YwHqC6bmzKa7j7I?ZihDb=hJ$RJy zumJFVdQ&MBb@0E8=oHvj+t diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/meta.json b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/meta.json new file mode 100644 index 0000000000..8f86af7053 --- /dev/null +++ b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/e00cae8d065f9cf520688cc0dd0e15ba5bef12a9/icons/obj/flora/jungleflora.dmi and recolor by TheShuEd", + "size": { + "x": 96, + "y": 96 + }, + "states": [ + { + "name": "tree01" + }, + { + "name": "tree02" + }, + { + "name": "tree03" + }, + { + "name": "tree04" + }, + { + "name": "tree05" + }, + { + "name": "tree06" + } + ] +} diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree01.png b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree01.png new file mode 100644 index 0000000000000000000000000000000000000000..99ca699d42035126a734630df4f811b04aa872ec GIT binary patch literal 5323 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree02.png b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree02.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa9a2913f696ec2c0f200b2d876199bb3f76e18 GIT binary patch literal 4671 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 YIKfl>3IBdZe;ESQm9>@N3fAHO1De_~tN;K2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree05.png b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree05.png new file mode 100644 index 0000000000000000000000000000000000000000..8b2cd2a30b03c07122e7b56f69c937dcd3676fae GIT binary patch literal 4801 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 O0;nlzE7r-|ME?&SElaTg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree06.png b/Resources/Textures/Objects/Decoration/Flora/flora_shadow_trees.rsi/tree06.png new file mode 100644 index 0000000000000000000000000000000000000000..888fbfd25b1ea23965517af129a9e40765ef41dd GIT binary patch literal 5196 zcmW+41yoaC|IwX;k)u-tNs+D*qZ?@uY5x*}#CCxGZF&;KnBx*8e(?4e~SzlL zhe4H${d0a>S$ZtZrQPuv68n1jJTuX>kdk-!1jFKNW4>e*oywi{t11y~!R=S@nb7h>b~y1eZ`2idnEUrysTiRI$N$64f>vvCGf%4rN32l-Kf^B&#OW;5bUgzvaHVT(KBd zoU@!*D7it8!~&|q{s~3BTk(6KrPEt)?fLX}L<9qOzb=6JHGA%Wp#!|P(*2QU-G@jU zaQiC)*unB~*tE%A`;z2iWX04mh;k7S0z^FEa-Q^MTba!>!WEqSb{*SdYP-hKEU4ja z0-glt4)2?{wMSUckcl73!hlF*>+UMLY%$3D&7<8{hGLi78lD$s2mIe_-!Jkav`?5Z zibPQ>mc$TBFt+oRlx|9)@MKT0ZnC-t3ihxDH!!fb_j7<^qH@#C-LM?@Lo_>myme(J z1#+I4&_-RkuvSAR?T=KxZQ;fTE>`+liq&#fgm%jUfV=zWbK;k^_BV${{ijN$hb+A`tBQzH zgJ%(g-sW^AmwM~Raahsd571kvn~gx1%l>tgfwmrujJ+FAB1WTBBkqISVPQrd`ers; z#jhW!b#s0KN#7R%YzOHdgNTA( zEPTP=*@{SwI3<;2*9$bFmV!7uO0NWfg0&2dzPeAZn~-sild__P(hL~i$`9R6I=_rS znj+U>r?N-UlNQT)&d^*-pbVBi(7>_#5ZIxfNH8(5+s6w#IZE6 za`qW75Y~{DN}))IMQNe5TJo-D+n+pRb>ZFvt4lplO9X3)isFxxy=xP}s3Q&iurynS z{)PfyHSI)#ltu-5e{*Acid5pgwm7p9F$cXawGy81u=70`VQJg;K1Z1@wh-49%#5(P zIJ1T#ujr+P_d`@6E~=I*L+NM2oAu*JRq8G=Iq|M8KaY zVxW-9(2AfzS2KxX2}^ty6fvEWb#f({&;MK~at~SK+gtE;QeRtN*rdihG=i0}v*7hN z=!3Mri#^*1;v+`2LQ--3tYuHZ7?OVv9$Un{b#rDKFKjiZlSA_#R#1E zj<|B5deRdur?vxcKoAlX=k-?gSX|-Hh|8~q4Bur%MM8aH->e@0bxq@0t`t`S5{*jW z%9?$3-zpWty;|^GAXlVSoc$BVo9kjp{_Q5T%DWMI2*LITMBCdiHX1dGx&lxp5%J>4 z(um*pCT@+(L)Lqv0KYrV^!?!X@Pn*uxZl#Y>~5Cv!#x?^>RO2XDON*H)`f+LNR>4X zTh#X#x3q6hRlnx8PbU8;pp{yUZjw!vbIIeF3=6R)qFK9HTDo7ues-<}vX^m@l7P9K zY7k@spT5;OR*RN*17 z!fNO(^gd0EmCjajDbS9ruU~NoK#0O^aF!*M{F-=|E4iNRIu%#xl_!f1v!C`)Gxqiimnz7S^;SBZCv_Mrbpl&Y-v`0qTYLE5C`)W3$( zb0Gh!uNmk*s>rmroqCF(5< zLQ7E#@mE+YH`d3u6m3YI+bs#5S9N~)DI4uNJ6R{=?{pv0I~nkChDf$PwEOylNB;^@ zjD!)y%!)$b(|B%sc#F_8->zwd+iza3S(x@7iFe8Nx|nDsVozFhfjVy6Nw`cePQ*WI zR>BD8OFf(L)M&qbNwlGO=bcPoAkTly;vAS_fJ1!wd+#w3+`u=3cx_dnxC+qd~qL{LImE5Zh7Cayv79L?e`zqczoCFdiob%y`FS^Ck|E0 zMgL=dGs~SGtY(<|r&uDw9bp%xs_e#+i6pdlna%$f`J>3Jl6!MGT*aE2IJ{cIWv#j6e7Wn2(ZUS(eg1YmH{B8OS}+)AhdrMc z{diCB=-@_O2$&cSTv2MjHO&!omTsvB|R^Qwp5hw>8Ct0OQxBszMW&S=crw?_)lTzt$4r z%)C|X6a6;i=3U=Tq7E-fbu0>S0 z%^Vi;AT3oy4vzZI{Ny^#s0Wh^WCOi2yDJWABM!gN-g*wg_VA5xYR3xA=eil!p}O_H zE+K1jlEpsGayM6@)M^t{_+oj2^H6FVK`A2ksOt_&Qyxp`NLgV9B2h^-NuCGUZT*MDjQ(dwLiTvI5k_f9=kYv-S1s`a$DmX48$v^(=m{bibTI>~} z1ofUOI4?^Z>*!s9ZT^iPrzD51`m3B4rp^0|1%V|4FHH)$zxXOI)fMnkpVXfn9JdI0 z)66J!TXMC!Zkh-y*RY8V9>j)gNK`69<`8{v$-%NMPWs7Uza}71JlshxI-TY>(6!Ih z{8@Ejr9(}+Oa(?0bgi;$22<+}dz5p>`&ICkdu2tu zR9U8RiazuaVQio3&v(jKeoDf<>WVMnK~@fPU&Vg9;$LvI&wl8(x{DXmG7vO|qQTzs13FJjAW4m{$snUC zv~@Y6@mbToh@VJXnHSfO!`UM9W<68r^Y9zw2(pZMRW%FUlLDndIayXuecQ^SSBaaa z53U$ly^rUyy3AVG_-kCwa35sGKDEYJ39x*LV~6c`ca zb=kx7G9u#e3Pl%-DE$$S;1OjA2*y}w!IQSBR55|Bt~4x)?sHn3Xc6YXbjdK+0&lowEr2OLsQmYEh z-yq$)uKUZ;Lx+BdMUuD74|;(-*OULgMW!cP{KLvBx{%MGP#vgyqbV=ULAF}OqPcFF z4$>i%Id7>eP7$KB{?g9Jx$_pcpiH0K-4mI*OodDR14B{NEXxbiISs{jg1|qrd}ZL` z0-B`DL@|xkm6U?U6SWTm5Vm^NksC;GtJ|E}AOp{v>*(%I zR3Qrc1W&{yGB2b1-`q~(G1>+^e-Pmm%47Mbn7@S*({>ja3dKOQPNo`!KtZ|4=iGaL zuFzF!AFQK`ZdsBQIX%cIlqHiTt5N9$%RWv+*tvFVKmw#5UwgS>ioQVyz3dcJ!gO#y zj^yy5mxidgGF;bv6NQK16I-kh_D^p6#!k`MefA{wFYaWr6eTv(o+&G&xAcwsJ|wBh z8)hlcerYjBq(OKL#YSaCKW5K4v2yLN+Gk|N?<|G8z(-dI1Z;cIpL!%+xznF zBLMw}o1If2qRd1iW+bN}x%=Q|iBdf)K>o}3DA6dpWm86P6{DQ$?`pF%?Z;&4XXW^2qsm@iJMI*-Te!3e&u;&t51OUGDuBDp zF3jI5K6?3R#Vh8PqOAwqRohFjhRj#7nm=BuCw?H)zkViAT$jYB?3LGTQs04c5yEw- zzP5KQzogBq97Y}6hutI}^$ewdW`4sR*3p|TL^lHHFNlDzyp+7j!^r2U(CB@1%I!!cnw!t2r_Ltmo? zEyLm+qZcJ89_bTZ`1_A;++ojPX(r?RBL!wNL-DlSYvPQmgx z?<}CSVRYaG$m33@?VdN`?#7#Pr#$q^rKGfr$^z+C=>L2iYP^XvS%qUWtY+vR7)QT+ zkx4?QS|RX>V8Pl48F@va;!goPZT9i=rA2 zNjwN*!%;YDd2xg|SHL`R^VUFkwM)S8TIB{VrMdL8jG-1Il5h#Z!^@IjDQ zSBA4nE1Qisem B&nf@_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/meta.json b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/meta.json new file mode 100644 index 0000000000..33dc4fa073 --- /dev/null +++ b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TGMC at commit https://github.com/tgstation/TerraGov-Marine-Corps/commit/4bf5d1aafbcbbb7bd2a7d0f52ef87f28e2bbb384", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "stalagmite1" + }, + { + "name": "stalagmite2" + }, + { + "name": "stalagmite3" + }, + { + "name": "stalagmite4" + }, + { + "name": "stalagmite5" + }, + { + "name": "stalagmite6" + } + ] +} diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite1.png b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite1.png new file mode 100644 index 0000000000000000000000000000000000000000..ed9ddfd8abbb2528608aa6441247d98c2164c2d7 GIT binary patch literal 714 zcmV;*0yX`KP)RCt`lmc32_K@^3DC=1H2@?%1@kiw_3F(wq6m}nst4Y9G( zLK71$NQ{lI!K>J4BNAZ|Su|_T;$82KGrJ>^>`llnFmvadbI<%Nb~+uAW-OXEJZtRv zjkB9fY5?;JV}R;v z3Z>}23?lzsHV^#6)2ql}PtSc}8pb7Xy$|8_M}ZFp?kM~ZP~;21kYD}{0P<4|C!gUv zm4WXMh3tYhk4h;c0A0B6lkgqO^Yp0h+l9Qa6m0>!SuHB_XaUfvQg(t_L4E|y5M=-W zmK--H0%g+e7pf&3s{jTh10t~;e_e8_hy~z-F(N|R(B>++Px^AQllnBv%eG^rt3?=7~s!7Rv zgjNAET#!(zzc=|%CRa@aGTr{{!{-lWOqf|idAb%f^C&BC-FBt}HWfiml zTrvzw^`oZ@fC2Z$SYt6T74x|N$Bj$rsVmP1ITn>W3r?R>n{3hQcB0XUY7)0e@ zymJWdX6_lN0x&wZ(Jt=t@(W!)EO5Kw3Xp^}GXmlJ0Noej2G#<|L02mrw;U2m5eSFI wN>bH+W&n!jMLRMZ-Obo!)-wUjD^dse0x~>jWzmT`n*aa+07*qoM6N<$f>V|-GXMYp literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite2.png b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite2.png new file mode 100644 index 0000000000000000000000000000000000000000..e8167762612ca6556da02e8340ee882a1eaaf1f2 GIT binary patch literal 557 zcmV+|0@D47P)oZP4!>$n&T+Fqit+VcuTo*_ulXQ-@EITY};l)vM(h6;uu=WdP9`*_FcAInWk#(g}V?D>6n-4Yib~dEGl@&lR%7(H>aQe@ie6xW&49mc) zfN^GkI4Az^-iQ1I;R|O0$^j^VCY3=608R*mj;M!lL`dJ?|Ii7O`i(eQ3(J6#QKWOCH91- z&7KFaxGP&C03A9s2E=Q(AN%R$ft-)eC}Y_@QK|rC!7CstB4)biT`B{d3({PX%I5~X#!CTNwO7QB*qvZAbQ%&05YN(r_vVeLp zzC^ITIwolD02ZAd(|e7n1rRNUi{fidNEyyP_ElKBt%jrD^A`Xx+$3zY>Z;ct%uc|`!OP_7 z;jy!xL@YiKQH*_j;3Z&Eq!8fv{>6BtlmkJ7$j=AfCCEo321MMj7wPdJs%dh3pi)Cd zsV6E6INpDeP*WRXK%o0ReV=zeBJBNPY5_vdVm64hnf}rRG6r!v))`PL^FX1Bf7%Z9^noAsdf)fH}Ogv%%O^2B(0aHrYh7D-z+?;jb*! z{FmJiGUvUdq|+l{XOIc~-6E+7J-`Hiep z09S2pJQ-0+-uwPT)x(u+PUZt6!Y*0946d7UVFvQ|eRi}=kTD#9NXVt{?T9O#1va)f z*E4b%lU_SgyXHP0EH}OpP3nyQ_GKhQcmq%Dzd4zjcq##TA+x~3zmER^dk$?gAvotc P00000NkvXXu0mjfKAKS0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite4.png b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite4.png new file mode 100644 index 0000000000000000000000000000000000000000..90e0e75a07f4cadaeecc9a07d152c611def74f96 GIT binary patch literal 695 zcmV;o0!aOdP)6l7a`zi~F(zJ2O!VN*i}B*k zgC-_kNQ@W12A{$^nwStpP+OIPseQ$PVQsftz!($X#afn`-@KXKmSnYB6~C$EPXw(T z?6}vpdvSbmm6#a7>HfC6b99yv8Y(Pgh427$qz#ZSnqqHb&DE(Yj6PFJjya#}6Z0!Yox1m5R!0ho+26K&YMzwy%~KhX&5fO!r#_ zP(bJmZR{aL8?3v>Z*yVU@BU1X03oE7#RkBaG0hMLi>xg#7l!7d<^dJwXZT74N(kEj3u002ovPDHLkV1ly@HfsO? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite5.png b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite5.png new file mode 100644 index 0000000000000000000000000000000000000000..a10cdb5d9b9ed3928573eef898bab2d329f47bc0 GIT binary patch literal 610 zcmV-o0-gPdP)LJ+j6O)ZirHFU(!FyE_3#zFAjJ7dxdGB~4ip7Wj$M|VD-XLfa- z+3oISFI+0$bu$MPiRtWkXR~{9c`FU!2!O7+nbBw~eb*5HJNo|ssC{~EiRnJiYycpm z)nP&1&knXWy1AQssYbL7kc@}zAe=o(Qv#0fdZ%0q$}~-G|3F zX3Y%NYph=ejG|F%Ob1|`Qj1YOe&wQ}d=F&+)Oj_vz{d{`0D_uOW*-OvAXs`m$ul

ZI6-PQ+ro_~1b~cCV{3h@Mx8|}US>x^09ZC8uh+v}Ae+&IB$S}l?(olu zKA=nlKroD&IneS-g1tN!`aw$75kLqf0H8=2gdCtPhZ|dikyN&zFaX^g8OH|aU^8BT zqU*4qu8|A20q~$<7InKG@UddgegrcIw`x)ul=c87g0e=Y<3uh@(nNs6(<>Jm(RvTJ%Kf;%z=<^WHxpL`>ds0YlTGLizItX|(s w{D|z#uBb=~V4R(qvumY4rAh$P(98jT0m%{iXN36K-T(jq07*qoM6N<$g5`4nyZ`_I literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite6.png b/Resources/Textures/Objects/Decoration/Flora/flora_stalagmite.rsi/stalagmite6.png new file mode 100644 index 0000000000000000000000000000000000000000..b424d6dfe0c1c0e23ed1b8bae86f6f2652af67e9 GIT binary patch literal 579 zcmV-J0=)f+P)?K@^2Y%%3C?lOUo+(r6h|(?j#<;%Y8509^$Jkc`f&ljd3QI`X7L^gIzPf zvNSRW`=L}KI(-0&^#;)T#_C`WV1D}`kRCAV?LiN`x4PC`skmbKc2#ub4xw)bMOh$lCEJCI4nRjc=9)f+&VTY4C8YoFvr}A5X;0Qoch2K zAeT*BzvJ$kYT%em8%16G8q)zPmpn2 zlk;Bw6EkKq7 zK7aYmz{|smAx1X`>^O3Y!AMOWMeN+IhYTsSb^xxp$0tuHT@dYn$+hYKRTbpHL60pB zC@aZeh!GPl1RVgfSWHxmfs<2^;rsXZ46k1O!cfD@%f|5e^Dj6J6FYeJHo<7Y>wuM$ zYX5^Qe)akln2*g8m^iXy(8b7h!0H`G8I)zj8DzxyPz;CB$N<@55F48sk{z&S+dgmt z3h{CRCoX$qRjlfeEu(4(;Bp8EfI@~EfTU~)a|kHA@pEx7eEjx<0YrlUs2qUF)64;unFC+|Iako#0n`WuibDVdC~*kc4uIu%N&&?oK&eA0a=??9pTOA=MAOv)cb~jO zX%E240=hW>1VDulHa1-x04jz-p@1$%HwTc@`lYG^s0l_LFzSF&2Mo9a0G+OWIR%an Q!2kdN07*qoM6N<$f=DcEkKq7 zK7aYmz{|smAx1X`>^O3Y!AMOWMeN+IhYTsSZ~(6O#;2B)v_Q}SstWQL!Hq2qC@aZ; zX;4&5u1)`++dPvfM-X%XD7fv7RT(~i{srdq^0I;1Fd7|z#5p+y8CFiJ{r~FqD+WRi zAu0{PEW{;-?l=a9_YB{^Gr%1Zp4W`i5kxrv*&+}d-S^0jLuTK8@Q~r|la~zPdAQ9c zDFkp?gbog#y$z<%AV7&j$aVm>!ila9pq4`@a=??9pTOA=MAOv)ph5?^ zJ%C&m(8U2DfLt;XDkZ7z0A(3*l%f|VMmGnL)B2^V1E>i`9Wd&EQ3njT0|1t7jG@n< R{cHdL002ovPDHLkV1norrz8LX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/mines.rsi/support.png b/Resources/Textures/Objects/Decoration/mines.rsi/support.png new file mode 100644 index 0000000000000000000000000000000000000000..29f7482b2868daf33dc53bd4a5a85622ed6aa436 GIT binary patch literal 404 zcmV;F0c-w=P)QXc@@ z!_l!Us%})I|Eb1)1(+|EZ~L_0>sl~?bpauds2i1%9afqhAX?4pt9-iNUUku)62J)v z5M&r%7>9E)zchwmRL)%iI6=U8r`@po0fNX-Kgw>Ly9VGPD4%=;NN&UK3qXVroukdG zbI$+-A-k}=I`;)2)3h@9HwFCc|BEm&fH3qM y0Er#Nxc~oaAV~Oq1BkER*a7hT!oyQ+^P?x4o19oyf!w(O0000<}`Dwl-p$UKgzP!9ND$6ojuNGet*lc$#3V=^v=}tPI5)z-j zqJ}99QG%T)49Q`a5KK&mOBa=scA5A;}0000< KMNUMnLSTX&|CC_> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/mines.rsi/support_wall.png b/Resources/Textures/Objects/Decoration/mines.rsi/support_wall.png new file mode 100644 index 0000000000000000000000000000000000000000..9b14590952a23fc1b830cf42f1f4d97f9b5956c4 GIT binary patch literal 571 zcmV-B0>u4^P)>0%UU06CCXC%iyFlYF2;fP=U4SA|R?8)!tnnN;mN=YA zXnP86Vm^r}hKs{-P666s;mZY_pNm!xBZ5yCm~!b~T)?-+T8jI-o29002ov JPDHLkV1gr|`-}hp literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Decoration/mines.rsi/support_wall_broken.png b/Resources/Textures/Objects/Decoration/mines.rsi/support_wall_broken.png new file mode 100644 index 0000000000000000000000000000000000000000..4032c6e45cf763e1a07ec62648aad5e9c568fd9d GIT binary patch literal 852 zcmV-a1FQUrP)zVT_ZLdF7}SF45; zbUJ&diYAU&-~>iL4u-R}OKWH5qQbBMbL>GMy7UyX4s36K+2IJlD9VWD+^LncW~s*T z*B?JC>s&4p0Q(tDb|3X4N}NcbzpJ#=9L-6Fs1&dmLzY3YODcU zfC5FwCKSVvq7rW3f0EdML5dLneD_2()yRO9(6g&2mM7oSDrbi07F31@#I)E|3 z4xH_v z_y{oI&jJkR6a!5~_O~v=NDyVYXvB!^f2Go`y=IJ=Gtb z@jgm)SSE63hehKg)J9q@I^%Ugkz5mU9acwz@*d=jpAGfuu&E5$E%Nq0`)S2&X34=azHQBi^N}L6cmmzge(h|4e}oy zI5rra1<3heYXsEq2-&G8#Zd}StjkK16Bb^swu?M-uq>3X2ZT}H1 e$&te7;_?T0CMoetaI+5p0000<>&pI|jYULIsOHD6nG6g9+MX_sArYL63Ig}v162$xU_`fG zQd06ix)`7x+#FF+QHJBkk29bf|8_>~jDX#_oefaGuitWiKtF$_-wK%4k**@i`&sv&^I ze1bxw4j2sqtRe8{&mWY;14`kbEQXxD$j$dC1_L=*vmv@75Fb|ZePT!eOQRIaU=i{N zq8$J-p4_~S&uLhr0G|eG%Z)l<>&pI|jYUL2%_Y1(mw`b*+tbA{B!ZJsLE!#-po)P7jOf-& zN=p7m7o!&c`Sa%(_Mr%XEVs0@WO)7hHMQ)7n?}dQWA`*kyc0w z0RuKRh8-Ln42za5VK{#BBvl+jk^^1~3xh2N`TX|n+h8`#A>@Vz$(h}y5m9(fkGjR6 zs;UZhh^4tX!_()_Np=U(ApnYZ5YThr24fIAbD0`ABtW4-E+8ocEW56P?UA+r3Z%Ii zE*N|oE#K9su z3P8RE;l~HL!A8O8<7L`l-!FRe1}qM;90X3kVh7WN2!aj(`5u(gK?x27kR1Ut9NF^V z@JO(5`;xsdX}mPnD8Quymg-?S0TlP`moGEKiHI=3e7<(&at2~82iZf=0idh}%3>e@ z3JFk(hdIP@n>oWlU^Yw!%7Nk>6zrr}4l=5^d4;hp`ePYmS3jq5Z6!&7l;3qcqgIx_I2qr?9LS!1` z5NV(z5AgB9g&*x-0B4iJz#0O?7|;w1dQj>oCa>c&kE{@Y83;=KlmdzzK&j;*{i6=R zng~H{cxrb{a77n}13+CUQ11v=M*^2Ygv3GSV)GQDc>^_p-knoI4yU=iO4fPd#Xn@$ PfGqNK^>bP0l+XkKu?X!X literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/health_analyzer.rsi/burn.png b/Resources/Textures/Objects/Devices/health_analyzer.rsi/burn.png new file mode 100644 index 0000000000000000000000000000000000000000..cf65084e44e786feff1ed98094f3b0036cb00755 GIT binary patch literal 414 zcmV;P0b%}$P)Zq}6o&tnGK8g4RS#a6ER~rJiJ2Q@>4|!m-hd0Rr7Huw2hU9^MNzr{1!E%H&ndrz z1m^kuALbcjU}HV#4V?4qz09PP3%^+d=log}1(Z_3%^728nq~pUDpLO7ecH) z)B<2I|CBNqz`lnt>Cq=)0^qxhkPx7}0FwRyfHHlawN3Bc1wc=pq(`f`AONPMUmrhC z@g#s-Qe{NyPX?fh43HA10ttXR{A7SM0kS;a24MR1yUKqgoB*b#(|3QWFaHCen`U{8 z_HZ@=1_!W7?lU8-0oDp`7=GV6@Gio)_m`P*md9STVEi92=~Q3P_UF4Q8W*E1kH>Z& zSpy6Zqh9|`^ES`Wju9v>874Pq_MMNUQN zn%qX4|Bx6*KnQ_-K$EpSff0Z)2Bp-^PCjCc8FyQoZ%#MYFTDh2*4cRjjsO4v07*qo IM6N<$f(wDISpWb4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/health_analyzer.rsi/genetic.png b/Resources/Textures/Objects/Devices/health_analyzer.rsi/genetic.png new file mode 100644 index 0000000000000000000000000000000000000000..b660aed537581d821913c32d4b4d581ab8c8ba0f GIT binary patch literal 4235 zcmc&%ZA_b06n@^8Qrf27pwv*xkOC$SL?vN!EPM=8!-oq&L*ll?iAxp|Hx^^VK->?r z#V!7t#3e4WA8anv&CQsMA7qJUuGv^HnQ<9L8J|^PQad8h@6y+E2`#R?h1-R=)7;+s z-mm95_nv$1xt})FS8LUoY5>~W8q1rM=dhHLO#jx7js?n+54>J&fyjQ{-`hT?8rAzX zd#!**&ys*I&t(9c3u`S^jeAr=&gQXM>hp9(h=n&Ajbd!wMtx6DPp`sztb&1;mX^Zl zbZ!)8bRL7jfd2k|#F9vg_E;`Nz=wy2W1F7%J3l`^u2QQAFcb!!lqA{oL?qaJjD(c% zqo~zL-oGF6v^026o&*HN%6wuFM~>tpB}I;|t`W@6hF03vDRC1J($k@;sevLl7qank z{PyQO^nd&U*Or&?e3llCjpv|L`q9@nNd(xLi{WI7$(2tDxI z$6FH9uV0nW3Ro<9SgkL>WK!V94Lf>!+wfg^IeZoi0xc~t$Ycm#y$ZHnyu!T#CQ~w+ znhLOW>x&o}IfMrfnvhFJvi0FZT)TfCUl@(ZXl{m(oz08A)Q@`wa&tAs0uXRX~_-Zh>gHjR=Y< z5LsFA9~Uh(QA`~-fzi=9ghGC#rTfs*;)hx-Cv0IUx!qgnveDqITn-1>Ln6XWV0_$7 zd+$U=g&V1jOWr!k_HseH7)mgp(Sv| znKKFb07jI11tMBqyy(K6J8zQ>G{a~%!%d;qCDK}P`gFqJaS5>VEh(gJlGTbfx(5s{ z7p{@l8yY%}va-uKb*cb5om_I*T9w>ez$Qr|m%FL45ju|te;+#rE8T`UIU+hccc88= z52K?VbazjXC*}{Vl4z6 z-v$JVgcM}$i*EN4yGSI&@>b`w6bbq0ZrFtMboNr>7k;{aKY|q9hKYc?=N+g8@`N(- zdSVFfu}|>h%f+O<5_5C>0V$)&O@IX>9tuXHB6@*EO3QNe=+BX2Lb)UX7Q=7!!z3Q7 zRRq`*ioK5FJtX2yv|c@%S4yeKjT#;Qe?Ly6z)!32ab^1luXtT*w)+-L_=Fs%>~se1$jSf7&1{wdmVk&(mllfA8ojliSwI&L<~S#iM`-b#hpll= zzyxISvol!asFRZ8*jpz+5`Ykh7R9okXIkbF1Ag7I3P1sYzy{E6%sGL(kE<4r z*)jo9S5H_4(z~(d6_S080zY`HT6@ F{ck!^*joSq literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/health_analyzer.rsi/unknown.png b/Resources/Textures/Objects/Devices/health_analyzer.rsi/unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..f68e2c990e59799c9cbd950445b51451cc98efda GIT binary patch literal 4235 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI z1_o|n5N2eUHAjMhK|tHn#W5s;lTkt7{(GRBfd!1{)=NrC{zn(17XSJ4=NR^(2!JfN zw6tV+{rWYv?1Y;mDk{ow{P=MObVsnjRX`aq%kSK|gDyojUqwX)r>8I+0I~&SISUI` zDY6^^G7sbkY=8-yAU(xK9WWXKqaiRF0;3@?8UmvsFd71*Aut*OqalE`@egXlQ@dk= ztErFS08keS)H}k}k-%jTA#sqo*gS>OHv}0%@6IV9htphs`fe@$z^Y@tAd5U*{an^L HB{Ts5?(jp` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/icon-potato-off.png b/Resources/Textures/Objects/Fun/pai.rsi/icon-potato-off.png new file mode 100644 index 0000000000000000000000000000000000000000..806d02d6f3d43be3a12c9ba6f97bb64bbc48a83e GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCik*1AIbUZKjy$OZ38X6k5bo+It8O{o2m{)1PuFYyJYFtWAq35p`-R(<^cYeRH;1SDy;VD5;+iVz& zZZ=$s>QM|iHp9{L>2iU^GsUzN?(Uwz6MWS-I(+BxR`)sV9-ddvJ?p(HlDxg*n9=mr zDmT*Xve!mmzF^<_RE;y`^|qC|#m|d)TyCthT3+6#>+$#2^FL2{`x*~B`p-X?(NzuR1fqggQu&X%Q~loCIEIS*`)vg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/meta.json b/Resources/Textures/Objects/Fun/pai.rsi/meta.json index 905a3684f8..f819450aa8 100644 --- a/Resources/Textures/Objects/Fun/pai.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/pai.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9ddb8cf084e292571d4e9c79745db25befbd82fe. pai-searching-overlay heavily modified. Syndicate variants by fedKotikeD", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/9ddb8cf084e292571d4e9c79745db25befbd82fe. pai-searching-overlay heavily modified. Syndicate variants by fedKotikeD, and potato by Doru991", "size": { "x": 32, "y": 32 @@ -13,6 +13,9 @@ { "name": "pai-base" }, + { + "name": "potato-base" + }, { "name": "pai-off-overlay" }, @@ -57,6 +60,18 @@ 0.8 ] ] + }, + { + "name": "icon-potato-off" + }, + { + "name": "potato-off-overlay" + }, + { + "name": "potato-on-overlay" + }, + { + "name": "potato-searching-overlay" } ] } diff --git a/Resources/Textures/Objects/Fun/pai.rsi/potato-base.png b/Resources/Textures/Objects/Fun/pai.rsi/potato-base.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e594430cd2bbb9ea259989541f8488b27329d3 GIT binary patch literal 476 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCikL1AIbUZKjy$ak!Iy+67&|8>O zU}a^sZ*tI_CDY#>%qq#rdbulUSEcCx+mjj^8n$%%b*3543T2pAX}_+~ra!}AS-s2p z78jrmpL{-T22%1RL4Lvi@dAdkl4SxwrJMyGk;M!Qd;={+1ukXCw{J?tR zy>@2bzriA%)PZ3>^b4{l4pWM{KtInbjFp00i_>zopr09{|xfB*mh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/potato-off-overlay.png b/Resources/Textures/Objects/Fun/pai.rsi/potato-off-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..0d3f73515881919ee768f51983ede0326c453966 GIT binary patch literal 162 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=Dh+L6~vJ#O${~L32+R$B+p3x5pRqG8k~MUX=GSKae>4-G13+ zR}2`pen0b+h2e+b#?ya8-glI`8~JA6wF7EOaH@*RX5Bh#!-eBO9)qW=pUXO@geCw) C4KgDD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/potato-on-overlay.png b/Resources/Textures/Objects/Fun/pai.rsi/potato-on-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..9926823662aa4a81604e6d89d32e93c3aa436e96 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=Dh+L6~vJ#O${~K@(3G$B+p3x92u;GAIbJ9Lzrv^u}*@XdH`n zfWfSjX1ll<;-=i&bZ(;h|J#p$AMs>h*defyVg3zopr0F8k! A&Hw-a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/pai.rsi/potato-searching-overlay.png b/Resources/Textures/Objects/Fun/pai.rsi/potato-searching-overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..5d8d7cde30c3b830b6a68e733c93d39ecb5ffd04 GIT binary patch literal 186 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$1AIbUFRV2FeAFDsOL?R|6-Y6c1o;L3|Icv!6faOM180FpWHAE+-yslY z6xHx*019e*x;Tbd_$MbQF}R63Fr4I)kXXng;SheHVMEEi%Jg@qYP XF0ucfcG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9R7#Nu1JzX3_Dj46++V3arC~)lgip33|7#bT~1SMTP6rBXk>VuxJI!)0! z64YhGw=$^Fxr@P$a+d2D# zg}0(}yvn4__SuuR23y|$^@i!&A0_^){A?fey<V|Ft@2o~9z-=b#=}Uf(qJW#>Yb4?Xem_xn|*7+aQPxA&c%xNtU$ zM+0Hx#JRvE)UB4!aP`#Xx`*#ae@=)$u)+3e6|39I%lCy(7cv-lJzUi<$M|)nefp~F zvN3Y+&0cT&GWW!%V=K9rn5|l((W#$5$79dlSE8DiDz|Oc+WLOuRiBs}qO<#_J((!| zr$K0yBn!iBeeWRg&jp|Nu0Hyh(QKAT)wiZI_0|PtGvnXyd)IB2u|S={@`2PAG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9RfSEPL)5S5Qg7NK5UoU1ukpmxZxP~{$eqhkr5$K(-VA~|Ww?W&st4Un* z#=QmM8ckbnuVX1+6uYzPt@fTqCnw{XQ-Xf-Pw|PHH2qBf%ba<|F&qjF3{2>R3U|zQ z|0CNiM82QB8j(?_A$Lkx*uGFr18|nky)_-JLqr0_#-q!5q5&;JWMiwyfhl#t%bq%lo)Op|n(9_k=Wt~$(69DGh B#f|^~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/toys.rsi/bee-inhand-right.png b/Resources/Textures/Objects/Fun/toys.rsi/bee-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..5563fc4d3c665cffaa23801cb571c86edfbd7203 GIT binary patch literal 1341 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F;KxA5N2eb5`33|fjKQRB%&n3*T*V3KUXg?B|j-uuOhbq ztjngt3dqb&ElE_U$j!+swyLmI0;{kBvO&W7N(x{lCE2!05xxNm&iO^D3TAo+dIm~% zTnY*bHbp6ERzWUqQ0+jTtx`rwNr9EVetCJhUb(Seeo?xG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9RfSEPS)5S5Qg7NK5$E-sRA`K7I#n-WDe_@Dvu`INz`H^7MSEksl?wJe4 z1+Pd~v<7MHDh(|NzcO|8a%CT}G`S-zvo-%T8azAux#Z`~#iR-_zUWlWRULoK>^8j%Tf68v_%ELIW-$fiogj zOgrysr*2))?%Srm|C3MeF{rwCt@vT@e+9=?)-tz@^Iuy|(cTuJ*06cYyyVFzqWbG! l{xp33J)#|MrohYtd@J9q;XP7%whB~qdAjJ*>H^-ePuXy&La6)GmqR*Bt{o|yVpx#5>~=$Fg?Nkl8UxnV@>AHGI{21kNH+>} S#{UPJ$>8bg=d#Wzp$Pyf^iT5u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/potatoai_chip.rsi/meta.json b/Resources/Textures/Objects/Misc/potatoai_chip.rsi/meta.json new file mode 100644 index 0000000000..dec5a8d3f7 --- /dev/null +++ b/Resources/Textures/Objects/Misc/potatoai_chip.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Drawn by @Doru991 for SS14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] +} diff --git a/Resources/Textures/Objects/Power/power_cells.rsi/meta.json b/Resources/Textures/Objects/Power/power_cells.rsi/meta.json index 01c2300621..66dbf30841 100644 --- a/Resources/Textures/Objects/Power/power_cells.rsi/meta.json +++ b/Resources/Textures/Objects/Power/power_cells.rsi/meta.json @@ -5,7 +5,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/commit/7dcdbc1468ffdc8689b984cb6b181d48ae41dbf2", + "copyright": "https://github.com/tgstation/tgstation/commit/7dcdbc1468ffdc8689b984cb6b181d48ae41dbf2, potato based on https://github.com/vgstation-coders/vgstation13/commit/1dbcf389b0ec6b2c51b002df5fef8dd1519f8068 edited by @Doru991", "states": [ { "name": "potato" diff --git a/Resources/Textures/Objects/Power/power_cells.rsi/potato.png b/Resources/Textures/Objects/Power/power_cells.rsi/potato.png index 5b0f7a5fe04b8b62f804fa629e1861933144196d..53572f46a122188df257488e291ff405b8d68d08 100644 GIT binary patch delta 448 zcmdnQex7-PWIZzj1B1(wu46!ou{g-xiDBJ2nU_EgOS+@4BLl<6e(pbstU!KXfKQ04 z%@h-z95pFNag{LnE!}=EcP0J5J?Y)Stc&w(YpaTVot>sk=q=1C*f%+7&XVct8f~ns ztV(jSc2$ZtG&FRk8O{o2m{)1vpJA}9-erA@3((Z%^;*aHfV6Z;kYDhBoPa^ygxeIT zjI+QavY3H^?=T269?xHq0u+4U>Eak-;s16*w@{OUfa}#Gu||_Q*8cd<|CVX>qs1TD ztOWl%j=oRZu$?ieum#nG-=a(Sh#WRtAECFa6We7c~&$a4+VY3ft&jY*;3Ow2ClP z7_M`RR@0JocM;NDF3ZK`e39NQ>Du14$?(m-aPYey&+qwuzkkp3%aa7|<9~+GXaWnY zRT6v3yC2a<6#*y(8A% zU4v_$Tk{T#jem|_>dm+6lA1HK1fJN6IWx< zLA0uXvC$E0lPtpZyNUbu?V*rW(Ppm^YFA*#b_!XQ(2nhV3DzrLe9U+%pCo_JL(t!fZsgH5l`C4haRC6u za*3{|?~qjt0VNV8=x?QB2o%dDg8o*Ayu}}&eEFuA)b0X0ZkTM@*2SsB38xiykA0#= zxPM!Ah>PVC#as?uQ!yTWn2#>Fk78E=2c{;4>B;Zu@9m*jF0rWTPLD(F3KOT#qh{vn z&g2&VCB3Mwlgl7XwZ5p8bOk)14!3Ylt|R6MlqMGBlqHdT>@+on?pgO4{b)0 z6?E;6%gb{a0OYX5@YfTb^KR%*!?B@3t022gsVlQr$M>-u{{f2{psVn%KTQAt002ov JPDHLkV1jHV*y#WO diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/dead.png b/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/dead.png new file mode 100644 index 0000000000000000000000000000000000000000..8fa7120b2964cbc3966c572209fe0d2a7ef7fdfa GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJEKe85kch)?CvD_CpuodoE415y zVfKa1?A2DGOEfk;NDU0QQ+h*UZu|^JpyE4c-dr{Qd$CJiFv51piMQ{TY@fe(*RE8r zN3vaQ`?m&9I{m^}Xw?#to9|?<{+rz&_T|3-?|YU-D?|es7>qZwKV2EJ{%wnwD$pPX MPgg&ebxsLQ0N9y7(*OVf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/harvest.png b/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/harvest.png new file mode 100644 index 0000000000000000000000000000000000000000..d4f146d88a045f75a88aa7d3d4950f14817a33bb GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ3!W~HArXg@6C_v{Cy4YkEo5Q} zfBjcIEccpS^M8@(jzq|Npw+-DBW>;LE4e?-%;r z5uS8dTr{PX!O+fO+HLXDse+OEp+yc4viAPp!EZIIeAslCy*ZG+ijM!VVu zXW=9O7<>&NHbfw}U;wT@4&-Y*7$*b1#{aIRgK46c%mv`;oFu<#EE+;4n+M}$kl0HY zvKMCVfz)G4;%hv_hKQZrt%x-T%npsRc~{5m%fl6w3gNvp{S>7>*Ed`*lNT22ff6fH$FofZMNYIO#H=grKc<2*VM4 zUXNx7)st{q$zk$@T&FkC5}GI!%ZRw*R7ZG_4v#hg0Iko{sZ)~(U>XQ*wF4NNkwIoX rYY2c6M6P+^h6CuSzyDYK?*V=QmQcuhOh{1p00000NkvXXu0mjfRWH$o literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/seed.png b/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/seed.png new file mode 100644 index 0000000000000000000000000000000000000000..7f7931e440f12703caabd7ecc051bfaf25a8a655 GIT binary patch literal 335 zcmV-V0kHmwP)2_4y|Q8!tNpA-dPDgppWt8Hp)~iVyYt zXBWB6;9)JrAjfRQ@aXR`ob-;P&lrBbQ6<_DL`4Cymdi0)F?d)@F|do=CdOFe9e@nv zn62>AqymZ(;i5|$DA7*21LE`o7-k(>Ly-fB&IQ=O<9&Fr2KPR1Oz*c~6|Di&;& z^K;)*^LMh<#|%^7zxMksNM3MhJ6{MjZwUhf%T1*ySCjo~f%Y+Yy85}Sb4q9e0ONT! A<^TWy literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-2.png b/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-2.png new file mode 100644 index 0000000000000000000000000000000000000000..b724176aa5c46dfa0f194ef4df7472762d3f3527 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJW=|K#kch*{2@ ztT|%VexDz)HS#ylzu>DyLA)wQH<}nv$m(05V&Qr5bc^?+pSSB%qQCrkYyWCV`+=)f z{|hBs^j9#4zy7;@*0O)|7YQ^pa+~j)EPCYlraYsdql`Cr4n5OI`S9th|EniVH3vPu l>bUzJ?*-ZAc5ng{gXCK4HFb;b%K)9j;OXk;vd$@?2>>D3OqKuu literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/pea.rsi/stage-3.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9cfaaa3df94ac3f149f72e1e0d78cbbd7b2fee GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJHJ&bxArXg@6C_v{Cy4YkEo5Q} zfBjcIEccpS^M8@(js%-YWf-$m);}CU3Bj+e!bL-k0WO7clqg#KZGJ4WbOSQ zcKM2?KQj*yi09R)Yj^ag-c4E3#k@hXS>9?(^R23&0- a3=AqRxl6WB*(wWkH-o3EpUXO@geCw2MOae+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/carved.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/carved.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb43adee10271f0c0cebebfc94c1145d445b6b2 GIT binary patch literal 783 zcmV+q1MvKbP)yoX$_}d=64V4XiwUBTan74Llb4;D-5LBfdtkZm zH}{--?t8F1B@=>KYV8#J9omBlxQmex|Lag zP7ZK9_smh`*K>Wc8uT45RGUq;9{0`6Y1>T_(Xj=ve8aPxAUU!2`MZjD^Sv_RG?WWG zhjFV@sRZcNlN=TUNIE8d;%mJ*S*`i&6U|0Q%x@9lSY`nr(XAvo*7Q4Z`P0%?g=RiH z1JJqhh^@{hwILz^2X))FE}yNE(iITV?pCpw>ut;IKpdv-SLDtEE0P#w`aPMQUy@QF zSQo_NT3u)>fY!s2h1xf{apk$1PhKsC>j20hkia@$3&@$L{^du6BT;~U>5%Bakv-ww zqo-9FD)eld>-%wefJ1#d(+eO_IRuQJEkqK-?(^O_ZV%r9`h7~}0D7cf#FCX$M3aG) zwDe_lO;wFJ+Hwh%u;GKsJv#X6&5GQrEOvecNkEU$dqgBh3z%FdMFg;iieWonOB`Ya z=q?}$6YCdE-S)s8>~jrZ^#pRnRo~VDieNRcd->zKiX>v6G1vFglD8E=5r{X7{qE37 zug}5FpACqXwWwZ2(3UjBsRR%~BA3qyq=yY}$&1FR;Wf5N21SqOhiz~8_xYtE!N$G8Tk0000EWmrjOO-%qQ00008000000002eQ6Rub;PLV)ef60+5E(jfa60Ye|q_@P8m+_`QuU7%0G5;1OBO zz`%D9gc)~C%zg_L%=dJ046*Qkd%=^h!GMSPfW_JW_j@jzYAUSrc;M`M_odPixlhg0 z%$qK^1uWo;+8?ggpmqI=T!lrTzCZ-izC%szYps}tTNO(sIs6-@Tv|Sl#lhj=^HXn> xACyh3`(NYA@b=xt@(zY?_7{W>l-e<#;X81f-*%cSQzOu722WQ%mvv4FO#t@u_Cy&hu)(erh7?PPU+kRoQdGX!h2=|GP WB6F6UwD$x$p25@A&t;ucLK6U?O@TK6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/lantern.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/lantern.png new file mode 100644 index 0000000000000000000000000000000000000000..e07dacbcc97b1cd0cbd89d884c2dc5eb1c271f01 GIT binary patch literal 773 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgBeIJTG)IXNHG=%xjQkeJ16rJ$jJ%t32_C| zmPO8%MQ$FQeriER`_c?%yC@kZ+1#7r@?vMo|1Z<)^kn|uv;ivn`DW6uE7m_RS?^BK zpXH+T`exg^qn57^ns18Jo$jJkXCU+FZ2j}S=8v|Uu8q=}1{5)pd2*rg<$jANyUf-{ z>(m*_2t4<+02-uH666=m@SiaFx+Jay=;ptkE{-7)t#7Yh?7L+kz#70YFY>XA+R-If zfbj4C`Zr%In$0$zbdL8}+OsuAHGPYeZ_|yp+iqp8Uc2qr`KkhsS+#ykz6O4F44qY`m0z(t+qcKwMBwz%S2p*Sc*%;?$E`VevEYd9Dy>k>qi0?` zEv=k0lR^ICW7W@HHOC)io}LnS{bb+$cP~Y4A8qroujjn?c0TVj33KUo^N+v3ELGlF zyGwUh^)BsQ^}F<|Dyn8w<{U`sH8irB^u*7$G<&VZrWfZd3sWxc{r>30qIQ8J6OHd5 zWj}vq!G}MpPeLE8oF7ooIVm1Q+y@c%Kw_nLvnPLDPsQqgugnfg%-qeAobpb%XJVy? z!LcJtn|*8E+=!DBzW;UR?H53Xak;qcZSUk~?-nOlXP&v^T#}>TYgw9^(PLJ4dB!=D z7~}K*9J9BIZcn-0RPJY8=)O+7;{8_f?@xX=@jJ4AbV!_0`DTTom|L=PXWN->89n{{(3U*wnD z=cUtL+irT%f1m%18B5B$6;kU{4_kaxS5N==t!MLtyQ1j_e_Nkx;xC^g-pBXHBf02j z&BOE`l?T`VS-em0$K3j>-(CNIzI8G1_|awOO@D>`528sVAd b>&u`8WOD#92wV!D45B<;{an^LB{Ts5!)S!Q literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/meta.json new file mode 100644 index 0000000000..a6409ac1ff --- /dev/null +++ b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/meta.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/blob/5d507cfbad6f73d1beaba66d93f31f893adb3a84/icons/obj/hydroponics/harvest.dmi, carved sprites by ps3moira", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "dead" + }, + { + "name": "harvest" + }, + { + "name": "produce" + }, + { + "name": "seed" + }, + { + "name": "stage-1" + }, + { + "name": "stage-2" + }, + { + "name": "stage-3" + }, + { + "name": "carved" + }, + { + "name": "lantern", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/produce.png new file mode 100644 index 0000000000000000000000000000000000000000..6fa2ec1939c78f0facbcd651b2b2dd1603ad2215 GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv#Q>iW*8>L*SQa^37P)zJ`l$sO z?MpM5?V@CuWOHwd%Zr^Ub$T-Y*q9aq6*HCu`2{mLJiCzw+)+rC3M%jtvux{-3%h(~^4~v&@1`5isBQdN zbu0VG;iHAy|CC(0KDF;&0?)C;qjCDO9|APRnF`ppzB^qcJ>xT9fJJVTyT^itDubCj zCv*G=3zu8=iy=hphl-%8gYKf|EGPVG3>Duo8XGJXW$o0e7Vw_jsIInDLa3lfo!P~( zEL=ZI`&iQC`PLhiMDE?)Y3Abn{VS)*8>L*@Eb7jXfP-wGZ@Wg z_&<~3%uI&=XBhscF_e6Is{vHTSQ6wH%;50sMjDV4=IP=XqA@W!LBhv@gM~$)MlCU2 zLBNT_U{*te;-&^}0Re#m7vTb4K37o=Uw>XlK@VPTUm(fN?JSzX&7JKi_~FHi1Mm5g m74A!VHaH5fOsKJzU}T8a6Fu=*A}|7I1B0ilpUXO@geCy8cQf<= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-1.png new file mode 100644 index 0000000000000000000000000000000000000000..762e986ae9263c5192b97c0d9995dc7839c358bf GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCikh0(?STw_aG0GRbfH-WH(1yj0n9Aax}{e!>6$|7UQ}TKNUY=PdAuEM{Qf zI|#yzJ0@no1qw!Zx;Tbd_`f|D$i<+@!4e?*zW%vv_+6f;U;S)~MRF5wsENDyu`WuR zbBg7jZR6}y43nxIHnQzpZ+w}-L~rlA1NYP1%_p)g5@|3#!T!T}-QG`SjQ@%nkH29Q X`p-RCFsMBeXa|F*tDnm{r-UW|3bsw+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-2.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-2.png new file mode 100644 index 0000000000000000000000000000000000000000..22f418d5712bcafc09edf1a9843e1987fdda9dd2 GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCikh0(?STw_aG0GRbfH-WH(1yj0n9Aax}{e!>6$|7UQ}TKNUY=PdAuEM{Qf zI|#yzJ0@no1qyb0x;Tbd_`jVH$aTPg!@2j~|8w3US=`Nk^EO-vy_n9sx#9xs%a(umIDZ9*(#7}gTe~DWM4f6y9Zm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/pumpkin.rsi/stage-3.png new file mode 100644 index 0000000000000000000000000000000000000000..eb08406899497d229313d04f3d13d55069ed1f7d GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCikh0(?STw_aG0GRbfH-WH(1yj0n9Aax}{e!>6$|7UQ}TKNUY=PdAuEM{Qf zI|#yzJ0@no1*!FPaSXBWe>=gO?}!11Gv}TE=aS#lc-&ewdt#b#Sai@ICKWOLU(A=p z88=@G-!1ll&&i*qe#Ipw%fqv$-DhAkEf&-IcTH*S8b$}+nc*IleJA&HF5_Yl=KGXw z9l|JZR`=WIYl<5MMf-kBFkG(eY56cSg#C%~{i^?#t}`9C9^`52X8pi0Wzp&gRI$xL>@x!dh|RePajzB~GrpFcgYb90@Yo%Qwg15EfjqvZ}X>H;MX&iP^rq&P}~{DS{O0K>iJ zy^%mM&H|6fVg?4j!ywFfJby(BQ1Fnai(`m|f9s`ap~DIstN{+f-}gU`JMhCvSN`mk zYPAOfTJ>4%88&wqlH~l99qhUoI$UQgox8qa(t@CRcNT#YvpE=)BByI9DV$ZDbbcd~ zu$kLjg5iSYNoUcJ~%f*1O43cFogf ze^}d}aKiV;<+`=Y_Jp$k-qY-S?||n21BUA#%(33_gsVf(l7aKGWq5;sbKg$JoNv2x qb>=#XNB=)|>B;TW+w>-eY1%K^EAE%p*!~3Q8wO8TKbLh*2~7aI+=w#( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..d728c4112be202cddeeacf7cc1a830342e8baf1d GIT binary patch literal 428 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`031o(uw%E`$&J3Hs*=IZO~A86DKFyZTrmIF!(CJTxIDUOmLzu^B6z;Lg5 zZzNERv%n*=n1O-sFbFdq&tH)Ow20Hw#W5tp{q3}yLd^<142}-}|MyE91hbm;9sg31 z5YN$=vsYusQ$=S37D*us$HTlnToX#_W-T*&-}GJT+609o98C)X4_7v_>1uea6wkQb z$n;*G%jrX!Be$=~y@*TO*y=UUN`?H1Yw&blkjolvuexAoyr@M~#f&X1TZ(?XZ(t3V zXi_}Eb181s9$d;c3j-aJFXUcgD2aO}8ezUe6JBc$@p_jqR^}9Z$8b zO?rE=Etw-|&eItiq|fZNY-(f;nm_Bh+FlnnkttOTJQ@bCx*ZprYixM6*|FKYhWi%N z^1O!&_VI*0u3&99@&B~Tf#-Md6W+#}5PsIH>Sf*=(mCX~r#)p|@hV56+2PP^U`R1| My85}Sb4q9e03I`k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`031o(uw%E`$&J3Hs*=IZO~A86DKFyZTrmIF!(CJTxIDUOmLzu^B6z;Lg5 zZzNERv%n*=n1O-sFbFdq&tH)Ow1~sg#W5tp{p~bIz7_=@*OdV~|M#-b(K@e);f#pR7ygC|(B=sBi#XT6HEjF|Rx9V5f3?(f&y3!(-720MP~V%X?>;9Fk4 z?E&Y;bne#+X1uFE)^R1xiz8g?)}BxSYnGf>{H(U#Kl%?aist?ZQTq_G<>7uA?c+0= zG*9>(%x3-6v5{Xk_dw_DrkbJ!HvZ4wWY(Q>w!DyC;+T8lr`*Bo2i_^HOnw&1n8v)j zImfncPN4{6o9SJ#8xHT*9yIW9JoWhH=B08`Y>GENaZPjN==qbjV3iZcni{i!K*i|} zYn`e&Gmp8($vbP0l+XkKT_U6h literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/meta.json new file mode 100644 index 0000000000..b8bbd26672 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "Made by Github user Psychpsyo for Space Station 14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..c0ae12785efb97f6cdbcb55d4de141abda3f2ed5 GIT binary patch literal 402 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`031o(uw%E`&)=H}|_>j#+dIXgRdM#~*&)CEdTh>f`nq&P}~{DS{O0K>iJ zy^%mM&H|6fVg?4j!ywFfJby(BQ1HE{i(^QH``c+Z`Hm=XxE4zP|KH!9z0xb%cY0-p z+MVgA9&t(qFZdI{X26ir5YE`~ZsWDsCv&WQKYVJfW91NuU82ym+&^l~qjgcbj4GcD zgMK+^9$b97G4xL8>QHS42QCNB+1jn9YZZ(SytWno*qD{a{DZqeZ@aGEo@Tr6f7Uhf zBru#{U~Ay{V8rnMt@@6@EtVG_9G8{5sFAJ8`rx0|F~1{@cR#x3x^wXT-CB~q|8%ND zXF>3_i+mq68P0H2#&a@QZmcj0V7Fb9U@f~r;=y!@^FqfN?i}24n7KgWEkljB@Bxim lKj-aho^5nMo}uU;)2Z9pGmZ<3TmyQY!PC{xWt~$(696yyniT*5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/sledgehammer.rsi/wielded-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..21c9a32a7fe85bacdd52cfe6c0f940e41755192d GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`031o(uw%E`&)=H}|_>j#+dIXgRdM#~*&)CEdTh>f`nq&P}~{DS{O0K>iJ zy^%mM&H|6fVg?4j!ywFfJby(BQ1Fqbi(^QH``c+3`3@^^xK4cZ=fC~Eqh3MUyG-vo zZ!U;i;m~(%Mu3(%rz6J{0h=&~FMF@QUNU9UHL>FTCQxWlp~)K8_!Aj{iEOYShp4=_>m`PG2FW$<+Mb6Mw<&;$T(JfBnm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/ammo.png b/Resources/Textures/Structures/Machines/techfab.rsi/ammo.png index 38f7a4dd2cb919e69d387d37efb188635921a680..c2f1c61ace7f267b6c31fd7ed040f793df9d48c2 100644 GIT binary patch delta 230 zcmV9aR4>I@NvM4D=$%Kx;Vfz4li4a<%Q3a431>5(WrJChrIpD^fn^bkc&`blP4j5JrAUPMjK`wGf g!6+C7qkswk0FNOqmO~aI^#A|>07*qoM6N<$g2lLAbN~PV delta 274 zcmV+t0qy>g1-u2Yv;lwFNkl+k`Of>8$y zxC4mJ1tG--R4Itac7TDV94+i8-T{slDkyw%%LTF>&_914HSB*Q-vKx7+@y&E23IbS zFk$)6FU(9=2VjH%D+d$9>?l(PRt_cRB!003fyH2SG2lw<$^01jnXNoGw=04e|g00;m8 Y000000Mb*F000UA07*qoM6N<$f(No};{X5v diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/cargo.png b/Resources/Textures/Structures/Machines/techfab.rsi/cargo.png new file mode 100644 index 0000000000000000000000000000000000000000..d89e51d1994efe50345556e996eeae43a436502f GIT binary patch literal 645 zcmV;00($+4P)EX>4Tx04R}tkv&MmKpe$i(@I4ug6$yUkfAzRDJtS9RV;#q(pG5I!Q|2}Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;qmz@Oi4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XRT(DP#3AESVO7iiXP`}^3onpV2qvfZ#3Ax90TL-pAn`u^?e6X0GwuF<0N`D6)Bk!mX8-^IyGcYrR9J;$U>F4>9Waurp(;lIKP48n zExCwdCkv?txLT?*eERr-EX(=$1sE6@82%$Wf{7f1PF{OWH9cfGfE0%iQbTeS-~xV? zyHWU?+Fgm#M^Ol%gH7$OL|Y64R0{zH2Fy?(22d0N=31f@t05}{uo+4y=y5rO>?rWB z+Cy?7h7C|P5z@^8&=QR*faECHef&1nEGNqWk6(VGssn~*8W?rJuyO#&x#0b$@3e5o fC>RB!U<3mIshuf!O=Bo|00000NkvXXu0mjfu^l3d literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/engi.png b/Resources/Textures/Structures/Machines/techfab.rsi/engi.png new file mode 100644 index 0000000000000000000000000000000000000000..5ba7c813b94d4f814f877a94f5cb92aab354a591 GIT binary patch literal 651 zcmV;60(AX}P)EX>4Tx04R}tkv&MmKpe$i(@I4ug6$yUkfAzRDJtS9RV;#q(pG5I!Q|2}Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;qmz@Oi4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XRT(DP#3AESVO7iiXP`}^3onpV2qvfZ#3Ax90TL-pAn`u^?e6X0GwuF<0N`D6)Bk!mX8-^I!AV3xR9J;$U>F4>9WaurVe@Q_|CCth zn|cGqPLdsP?|8ufPai*$WjP-|Kf~24H&7hGM2pz{k%|H3yI!1y`@!pqk}mIpE68_f&Pj&`blP4j5JrAUPL2 ldiI?b?idB5U=)mC007idGlE=qvO53(002ovPDHLkV1l5kDV_iT literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/icon.png b/Resources/Textures/Structures/Machines/techfab.rsi/icon.png index 4015336f16be039212b77c4bdffe50b222dd8a26..186fd30082bff99b748392c422265ee93f793237 100644 GIT binary patch delta 732 zcmV<20weu~HR1@6BNYLJX+uL$Nkc;*aB^>EX>4Tx04R~O9SL;-e-f3JGynhsnMp)J zR9J=WmcMV)KorNnpc*A@)m+o4RZ@mTN(WaAj#`3>klH0vH~0fU0w%_`BVy{*GBP5u z0UJnc9Vlain|P?|0T4loZ5*m_k(xAMp)e%A#y|7J5iI>m*7@E&zxTQ4yR(4{{byaW z8}8lTYI!-oc)sKCe-ElLd-5lbH=t@K4#z}11^_MTa4%3oNs=s+7_&Px&YA##q9ik0 zM&Ow}l}e#ntqzqu8jS)#s~h67n`2RuA&Plq1RkQ8x4-~EtyXgccDwwZ@dYq-=k_`t zKDg^S?iF+pA76lfp$mXO0Fg)}u#aOK4wJZ_ZRrK#02mL4e~=M)0KoEc7DY)$M&L0X z4q5zC>1^M?-4dc{2urz^d8#@9raGjAT(>|?xy)c|^ARXL9SDGsN$l)CV|@#Nrm1-O z>Rrzu_CqF!EC7^Jh+^L1q-iSR@dRY~7{3|{fOaWI4q!@_k3k3l0L0@7gs;@uSfkNk zQ1ACY4wY2Xe^h?}0BF|B;5ZII0;N(3!pwqY+^t$4_IrORSJ!f&l=cP)O<6s!Z zXaRVB(bCr{2FQ$ifRR_Adxe@JgfM%(-rf<@vG!Qgf0#tGQ-F%DU}JOJGuhMKZO7y+ z|7SODu6zEF+EvjN%+AfT?b@#>rKso%zJ8J1kK&b;Tdohv@)3Cc8tcD(^BNUhK}A;v z0%c&6@|h9etiGTDsKTet)G8b%$4uA z1N=ltI+Rt@Y~9wE;}yvAQRi*~XPVm8x(D#mc^rQ^01AbJzLQ*N6#5GooB&i;3?JqI O0000GMJOoYi1eL=n* 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 diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/inserting.png b/Resources/Textures/Structures/Machines/techfab.rsi/inserting.png index 3f3c09debfbc3ef9ed2b2b1358ef0636181d9141..647eb27246f727f5155ced61ad1fecea6b20e684 100644 GIT binary patch delta 320 zcmbQHdy;j6vM6Iqrn7T^r?ay{K~a8MW=<*tgT}s^9gbTKe6GI+W;hE&XX zdwXMEvw;X}!1j`l>L32!Z@Urcz~i@^PqJXimXF1+iq%vEww25mXwLU)`L$!$#&xgX zKChbh{Pgo5bJyQGJE!>8_q|u+-t`zUTxD3)YrrsnebvYM3B`3krIs%K1LT=9?9b$)+;%>F5pw&ik1%foavsAryFSv`+8 zx6p21TI96bkC)$z-rip9uGo;k#Ia0K_{}Ey2Q@Zw5akDM|7H_#D;7F(lScz2;_2$= Jvd$@?2>@lvg!KRb literal 5782 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 AyZ`_I diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/med.png b/Resources/Textures/Structures/Machines/techfab.rsi/med.png index 506b03568a64b240ca60f6d7ebf52a3c0f31abb0..86a740cb4ca7b4722c7b387daddaf2353d8d12d5 100644 GIT binary patch delta 219 zcmV<103`pK1&0N&wE=&i$qqWs)PW{r=<8C1}F*vVP#2*)sPhexD3VTb6k4Jj)GHVS*|3PA=toxCql9u zz$++BH3yI!1rN?#p_=7nIpEj3pHy|g&`blP4j5JrAUPL&e)^6U?idB5U=)mC003`# VF%F*nid_Hz002ovPDHLkV1h6-TaEw# delta 238 zcmV!g5n4!icF*eU?EoF%t#}mLkk&1P1}t(>S!JU%d%YYI()#RVAKHv z?f{~50ksMuvK=6-EJ+LdiFW|6pfC!b+;V|z2Rt})g&Ove?|^1s?|#z60fQ?Sn7DQR z=j7w2s{=4XfQ6TxAvsKwfrXbHj+4VQQPjkHD$&jXFvAJaG;_eh?e~bHsRdB-vWZ(K o(WTv)UFB3M2S&jt7zLvM0L>UT%%gQ=(f|Me07*qoM6N<$g0OXMDgXcg diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/meta.json b/Resources/Textures/Structures/Machines/techfab.rsi/meta.json index 11a48c4a0d..7530b9322a 100644 --- a/Resources/Textures/Structures/Machines/techfab.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/techfab.rsi/meta.json @@ -14,7 +14,22 @@ "name": "med" }, { - "name": "ammo" + "name": "sec" + }, + { + "name": "sci" + }, + { + "name": "engi" + }, + { + "name": "service" + }, + { + "name": "cargo" + }, + { + "name": "ammo" }, { "name": "panel" diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/sci.png b/Resources/Textures/Structures/Machines/techfab.rsi/sci.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c7e72cab72a5d5b4fe2ef30b48ad85c78065a8 GIT binary patch literal 677 zcmV;W0$TlvP)EX>4Tx04R}tkv&MmKpe$i(@I4ug6$yUkfAzRDJtS9RV;#q(pG5I!Q|2}Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;qmz@Oi4rtTK|Hf* z>74h8L#!kz#OK8023?T&k?XRT(DP#3AESVO7iiXP`}^3onpV2qvfZ#3Ax90TL-pAn`u^?e6X0GwuF<0N`D6)Bk!mX8-^I+et)0R9J;$U>F4>9WaurA=f?sKP47U z-Z>G)P8L!PFj6pP`1a!)S(bBga53b%=l@4`1QR(1-FR^wLo9Z36jnAqJq!$FgaEps z8WNfe3=9kmi*uL3Enb|v467P!fUFR}24W{iF)YqqhT;%n0M#5oE}$q1kO8hJAOt81 z0pz&F6$SX>pMimla$tV?qW_d+!*dVLqLc+>M?v<&43Zs>4Gef9B+CI@99&d$0Lf8s z?!j5ASx%M%UVeBEX>4Tx04R}tkv&MmKpe$iQ>7vm2Qx@<$WWauh+jBL6^me@v=v%)FuC*#ni!H4 z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0HIN3n$)S(glehxvqHp#<}FOz%xZNo1P;UiKS8pD;>LMR8WPD7_B-f7SgmI_wh$ue~MfRxhi1f zn8yY*$gUs!4}N!R6(`2Mq;MSQesP?SVIZ^%H0zG@ee5{R6Cn5uT)|5Tqat9cEGGtSBr65hASOnhB=$rDuz%9_b>h;#z$LRx*rLLB4fP+I| zq(s?kKJV`7?Csw(t^R%hpFMK95|x%T0002aNklb%eCUOkA`|&-7nCZ^VSlRgWFffo20_cV+ z^9vHR7+DQEAS(pW0nFml?!FAC-FJCEC)RP_m8R$ x7@BEd)B(fF0VL;w``>@i!X2Yv6pVrq3;@T%IGa*ZTPOek002ovPDHLkV1jChB4q#o literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/techfab.rsi/service.png b/Resources/Textures/Structures/Machines/techfab.rsi/service.png new file mode 100644 index 0000000000000000000000000000000000000000..4270548bbbab2b0c10f2e7b769401322d1e0cfe3 GIT binary patch literal 648 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 diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm0.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm0.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm0.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm0.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm1.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm1.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm1.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm1.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm2.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm2.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm2.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm2.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm3.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm3.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm3.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm3.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm4.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm4.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm4.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm4.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm5.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm5.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm5.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm5.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm6.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm6.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm6.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm6.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/chasm7.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm7.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/chasm7.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/chasm7.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/full.png b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/full.png similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/full.png rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/full.png diff --git a/Resources/Textures/Tiles/Planet/chasm.rsi/meta.json b/Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/meta.json similarity index 100% rename from Resources/Textures/Tiles/Planet/chasm.rsi/meta.json rename to Resources/Textures/Tiles/Planet/Chasms/basalt_chasm.rsi/meta.json diff --git a/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm.png b/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm.png new file mode 100644 index 0000000000000000000000000000000000000000..81355cd0cb3be08664bfb3abc5fe02339d0c805c GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=Dh+L6~vJ#O${~K~GN?$B+p3x91GG7!-J%FNVzN`fk5+ae$yz z$Li*0d+*DtHpSlqj%A%zJNn}0yP~{x_4oBE=Yxzx20vsKd`%v4#kPdp{Rk5GboFyt I=akR{0HEwN_5c6? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm0.png b/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/chasm0.png new file mode 100644 index 0000000000000000000000000000000000000000..18b35146730eb67854850f76e7176fa9498e8114 GIT binary patch literal 1402 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/full.png b/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/full.png new file mode 100644 index 0000000000000000000000000000000000000000..59b9454af0b4a23dbd24489e1549d251c8766554 GIT binary patch literal 974 zcmV;<12O!GP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!2kdb!2!6DYwZ9417k@i?xSsJOaP5`E~kpXQ-3kB}@(FZbUyM-|D$qs_<7nZCzW z&XM!kud5l(`sw4R_cJ1@vBiwNyT7^H`uaX&(f0z4t+C?dc( z!HmewHvtBm92|aHs;&z{UZY=y2qU`IM35Q_ngCF#)FMw7pr*b@6;sCwmuM}8hgi{N zOM|JV8j!~*spk+@5eB^ou%4ev98P^Z2l8!F2-0mU0?tN+S0QVvuR6v_TssG%5@KXa za&q04yhlF4)K@t5^PMNJ&PK&Wh_oducLhSVm0)_bB1GQQoEszlU*v$Czg51L2aywR z`|`8NTz_=l1vPTpoUJBETV6&vw~_l~BEkaubr+<#fzQ6Mao*@ZqNu)&kV>BPBh7Z_ zj%i;3Wi>rLzMP+soZWOw@`*u9^JQ%zH?9TWZbKq0&_*JXo!f{=;URPpIhL(eln|e- z2@~07*qoM6N<$f&uWxDF6Tf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/meta.json b/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/meta.json new file mode 100644 index 0000000000..e303031e1f --- /dev/null +++ b/Resources/Textures/Tiles/Planet/Chasms/chromite_chasm.rsi/meta.json @@ -0,0 +1,49 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "Created by TheShuEd (github) for ss14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "full" + }, + { + "name": "chasm0", + "directions": 4 + }, + { + "name": "chasm1", + "directions": 4 + }, + { + "name": "chasm2", + "directions": 4 + }, + { + "name": "chasm3", + "directions": 4 + }, + { + "name": "chasm4", + "directions": 4 + }, + { + "name": "chasm5", + "directions": 4 + }, + { + "name": "chasm6", + "directions": 4 + }, + { + "name": "chasm7", + "directions": 4 + }, + { + "name": "chasm" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm.png new file mode 100644 index 0000000000000000000000000000000000000000..e09eb93e426d83343fec43d7a84d0ccb6ee4ee0c GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=Dh+L6~vJ#O${~!KI!qjv*25Z>JvQYB1n&Uaio<^Z&oIEr*;) z>LCH_+h<#?Yk-tJ(Jm za2IqhWQ!Ebh&N*q3E0!oPx-u}MThRCt`-n@fmfR~g5D=W)-yx87Y{-8180d>e7;HiFErtE#K+t-8;1&v8+9C&uU`sn?MIrs*n* ze|`V&f6n>peBTx98MprSvd{CJAP7j38S}FVT1%|0X{<$QO%%n1QJZ$Bi}x^@jL}Nc zG?uSF{8O#sh~pS3h9vVDMNwi*z+#b7RTUy#;9WytB1WSlTw_@- z7i;s&4aBe(=JPq$TCBB{Wks5%6h(m$5+Nk*b_ZKqyt7Ovr=;nO$@qk_tS}~8n}6>D z0MvDj)|$!bJ18j#qX;QAb!|!03@HU#Yie6FpG~RCj3hZD%d@q)_r3%IEion_O;ds( zq_Gy)Sn9eWFowg?h%#SrcyyJx)gsTbi@%$|-UYCBmHj9R>Gt|87b!+bl6gWD8kUPW zmo7iR3(vgBG|3qDT1=D81P}Lt09943HaV%lH3UJ35T2t;$Fy2~0Ipwqo?)*Az%qWkH@T84eH8L5QJs5%_zv{?@HC07kv_H$b=#1ZcOrESD*vQDlob zCntCK)YZ>&{o3;Y|6%v@%-_77ikr97jqvaN6sWBwFd>a|n5a#j*Tk*XMdr`(-rzUM zzjpzwwFsf;_Xl*_9lr3zFY)Y??`Hqp^4r4Rmw=!lj=SI?h+?8B=I^&A9FJmPmGMz8 z@&Mzc*f{^*9WXwzX{vsjBkcAJ{Us>VOBYbUnb!ulx*aE#s57De?^OJwi&vUibeMw!Q>j|I4p9 zn@%b61R*50u~c=5RFbl+woQLeY*m0iz49by(<#>0bUJ-Z)IzBM5NNsg8VuOt9`NRk z=e)I+G@a2{OBjv_O$*VNxW?jKL!i~R=sz^JBEWg@f`%{*X{2PaSP(}s#u%J$D2sw5 znQepqBVla;-n{Xg@Ai5Z|EEcUwU)+KlvPO-MU+KB6ljt(!5G8wr7NUqinVrK`n9pP z0F&`MIA?JV4u(Ujsw9d+l46PXp0X_I4+dCU6GqVM9Z(h(S{n|JE^i`+wXpV1q?G1t zI!4J=oj({1S!OxjdqNW;gupfpS_f!l2y{T>9D~7t9sCx%C)Rd=_kyNr$g-6Ae8%M~ zS2-Mx@HozPzrZ@J)}}JO+#H*q{)n;$j~|Ut$EOWAKf$$zF1x1k|1+-c%obz{5O9C=Z3AH=`D0Ox_f7w4|{(c@2XbbOiP%by`zCZzKzdA`8fntrd3bNgQcTe+1O zC&k4m%a0y^ii6>h2R`>zs((9SKA%w6B|#8ugZ?97D+0W~m-q8)&!V;F>ZiXpRIxrX$?vnlkvG*H^H*Y-a=d&42V+q3m=N#Yo*3&!tUVHCO%+980 zEms$)m1WmC*}DK*YZi+I#%Pq1IOloj!K0m(hKLSIKn$<;u@_F`14DTdgmIx{mAb(UL@?@0Y#n@ zXoa;7Ar(?-oO4uFi4=mmwwN$R>5$j|@R)z?rAIgFh`pD>H(vd*UoKYjLqaOzR)@IN zMhb!Vj=Cx-%N(f!!qAXs8Ff{nl%%Q~9{$d6){0^84j3GaI2azSZiu}@3cuQG}maEAUAtZ6sA}|5oHPltkd^W)Zip6rt;o%7Hq19?51REK){ufj{DT@jC Rs!jj^002ovPDHLkV1hPzSn>b> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm1.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm1.png new file mode 100644 index 0000000000000000000000000000000000000000..dce7efd9a639c63eb82a9dd450aa5327c811f0b8 GIT binary patch literal 1298 zcmV+t1?~EYP)Px(%t=H+RCt{2n>~-zRuqOG`(A&{_l%icfk+t%r43CaQc>q$q)AI?5JE~3gpd+J zn==1^G->IOQjv~8vr-}j!ZIKBcxL={?VAE7VmFHr@!-1=^Hi2?`Sp2y?j8G_I~ImH z`1MDfBngh=uvmmd^C?o=C{<7@g^&{8Z{hhJI^7;x!*n`93Y)T2eE!8ZRvmr0tw8=O zRaN1-ER>zrHe9-}r;i79>B64gZ10a-TS@ujoQe#9H>dJu|MAq{7N^F5x3QTR zx6P?G;PtHdpfh0Gl5NO`CnwfjvYI8?AWnm$BrF4c5Iv4pP3Ku-_Zd5!Qh{L zA7A|Pjn{p6|Bl|AyNDt_z5KP&Pu<#mf$8KaqhO!ebjm0Qm`+|C3Gz6r)soe6MWr>i z5Ow8iQ`-O`B=gyXAQ)2=Im2PVbT%Q5LmcU#N`>orNFgYSlEGj|n&pf}BcdqUMhvy6 zZGhGmWm&Rb$3#)c*>mSP6O7SR#ES^avakT#mW+ZS>ve+Xd1P5eyWM{4_1`zO3nIOK zA6p2@vZN?-;zdZBu94EgZ?(yb0wE+>mXfU3SeEsw5t?CH<||!|-ob;Pztw}m5Gh?8 z*Ch-?E?&N3)P+V%Vvgf5pG}$1XDFqps;Wu(6KS+NoTeGAmX8pUJj>{Ap}Sj`Mh$RX zhh)75Ti|;Y9nou2{zMub0_}F2s?u~j9SW5*ojh++{zRIc16-d`5D>=;bX5ZHrPTjU zG-|;0tG95y7XAK^UawED*Kbn(L>h05EEf@FS&^hUr{G7RSpyy&%t?|ZN)-(H1FGr+ z8v+1>VL%j3DT?gXYA~}HStTYcc>3q>_fG5vl%k^4lt*J^ymaUtVKM^zC zVavw0ZL;+JEP8ks8a3dzUw+Wxd_u23q(2y8S?0U*jn4tL{qpIfHNkkVY59NAxB)^q zC{-XG7op9+2pF$OJiPzCj>3?#RCu1lc>g?~eD+mi_hoz#hVvOx+GwrGa@DxLaRa23 zESF1MS0Y67w`1IZ;phy$?~~^_j%@zD%=rHW(lo>M+E`YKblk@Ejb}g@PH43}di?>; zhiCx058_@1_DT;!{V$OOM^V7ZW8r3&$z;HBX6zrijEEi$p`o>>`Ds2-4 z`y^>frOU?kjT>ND7SeTTclxiICCy@d2nZp_vX?7MOjL;e2GwB%d2_tXA^-pY07*qo IM6N<$f+ezY%m4rY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm2.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm2.png new file mode 100644 index 0000000000000000000000000000000000000000..7139091f1e1a6d15a27fec32cbe379530d7709b7 GIT binary patch literal 2295 zcmVPx-u}MThRCt`-n@fmfR~g5D=W)-yx87Y{-8180d>e7;HiFErtE#K+t-8;1&v8+9C&uU`sn?MIrs*n* ze|`V&f6n>peBTx98MprSvd{CJAP7j38S}FVT1%|0X{<$QO%%n1QJZ$Bi}x^@jL}Nc zG?uSF{8O#sh~pS3h9vVDMNwi*z+#b7RTUy#;9WytB1WSlTw_@- z7i;s&4aBe(=JPq$TCBB{Wks5%6h(m$5+Nk*b_ZKqyt7Ovr=;nO$@qk_tS}~8n}6>D z0MvDj)|$!bJ18j#qX;QAb!|!03@HU#Yie6FpG~RCj3hZD%d@q)_r3%IEion_O;ds( zq_Gy)Sn9eWFowg?h%#SrcyyJx)gsTbi@%$|-UYCBmHj9R>Gt|87b!+bl6gWD8kUPW zmo7iR3(vgBG|3qDT1=D81P}Lt09943HaV%lH3UJ35T2t;$Fy2~0Ipwqo?)*Az%qWkH@T84eH8L5QJs5%_zv{?@HC07kv_H$b=#1ZcOrESD*vQDlob zCntCK)YZ>&{o3;Y|6%v@%-_77ikr97jqvaN6sWBwFd>a|n5a#j*Tk*XMdr`(-rzUM zzjpzwwFsf;_Xl*_9lr3zFY)Y??`Hqp^4r4Rmw=!lj=SI?h+?8B=I^&A9FJmPmGMz8 z@&Mzc*f{^*9WXwzX{vsjBkcAJ{Us>VOBYbUnb!ulx*aE#s57De?^OJwi&vUibeMw!Q>j|I4p9 zn@%b61R*50u~c=5RFbl+woQLeY*m0iz49by(<#>0bUJ-Z)IzBM5NNsg8VuOt9`NRk z=e)I+G@a2{OBjv_O$*VNxW?jKL!i~R=sz^JBEWg@f`%{*X{2PaSP(}s#u%J$D2sw5 znQepqBVla;-n{Xg@Ai5Z|EEcUwU)+KlvPO-MU+KB6ljt(!5G8wr7NUqinVrK`n9pP z0F&`MIA?JV4u(Ujsw9d+l46PXp0X_I4+dCU6GqVM9Z(h(S{n|JE^i`+wXpV1q?G1t zI!4J=oj({1S!OxjdqNW;gupfpS_f!l2y{T>9D~7t9sCx%C)Rd=_kyNr$g-6Ae8%M~ zS2-Mx@HozPzrZ@J)}}JO+#H*q{)n;$j~|Ut$EOWAKf$$zF1x1k|1+-c%obz{5O9C=Z3AH=`D0Ox_f7w4|{(c@2XbbOiP%by`zCZzKzdA`8fntrd3bNgQcTe+1O zC&k4m%a0y^ii6>h2R`>zs((9SKA%w6B|#8ugZ?97D+0W~m-q8)&!V;F>ZiXpRIxrX$?vnlkvG*H^H*Y-a=d&42V+q3m=N#Yo*3&!tUVHCO%+980 zEms$)m1WmC*}DK*YZi+I#%Pq1IOloj!K0m(hKLSIKn$<;u@_F`14DTdgmIx{mAb(UL@?@0Y#n@ zXoa;7Ar(?-oO4uFi4=mmwwN$R>5$j|@R)z?rAIgFh`pD>H(vd*UoKYjLqaOzR)@IN zMhb!Vj=Cx-%N(f!!qAXs8Ff{nl%%Q~9{$d6){0^84j3GaI2azSZiu}@3cuQG}maEAUAtZ6sA}|5oHPltkd^W)Zip6rt;o%7Hq19?51REK){ufj{DT@jC Rs!jj^002ovPDHLkV1hPzSn>b> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm3.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm3.png new file mode 100644 index 0000000000000000000000000000000000000000..dce7efd9a639c63eb82a9dd450aa5327c811f0b8 GIT binary patch literal 1298 zcmV+t1?~EYP)Px(%t=H+RCt{2n>~-zRuqOG`(A&{_l%icfk+t%r43CaQc>q$q)AI?5JE~3gpd+J zn==1^G->IOQjv~8vr-}j!ZIKBcxL={?VAE7VmFHr@!-1=^Hi2?`Sp2y?j8G_I~ImH z`1MDfBngh=uvmmd^C?o=C{<7@g^&{8Z{hhJI^7;x!*n`93Y)T2eE!8ZRvmr0tw8=O zRaN1-ER>zrHe9-}r;i79>B64gZ10a-TS@ujoQe#9H>dJu|MAq{7N^F5x3QTR zx6P?G;PtHdpfh0Gl5NO`CnwfjvYI8?AWnm$BrF4c5Iv4pP3Ku-_Zd5!Qh{L zA7A|Pjn{p6|Bl|AyNDt_z5KP&Pu<#mf$8KaqhO!ebjm0Qm`+|C3Gz6r)soe6MWr>i z5Ow8iQ`-O`B=gyXAQ)2=Im2PVbT%Q5LmcU#N`>orNFgYSlEGj|n&pf}BcdqUMhvy6 zZGhGmWm&Rb$3#)c*>mSP6O7SR#ES^avakT#mW+ZS>ve+Xd1P5eyWM{4_1`zO3nIOK zA6p2@vZN?-;zdZBu94EgZ?(yb0wE+>mXfU3SeEsw5t?CH<||!|-ob;Pztw}m5Gh?8 z*Ch-?E?&N3)P+V%Vvgf5pG}$1XDFqps;Wu(6KS+NoTeGAmX8pUJj>{Ap}Sj`Mh$RX zhh)75Ti|;Y9nou2{zMub0_}F2s?u~j9SW5*ojh++{zRIc16-d`5D>=;bX5ZHrPTjU zG-|;0tG95y7XAK^UawED*Kbn(L>h05EEf@FS&^hUr{G7RSpyy&%t?|ZN)-(H1FGr+ z8v+1>VL%j3DT?gXYA~}HStTYcc>3q>_fG5vl%k^4lt*J^ymaUtVKM^zC zVavw0ZL;+JEP8ks8a3dzUw+Wxd_u23q(2y8S?0U*jn4tL{qpIfHNkkVY59NAxB)^q zC{-XG7op9+2pF$OJiPzCj>3?#RCu1lc>g?~eD+mi_hoz#hVvOx+GwrGa@DxLaRa23 zESF1MS0Y67w`1IZ;phy$?~~^_j%@zD%=rHW(lo>M+E`YKblk@Ejb}g@PH43}di?>; zhiCx058_@1_DT;!{V$OOM^V7ZW8r3&$z;HBX6zrijEEi$p`o>>`Ds2-4 z`y^>frOU?kjT>ND7SeTTclxiICCy@d2nZp_vX?7MOjL;e2GwB%d2_tXA^-pY07*qo IM6N<$f+ezY%m4rY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm4.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/chasm4.png new file mode 100644 index 0000000000000000000000000000000000000000..5cc155f8252a7761f777562faf37e7b6b1f68043 GIT binary patch literal 1464 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/full.png b/Resources/Textures/Tiles/Planet/Chasms/desert_chasm.rsi/full.png new file mode 100644 index 0000000000000000000000000000000000000000..03aa532353e8cda95c956194f8636be5290a38eb GIT binary patch literal 1951 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 YA4MS#kLjY|Z~y=R07*qoM6N<$f<6}8#{d8T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm1.png b/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm1.png new file mode 100644 index 0000000000000000000000000000000000000000..502b9e3d7199a3916686fe138b92807ca1e35351 GIT binary patch literal 904 zcmV;319$w1P)Px&LPjhdv^lN42MH< zT^Ef;14INNM66s00V0aN+qMm@HNr525CZjjT_k_=Ay{b+&H|+r8jS`3z;PUSo(J2u z0RUQS5K&BkQVN!3jft9-XPNv;O5BU{XuI8PK`8|Quq-S3G!m-SYE(XY+^nz*a4*hr z*mEbAwVN#fK&@7TQVK+b!C)};xQDbul&*#(%2clNf$>e@QBpTCH{1BfJ; zGv4iyP35x)&b?lzO2}^RcQmKqh zec^(o1ym{(1VMl>3^~HbU=eVAeGMT5Zf|cn!pC5J3e@X$&hP+o7Le=%Xsz=MKat#9 zfaxk1;RXmW2r!jr?g2-XJ;6MK9roNzW_M;ut^&;THUL;!T6((u04XIr&nrZCI9CB? zribtQg}Di`GaL@7-|v&>c{FW6bsn%k1xD8kaKJ7A;2j$*gaESuf`dW`;G_@&gb)aV zfF*Vz1P~D%$3eT2HE+EP)Px);7LS5RCt`-Tg`6UMiBm%GXK1klfbHcs1P7+fx<`-I63B+b047h9{U1CAE4+9 z^w?7`1&UsZqChV>=I9EB1EYXl1BQy)jvClrQd*J`r-yVmB&FJkxfI!a7g?mF@qD}U zvok}6hLNTzjYcE%dOZ*k7-NO|j4=?Ae(!l6vMfU!$6$=1+wHRQZ@vwzDql7MDJ6Qn z9st1ieF!1oc^&{D%Q6sAfdDBbEX$fB>bhv0003HHDJ8nyE~JzI0L!upuK?gUj=paK zE5?4Q0T8bUfQS&s zF`l2F8CM=?2?2RbCKGVZA*ICl;#^-}r2NisyRy925WqP{6h&BBSpgAYd~rT!>t*GC z{{Gv_v9R$l7)4Rx)pcF``TTS#$^$Lf0i5%N86dFO)=g~tJQ^ne0J_~Sgb-kifpZRE zUirM@qoYG(vKu!6;FaS`k_4XT;rGKo3fq5YxQ(6RHbzH>dfN}5J~5LAqa_4nS%xG@ zbVjIFU#)t6#Z9h0&;k=6B1kD=+jb$*`Q@h{3!gK&>aBthf`kwhMG@^C?9-QDe?wc3 z9@Ev|{GVd)V4uP;q~qgb3d68*MVIOW_73)G(BFV<+dBL;jiva2y@P!MfI)u)0FWff zGQ_?SY9~OgdK*@I5td>CjIlyhCkTRNhP}^S}bb!}n zl#88Bp*8}P@|VG6ar3$`Y68mJ1Ft=?=!|QolZ@PzZQ%T zu*livp|<*^4^YZyS%x48=E9s>@iy4LLS^>TG^IC*=V_WENs>ZH1m1xipp?HXqy<3$ z&iS13Z9ruLq9{U^W&dgSjIn~lYs(oxp)vuSbF8hc>GwpWL!EjrgwOS8S^MFOY`ayp~=lrhg zA`C9?>`a?Vr_+HD0&yIh5MK$E2~bUpd-v|@Yh^+P z{SDl@bxV)9BuN6s7-q9sRq>Tk*(HDS>1T9*>*3t>JRuJ@2k5Qcm`j%}%L3=T(Xdc? z2mITwD;V?rt%um%eO4f$tUU1gkkllMvA^}`F%53t!RY7^gWGqYc7-D0!R7z}@cw&! z?I2AII#z|Tg2=1h-D6U(KyfGJ{lcKX(VB#)ma1@>ggg`xSJexb1*50Id<^a;zi zvUhi%8J+Gjg<8wv!>3Q!&Tv~R{?!+sYl4CxcsKHZt567VO+w=Y5K$pZT=V>;lF+yz zo}ZtSWm$8>lIod&%@04S^?z)ffP7hH3eWS9rm1eWj!sYT z-4DOkBERub*>X|DwrxzO)57yYfcY_bg~oTlBFtv9!c-Yxen?uOHDNG6J(Bkcj^p6v z%a=Gh{;QU7*ct)==wv8QMifQhoMSqj;%{*=_x-A*H0}cw)I(E1agN#zw$3sgb;$_I4%@N%F|?vz&Te>m{!u^ YA4MS#kLjY|Z~y=R07*qoM6N<$f<6}8#{d8T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm3.png b/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/chasm3.png new file mode 100644 index 0000000000000000000000000000000000000000..502b9e3d7199a3916686fe138b92807ca1e35351 GIT binary patch literal 904 zcmV;319$w1P)Px&LPjhdv^lN42MH< zT^Ef;14INNM66s00V0aN+qMm@HNr525CZjjT_k_=Ay{b+&H|+r8jS`3z;PUSo(J2u z0RUQS5K&BkQVN!3jft9-XPNv;O5BU{XuI8PK`8|Quq-S3G!m-SYE(XY+^nz*a4*hr z*mEbAwVN#fK&@7TQVK+b!C)};xQDbul&*#(%2clNf$>e@QBpTCH{1BfJ; zGv4iyP35x)&b?lzO2}^RcQmKqh zec^(o1ym{(1VMl>3^~HbU=eVAeGMT5Zf|cn!pC5J3e@X$&hP+o7Le=%Xsz=MKat#9 zfaxk1;RXmW2r!jr?g2-XJ;6MK9roNzW_M;ut^&;THUL;!T6((u04XIr&nrZCI9CB? zribtQg}Di`GaL@7-|v&>c{FW6bsn%k1xD8kaKJ7A;2j$*gaESuf`dW`;G_@&gb)aV zfF*Vz1P~D%$3eT1KIqEP)Px%;7LS5RCt{2o4;?`KorNnMzv*RgH%x^3u=dEiGr%MW5@oVnNn4ex@PIpv15Xw zR4kxMEdyj>@EPMX+;xcT9hc7JYawUjYb3GhiNAM zu79I9zSd|3L{XG&>lP0fU_i6k1n@`v_~#F;@tcz<>FrVHHAobUy~h8E|l60=I*4HUXN>1yZ8jfKMMUvu$-QfC}vfs53t%b%t6=tHB@$$U6e< z888?PW%uaVi1Y^t3n9)q9LJ#wpFv`P>$(8UD2Yi7P(OxHLt=m_RUlA7C7AZ)zVCxE zR@lb(eQ?f=NclXaGaw8@2q89#w=8R|!!zmb0~KVzEM%C44Bew+0FO2Pa=FZ2bHApO zwf4_FADvDIQ4|?rMri|X2jl-b|Ms+tSy-Gc6jU}E++@W4{r9Ru?1j<>hsN8_3l>Rj}H8nLgH8nLgHHQoNsO?`%Px$qe(ALG!3T^w-Ig~))8j?O#)J8$6=_yUej5aR6Iuy`;kZyj5MlD1oA`fIxBuS5ZAtFA7cjP1EF?)1$+Ao)lZk|JB%1jp z&9H5{Fc*{7IzG<<^}rg-Rf)UwSBkd8;IXFp6a7`&?H zn-{DLF83lPSUoK%iABll8Y0ePOo^E`-{fByg|cZdBj#YL@(&#zoFb|=*WJaju4G%f)E z_4>JH^siJ4uRsib+qWQ`Jk;1@i)k f21KIqEP)Px%;7LS5RCt{2o4;?`KorNnMzv*RgH%x^3u=dEiGr%MW5@oVnNn4ex@PIpv15Xw zR4kxMEdyj>@EPMX+;xcT9hc7JYawUjYb3GhiNAM zu79I9zSd|3L{XG&>lP0fU_i6k1n@`v_~#F;@tcz<>FrVHHAobUy~h8E|l60=I*4HUXN>1yZ8jfKMMUvu$-QfC}vfs53t%b%t6=tHB@$$U6e< z888?PW%uaVi1Y^t3n9)q9LJ#wpFv`P>$(8UD2Yi7P(OxHLt=m_RUlA7C7AZ)zVCxE zR@lb(eQ?f=NclXaGaw8@2q89#w=8R|!!zmb0~KVzEM%C44Bew+0FO2Pa=FZ2bHApO zwf4_FADvDIQ4|?rMri|X2jl-b|Ms+tSy-Gc6jU}E++@W4{r9Ru?1j<>hsN8_3l>Rj}H8nLgH8nLgHHQoNsO?`%Ygr+Ar*7p9%SSN@(wNd?w`wN fz5vKX1`XxR4h{^A{hv+-f`mO?{an^LB{Ts5qcarg literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/full.png b/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/full.png new file mode 100644 index 0000000000000000000000000000000000000000..525cdc2680e3c3c19c602e4a7c555d7f16995ec7 GIT binary patch literal 1225 zcmV;)1UCDLP)Px(gGod|R9JH8B)rUfH;mZ3`3KLVMvx`YsrNWq-jd4)zahAd=LcEwr%1#u3ez&g;uMzVoA|@ zDJ54|SD2=$=aVGCvMepQ-EI>_5kd%>%BoGUEQ>gfky4VTDWlgHrTM$ATN1akvqKn$ zT2Q;)=H<(m+_`fH$USRW7HOL10*a7Q;&~oI2*%?v$~(%+(d!HT{A;vPu;1-r7=|XA z&1Q5u9laHeMni9HQ@MCPpW`?V^Z6Vh1VRWJjfP&dNX$MTp=&w@bI8kz|p>s-|ekr6Xfx*A|MPyT-POz zW5&~oeqKj@deR5r-u>f^f{ylmI@`B&b}1N!aUBD$>k@_`&1MrRCFAL2#kE!Pr@#GL zYxTYR#|#F;l87of9W)>`*Is0u#X_qn_G zH9-(ySr$zp1diii7zRuy34)Rdpvvk%O@A0(C1E6d0T{R+s1Jm{BDoiw|40F zpM8`7wYK7cJO#CYD2nu8JRTFrF;NuZx-OPw;dgr2b*7K?@c z|Dht3`&E0U#1ust%jI&VSx}v9^_2V&@=b{2n5Jo(CGy2$!S?nx)9F+zAHBZd;m^O{ zh*Y6SUNl4<#Q>&h(o_Ql(=>^qsMHU_`eV3Ae#`lct*tEpmdhnsmSLKvZfL75z2|ut zb&D;R%Tm!L<{g}pJj^lWxFKo41*8)^iT1DN5 zo8~rMQtQMSsywQFs+LSe@aD}M{Y+)eI`S;b@H}tj%BQxuSo}l~1hRN}R4>+DrHgP~ n7a;^!S6A=6TSA`Rb+zSxe7?&vQbxhA00000NkvXXu0mjfKw3wE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/meta.json b/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/meta.json new file mode 100644 index 0000000000..e303031e1f --- /dev/null +++ b/Resources/Textures/Tiles/Planet/Chasms/snow_chasm.rsi/meta.json @@ -0,0 +1,49 @@ +{ + "version": 1, + "license": "CC0-1.0", + "copyright": "Created by TheShuEd (github) for ss14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "full" + }, + { + "name": "chasm0", + "directions": 4 + }, + { + "name": "chasm1", + "directions": 4 + }, + { + "name": "chasm2", + "directions": 4 + }, + { + "name": "chasm3", + "directions": 4 + }, + { + "name": "chasm4", + "directions": 4 + }, + { + "name": "chasm5", + "directions": 4 + }, + { + "name": "chasm6", + "directions": 4 + }, + { + "name": "chasm7", + "directions": 4 + }, + { + "name": "chasm" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt1.png b/Resources/Textures/Tiles/Planet/shadowbasalt.rsi/basalt1.png new file mode 100644 index 0000000000000000000000000000000000000000..e8f873286cba8a7cbb2e32bd29148f927418bd65 GIT binary patch literal 968 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Tiles/Planet/shadowbasalt.rsi/meta.json b/Resources/Textures/Tiles/Planet/shadowbasalt.rsi/meta.json new file mode 100644 index 0000000000..0d71d4b561 --- /dev/null +++ b/Resources/Textures/Tiles/Planet/shadowbasalt.rsi/meta.json @@ -0,0 +1,66 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "taken from tgstation @ commit a0ca7b3f46132517f71f08bfda465667d133b5d7 and edited by TheShuEd", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "basalt1", + "delays": [ + [ + 2, + 2, + 2, + 2 + ] + ] + }, + { + "name": "basalt2", + "delays": [ + [ + 2, + 2, + 2, + 2 + ] + ] + }, + { + "name": "basalt3", + "delays": [ + [ + 2, + 2, + 2, + 2 + ] + ] + }, + { + "name": "basalt4", + "delays": [ + [ + 2, + 2, + 2, + 2 + ] + ] + }, + { + "name": "basalt5", + "delays": [ + [ + 2, + 2, + 2, + 2 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Tiles/attributions.yml b/Resources/Textures/Tiles/attributions.yml index 641100fe42..b732333dd7 100644 --- a/Resources/Textures/Tiles/attributions.yml +++ b/Resources/Textures/Tiles/attributions.yml @@ -95,3 +95,8 @@ license: "CC-BY-SA-3.0" copyright: "taken at https://github.com/ParadiseSS13/Paradise/blob/8b7f4c8b69c74c6de5a755272eb8d3520f3d87c7/icons/turf/floors.dmi" source: "https://github.com/ParadiseSS13/Paradise" + +- files: ["chromite.png"] + license: "CC-BY-NC-SA-3.0" + copyright: "taken at commit 0587dd16e28108bdf0b0a28e2caae4319845e861, and recolored by TheShuEd" + source: "https://github.com/Mojave-Sun/mojave-sun-13" \ No newline at end of file diff --git a/Resources/Textures/Tiles/chromite.png b/Resources/Textures/Tiles/chromite.png new file mode 100644 index 0000000000000000000000000000000000000000..631b9bf84e747ad3134996d965bf722f3dd13e34 GIT binary patch literal 3171 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 JPDHLkV1lO{iqrrA literal 0 HcmV?d00001 diff --git a/RobustToolbox b/RobustToolbox index 554e0777b1..f5874ea402 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 554e0777b1ba6ba096d8f4407d5c35ecc7b0f22f +Subproject commit f5874ea402430bb902a5d5d1f47953679d79d781