Skip to content

Commands: telling companions and squads what to do

A pet you tell to fetch, a platoon you tell to focus fire: both are the player giving orders. The engine splits that in two:

  • The command layer (this page, kke/Orders.h, kke/OrderScript.h): who is selected, what a click, a tap or a radial-menu pick means, where each unit of a squad should stand, and every unit's standing order. It never moves anyone.
  • Brains (the AI core, docs/AI.md): read a unit's order, decide how to carry it out (paths, cover, when to shoot, how a dog feels about it) and report back when it is done or failed.

The pet companion (games/pet_companion) and platoon (games/platoon) demos show both halves together: the pug and every soldier are AI core agents, ordered through AiOrderBridge (below). In the platoon, formations, cover spots and the hit rolls stay in the game; the AI moves and decides who to shoot.

Orders

Order Needs What it means
move "Go there" a place go there; a group spreads into a formation
follow "Follow me" someone stay with them, never in their way
stay "Hold position" (a place) hold this spot, defend it, don't chase
attack a target engage it (may pick others once it is down)
focus "Focus fire" a target everyone on this one, nothing else until it is down
fetch a thing bring it back to whoever gave the order
drop "Drop it" let go of what you carry
sit sit
pet the player is petting you: stand still, enjoy it
regroup (a place) gather around the player (or the place)
free "At ease" no order: do what you like

Every unit has one current order and a queue (Shift adds to the queue). A brain marks its order running, then complete(unit, ok); the next queued order takes over. A new order without Shift replaces the old ones silently (they were overruled, not failed). When a target leaves the world (OrderBoard::targetGone), attacks on it end as done and fetches or follows as failed.

Squads and formations

A move, regroup, or stay at a place gives each unit its own slot in a formation: wedge (default), line, column or circle, facing the way the squad travels unless a facing is given (drag while giving the order). Slots are handed out with the Hungarian method, so the squad travels the least in total and no two paths cross.

Selection works like every real-time strategy game: click or tap one, drag a box, Shift adds or removes, Ctrl+1..9 stores a group and 1..9 recalls it.

What a click means

Pointing at something with units selected gives the one obvious order (contextOrder):

Pointing at Order With the force modifier (Ctrl, a held button)
an enemy attack focus fire
an item fetch (units that can't fetch walk there)
the player, a friend, another unit follow them
the ground go there hold position there

Controls

Every order can be given with a mouse and keyboard, a controller or a finger, and all of them are rebindable actions (docs/INPUT.md).

  • Mouse and keyboard: left click selects, drag selects a box, right click gives the context order, keys give the rest (each demo's README).
  • Controller: the reticle in the middle of the view is the pointer. A gives the context order, the D-pad gives the four most used orders, and holding LB opens the radial wheel with every order: tilt the right stick to pick, let go of LB to give it. Back in the middle keeps the pick, so a flick and a release is enough; B closes the wheel.
  • Touch: tap a unit to select, tap the ground or a thing for the context order, hold a finger to open the wheel under it (drag to pick, let go to give, back to the middle to cancel), and the big picture buttons along the bottom give an order with one tap.

Carried out by the AI core: AiOrderBridge

kke::AiOrderBridge (kke/OrderBridge.h) joins the two halves: every new board order becomes an ai::Order for that agent in the AiWorld, and the AI's Arrived events become done.

Board order AI order Done when
move, regroup MoveTo its formation slot (runs when far) it arrives (then it holds there)
follow Follow at followDistance never: it stands until replaced
stay Hold the spot (or where it stands) never
sit Hold where it is; the game shows it sitting never
attack, focus Attack the target the game calls targetGone
fetch Interact the thing, then Interact the issuer the deliver hook ran
pet Interact the issuer the game says the pat is over
drop (the drop hook) at once
free clearOrder: back to its own wants at once

The game supplies only what it alone can do: pickUp (take the thing into a mouth or a hand; false fails the fetch), deliver, drop and petStart. Units that aren't agents are left alone, so a scripted unit can still answer with order.done. Call bridge.handle(world.takeEvents()) after AiWorld::update every frame.

order.* (this page) is what the player tells a unit; ai.* (docs/AI.md) is the brain underneath. Use order.* for anything the player could have said, so the HUD, the events and the bridge all see it.

Reading the player (companions)

A good companion acts before it is told. IntentReader watches the player's own movement and view and reports what they seem to be doing: standing a while (idle), walking, running (with where they will be in a moment), looking at something for a moment (looking), or walking up to something (approaching, e.g. the pet itself: it wants petting). The brain decides what to do with it.

In the pet demo, with no order standing, what the player seems to be doing becomes a soft AI order (never a board order): walking or running, it follows; looking at something, it goes to have a look; walking up to the dog, it holds still for a pat; standing about, it clears the order and the dog lives its own life (sniffing, resting, watching you).

followSlot says where a follower should be so it never blocks the player: to one side and a little behind, on the side it is already on (so it never crosses in front), further aside the faster the player goes. inLeadersWay says whether a spot is on the player's path.

One set of blocks, three levels

Orders are play blocks (docs/PLAY_TO_MAKE.md):

  • Simple: the picture buttons (Come, Sit, Stay, Fetch, Go, Attack) and tapping in the world.
  • Nodes: every order is a node in the Orders section ("Send to", "Follow", "Focus fire", ...), plus the events When given an order and When an order is done. Left unconnected, "Who" is whoever is selected, or the thing itself in a thing's own graph.
  • Lua:
order.move({ a, b, c }, Vec(10, 0, -4), "line")
order.focus(order.selected(), tank)
order.fetch(dog, ball)
hook.Add("OrderDone", "cheer", function(e)
    if e.order == "fetch" and e.ok then play.say("Good dog!") end
end)

Events queue while a frame runs and fire once a frame (OrderScript::fireEvents), so an order given from a hook never re-enters the script that gave it.