Waves of minions

Usage guide of minion.waves: the wave state machine, routes and teams, settings and defaults, minion types, recipes, hooks minion.spawn and minion.reward, events, service, save.

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

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

Waves of minions (minion.waves) #

AI units that spawn in waves, walk a route toward the other end, fight what they meet, die and pay a reward. One kit serves a MOBA, a tower defense, an RTS skirmish or a siege, with a different config. Readable offline: gripforge docs minion-waves, or the MCP tool gripforge_docs (topic minion-waves).

What it is for #

Every step is a named state and an event, and every rule is a config key. The kit holds no wallet and draws nothing itself: it sends units down routes, runs their state machine and announces rewards; health, damage and attacks come from the combat kits, the model comes from a slot of your game.

StepWhat happensRule (config)Event or state
SpawnWaveeach team sends the composition down every routefirstWave, interval, composition, maxActive, rowSize, spacingminion.wave
FollowPathwalk the route toward the other endtype speedstate follow
SelectTargetnearest enemy of the first wanted category within aggrotargetPriority, assistHeroes
EnterCombatchase the target into attack rangeengagestate combat
Attackone hit every cooldowntype damage, range, cooldownminion.attack
LoseAggrotarget dead, out of aggro x 1.3, or too far off the routechaseDistancestate return
ReturnToPathwalk back to the route, or resume from the nearest pointreturnToLanereturn then follow
Diedeath animation, then despawndespawnDelaystate dead
GiveRewardgold to the last hit, experience split between enemy heroes nearbyrewards.*minion.killed

Every state change is minion.state { minion, from, to, target }; each minion carries the component minion.ai { state, target, type, route, aggro, range }.

Turn it on #

gripforge_gamekit_install   { project_id: "gkp_…", id: "minion.waves" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "minion.waves",
                              config: { "interval": 45, "targetPriority": ["structure"] } }

It requires combat.attacks, combat.health, combat.damage and game.engine. The full reference is gripforge kit api minion.waves.

Routes and teams #

  • A kit that provides lanes.routes (moba.lanes does) gives the routes and the two teams.
  • Otherwise the collection minion_routes holds { id, points: [[x, z]…] } (ground points from the first team's end to the second's) and teams names the two teams.
  • A scene may carry its own routes in data.minion_routes. Entering the scene starts its waves over (firstWave after the entry); leaving it removes its minions.

The first team walks a route forward, the second backward, so opposite waves leave together and meet midway.

Settings and defaults #

KeyDefaultMeaning
teams["blue", "red"]the two teams (ignored when a kit provides lanes.routes)
firstWave, interval8, 30seconds before the first wave, between waves
compositionmelee x3, siege x1 every 3 waves, ranged x3front row first; { type, count, every? }
maxActive80no wave is sent while that many minions are alive
rowSize, spacing3, 2minions side by side; metres between minions
scale1size factor over a 1.8 m standard character
engagetruefalse: they only walk (a tower defense)
chaseDistance6metres from the route a chase may take a minion
returnToLanetruewalk back to the route after a fight
targetPriority["minion", "hero", "structure"]most wanted first; a category left out is ignored (also monster, other)
assistHeroes, assistRadiustrue, 9turn on an enemy hero who hits an allied hero nearby
avoidancetruekeep spacing x 0.7 apart instead of stacking
formationfalsea wave walks as a group at the pace of its slowest minion
poolfalsethe look of a dead minion is handed to the next minion of the same model
scaling{ mode: "time", every: 180, hp: 0.05, damage: 0.04, armor: 2 }growth per step; mode is time (seconds) or wave
rewards{ lastHitOnly: true, shareXp: true, shareRadius: 14, goldFactor: 1, xpFactor: 1 }
despawnDelay1.5seconds a dead minion stays
entityKind, slotPrefix, tagsminion, minion_, []entity kind, model slot prefix, extra tags
debugfalsedraw routes, detection and attack ranges, the current target

Types #

The collection minion_types holds { id, name?, hp, damage, armor?, range, cooldown, speed, aggro, scale?, slot?, windup?, projectileSpeed?, color?, reward?: { gold?, xp? } }. Built in: melee, ranged, siege, super. A range above 3 m is a ranged attack (a projectile is drawn); armor divides damage by (100 + armor) / 100. The model of a type is the slot slotPrefix + id with the team as variant (minion_melee:blue); the slot declares the animation clips it needs (idle, run, attack1, death).

Recipes #

  • Minions ignore heroes and only attack towers: targetPriority: ["structure"].
  • A tower defense (creeps walk, never fight): engage: false, with one empty team.
  • Bigger, slower waves: composition: [{ "type": "melee", "count": 6 }, { "type": "siege", "count": 2 }], interval: 45.
  • Late-game pressure: scaling: { "mode": "wave", "every": 2, "hp": 0.1, "damage": 0.08, "armor": 3 }.
  • A boss every fifth wave: a minion_types entry brute and { "type": "brute", "count": 1, "every": 5 }.

Hooks, mods, services #

WhatNameDetail
Hookminion.spawn{ wave, route, team, count, reinforced }, asked once per route and team of a wave. A tap changes count (fewer: the rear stays home; more: the composition is repeated from its head; 48 at most) or cancels (nobody leaves for that team on that route; the wave still counts)
Hookminion.reward{ minion, type, team, route, by, gold, xp }, once per death, before minion.killed; a tap changes gold and xp, a cancel pays nothing (minion.killed is still sent with 0)
Registriesminion_types, minion_routesa mod adds, patches or removes documents
Moddable configall keys but teams, entityKind and tagswave, chase, priority, scaling and reward keys
Eventsminion.wave { wave, routes, count }, minion.state, minion.attack { source, target, ranged, synchronized, type }, minion.killed { minion, type, team, route, by, gold, xp, sharers }an economy or match kit pays gold to by and splits xp between sharers
Listenscombat.killed, combat.damaged
Serviceminion.wavesspawnWave(), spawn(type, team, route, t?, side?), list(), get(id), front(route, team), count(team?), wave(), routes(), teams(), types(), priority(), setPriority(list), setReinforcements(route, team, entries) (super minions after an inhibitor), setDebug(on), debug()
{ "id": "thin_red_waves", "hook": "minion.spawn", "match": { "team": "red" }, "add": { "count": -2 } }

Which enemy a minion may hit is a service another kit provides, combat.targeting { canTarget?(attacker, target), radius?(id), category?(id) } (a tower that cannot be hit yet, a neutral camp, a wide building). Without it the category is read from tags (minion, hero / player, structure / tower, monster). A kit that provides world.navigation { next(key, from, to) } lets minions bend around walls when a chase takes them off their route.

Variables: minion.wave, minion.count, minion.debug.

Save #

The wave count and clock, every minion (type, team, route, progress, state, target, cooldown), the reinforcements and the target priority. After a load the minions walk and fight on and the next wave leaves on time; a minion whose type, route or team is gone (a mod removed it) is dropped.

Engines #

Web and native player run the same rules (waves, rows, scaling, the state machine, rewards, hooks, save). Health, damage, targeting, attacks, navigation, water and ground are called from the modules that serve them.