AI scripts receive data from the engine about the current simulation state, once per simulation turn. This is a fairly low-level mechanism - it is expected that AI scripts will use a wrapper to provide more convenient access to the data. Currently this wrapper is implemented in `common-ai/base.js`. > Note by lexa: here isĀ [http://code.google.com/p/split-bot/source/browse/#svn%2Ftrunk%2Fsrc%2Forg%2Fzeroad%2Fcommon_api a fully typed description of the javascript classes] The Engine uses the AIInterface and AIProxy components to provide this data. The AIInterface is a player level component which handles communication with the AI. AIProxy is an entity level component which creates a proxy representation of each entity to be given to the AI. The AI's `HandleMessage` method is called with one argument: {{{#!js state = { entities: ..., events: ..., players: [...], timeElapsed: ..., // seconds since the start of the match territoryMap: ..., // map of player territories passabilityMap: ..., // Map showing where obstructions are passabilityClasses: ... }}} == `entities` == Each entity has a set of dynamic properties which are kept up to date. The AI can also access the template data for all entities. An entity will have the form {{{#!js var ret = { "id": 172, // This id is unique and permanent "template": "unit/hele_spearman", "position": [102.2, 34.7], // The unit position is undefined in some cases (e.g. garrisoned) "hitpoints": 80, "owner": 4, // Player who owns this unit "idle": true, "unitAIState": "UNIT/INDIVIDUAL/GATHERING", "unitAIOrderData": cmpUnitAI.GetOrderData(), "trainingQueue": [{ "id": 7, "unitTemplate": "spearman", // If this is a unit being trained "technologyTemplate": "phase_city", // If this is a technology being researched "count": 5, // number of units being trained "progress": 0.78, // Proportion of training completed (range 0.0 to 1.0) "metadata": {"role": "worker"}, // The AI can set metadata when adding a unit to the queue }, ... ], // Array of items currently in the training queue "foundationProgress": 78, // Percentage complete for construction "resourceSupplyAmount": 195, // Current resources in a resource deposit (tree, mine, ...) "resourceCarrying": [{ "type": "wood", // Resource type "amount": 8, // Amount currently being carried "max": 20 // Maximum amout of this resource which can be carried }, ... ], // array of resources being carried by a gathering unit "garrisoned": [167, 377, 345] // array of entity id's for the garrisoned entities } }}} == `events` == TODO == `passabilityMap` and `passabilityClasses` == {{{#!js state.passabilityMap = { width: 256, height: 256, data: [ ... ] // Uint16Array with width*height entries }; }}} {{{#!js state.passabilityClasses = { "pathfinderObstruction": 1, "foundationObstruction": 2, "building-land": ..., // these are all the PassabilityClasses defined in simulation/data/pathfinder.xml ... }; }}} `state.passabilityMap.data` encodes all the passability data of each terrain tile. `state.passabilityClasses` gives bitmasks that define how to interpret `state.map.data`. For example: {{{#!js // Get the bitmask for tiles that will obstruct foundations (i.e. you can't place any buildings there) var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction"); for (var i = 0; i < map.data.length; ++i) if (map.data[i] & obstructionMask) ; // tile i is an unbuildable location }}} Since these are bitmasks, you can 'or' them together: {{{#!js var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction"); // Add in the bitmask for tiles that are obstructed for the "building-land" passability class // (i.e. tiles that are underwater or too steep, based on the definition in pathfinder.xml) obstructionMask |= gameState.getPassabilityClassMask("building-land"); for (var i = 0; i < map.data.length; ++i) if (map.data[i] & obstructionMask) ; // tile i is an unbuildable location for land-based buildings }}}