Rapid Piping Device: Atmosia's Revenge#124
Conversation
…criminator)
Brings in the funky-station RPD subsystem as the foundation for a coherent
RPD-as-feature port:
- RCDComponent.IsRpd / UseMirrorPrototype fields
- RCDDeconstructableComponent.RpdDeconstructable whitelist
- RCDPrototype.MirrorPrototype (flipped variants) and NoLayers
- RCDSystem deconstruct guards (RPD only chews RPD-whitelisted atmos
hardware; never tiles) and mirror-aware ConstructObject spawn
- RPD entity in tools.yml (parent: BaseItem, size: Huge, back/backStorage
slots, melee Blunt 12)
- RPD/Empty/Recharging variants and 27 construction recipes under
Resources/Prototypes/_Triad/RPD/rpd.yml
- RCDMenu.xaml piping/atmos/pumps/vents/sensors categories + locale
- RCDDeconstructable (rpd: true) added to gas pipes
- RPD seeded in the atmospherics locker fill
Adapted to Triad's no-CachedPrototype pattern (RCDSystem reads ProtoId via
_protoManager.Index directly). HeatPump and GasTemperatureGate omitted
because the upstream atmos prototypes aren't in this fork yet. Funky's
fractional cost: 0.5 rounded to 1; RPD maxCharges set to 45 to preserve
effective build count.
Color picker UI and quadrant-based pipe-layer placement land in the next
two commits. Sources: funky-station PRs Triad-Sector#62, #1244, #1289, #1338, #1345,
#1458, plus Monolith PR #3930 for distribution patterns.
Wraps the existing RCDMenu radial with a 13-color palette strip (waste, distro, air, mix, plus the basic primary/secondary palette). Selecting a color sends RCDColorChangeMessage to the server-side RCDSystem, which stores it on the per-tool RCDComponent.PipeColor. On ConstructObject the chosen color is applied to the spawned entity via PipeColorVisuals.Color so newly-built pipes inherit the operator's color choice. "default" leaves pipes unpainted. Adds: - RPDMenu / RPDMenu.xaml.cs / RPDMenuBoundUserInterface in Content.Client - RCDColorChangeMessage + RpdUiKey in Content.Shared/RCD/RCDEvents.cs - RCDComponent.PipeColor tuple field - OnColorChange handler + appearance application in RCDSystem - RPD entity now opens via RpdUiKey + RPDMenuBoundUserInterface (was RcdUiKey) Source: funky-station PR #1244.
Adds the cursor-quadrant-picks-layer UX from funky-station PR #1338.
Holding an RPD on a layer-capable recipe switches the placement ghost to
AlignRPDAtmosPipeLayers, which:
- Draws three guide circles (Primary/Secondary/Tertiary) on the cursor
tile so the operator can see which layer they're about to commit to.
- Computes the target layer from the cursor's offset inside the tile:
near-center → Primary, NE quadrant → Secondary, SW quadrant → Tertiary
(mirrored when the grid is rotated). The math accounts for grid
rotation and player eye rotation.
- Updates the placement ghost prototype via
SharedAtmosPipeLayersSystem.TryGetAlternativePrototype so the preview
matches what will spawn.
- Pushes the client eye rotation to the server via RPDEyeRotationEvent
because eye rotation isn't networked natively. Server reproduces the
same layer pick when the placement commits.
NoLayers-flagged prototypes (vents, scrubbers, alarms) skip the placement
mode swap entirely and place via the standard AlignRCDConstruction.
Adds:
- RCDComponent.LastKnownEyeRotation field
- RPDEyeRotationEvent in Content.Shared/RCD/RCDEvents.cs
- OnRPDEyeRotationEvent handler in RCDSystem
- Cursor-quadrant layer math in OnAfterInteract
- TryGetAlternativePrototype hook in ConstructObject spawn
- AlignRPDAtmosPipeLayers placement mode (Content.Client/RCD)
- RCDConstructionGhostSystem now picks per-tool placement mode
Source: funky-station PR #1338.
Adds the client-side flip key binding that activates the RCDComponent.UseMirrorPrototype state plumbed in earlier. Pressing EditorFlipObject (default R) while holding an RCD/RPD on a recipe with a MirrorPrototype defined toggles the variant, rebuilds the placement ghost with the flipped prototype, and mirrors the state to the server via RCDConstructionGhostFlipEvent so the next ConstructObject spawns the right entity. Recipes without a MirrorPrototype no-op. In practice this is the gas filter / gas mixer flip toggle ports already use upstream — placement was previously stuck on the non-mirrored variants because the field existed but had no input binding. Source: funky-station RPD subsystem (PR #1244).
Drops the `IsRpd: bool` discriminator and replaces the IsRpd branches in RCDSystem with three by-ref extensibility events (RCDDeconstructAttempt, RCDObjectSpawnAttempt, RCDObjectSpawned). RPDSystem subscribes to them plus AfterInteractEvent and contributes RPD-specific behavior without RCDSystem knowing it exists. Per-entity state (PipeColor, CurrentLayer, LastKnownEyeRotation) moves onto the new RPDComponent, closing the multi-user race where AlignRPDAtmosPipeLayers's _currentLayer was static on the client system. New shared module Content.Shared/RPD/ holds the component/system plus RPDLayerMath (single source of truth for cursor-quadrant -> AtmosPipeLayer math, called from both the client placement preview and the server spawn), RPDPalette (server-validated color palette), and RPDEvents. Client-side RPD files move from Content.Client/RCD/ to Content.Client/RPD/.
- ManifoldGas recipe sprite now points at manifold.rsi (its own RSI in this fork; Funky/upstream had it under pipe.rsi/pipeManifold). - RPD entity sprite gets `state: icon` so the picker shows the actual tool sprite instead of a blank cell. - Clothing slots changed from Back/BackStorage (Funky enum) to Back/SuitStorage (this fork's SlotFlags); equipped-BACKSTORAGE.png renamed to equipped-SUITSTORAGE.png and meta.json updated. - Replaces all 30 pre-rendered single-frame PNGs under Textures/Interface/Radial/RPD/ with code-driven Frame0 extracts from the actual entity RSIs. Recipe-spoke icons already used Frame0; the top-level category buttons in RCDMenu.xaml have their TextureRect children built in code (ApplyRPDCategoryIcons) for the same reason — XAML's TexturePath would render a multi-direction sprite sheet. Sprite swaps in the atmos hardware now propagate to the picker automatically. - Adds rpd-component-deconstruct-target-invalid locale string.
Two bugs that together caused every pipe placement to land on the Primary layer regardless of cursor position: 1. RPDSystem.OnAfterInteract bailed at `if (args.Handled)` because RCDSystem's handler ran first and set args.Handled = true after queueing the DoAfter. CurrentLayer stayed at its default (Primary), so RCDObjectSpawnAttemptEvent always picked the Primary variant. Subscribing with `before: typeof(RCDSystem)` lets us commit CurrentLayer onto the RPDComponent before RCDSystem captures the click; the DoAfter then completes against the right layer. 2. Server-side mouseDiff was `location.Position - tileCenter - (0.5, 0.5)`, biasing the cursor offset toward the SW quadrant by half a tile. Client-side AlignRPDAtmosPipeLayers.AlignPlacementMode used the correct `raw - tileCenter` formula. Drop the spurious offset so the server math matches the ghost.
|
RSI Diff Bot; head commit 91fe731 merging into 7991bb3 Resources/Textures/Objects/Tools/rpd.rsi
|
|
Oh I guess I should add it to vending machines or something and give it an actual price. Whoops! Thanks arbitrage checker! |
|
link the PR where this is cherrypicked from |
Added them to the PR summary! |
|
Added a few extra tweaks and also fixed arbitrage issues. This SHOULD be completely set. Just a lot of moving parts. |
TheRealMasterChief117
left a comment
There was a problem hiding this comment.
Add the colors that were added in #129
IF it fits into the UI
Other than that, looks fine.
Literally thought the same thing yesterday when I saw it mentioned. Let me see what I can do! Would be nice to have a harmonized colour scheme. |
Mirrors the atmos subset of the new spray painter palette so a pipe built by the RPD and a label sprayed by the painter read the same color. Keys + hex values are byte-identical to spray_painter.yml. RPDPalette now exposes two ordered groups for the UI: GeneralKeys: default, waste, distro, air, mix, external GasKeys: 14 named gases, alphabetized Decorative entries from the painter (bright yellow, coral, pink, etc.) are intentionally omitted — they have no atmos meaning and the RPD is an atmos tool. RPDMenu renders the two groups as separate horizontal rows, each centered, so the smaller general row sits centered above the wider gas row. Shared button-build logic factored into BuildSwatchButton. Addresses TheRealMasterChief117's review on PR Triad-Sector#124.






About the PR
Adds the Rapid Piping Device (RPD), a sister tool to the RCD that handles atmos hardware. Builds and removes pipes, vents, scrubbers, pumps, mixers, filters, valves, ports, heat exchangers, gas-pipe sensors, air sensors, and air alarms. Plain RCDs cannot touch these targets (same behavior as before this PR); only the RPD can.
Features beyond the base RCD behavior:
PipeColorVisuals. The palette mirrors the atmos subset of the new spray painter (PR Spray Painter Update #129), so a pipe built by the RPD and a label sprayed by the painter share the same key + hex. Picker renders in two centered rows: general pipe-loop labels (default / waste / distro / air / mix / external) on top, alphabetized named gases below.MirrorPrototype(gas filter, mixer, future asymmetric airlocks) can be flipped before placement. Works for the RCD too, not just the RPD.Upstream
How to acquire
RPDrecipe added alongsideRCDin theNFEngineeringpack (Protolathe) and the MonoRCDpack (Engineering Techfab). Researched viaAdvancedToolsTechnology(Industrial, tier 2, 23500 RP), the same gate as the RCD. Reuses RCDAmmo cartridges.MailMonoRPDreward (tool + 2 RCDAmmo), parallel toMailMonoRCD.TechDiskRCDnow teaches RPD in addition to RCD/RCDAmmo.CrateRPD+EngineeringRPDcargo product added. Markedabstract: trueto match the RCD's current Frontier-inherited state (neither is buyable from the cargo console on this fork).Why / Balance
What if Atmos was actually tolerable and dare I say fun? Now I don't have to accidentally ignite myself in the plasma tank trying to get my steel back after a botched pipe placement.
Also because ricky said "IsRCD" is bad, so I did this instead.
Palette parity with the spray painter (PR #129) lets an atmos tech mark a tritium loop the same color whether they're laying new pipe with the RPD or relabeling existing pipe with the spray gun. No more "wait, which tool calls this color what."
Media
(Refreshed picker screenshot pending. The two-row palette is new since the last media drop.)
Requirements
How to test
RPDand a stack ofRCDAmmo. Load the ammo.default / waste / distro / air / mix / external; row 2 is 13 named gases in alphabetical order (ammoniathroughwater vapor).plasma). Build a pipe; confirm the pipe spawns stained that color and that the swatch hex matches the same key on a spray painter.RCD. Confirm it cannot deconstruct any of the atmos targets in step 6 (popup: "not on the whitelist").TechDiskRCDto a research server; confirm RPD is among the unlocked recipes.Breaking changes
RCDDeconstructableComponent.RpdDeconstructable. New field, defaultsfalse. Existing prototypes unaffected.RCDPrototype.MirrorPrototypeandNoLayers. New fields, optional. Existing recipes unaffected.RCDComponent.UseMirrorPrototype. New networked field, defaultsfalse.Content.Shared.RPD.*namespaces, newRPDComponent/RPDSystem. Additive only.RCDSystem:RCDDeconstructAttemptEvent,RCDObjectSpawnAttemptEvent,RCDObjectSpawnedEvent. Additive; existing RCD consumers unaffected.RCDDeconstructable { rpd: true, deconstructable: false }. Plain RCD behavior unchanged (these previously had noRCDDeconstructableat all).RPDPalette.Colorskeyset changed: the picker now serves the atmos subset of the spray painter (PR Spray Painter Update #129) instead of the original 13-color generic palette.RPDComponent.PipeColorvalues stored on existing RPDs will be reset todefaulton next open if they hold a key the new palette no longer recognizes (server validates viaRPDPalette.IsValid).Changelog
🆑