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.

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.

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.

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.