Skip to content

Rapid Piping Device: Atmosia's Revenge#124

Merged
DDrakov merged 11 commits into
Triad-Sector:mainfrom
rebaserHEAD:feat/rcd-rpd-overhaul
May 26, 2026
Merged

Rapid Piping Device: Atmosia's Revenge#124
DDrakov merged 11 commits into
Triad-Sector:mainfrom
rebaserHEAD:feat/rcd-rpd-overhaul

Conversation

@rebaserHEAD

@rebaserHEAD rebaserHEAD commented May 24, 2026

Copy link
Copy Markdown
Collaborator

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:

  • Pipe-layer placement. Cursor position inside the clicked tile picks Primary / Secondary / Tertiary, with three guide circles showing which layer the cursor is currently on.
  • Color picker. Stains spawned pipes and atmos hardware via 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.
  • R-key flip toggle. Recipes with a 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

  • Lathe. RPD recipe added alongside RCD in the NFEngineering pack (Protolathe) and the Mono RCD pack (Engineering Techfab). Researched via AdvancedToolsTechnology (Industrial, tier 2, 23500 RP), the same gate as the RCD. Reuses RCDAmmo cartridges.
  • CE locker + engineer locker. RPD now spawns in both.
  • Mail. New MailMonoRPD reward (tool + 2 RCDAmmo), parallel to MailMonoRCD.
  • Tech disk. TechDiskRCD now teaches RPD in addition to RCD/RCDAmmo.
  • Cargo crate. CrateRPD + EngineeringRPD cargo product added. Marked abstract: true to 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

image image

(Refreshed picker screenshot pending. The two-row palette is new since the last media drop.)

Requirements

  • I have read relevant guidelines/documentation to this PR found on our devwiki.
  • I have added media to this PR or it does not require an ingame showcase.
  • I can confirm this PR contains either no AI-generated content, or AI-generated content that meets our guidelines.

How to test

  1. Spawn an RPD and a stack of RCDAmmo. Load the ammo.
  2. Open the RPD menu (use-in-hand). Confirm the color picker shows two centered rows: row 1 is default / waste / distro / air / mix / external; row 2 is 13 named gases in alphabetical order (ammonia through water vapor).
  3. Pick a recipe and a gas color (e.g. plasma). Build a pipe; confirm the pipe spawns stained that color and that the swatch hex matches the same key on a spray painter.
  4. Hover the cursor near the tile edge before clicking and confirm the pipe lands on the matching layer (cursor center = Primary, NE/E edge = Secondary, SW/W edge = Tertiary; guide dots show which is which).
  5. Select a gas filter or gas mixer. Press R; confirm the placement ghost flips. Build it; confirm the mirrored variant spawns.
  6. Switch to deconstruct. Confirm RPD can remove gas pipes, vents, scrubbers, pumps, mixers, filters, ports, valves, heat exchangers, gas-pipe sensors, air sensors, and air alarms.
  7. Spawn a plain RCD. Confirm it cannot deconstruct any of the atmos targets in step 6 (popup: "not on the whitelist").
  8. Swap between two RPDs (or RPD + RCD) while a flip is active; confirm the flip state syncs to whichever tool you just picked up.
  9. Open the CE locker on round-start; confirm an RPD is inside. Same for the engineer locker.
  10. Research Advanced Tools Technology; confirm the RPD lathe recipe becomes available on the Protolathe and Engineering Techfab.
  11. Apply a TechDiskRCD to a research server; confirm RPD is among the unlocked recipes.

Breaking changes

  • RCDDeconstructableComponent.RpdDeconstructable. New field, defaults false. Existing prototypes unaffected.
  • RCDPrototype.MirrorPrototype and NoLayers. New fields, optional. Existing recipes unaffected.
  • RCDComponent.UseMirrorPrototype. New networked field, defaults false.
  • New Content.Shared.RPD.* namespaces, new RPDComponent / RPDSystem. Additive only.
  • Three new ByRef events on RCDSystem: RCDDeconstructAttemptEvent, RCDObjectSpawnAttemptEvent, RCDObjectSpawnedEvent. Additive; existing RCD consumers unaffected.
  • Gas pipes, the gas-pipe sensor, the air sensor, and the air alarm gain RCDDeconstructable { rpd: true, deconstructable: false }. Plain RCD behavior unchanged (these previously had no RCDDeconstructable at all).
  • RPDPalette.Colors keyset 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.PipeColor values stored on existing RPDs will be reset to default on next open if they hold a key the new palette no longer recognizes (server validates via RPDPalette.IsValid).

Changelog

🆑

  • add: Added the Rapid Piping Device (RPD), a specialized engineering tool that builds and removes pipes, atmos hardware, air sensors, and air alarms. Supports per-tile layer selection, color staining, and a flip toggle (R) for asymmetric recipes like the gas filter and mixer. Available from the engineering and CE lockers, the Protolathe (after researching Advanced Tools Technology), and as a rare mail reward.
  • tweak: The RPD color picker now mirrors the spray painter's atmos palette (pipe-loop labels plus a row of named-gas colors, alphabetized) so the two tools agree on every color.

…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.
@Triad-Sector Triad-Sector changed the title Feat/rcd rpd overhaul Feat/Rcd Rpd Overhaul May 24, 2026
@github-actions

github-actions Bot commented May 24, 2026

Copy link
Copy Markdown

RSI Diff Bot; head commit 91fe731 merging into 7991bb3
This PR makes changes to 1 or more RSIs. Here is a summary of all changes:

Resources/Textures/Objects/Tools/rpd.rsi

State Old New Status
equipped-BACKPACK Added
equipped-SUITSTORAGE Added
icon Added
inhand-left Added
inhand-right Added

Resources/Textures/Objects/Tools/rpd_storage_64x.rsi

State Old New Status
storage Added

Edit: diff updated after 91fe731

@rebaserHEAD rebaserHEAD changed the title Feat/Rcd Rpd Overhaul Rapid Piping Device 2: Atmosia's Revenge May 24, 2026
@rebaserHEAD

Copy link
Copy Markdown
Collaborator Author

Oh I guess I should add it to vending machines or something and give it an actual price. Whoops! Thanks arbitrage checker!

@TheRealMasterChief117

Copy link
Copy Markdown
Collaborator

link the PR where this is cherrypicked from

@rebaserHEAD

Copy link
Copy Markdown
Collaborator Author

link the PR where this is cherrypicked from

Added them to the PR summary!

@rebaserHEAD

Copy link
Copy Markdown
Collaborator Author

Added a few extra tweaks and also fixed arbitrage issues. This SHOULD be completely set. Just a lot of moving parts.

@TheRealMasterChief117 TheRealMasterChief117 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the colors that were added in #129
IF it fits into the UI

Other than that, looks fine.

@rebaserHEAD

Copy link
Copy Markdown
Collaborator Author

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.

@DDrakov DDrakov left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image Works like a charm (I'm ass at engie)

Comment thread Content.Shared/RPD/RPDPalette.cs Outdated
@DDrakov DDrakov merged commit 7cab5d3 into Triad-Sector:main May 26, 2026
25 checks passed
Triad-Sector added a commit that referenced this pull request May 26, 2026
@rebaserHEAD rebaserHEAD changed the title Rapid Piping Device 2: Atmosia's Revenge Rapid Piping Device: Atmosia's Revenge Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants