Practical BAR modding: build commands, CommandAI behavior, and unit detection ranges

How to issue build orders through Spring API commands, where to find engine-level documentation for unit behavior, and using unit detection ranges in custom scripts.

lua · unitdefs · modding · beyond all reason · raptors

Build commands use negative unitdef IDs

Modders trying to make a constructor build a specific unit run into a common roadblock. CMD.BUILD does not exist as a named command the way CMD.MOVE does. Build commands carry the negative ID of the target unitdef.

The working pattern is to pass the negative of UnitDefNames.targetunit.id as the command ID to Spring.GiveOrderToUnit. This tells the constructor what to build, and the position parameters tell it where. CreateUnit remains available for game logic scripts such as raptor wave spawns, but it is not the right tool for issuing build orders to constructors.

Any mod that wants a builder to construct something programmatically must use this negative-ID pattern rather than searching for a named build constant.

Unit command behavior lives in the engine source

Players who want to understand exactly what happens during commands like attack-move find the answer in the spring engine C++ source. The CommandAI directory under the engine's unit simulation code defines how each command type resolves.

Attack-move behavior, for example, is not documented cleanly in a single Lua reference page. The engine implements pathfinding, target acquisition, and movement rules in C++. Modders who need to predict or modify unit behavior under attack-move should read the relevant CommandAI class rather than guessing from observed gameplay.

This applies to any command type. Move, patrol, fight, reclaim, and repair all have engine-level implementations that may differ from what widget-level documentation suggests.

Using GetUnitNearestEnemy with custom ranges

The Lua function Spring.GetUnitNearestEnemy(unitID, range) returns the closest enemy unit within the specified range, or nil if nothing is nearby. This is useful for proximity-triggered effects like detonation mines.

A common pattern is to store the trigger range in a unit's customparams, read it at runtime with UnitDefs[unitDefID].customParams.detonaterange, and pass it as the range argument. The function behaves correctly as long as the range value is a valid number. Units outside the range return nil without error.

Modders building custom proximity weapons should test the range parameter carefully. The function measures from the unit position, not from the weapon projectile position, which matters for tall or airborne units.

Closing thoughts

BAR modding means working with the spring engine directly when the Lua docs fall short. Build commands need negative unitdef IDs. Command behavior traces to C++ source. Proximity detection uses GetUnitNearestEnemy with customparam-defined ranges. Read the source, test in skirmish, and share what works.

"Gaming actually fulfills a human purpose here - cooperation, mutual upbuilding, fun and striving for greatness together. Instead of random anonymity, you meet, learn from, and enjoy real people."

Creed of Champions member