Strategy opponent
Usage guide of rts.ai: data plans (easy, normal, hard) that play an rts.production faction by the player's own rules, the difficulty setting, service, wave event and the ai.attack, ai.build and ai.defend hooks.
A computer opponent for strategy skirmishes (rts.ai) #
What it is for #
rts.ai is the computer side of an rts.production skirmish. It plays by the same rules as the player, through the same services, with no cheat and no extra resource. Every think seconds a faction puts its idle workers on the nearest nodes, trains workers up to a target, builds supply before a shortage, follows a build order, trains an army by weights, and sends attack waves on a schedule, larger each time. It can also defend its base. How it plays is data: its plans (easy, normal, hard) are documents you can edit or add to. The kit holds no rendering and no screen.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "rts.ai" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "rts.ai", config: { "difficulty": "hard" } }
It requires game.engine, rts.production and units.command. A faction is played by this kit when its ai field, in the factions of rts.production, names a plan. Targets: web and the Rust kit host.
First example #
<!-- test: kits/rts_ai/tests/rts_ai.rs::a_plan_can_be_chosen_for_a_faction_and_an_unknown_one_is_refused --> With the default plans, a computer faction bot plays easy. Calling the service setPlan("bot", "hard") answers true and plan("bot") now returns the hard plan. setPlan("bot", "impossible") or a non-string answers false and leaves the plan unchanged. factions() lists only the computer factions, with { faction, plan, step, wave, nextWave }; plan returns null for the player's own faction or an unknown one.
How it plays #
Every think seconds:
- Idle workers go to the nearest node of the item furthest below its
gathershare (the rest go to the first item). - A supply building goes up when fewer than
supplyMarginsupply are free (housenames it; default: the cheapest one that gives supply). - Workers are trained up to
workers. - The next building of
buildis placed as soon as it is allowed and paid for, on a free spot around the base. - Each finished building trains the army type furthest below its
armyweight (two in queue at most). - When a wave is due, the idle army attack-moves to the nearest enemy building: at once when it has the planned size, else after 30 seconds with what it has.
With defend, a strike on its base sends its idle army at the attacker.
Data: the rts_ai_plans collection #
| Field | Meaning |
|---|---|
id, name | Plan id and name (required, like every field below). |
think | Seconds between two decisions (0.2 to 30). |
workers | Workers it trains up to. |
gather | Share of workers per item, e.g. { "ore": 0.65, "wood": 0.35 } (optional). |
supplyMargin | Builds supply when fewer are free. |
house | The supply building (optional). |
build | Build order, one building after the other. |
army | List of { unit, weight }. |
waves | The first waves: { at, size }, match seconds and units. |
every, growth | Seconds between later waves (10 to 3600) and units added to each later wave. |
defend | Whether the idle army answers a strike on the base. |
Defaults shipped: easy (think 3, 7 workers, one wave at 300 s of 3 units, no defence), normal (think 1.5, 10 workers, first wave at 210 s of 4, defends), hard (think 0.75, 14 workers, first wave at 160 s of 5, defends). A project that defines rts_ai_plans uses its own plans.
Settings and defaults #
| Setting | Type | Default | Meaning |
|---|---|---|---|
difficulty | string | empty | A plan every AI faction plays. Empty: the ai of each faction in rts.production. |
Service and events #
Service rts.ai:
factions():[{ faction, plan, step, wave, nextWave }].plan(faction): the plan document, or null.setPlan(faction, plan): true when the plan exists.
| Event | Payload |
|---|---|
rts.ai.wave | { faction, wave, size, planned, at, target }: a wave left, with its units, the size the plan asked for, the match time and where it goes. |
It listens to combat.damaged. The decision clock, the build order step and the waves sent are saved with the game, and so is the plan chosen by setPlan.
Hooks and modding #
| Hook | Payload | Mutable | Cancelled |
|---|---|---|---|
ai.attack | { faction, plan, wave, size, planned, at, x, z } | x, z | The wave is skipped; the next comes at its time. |
ai.build | { faction, plan, type, reason, step, x, z } | none | A build order step is skipped; a supply building is not asked again while the shortage lasts. reason is order or supply. |
ai.defend | { faction, plan, attacker, target, size, x, z } | none | The army stays where it is. Asked at most every 3 seconds per faction. |
{ "id": "truce", "hook": "ai.attack", "if": [{ "var": "story.truce", "op": "==", "value": true }], "cancel": true }
A mod may override difficulty and add, patch or remove documents of rts_ai_plans.
When it does not do what you expect #
- A faction does nothing: its
ainames no plan, or the match clock has not started, or the game is over. - Waves are small or late: the army is below the planned size, so the wave leaves 30 seconds after it was due with what exists.
- A plan with no
wavesstill attacks: the schedule then starts at 300 seconds with 3 units, spaced byeveryandgrowth. setPlananswers false: the plan id is not in the plans, or is not a string.
Limits #
- It uses only the services of
rts.production,units.commandandresource.nodes; it cannot do what the player cannot. - Its targets are enemy buildings; there is no scouting or tactics beyond waves and defence.
Versions #
Kit 1.1.0; service rts.ai 1.0.0. Hooks and moddable plans since 1.1.0 (game.engine 1.2).