Survival needs

Usage guide of survival.needs: named gauges (oxygen, water, food, warmth, sanity) that drain, hurt at zero and come back from items, world sources, rest and other kits, with stages, settings, service, events and hooks.

Source: module-kits:kits/survival_needs/usage/en.mdView Markdown source

Also read offline — CLI: grip-forge docs survival-needsMCP tool: gripforge_docs { "topic": "survival-needs" }

Survival needs (survival.needs) #

What it is for #

Gauges the player must keep up. The kit does not know what oxygen or hunger is: a need is a name, a maximum, a drain and what it costs at zero. Oxygen on a hostile planet, warmth in a blizzard or sanity in a haunted house are the same thing with other numbers. Each drains over time, hurts at zero (through combat.damage when the game has combat), and comes back from consumed items, sources in the world, rest, or another kit. The HUD draws the gauges. Where the player's health lives is for the combat kits (see Combat).

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "survival.needs" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "survival.needs",
                              config: { "needs": [
                                { "id": "thirst", "label": "Water", "max": 100, "drain": 0.2, "damage": 3, "lowAt": 0.25 },
                                { "id": "warmth", "max": 100, "drain": 0.5, "damage": 2 } ] } }

It requires only game.engine. Without a configuration the three default needs are oxygen, thirst and hunger.

First example #

<!-- test: kits/game_engine/host/tests/parity.rs::rust_host_matches_the_typescript_traces (fixture survival.needs.gauges) --> The parity scenario runs the gauges with a vent (need_source giving air back to a player near it), a fire (need_source for warmth) and a bed (rest_spot). It reads needs(), takes some air away with restore("air", -5), reads value, ratio, max and stage, and also reads an unknown need:

restore ["air", -5]          -> the gauge loses 5 units
value   ["air"]              -> its current value
stage   ["food"]             -> { id, label, effects } or null

Settings and defaults #

SettingDefaultMeaning
needsoxygen, thirst, hungerthe gauges of the game (1 to 12)
pausedfalsestart with the gauges frozen (a tutorial, a safe hub)
refillOnRespawntrueback to the start values when the player comes back to life
restLabelSleepprompt of a rest spot without its own label

Each entry of needs:

FieldMeaning
idlowercase id (oxygen, thirst, hunger, warmth, sanity...)
label, colorHUD name and colour
max, startmaximum and value at the start and after a respawn (default: max)
drainunits lost per second
damagehealth lost per second while the need is at zero
lowAtshare of the maximum under which the need is low
stagesup to 8 thresholds { id, below, label?, effects? }

The defaults: oxygen (max 100, drain 0.9, damage 12), thirst (drain 0.2, damage 3), hunger (drain 0.12, damage 2), all with lowAt 0.25.

Ways to get a need back:

  • an item: a document of the consumables collection, { "item": "water_bottle", "restores": { "thirst": 40 } }, applied when inventory.used fires;
  • a source in the world: an entity with need_source { need, perSecond, radius } (default radius 4 m) refills the player standing in reach;
  • rest: rest_spot { hours, restore, label } on furniture, or the rest action; time passes on world.clock when installed;
  • another kit: setSupply(need, perSecond, source) and setDrain(need, multiplier, source);
  • equipment: a worn piece with the stat <need>_max (for example oxygen_max) raises that maximum.

Stages name thresholds with effects:

{ "id": "sanity", "max": 100, "drain": 0, "stages": [
  { "id": "uneasy", "below": 0.6, "effects": { "vignette": 0.25 } },
  { "id": "panic",  "below": 0.15, "effects": { "vignette": 0.8, "heartbeat": 2 } } ] }

The deepest stage reached is the variable need.<id>.stage, and each effect is need.<id>.fx.<name> (0 when the stage does not set it).

Services, events, variables #

  • survival.needs (service): needs(), value(id), max(id), ratio(id), restore(id, amount, source?), set(id, value), setMax(id, max, refill?), setDrain(id, multiplier, source), setSupply(id, perSecond, source), pause(on?), refill(), rest({ hours?, restore? }), stage(id).
  • Events: need.low, need.depleted, need.recovered, need.restored, need.stage (need, stage, from), need.rested (hours, entity).
  • Variables: need.<id>, need.<id>.max, need.<id>.stage, need.<id>.fx.<name>.
  • Script verbs: actions restore_need, set_need, pause_needs, rest; condition need_below (need, ratio).

Hooks and modding #

Each hook is asked when the decision is taken, never every tick.

HookPayloadEffect
need.restoreneed, entity, amount, source, value, maxmutable amount; cancelled: nothing restored
need.feedneed, entity, source, perSecondmutable perSecond; cancelled: that source gives this player nothing until they leave and return
need.decayneed, entity, source, multipliermutable multiplier; cancelled: the previous multiplier stays
need.depleteneed, entity, damagemutable damage (0: no harm this time); cancelled: no need.depleted and no damage until the need has recovered and emptied again
{ "id": "big_sips", "hook": "need.restore", "match": { "need": "thirst" }, "mul": { "amount": 1.5 } }

A mod may override needs, paused, refillOnRespawn and restLabel, and add to, patch or remove from consumables.

Engines #

The web player and the native kit host run the same rules. With several players (co-op), every player entity has its own gauges, stages and damage in the component survival.needs; the service acts on the current player and the variables show the HUD player's. A solo game saves exactly as before. The gauges HUD view draws one bar per need and names the stage.

When it does not do what you expect #

  • A gauge does not move: the game is paused, the player is dead (nothing drains while dead), or the need has drain 0.
  • A used item restores nothing: no consumables document names that item.
  • Health does not drop at zero: damage is 0, or a tap of need.deplete set it to 0.
  • A source feeds nobody: the player is outside its radius, or a tap of need.feed cancelled it.

Limits #

  • It manages gauges, not the player's health or items: damage goes through the combat kit, items through the inventory.
  • Hooks do not see what is taken away (a negative amount) nor what flows per second.

Versions #

Kit 1.4.1, service contract 1.3.0. 1.4.0: the game.engine hook contract; 1.3.0: several players; 1.2.0: stages; 1.1.0: rest; 1.0.0: first release.