---
title: "Combat damage health and respawn scripting"
description: "Any fight loop: a projectile hits, a sword swings, contact hurts, health drops, and the loser dies and respawns. The engine has NO `HealthComponent`, `DamageOnContactComponent`, `ProjectileComponent`, or `RespawnTimerComponent` (all stripped, see component-types.md). You express the loop as a script."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/combat-damage-and-respawn/
---

# Combat damage health and respawn scripting

## When to use

Any fight loop: a projectile hits, a sword swings, contact hurts, health drops,
and the loser dies and respawns. The engine has NO `HealthComponent`,
`DamageOnContactComponent`, `ProjectileComponent`, or `RespawnTimerComponent`
(all stripped, see component-types.md). You express the loop as a script.

## The recipe

Author with `project_apply_script_semantic_patch` (AI name
`apply_script_semantic_patch`) using only the `ai_safe` operation pack. Every
op that lives inside a handler takes `scope: { "kind":"handler",
"handlerRef": <handlerKey> }`.

1. Seed health as durable state: `writeTypedStateValue`
   `{ "storeKey":"progress", "recordKey":"player", "field":"health",
   "valueType":"number", "value": 100 }` (defaults storeKey `progress`,
   recordKey `player`).
2. Make the attacker's shot a verb: `addActionHandler`
   `{ "actionKey":"fire", "handlerKey":"onFire" }` (the input action from
   input-mapping-actions-bindings). Or make contact hurt: give the hazard a
   trigger `ColliderComponent` and `addTriggerHandler`
   `{ "handlerKey":"onHurt" }`.
3. Apply damage inside that handler: `incrementNumericState`
   `{ "scope":{...}, "field":"health", "by": -25 }`. Negative `by` subtracts.
4. Detect death: `readTypedStateValue` health into a binding
   (`assignTo:"hp"`), then branch. For the simplest match-level check use
   `setBooleanState` `{ "field":"dead", "value": true }` when health reaches 0.
5. Respawn: `spawnEntityFromTemplate`
   `{ "templateKey":"player-spawn" }` or `{ "prefabKey": <prefab key> }` with a
   `config` of validated inline overrides, and reset health with another
   `writeTypedStateValue` back to 100.
6. For a whole-game outcome, transition the match phase from a GessaScript body
   with `ctx.match.setPhase`, or use `declareWinCondition` for count-based wins.

## Pitfalls

- Do not attach a component named for health or damage; there is none. Health is
  a warehouse field.
- `incrementNumericState` mutates durable state and carries `requiresAuthority`;
  it runs server-authoritatively. Do not expect a client-only visual to persist.
- `addTriggerHandler` takes NO trigger key: its payload has no trigger-identity
  field. Distinguish hazards by inspecting `firstEntityId`/`secondEntityId` or
  entity tags inside the handler.
- The rich `addShooterCollectorLoop` op is NOT AI-expressible (visual_editor and
  template contexts only). Compose the loop from the ai_safe primitives above.
- For anything the add-only op alphabet cannot express (custom branching, math),
  drop to `replaceScriptFromGessaScript` and call `ctx.warehouse.*` /
  `ctx.match.*` directly.

## Verify

- `simulation_run` (`qa.run.start`) to prove health drops on hit and the entity
  respawns.
- `project_get_graph_snapshot` to confirm the trigger/action handlers and the
  ScriptComponent binding exist.
