Gessa Docs
Recipes

Recipe

Combat damage health and respawn scripting

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.
engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, persistence.v1Copy for LLM

Use this for

dealing damage on hit or contact; tracking health as durable state; death and respawn; hitscan or melee verbs

Not for

cosmetic hit sparks only (see audio-feedback and atmosphere); anything expecting a HealthComponent or DamageComponent (they do not exist)

Pairs with: Collectibles pickups scoring and win condition, Spawn points checkpoints and respawn flow, UI HUD panels widgets and world nameplates, Physics colliders rigid bodies triggers and joints

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.
Was this helpful?Report an issueContact support

On this page