/**
* @fileOverview Provides a skeleton implementation of an AI player.
*/
/**
* @summary Numeric id of the player currently evaluated by the game
* engine.
* @type Number
*/
var PlayerID = -1;
/**
* @summary Enables output of debug information by a bot.
* @type Boolean
* @see API3.debug
*/
API3.DebugEnabled = false;
/**
* @class
* @summary Base class for computer players.
* @description In 0AD, each computer player ("bot") is implemented as
* a set of JavaScript files, located within a separate
* directory below
* <code>/binaries/data/mods/public/simulation/ai</code>.
* A file named <code>data.json</code> controls loading
* the AI script code:
*
* <pre>
*{
* "name": "Tutorial AI",
* "description": "The Tutorial AI should only be used on the \"Introductory Tutorial\" scenario.",
* "constructor": "TutorialAI",
* "moduleName" : "TutorialAI",
* "hidden": true,
* "useShared": true
* }
* </pre>
* In this file, the <code>"moduleName"</code> has to refer
* to a JavaScript namespace which holds an object
* constructor as named in the <code>"constructor"</code>
* property of the JSON file.This object is constructed
* when the AI enters a game. Usually, this constructor
* is a derivative of the <code>BaseAI</code> class (it
* is possible to operate without the BaseAI, but
* cumbersome as the engine data decoding had to be done
* by the implementor).
*
* The <code>BaseAI</code> class does not perform any
* action on its own during a game, but provides the
* infrastructure to communicate with the Pyrogenesis
* engine in a more friendly way.
* @param settings {Object} The game settings as passed by the
* GameSetup code.
*/
API3.BaseAI = function(settings) {
if (!settings)
return;
/**
* @summary Numeric player index of this AI instance.
* @type Number
*/
this.player = settings.player;
/**
* @summary Turn counter.
* @description For AIs, it is advisable to not run through all of
* its computations at each game turn to limit CPU
* usage. A common method is to run the AI only at
* each <em>n</em>-th turn, where <em>n</em> is the
* number of players in the game. To distribute CPU
* load evenly, usually player 1 will operate when
* the turn counter is 1 (modulo number of players),
* player 2 when turn counter is 2 (modulo...), and so
* on.
* @type Number
*/
this.turn = 0;
};
/**
* @summary Converts the AI runtime data into a simple structure.
* @description For saving and restoring of games, the whole game
* state is <em>serialized</em>, i.e. stored in a
* permanent format. To allow continuation of the AI
* after a save/restore cycle, an AI player has to
* return an object here which allows to restore it to
* it's exact same state using the
* [Deserialize]{@link API3.BaseAI.Deserialize} function.
*
* This function shall be overridden by derived classes.
* @return {Object} An arbitrary but simple object (JSON-compatible)
* which describes the current internal state of the
* AI. As this object has to be stored in a file, no
* complex elements (like classes, functions or
* closures) shall be used.
*/
API3.BaseAI.prototype.Serialize = function()
{
// TODO: ought to get the AI script subclass to serialize its own state
// TODO: actually this is part of a larger reflection on wether AIs should or not.
return {};
};
/**
* @summary Restores the AI to a previous state.
* @description This function shall be overridden by derived classes
* to allow saving and loading of games. See the
* description of
* [Serialize]{@link API3.BaseAI.Serialize} on how to use
* these functions.
*
* The function will be called right after the object
* constructor when a game is loaded.
* @param data {Object} An object returned by a previous serialization
* of the AI.
* @param sharedScript {API3.SharedScript} The new shared component to
* use.
* @return undefined
*/
API3.BaseAI.prototype.Deserialize = function(data, sharedScript)
{
// TODO: ought to get the AI script subclass to deserialize its own state
// TODO: actually this is part of a larger reflection on wether AIs should or not.
this.isDeserialized = true;
};
/**
* @summary Initializes the AI.
* @description When the AI object is constructed, some components of
* the game, such as the maps, are not yet available.
* Therefore, a second initialization step is provided
* where all of this informations can be used. Derived
* classes should use the
* [CustomInit]{@link API3.BaseAI.CustomInit} function
* instead to do their own initialization.
* @return undefined
* @private
*/
API3.BaseAI.prototype.Init = function(state, playerID, sharedAI)
{
PlayerID = playerID;
// define some references
this.entities = sharedAI.entities;
this.templates = sharedAI.templates;
this.passabilityClasses = sharedAI.passabilityClasses;
this.passabilityMap = sharedAI.passabilityMap;
this.territoryMap = sharedAI.territoryMap;
this.accessibility = sharedAI.accessibility;
this.terrainAnalyzer = sharedAI.terrainAnalyzer;
this.techModifications = sharedAI._techModifications[this.player];
this.playerData = sharedAI.playersData[this.player];
this.gameState = sharedAI.gameState[this.player];
this.gameState.ai = this;
this.sharedScript = sharedAI;
this.timeElapsed = sharedAI.timeElapsed;
this.circularMap = sharedAI.circularMap;
this.gameType = sharedAI.gameType;
this.barterPrices = sharedAI.barterPrices;
this.CustomInit(this.gameState, this.sharedScript);
};
/**
* @summary Allows for initialization of the AI.
* @description During the constructor run of an AI, dynamic game data
* such as the territory and passability maps are not yet
* available. When initializations require such values,
* they may be done during the CustomInit step.
* @return undefined
*/
API3.BaseAI.prototype.CustomInit = function() {
};
/**
* @summary Handles the game engine update messages.
* @description The game simulation is computed in "turns", where in
* each turn, the engine passes the differences to the
* previous turn to the AI players. At the very first
* turn, a complete description of the whole game is
* handed to the AIs.
* @param state {Object} The delta values of the current game state to
* the previous state.
* @param sharedAI {API3.SharedScript} The shared data container to be
* used by the AI.
* @todo Describe the intention of the playerID parameter.
*/
API3.BaseAI.prototype.HandleMessage = function(state, playerID, sharedAI)
{
PlayerID = playerID;
this.events = sharedAI.events;
this.passabilityMap = sharedAI.passabilityMap;
this.territoryMap = sharedAI.territoryMap;
if (this.isDeserialized)
{
this.Init(state, playerID, sharedAI);
this.isDeserialized = false;
}
this.OnUpdate(sharedAI);
};
/**
* @summary Hook for derived classes to perform periodic updates.
* @description This function is run once each game turn, after all of
* the delta values sent by the game engine have been
* applied to the representation seen by the AI (see
* [HandleMessage]{@link API3.BaseAI.HandleMessage} for a
* description on the update cycle).
*
* For simpler AIs, overriding this function is the
* preferred method of running periodic tasks. Advanced
* AIs might override <code>HandleMessage</code> to
* analyze the engine messages directly for performance
* optimizations.
* @return undefined
*/
API3.BaseAI.prototype.OnUpdate = function() {
};
/**
* @summary Sends a message to all players in the current game.
* @param message {String} The chat message to send.
* @return undefined
*/
API3.BaseAI.prototype.chat = function(message) {
Engine.PostCommand(PlayerID,{"type": "aichat", "message": message});
};
/**
* @summary Sends a message to all player allied with the current
* player.
* @param message {String} The chat message to send.
* @return undefined
*/
API3.BaseAI.prototype.chatTeam = function(message)
{
Engine.PostCommand(PlayerID,{"type": "aichat", "message": "/team " +message});
};
/**
* @summary Sends a message to all enemies of the current player.
* @param message {String} The chat message to send.
* @return undefined
*/
API3.BaseAI.prototype.chatEnemies = function(message)
{
Engine.PostCommand(PlayerID,{"type": "aichat", "message": "/enemy " +message});
};
// -------------------------------------------------------------------
// End of file
// -------------------------------------------------------------------