I know I'm coming to this discussion late, and that it's already been taken over by a 5 page rant on the merits of disclosure but since I intend to begin work on a Spring AI later this year I would like to see a useable API in place so I can work mostly in Lua.
I am currently working on an AI framework for Supreme Commander. SupCom exposes a lot of the engine to Lua so it serves as a good example (though it is far from perfect):
SupCom Lua Docs
Unfortunately it is only useful as an overview because it is almost entirely undocumented. Most of my work has been through guessing and trial-and-error.
I realise a lot of the Spring AI code is currently in C++ however I would like to see these functions included as a Lua interface as well. It should work something like this:
event -> C_Callback -> Lua_Callback.
Both the C++ and Lua interfaces should be passed the same data (or nearest approximation). Most of the time this will be at minimum a pointer to a unit. I also recommend the callbacks be implemented, where possible, as methods to avoid name conflicts between, unit, squad and army functions.
Anyway here are my recommendations. I've stuck to common functions that require the speed of C++. More complex functions can be implemented by the AI author in C++ or Lua as needed. My apologises if some/most of these have been suggested or implemented already:
UNIT CALLBACKS
Unit callbacks can be used for unit or squad AIs. They should account for the possibility that the events may be triggered by a player or AI sharing control of the army (support AI). In other words don't assume the AI will know why the event happened (particularly with OnCommand). In the case of events under AI control (like issuing orders) the AI must be able to abort the event by returning false from the handler. In some cases (like OnHit) the army may not have seen the attacker on radar. In this case the unit passed as 'attacker' should be a special value to indicate 'unknown'.
OnCreate(unit) -- Unit built or spawned
OnActivate(unit) -- Unit switched on
OnDeactivate(unit) -- Unit switched off
OnCaptured(unit) -- Unit captured from enemy
OnKilled(unit, killer)
OnHit(unit, attacker) -- attacker may be unknown
OnFire(unit, target) -- target may be ground
OnMove(unit) -- not just move order but any reason (like getting out the way)
OnBuild(unit, unitBeingBuilt) -- For shift/alt build call once per structure
OnBuildComplete(unit, unitBeingBuilt)
OnBuildCancelled(unit, unitBeingBuilt)
OnOrder(unit, order, args...)
OnOrderComplete(unit, order_id)
OnOrderCancelled(unit, order_id)
OnIdle(unit) -- Idle means orders queue finished
OnGrouped(unit,group_id)
OnUngrouped(unit,group_id)
OnLoad(unit, transport)
OnUnload(unit, transport)
ARMY CALLBACKS
OnFrame() -- called when game state changes
OnStartGame()
OnEndGame()
OnEnemySighted(enemy)
OnEnemyDetectedByRadar(blip)
OnAllianceChanged(army1, army2, old, new) -- when diplomacy happens
OnArmyKilled(army)
OnIntelUpdate() -- every time radar/jamming is calculated
INTEL FUNCTIONS
Functions to query intel data from the engine. Intel 'maps' should be defined as a grid of 100m2 rectangles (cells). The functions below should combine in many ways to form precise queries like ('find the combined threat level of all anti-air units or structures in the top right corner of the map owned by enemy armies') or ('find all enemies along this route')
GetThreatMap(type) -- Array containing each map grid square with a relative threat level. Type should be something like 'air', 'surface' or 'sub' to indicate what units are being threatened.
GetResourceMap(type) -- Array containing the desirability of a location for a given resource type (metal or energy or mod-defined type)
FilterMapByThreat(map, level, comparison) -- Filter a threat or resource map by threat level, ie. only return cells matching the query
FilterMapByTerrainType(map, type)
FilterMapByRect(map, rect) -- return cells inside or touching rect
FilterMapByCircle(map, pos, radius) -- return cells inside or touching circle
FilterMapByLine(map, pos1, pos2) -- only return cells that line passes through
FilterMapByPoint(pos) -- given a standard position vector return the cell surrounding it.
SortUnitsByThreat(map, dir) -- where direction is 'ASC' or 'DESC'
SortMapByThreat(map, dir) -- Reorder map cells based on threat instead of grid position
UNIT SELECTION
The AI will need to find or group units according to a range of properties. SupCom enumerates these properties in the unit definition and then allows
them to be combined into queries eg. TECH2 + LAND - ANTIAIR gives you all tier 2 tanks except anti-air.
GetUnitsByType(type) -- All units matching category or class id.
GetUnitsInRect(type, rect) -- List of units in a rectangle
GetUnitsInCircle(type, pos, radius) -- List of units in a circle
GetNearestUnit(unit_list) -- Get closest unit based on category or class id.
FilterUnitsByType(unit_list, type) -- Return units of 'type' only. Types should be 'land','water','air' or a more complex enumeration such as 'structure|missile|water' (a floating missile launcher).
FilterUnitsByAllegiance(unit_list, alliegance) -- Return only 'allied' or 'enemy' or 'own' units
FilterUnitsByThreat(unit_list, level, comparison) -- Return units related to the threat level by comparison where comparison is a string operator like '=', '>', etc..
PATHING
Path calculations are always slow. The AI should always leave it to the engine.
CanMoveTo(unit, pos, terrain_only) -- true if unit can reach destination (optionally ignoring barriers and structures)
GetRouteTo(unit, pos, terrain_only) -- Return a set of lines indicating best guess at unit route to reach pos.
GetETA(unit, pos) -- best guess at time to arrive at pos (assuming uninterrupted move)
GetTerrainType(pos) -- given a location return 'land' or 'water'
GetTerrainHeight(pos)
GetNearestTerrainByType(type) -- given 'land' or 'water' get the closest point. Useful for transports or starting naval construction.