Description:
The Ctrl+Shift interaction panel uses /datum/component/interactable for the UI and
/datum/interaction for configured actions, messages, and effects. The server takes the
actor from the TGUI session and the target from the component parent.
An interaction route supplies access to a participant through another object. A null
route uses ordinary adjacency, unless the interaction permits distance. The portal
module implements two routes:
portal_relay reaches the half of a wall portal's occupant that its body relay shows.
The rest of the occupant can only be reached in person.
portal_device checks the operator, held device, worn receiver, links, and selected
parts. It also supports the receiver wearer filling both interaction roles. Its
muffles_sound() keeps interaction sounds around the wearer quieter than in person.
Movables that represent a participant can implement interaction_route_for().
The component asks the device linked to any receiver its parent wears first, then a
remote body relay. A device the viewer holds or stands next to offers the viewer's own
parts on the receiver wearer's panel, whether or not the viewer is that wearer. Device
attacks can also construct a route directly.
Validation and ownership:
can_execute() checks participant state, route authority, preferences, and required
parts. The menu uses it when listing actions, act() checks again before sending
messages, and apply_effects() checks before deferred effects. Only the deferred and
menu passes ignore the interaction cooldown; successful callers start the shared
cooldown on both participants.
Route preferences apply to ordinary interactions too. Lewd interactions additionally
require both participants' ERP preference. Routes and deferred participants use weak
references, so a dropped, replaced, or deleted endpoint cannot authorize old effects.
Keep these boundary checks when adding a new route.
The panel names a target only while their body is visible. Otherwise it displays their
current relay name, or "Unknown" if no relay remains. Leaving a relay or ending its
session therefore cannot reveal the remote identity; direct actions remain available.
Message templates:
act() gets anonymity from the route. Public messages use the observer perspective;
private messages address their recipient as "you". Known self interactions read
reflexively for everyone ("yourself", "herself", "her own"): a bare %TARGET% is an
object and %TARGET_CAPITAL% a subject, and the target message is skipped because the
user message already addresses them. Anonymity takes precedence over shared identity.
Ordinary direct messages also hide an unseen target, so a distant action cannot recover
their name after a relay ends. An explicit route retains its own identity policy,
including a device configured to reveal its remote participant. Administrative logs
retain the real participants.
Both USER and TARGET support these tokens:
| Token | Purpose |
%USER%, %USER_CAPITAL% | Participant name, optionally capitalized |
%USER_OBJECT% | Object form, including "yourself" for known self interactions |
%USER%'s | Possessive, including "your" or "your own" for the recipient |
%USER_VERB_S%, %USER_VERB_ES% | Verb ending omitted for a second-person subject |
%USER_PRONOUN_THEIR%, %USER_PRONOUN_THEIRS% | Possessive pronouns |
%USER_PRONOUN_THEM%, %USER_PRONOUN_THEY%, %USER_PRONOUN_THEMSELVES% | Other pronoun forms |
%USER_BREASTS%, %USER_TITS%, %USER_BOOBS%, %USER_BREAST%, %USER_BOOB%, %USER_CHEST% | Chest words; for a participant with pecs every one reads "pecs" or "pec" |
%USER_CROTCH% | "bulge" while the participant has one (see self_bulge below), otherwise "crotch" |
%USER_BULGE_COVER% | What a bulge shows through: the suit or uniform's name, a groin-length undershirt ("leotard"), or "underwear" |
%USER_DEVICE% | The worn device closing off the participant's penis, else their vagina, like "chastity cage" |
For example, %USER_CAPITAL% wave%USER_VERB_S% to %TARGET_OBJECT%. works for both
observer and recipient messages. An optional name_pecs gives the menu button its pec wording
("Pecjob" for "Boobjob") when the chest the interaction uses, the user's if breasts is in
user_required_parts and otherwise the target's, is pecs. When that chest is pecs drawn without
nipples, the optional name_nippleless, message_nippleless, user_messages_nippleless and
target_messages_nippleless stand in for the label and message lists, so nipple interactions can read
sensibly; each falls back to the usual field when absent. Existing private templates need explicit verb-ending
tokens when their subject can become "you"; the formatter does not conjugate prose.
interaction_requires also takes self_bulge and target_bulge: a penis at least half hard and covered
by clothes or underwear, exactly when the plain penis interactions would call it unexposed (one set to never
show has no bulge). Bulge interactions use these instead of penis in the required parts, which would ask
for it to be exposed. Portals relay a bulge wherever they relay the penis.
self_pokes_out and target_pokes_out need a bulge that still shows some of the penis (bulge_pokes_out(), in
the bulge module): some of it drawn over the cloth (a tip or head past the garment, what a printed patch leaves
bare, the shaft over a revealing skirt) or behind a cover cut or lifted for it (a revealing skirt or a loincloth,
hard). Any pixel drawn counts. Not counted: a penis showing below the hem of a skirt not cut for it (half hard) or
past a long curtain skirt; and the smallest Tentacled (Alt) penis under a hard loincloth counts, though its drape
hides it. Portals relay them wherever they relay a bulge.
Likewise self_caged/target_caged need a penis closed off by a worn device such as a chastity cage, and
self_belted/target_belted a vagina closed off by one. self_arm/target_arm need at least one arm, for
armpit interactions, whatever hair is there. A genital a device closes off fails every
interaction that lists it in the required parts, and takes no other toy. See the chastity module's readme.
Configuration loads from config/nova/interactions/, including nested JSON files.
Portal device mappings depend on the external interaction set described in the
modular items documentation.
Verification:
The portal route tests cover anonymous panel titles, route preferences, and stale
offered sessions. Device and lifecycle tests cover endpoint authority and cleanup.
The ordinary CI deployment does not copy the interaction configuration directory;
runtime routing tests use deterministic fixtures, while deployment-specific JSON
validation requires supplying that configuration.
TG Proc/File Changes:
Defines:
Master file additions:
Included files that are not contained in this module:
|