/tg/ Station 13 - Modules - Types

modular_nova/modules/interaction_menu/readme.md

Title: INTERACTION MENU

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:

TokenPurpose
%USER%, %USER_CAPITAL%Participant name, optionally capitalized
%USER_OBJECT%Object form, including "yourself" for known self interactions
%USER%'sPossessive, 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:

  • N/A

Defines:

  • N/A

Master file additions:

  • N/A

Included files that are not contained in this module:

  • N/A