Path waves

Usage guide of defense.waves: paths, enemies and scripted waves, lives and leaks, early call bonus, settings and defaults, service, events, verbs and hooks.

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

Also read offline — CLI: grip-forge docs defense-wavesMCP tool: gripforge_docs { "topic": "defense-waves" }

Wave defense in your game (defense.waves) #

What it is for #

Enemies march along authored paths toward an exit, in scripted waves. A wave lists groups (which enemy, how many, how far apart, on which path). An enemy that gets through costs lives; no lives left is a defeat, every wave beaten is a victory. Waves come on a countdown and calling the next one early pays money. Enemies are combat.core entities, so any kit that deals damage kills them and slowing statuses slow them. Towers and money come from other kits (for example defense.towers, economy.money).

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "defense.waves" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "defense.waves",
                              config: { "lives": 20, "prepTime": 20, "interval": 12 } }

Needs combat.core, game.engine; installing the kit brings them along.

First example #

<!-- test: kits/game_engine/host/tests/parity.rs::rust_host_matches_the_typescript_traces (fixture defense.waves.march) --> One road, one enemy type, and a first wave of three runners (config { "lives": 6, "prepTime": 1, "interval": 2 }). The wave starts after prepTime seconds, a runner appears every 0.5 s, each one that reaches the end of the road costs one life, and the 15 money of the wave is paid when its last enemy is gone.

{ "defense_paths":   [{ "id": "main", "points": [[-10, 0], [0, 0], [0, 8]] }],
  "defense_enemies": [{ "id": "runner", "name": "Runner", "hp": 20, "speed": 5, "reward": 4 }],
  "defense_waves":   [{ "id": "w1", "reward": 15, "groups": [{ "enemy": "runner", "count": 3, "every": 0.5 }] }] }

Settings and defaults #

SettingDefaultMeaning
lives20Lives at the start.
prepTime20Seconds before the first wave.
interval12Seconds between the end of a wave's spawning and the next wave.
autoStarttrueWaves come on their own when the countdown ends; off: only when called.
earlyBonus2Money per second of countdown skipped when the next wave is called early.
flyHeight4Height of flyers above the ground (m).
teamenemycombat.core team of the enemies.
despawnDelay0.6Seconds a killed enemy stays (its death).
drawPathstrueLay a flat road along every ground path.
pathWidth3Width of that road (m).
finishtrueWithout game.endings, the kit ends the game itself on an end screen; with it, endings read defense.result.
winTitle, winText, loseTitle, loseTextVictory, Every wave was held back., Defeat, Too many enemies got through.Texts of the end screen.
hidePlayerfalseA game without an avatar: the player entity is hidden and stands at the centre of the paths, as the camera anchor.

Three collections hold the content (all optional fields are in the manifest, gripforge kit api defense.waves lists them):

CollectionFields
defense_pathsid, points ([x, z], 2 to 64), air
defense_enemiesid, name, hp, speed, armor, reward, lives, flying, scale, color
defense_wavesid, name, groups (enemy, count, every, delay, path), hp, reward, next

Armor divides every hit by (100 + armor) / 100. A flyer takes an air path, else it goes straight from the entry to the exit. A group without path takes the paths in turn. The enemy models are bound to the asset slot defense_enemy (variant = enemy id).

Services, events, variables #

  • Service defense.waves: state(), wave(), waves(), lives(), maxLives(), countdown(), bonus(), callNext(), preview(wave?), enemies(), remaining(entity), paths(), addLives(n). callNext() starts the next wave now and pays the early bonus; it answers null when a hook cancels it.
  • Events: defense.wave (wave, waves, count, early, bonus), defense.spawned (entity, enemy, path, wave), defense.leaked (entity, enemy, lives, left), defense.killed (entity, enemy, by, reward), defense.wave_cleared (wave, reward), defense.won, defense.lost. It listens to combat.killed.
  • Variables: defense.wave, defense.waves, defense.lives, defense.lives.max, defense.countdown, defense.enemies, defense.result (won, lost or empty). The input action defense.call_wave (key T) calls the next wave.
  • Verbs and conditions:
{ "type": "call_wave" }
{ "add_lives": 5 }
{ "wave_reached": 5 }
{ "lives_at_least": 10 }

Hooks and modding #

HookMeaning
wave.startThe next wave is about to start (countdown over or called early); bonus is mutable; cancelled, it does not start.
wave.spawnAn enemy is about to appear at the entry of a path; hp, reward and lives are mutable; cancelled, this one does not appear.
wave.leakAn enemy reached the exit; lives is mutable (0: it gets through for free).
wave.clearA wave has spawned and none of its enemies is left; reward is mutable.
{ "hook": "wave.spawn", "match": { "enemy": "runner" }, "mul": { "hp": 2 } }

Every setting and the listed collections are moddable.

Limits #

Runs on the web player and the native player; Godot, Unity and Unreal have no native delivery of this kit. It places no towers and keeps no money: pair it with a tower kit and an economy kit. Flyers ignore towers that cannot hit the air.

Versions #

Kit 1.1.0 (the hooks arrived in 1.1.0); service defense.waves 1.0.0. It relies on the contract of game.engine ^1 and on the health and damage services of combat.core ^1.