The handheld device and
receiver connect two equipped endpoints. The
portal bore creates a pair of wall portals
and a body relay for their occupant. Both use the generic
interaction route API.
Controls
- Link the handheld device and receiver by using either item on the other.
- Put the receiver in a genital slot or the mouth slot through the interaction
panel. It doesn't show on examine, and a mask can be worn over it.
- Activate the handheld device in hand to cycle the target used when selecting
the groin. Other selected body zones choose their corresponding endpoint.
- Use the handheld device on yourself or someone else to put the part you aim at
against it, the groin using the device's target. Ctrl-Shift-click it from up to
a tile away to open the interaction panel of the receiver's wearer instead,
listing everything your own parts can do through the portal. The wearer can do
the same to reach their own receiver.
- Use one linked device on another to pick from the interactions between their
two wearers. The device in your hand is the active side.
- Climaxing from your penis with an open device in reach offers it as a place to
finish. A receiver on a penis gets the load on it, any other part inside.
- Right-click the device or receiver to toggle that item's anonymity. Alt-click
either linked item to unlink it.
- Use the bore on two supported walls to create its portal pair. Activate an
empty bore to change modes; activate it after placement to collapse its portals.
- Right-click an unoccupied wall portal to change both endpoints' mode. Buckle
into one endpoint to create the relay at its peer, then unbuckle to leave.
A gloryhole relays the penis and balls, and a wallstuck portal everything below
the waist. Interactions with the relayed half only work next to the relay, and
the rest of the occupant only in person.
Ownership and validation
The handheld device and receiver are linked peers. Neither owns the other:
unlinking or deleting one clears the surviving item's reciprocal reference.
Equipped receiver authority comes from its exact inventory slot, not its location
inside a mob's contents or its cached target alone.
The bore owns its wall endpoints. Removing either endpoint collapses the pair.
The occupied endpoint owns its relay and borrows the occupant; teardown deletes
the relay and restores the occupant's presentation. The interaction component
only observes the relay through a weak reference. Keep teardown idempotent because
endpoint, occupant, and relay deletion can enter the same cleanup path.
A worn receiver is always open: it sits on its part underneath any clothing, so
clothing, masks and sheaths never close it. The device end follows face to face
exposure rules through portal_target_is_accessible() in
the human helpers. Slot and link checks stay with
the items that own those relationships. Physical access and visible sprite state
are distinct: rendering checks native appearances separately and copies them
before filtering. The occupant's preferences are never changed: a gloryhole
occupant's penis overlay refuses to draw for the session, and a wallstuck occupant
has body layers stripped as they are applied. Both keep a rebuild between queued
refreshes from showing the hidden body for a tick.
Routes in portal_interaction_routes.dm
bind interactions to their current endpoints using weak references. Revalidate
after prompts or delays so unlinking, equipment changes, preference changes, or a
replacement session cannot authorize an old action. Both participants must allow
ERP and sex-toy use.
Deployment configuration
Handheld interactions resolve the names in the device's interaction_map through
GLOB.interaction_instances. A deployment must supply the corresponding JSON
definitions under config/nova/interactions/ in the server's working directory.
The repository's example interaction files do not supply that complete set.
Each part pairing lists one or more names, default first. A mapped definition must
be lewd, have usage = "other", use a visible category, and may only require the
genitals at its own two endpoints.
The validator rejects absent or incompatible definitions. JSON filenames do not
form the contract; the loaded interaction names and metadata do. See the
interaction datum for loading
and message-template fields.
Tests
code/modules/unit_tests/~nova/portal_device.dm, portal_lifecycle.dm, and
portal_routes.dm cover equipment authority, rendering invalidation, ownership,
route execution, and message formatting. Shared fixtures live in
portal_test_helpers.dm. Default tests install temporary real interaction datums
and use neutral message templates, so the ordinary CI deployment can run them
without production interaction JSON. Each test restores any registry entries it
replaces.
Run the DM suite from the repository root with tools/build/build.bat dm-test
on Windows or tools/build/build.sh dm-test on Linux. For a focused local run,
temporarily add TEST_FOCUS(/datum/unit_test/portal_device) and
TEST_FOCUS(/datum/unit_test/portal_lifecycle) after the test includes; remove
those focus declarations when finished.
Adult items
A new item family gets its own file and icons here; an addition to an existing
family goes in that family's file. The lewd items config removes every item
(_erp_disabled_item_enforcement.dm),
and the adult_items_kill_switch unit test checks the top types each family
lists in adult_items_gated_types() (_gated_types.dm).
A new family adds its line there.
- Medipens (medipens.dm). Five
single-use 30u medipens: crocin, hexacrocin, succubus milk, incubus draft, and
the La Coom Bomb (10u each of the last three), plus a box with one of each.
LustWish sells them (the hexacrocin pen, the La Coom Bomb and the box once
hacked), and they're in the Erotic loadout.
- Condom box (condom_box.dm). Ten condom
packs, and it only holds condom packs. LustWish and the Erotic loadout.
- Bluespace fleshlight (fleshlight.dm).
Catches an immovable rod, which flings the user up to 12 tiles along its path
to a soft landing. A wizard in rod form is set down unharmed. A premium
LustWish item at ten command paychecks.
- Leash (leash.dm). The leashed follows the
holder's route a step at a time: round corners and hazards, through doors, up
and down stairs. Where they can't follow, the leash goes taut and holds the
holder at two tiles. A leashed who falls drags their holder to the hole after
a moment to let go. A dropped leash stays hooked and trails the leashed, and
anyone their sex toy preference allows can pick it up. It unhooks when the
holder uses it on the leashed, when the leashed breaks free, or with the
safeword. A line in the strap's colour runs from the holding hand, or from the
leash on the floor, while the two are in reach.
- Pointe boots (lewd_shoes.dm). Ballet
heels with the feet held en pointe, GAGS, with digitigrade sprites. LustWish,
the shoes loadout and the Grimoire Libidine NIFSoft.
- Latex half-catsuit (latex_halfcatsuit.dm).
The latex catsuit without the legs. It picks its male or female sprite by body
type, previews included, and has digitigrade, Vox, Vox Primalis and Teshari
sprites. Unlike the catsuit, it doesn't bulge or hide the wearer's parts or
taur body. LustWish, the under loadout and the Grimoire Libidine NIFSoft.
- Paw mood and cat paws (lewd_gloves.dm).
Paw mittens give the paw mood while worn. The cat paws are bigger GAGS paw
mittens with toe beans and a cuff tag. Both need the sex toy preference.
LustWish and the Erotic loadout.
- R.U.T.T. (rutt.dm). A much
stronger aphrodisiac than hexacrocin that can cause climaxes, behind the
aphrodisiac preference. Mixes from crocin, dopamine, femcum and epinephrine at
322K. Dopamine, which only came from climaxing, now mixes from diethylamine,
ephedrine, hydrogen and phenol at 373K. The bottle, pill and Rut-Kit neuroware
are in a hacked LustWish; the bottle and pill are also in the Erotic loadout.
- Denbu tincture (butt_enlarger.dm).
Grows the butt up to the largest pickable size, behind the butt enlargement
preference, and grows one on players who allow new genital growth. Clothes
strain and hurt over the last two sizes. A camphor overdose moves the butt back
to its preference size. Mixes from saline-glucose, sugar, silicon and crocin.
LustWish and the Erotic loadout.
- Bridle (bridle.dm). A three-colour GAGS
bridle. Lowered blinders darken sight like a welding mask, and a set bit
muffles speech, emotes and spoken spells. Toggled with action buttons or
alt-click, or from the strip menu by someone with ERP on, if the wearer has the
sex toy preference on; that warns the wearer and is logged. Securing the straps
locks it. LustWish and the Erotic loadout.
- Lustwish MOD suit (lustwish_mod.dm).
The standard MOD suit in LustWish's skin, with a purple hardlight. The hypnotic
visor module hypnotizes the wearer like the hypnotic goggles, while on, or
always once its wire is cut. The remote control module comes with a remote
that controls the suit from up to seven tiles away: activation, parts, modules,
lock and forced emotes. The visor needs the wearer's sex toy preference; the
remote needs that and the holder's ERP preference. Sold in LustWish's MOD Suit
category.
- Known issue: a forced emote starting with "says", "exclaims", "yells" or
"asks" shows the wearer "Invalid emote." and tells the holder nothing,
because the custom emote's own check (
emote_is_valid()) judges the wearer.
Files outside this module
icons/map_icons/clothing/shoes.dmi, _clothing.dmi and mask.dmi: map
icons for the pointe boots, cat paws and bridle.
tgui/packages/tgui/interfaces/StripMenu.tsx: the "Adjust bridle" button.
tgui/packages/tgui/interfaces/MODsuitRemote.tsx: the MOD remote's window.
modular_nova/master_files/code/modules/client/preferences/erp_preferences.dm
and tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/nova/erp_preferences.tsx:
the butt enlargement preference and its toggle.
modular_nova/modules/GAGS/nsfw/gloves.dm, masks.dm and shoes.dm, with
their JSON configs: the cat paws', bridle's and pointe boots' GAGS configs.
modular_nova/modules/loadouts/loadout_items/loadout_datum_erp.dm,
loadout_datum_shoes.dm and under/loadout_datum_under.dm: loadout entries.
modular_nova/modules/modular_implants/code/nifsofts/dorms.dm: the pointe
boots and half-catsuit in the Grimoire Libidine NIFSoft.
code/modules/unit_tests/~nova/adult_items_kill_switch.dm: the lewd items
config test for every family.
|