Skip to content

BT Boss Demo

App: apps/bt_boss_demo/

The payoff for behaviour-tree authoring (engine PLM-219, ADR 0068): three enemies that share one .bt.toml schema, loader and editor, differing only in their data.

EnemyTreeShape
Grunt (regular)trees/enemy.bt.tomlone root selector — chase if near, else patrol; no phases
Mini-bosstrees/miniboss.bt.tomla phase_switch with 2 cases (opener → enraged)
Bosstrees/boss.bt.tomlthe same phase_switch with 4 cases (opener → aggressive → desperate → last stand)

That is the whole thesis of the block: authoring a harder fight is more data, not more machinery.

The engine never reads an HP field. Each frame the demo’s Wren owns and drains _hp, feeds health01 to PhaseEvaluator.evaluate (forward-only — a heal never drops a phase), and writes the returned phase to the tree’s blackboard int the phase_switch node reads. A phase change fires a game-side entry hook (the HUD banner). The HUD shows, per enemy: an HP bar, the current phase, the current action (read from the ticking tree’s blackboard), and a flash banner the instant a new phase begins.

Because the two bosses drain at the same rate but carry different thresholds, at (say) 68 % HP the boss has already crossed into phase 1 (its threshold is 75 %) and switched its subtree, while the mini-boss is still in phase 0 (its threshold is 50 %) — same HP, different phase, purely because the data differs.

Terminal window
% ./plume3d bt_boss_demo
Terminal window
% ./plume3d --test apps/bt_boss_demo

Loads all three trees under the same loader and walks the boss phase machine 0 → 3 forward-only. The tick-time subtree swap is covered by tests/unit/test_bt_load_wren.cpp.