# Interaction system (interaction.system) ## What it is for Registers world entities as interactive, finds the closest one in reach of the player, shows its prompt with the player's own key, handles slow holds and refuses with a reason when a thing is locked or too far. It needs `character.control`, `input.actions`, `game.engine`; installing it brings them in. ## Turn it on Install the kit in a project, then change a setting (the values shown are its defaults): ```text gripforge_gamekit_install { project_id: "gkp_…", id: "interaction.system" } gripforge_gamekit_configure { project_id: "gkp_…", id: "interaction.system", config: { "radius": 2.5, "action": "interact" } } ``` ## First example This is the body of the passing test `the_thing_within_reach_becomes_the_candidate_with_a_prompt`; the helper functions it calls are defined at the top of the same test file. ```rust #[test] fn the_thing_within_reach_becomes_the_candidate_with_a_prompt() { let (mut s, _, door) = scene(json!({}), [1.0, 0.0, 0.0], "Open door"); step(&mut s, 1); assert_eq!(current(&mut s), json!(door)); let p = prompt_var(&s); assert!(p.as_str().unwrap().contains("Open door"), "{p}"); assert_eq!(call(&mut s, PROMPT, "text", json!([])).unwrap(), p); assert_eq!( call(&mut s, PROMPT, "label", json!([])).unwrap(), json!("Open door") ); assert_eq!( call(&mut s, PROMPT, "action", json!([])).unwrap(), json!("interact") ); assert_eq!( call(&mut s, PROMPT, "target", json!([])).unwrap(), json!(door) ); assert_eq!( call(&mut s, USE, "labelOf", json!([door])).unwrap(), json!("Open door") ); let seen = topics(&s, "interaction.available"); assert_eq!(seen.len(), 1); assert_eq!(seen[0]["entity"], json!(door)); assert_eq!(seen[0]["action"], "interact"); // Still the same candidate a tick later: announced once. step(&mut s, 3); assert_eq!(topics(&s, "interaction.available").len(), 1); } ``` ## Settings and defaults Descriptions come from the kit manifest and stay in English. | Setting | Type | Default | Range or values | Meaning | |---|---|---|---|---| | `radius` | number | `2.5` | 0.5–10 | Reach in meters from the player. | | `action` | string | `"interact"` | | Input action that triggers the use. | | `showPrompt` | boolean | `true` | | | | `holdSeconds` | number | `0` | 0–10 | 1.5.0: seconds the action is held before a use, for every interactive without its own hold (0: a press uses at once). | | `vehicleScheme` | string | `"vehicle"` | | 1.6.0: the input.scheme scheme of a player at the wheel (input.scheme pushes it on vehicle.entered): then only the interactives… | | `vehicleRadius` | number | `6` | 1–30 | 1.6.0: reach in metres from the vehicle the player drives. | | `pointerTarget` | boolean | `false` | | 1.5.0: without input.scheme, the interactive under the pointer (the aim.target variable) is the candidate when in reach; with or… | | `clickApproach` | boolean | `false` | | 1.7.0: with pointerTarget, a click on an interactive out of reach walks the player to it (an input.scheme move order) and uses it… | | `approachSeconds` | number | `8` | 0.5–30 | 1.7.0: the longest walk of a clickApproach before it is given up. | ## Services, events, variables - Service `interaction.use`: register(entity, label, action?, kind?) / unregister; kindOf(entity), setLocked(entity, on), setHold(entity, seconds), setFromVehicle(entity, on); the nearest interactive in range receives interaction.requested. - Service `interaction.prompt`: The current prompt label as GameState interaction.prompt (`E · Open door`, key from labelFor); action() / label() / kind() / locked() of the current target, progress() of a hold (0..1, null when nothing is held) for ui.prompts and interaction.feedback. - Events emitted: - `interaction.completed` (`entity`, `label`) — A completion condition became true during play. - `interaction.available` (`entity`, `targetId`, `label`, `action`) — An interactive entered reach (the HUD shows the prompt); entity is the interactive. - `interaction.hidden` (`entity`) — No interactive in reach any more; entity is the one that was offered. - `interaction.requested` (`entity`, `target`, `targetId`, `label`, `action`) — The player (entity) pressed an action on the available interactive (target). - `interaction.refused` (`entity`, `target`, `label`, `action`, `reason`) — The use was refused: a tap of the hook interaction.use cancelled it (reason: the tap's, default refused), the interactive is locked (locked) or out… - `interaction.hold.started` (`entity`, `target`, `action`, `seconds`) — 1.5.0: the player started holding the action on an interactive that needs a hold (seconds: how long). - `interaction.hold.cancelled` (`entity`, `target`, `action`, `progress`) — 1.5.0: the hold stopped before its end (released, or the target changed). - `interaction.approach` (`entity`, `target`, `label`, `action`) — 1.7.0: clickApproach — the player (entity) clicked an interactive out of reach (target) and walks to it; used on arrival. - `interaction.approach.cancelled` (`entity`, `target`, `action`, `reason`) — 1.7.0: the walk of a clickApproach stopped before arrival (reason: replaced by another click, gone, timeout, no_player). - Events listened to: `input.action`, `engine.state.changed`, `engine.visibility` - Variables: - `interaction.prompt` (string) — Interaction prompt ## Hooks and modding - Hooks (a game or a mod can intercept them): - `interaction.use` (cancellable) — The player (entity) pressed action on the interactive in reach (target): a door the story keeps shut, a lever that needs a tool. - Moddable settings: `radius`, `action`, `showPrompt`, `holdSeconds`, `vehicleScheme`, `vehicleRadius`, `pointerTarget`, `clickApproach`, `approachSeconds` - Components: `interactable` ## Engines Declared targets: `web`, `godot`, `unity`, `unreal`, `rust`. `gripforge kit api interaction.system` lists the exact settings and services of your version. ## Versions Kit version 1.8.0.