# Stealth takedowns and hiding (stealth.takedown) ## What it is for The player side of stealth. The player sneaks up behind a perceiver that has noticed nothing and takes it down silently, carries the body and hides it in a container before someone finds it, or hides in a locker, a wardrobe or under a bed so nothing can see them, then steps out again. It works on the perceivers of [Stealth perception](guide:stealth-detection) and offers its actions through the interaction prompt (see [Interaction guide](guide:interaction-system)). Animations, models and the guards' patrols stay with the other kits. ## Turn it on ```text gripforge_gamekit_install { project_id: "gkp_…", id: "stealth.takedown" } gripforge_gamekit_configure { project_id: "gkp_…", id: "stealth.takedown", config: { "reach": 1.6, "behindAngle": 120, "immuneTags": ["boss"] } } ``` It requires `stealth.detection`, `interaction.use`, `npc.behavior` and `game.engine`. A hiding place is an entity with the `hiding_spot` component: ```json { "label": "Hide in the locker", "capacity": 1 } ``` ## First example The parity scenario puts a player among unaware guards, a locker and a crate, and replays the whole cycle: `canTakedown` is true only for a guard the player stands behind within `reach`, `takedown` lays it down (tag `downed`, event `stealth.takedown`), `downed()` lists the bodies, `carry(body)`, `drop()` and `stow(spot)` move a body, and `hide(spot)` then `leave()` take the player in and out of a spot. ```text canTakedown ["e1"] -> true or false, depending on where the player stands takedown ["e1"] -> true (the guard lies down: a body others may find) carry ["e1"] -> true stow ["e4"] -> true (event stealth.body_hidden: nobody will find it) ``` ## Settings and defaults | Setting | Default | Meaning | |---|---|---| | `reach` | 1.6 | how close behind a perceiver the player must stand (m) | | `behindAngle` | 120 | the player must stand at least this far (degrees) off the perceiver's facing | | `allowSuspicious` | `false` | also take down a suspicious perceiver (never a searching or alert one) | | `immuneTags` | `stalker`, `boss` | perceivers with one of these tags are never taken down | | `noiseRadius` | 2 | radius of the almost silent noise of a takedown (0: none) | | `noiseLoudness` | 20 | suspicion that noise adds at its source | | `carryDistance` | 0.6 | how far behind the player a carried body follows (m) | | `dropDistance` | 0.9 | how far in front of the player a dropped body lands (m) | | `downClip` | `death` | animation of a downed body | | `takedownLabel` | Takedown | prompt label | | `carryLabel` | Carry body | prompt label | | `hideLabel` | Hide | prompt label | | `hideBodyLabel` | Hide body | prompt label | | `leaveLabel` | Leave | prompt label | A `hiding_spot` accepts `label`, `player` (the player can hide in it, default true), `bodies` (bodies can be hidden in it, default true), `capacity` (bodies it holds, default 1) and `exit` (metres in front where the player steps out, default 1). ## Services, events, variables - `stealth.takedown` (service): `canTakedown(entity)`, `candidate()`, `takedown(entity)`, `downed()`, `carry(body)`, `drop()`, `carrying()`, `stow(spot)`, `hide(spot)`, `leave()`, `hidingIn()`, `spots()`. - Events: `stealth.takedown` (a perceiver was taken down), `stealth.body_carried`, `stealth.body_dropped`, `stealth.body_hidden` (a body went into a spot: nobody will find it), `stealth.hid`, `stealth.left`. - Variables: `takedown.count`, `takedown.carrying`, `takedown.hiding`, `takedown.available`. - Script verbs: condition `takedowns_at_least`, NPC behaviour `stealth_down`. A downed body stays a body that other perceivers can find until it is stowed. State is kept in the components `stealth.body`, `stealth.spot` and `stealth.hiding`, saved with their entities. ## Hooks and modding | Hook | Payload | Effect | |---|---|---| | `stealth.take_down` | `entity`, `player`, `noiseRadius` | mutable `noiseRadius`; cancelled: nothing happens and `takedown()` answers false | | `stealth.body.carry` | `body` | cancelled: the body stays where it lies | | `stealth.body.drop` | `body` | cancelled: the player keeps carrying it | | `stealth.body.stow` | `body`, `spot` | cancelled: the player keeps carrying it | | `stealth.hide` | `spot` | cancelled: the player stays outside | | `stealth.leave` | `spot`, `exit` | mutable `exit`; cancelled: the player stays inside | ```json { "id": "silent_arms", "hook": "stealth.take_down", "set": { "noiseRadius": 0 } } ``` A mod may override every setting above. ## Engines The web player and the native kit host run the same rules. Hiding and leaving move the player through `character.control`; the `stealth_down` behaviour is handed to `npc.behavior`. A status pastille on the HUD shows hidden, carrying a body, or a takedown within reach. ## When it does not do what you expect - `canTakedown` is false: the perceiver is searching or alert (or suspicious without `allowSuspicious`), too far, not behind enough, or carries an immune tag. - The prompt shows but the takedown does nothing: a tap of `stealth.take_down` cancelled it; use `immuneTags` to hide the prompt too. - A body cannot be stowed: the spot has no `bodies` or is at `capacity`. ## Limits - It does not detect anything: awareness belongs to `stealth.detection`. - Only perceivers of `stealth.detection` can be taken down, and only the player takes them down. ## Versions Kit 1.1.1, service contract 1.0.0. 1.1.0: the `game.engine` hook contract; 1.0.0: first release.