1
0
forked from 0ad/0ad
0ad/binaries/data/mods/public/simulation/ai/qbot/qbot.js
2012-04-22 13:04:31 +00:00

181 lines
4.8 KiB
JavaScript

function QBotAI(settings) {
BaseAI.call(this, settings);
this.turn = 0;
this.modules = {
"economy": new EconomyManager(),
"military": new MilitaryAttackManager(),
"housing": new HousingManager()
};
// this.queues cannot be modified past initialisation or queue-manager will break
this.queues = {
house : new Queue(),
citizenSoldier : new Queue(),
villager : new Queue(),
economicBuilding : new Queue(),
field : new Queue(),
advancedSoldier : new Queue(),
siege : new Queue(),
militaryBuilding : new Queue(),
defenceBuilding : new Queue(),
civilCentre: new Queue()
};
this.productionQueues = [];
this.priorities = Config.priorities;
this.queueManager = new QueueManager(this.queues, this.priorities);
this.firstTime = true;
this.savedEvents = [];
}
QBotAI.prototype = new BaseAI();
//Some modules need the gameState to fully initialise
QBotAI.prototype.runInit = function(gameState){
if (this.firstTime){
for (var i in this.modules){
if (this.modules[i].init){
this.modules[i].init(gameState);
}
}
this.timer = new Timer();
this.firstTime = false;
var myKeyEntities = gameState.getOwnEntities().filter(function(ent) {
return ent.hasClass("CivCentre");
});
if (myKeyEntities.length == 0){
myKeyEntities = gameState.getOwnEntities();
}
var filter = Filters.byClass("CivCentre");
var enemyKeyEntities = gameState.getEnemyEntities().filter(filter);
if (enemyKeyEntities.length == 0){
enemyKeyEntities = gameState.getEnemyEntities();
}
this.accessibility = new Accessibility(gameState, myKeyEntities.toEntityArray()[0].position());
if (enemyKeyEntities.length == 0)
return;
var pathFinder = new PathFinder(gameState);
this.pathsToMe = pathFinder.getPaths(enemyKeyEntities.toEntityArray()[0].position(), myKeyEntities.toEntityArray()[0].position(), 'entryPoints');
}
};
QBotAI.prototype.OnUpdate = function() {
if (this.gameFinished){
return;
}
if (this.events.length > 0){
this.savedEvents = this.savedEvents.concat(this.events);
}
// Run the update every n turns, offset depending on player ID to balance
// the load
if ((this.turn + this.player) % 10 == 0) {
Engine.ProfileStart("qBot");
var gameState = new GameState(this);
if (gameState.getOwnEntities().length === 0){
Engine.ProfileStop();
return; // With no entities to control the AI cannot do anything
}
this.runInit(gameState);
for (var i in this.modules){
this.modules[i].update(gameState, this.queues, this.savedEvents);
}
this.updateDynamicPriorities(gameState, this.queues);
this.queueManager.update(gameState);
// Generate some entropy in the random numbers (against humans) until the engine gets random initialised numbers
// TODO: remove this when the engine gives a random seed
var n = this.savedEvents.length % 29;
for (var i = 0; i < n; i++){
Math.random();
}
delete this.savedEvents;
this.savedEvents = [];
Engine.ProfileStop();
}
this.turn++;
};
QBotAI.prototype.updateDynamicPriorities = function(gameState, queues){
// Dynamically change priorities
Engine.ProfileStart("Change Priorities");
var females = gameState.countEntitiesByType(gameState.applyCiv("units/{civ}_support_female_citizen"));
var femalesTarget = this.modules["economy"].targetNumWorkers;
var enemyStrength = this.modules["military"].measureEnemyStrength(gameState);
var availableStrength = this.modules["military"].measureAvailableStrength();
var additionalPriority = (enemyStrength - availableStrength) * 5;
additionalPriority = Math.min(Math.max(additionalPriority, -50), 220);
var advancedProportion = (availableStrength / 40) * (females/femalesTarget);
advancedProportion = Math.min(advancedProportion, 0.7);
this.priorities.citizenSoldier = (1-advancedProportion) * (150 + additionalPriority) + 1;
this.priorities.advancedSoldier = advancedProportion * (150 + additionalPriority) + 1;
if (females/femalesTarget > 0.7){
this.priorities.defenceBuilding = 70;
}
Engine.ProfileStop();
};
// TODO: Remove override when the whole AI state is serialised
QBotAI.prototype.Deserialize = function(data)
{
BaseAI.prototype.Deserialize.call(this, data);
};
// Override the default serializer
QBotAI.prototype.Serialize = function()
{
var ret = BaseAI.prototype.Serialize.call(this);
ret._entityMetadata = {};
return ret;
};
function debug(output){
if (Config.debug){
if (typeof output === "string"){
warn(output);
}else{
warn(uneval(output));
}
}
}
function copyPrototype(descendant, parent) {
var sConstructor = parent.toString();
var aMatch = sConstructor.match( /\s*function (.*)\(/ );
if ( aMatch != null ) { descendant.prototype[aMatch[1]] = parent; }
for (var m in parent.prototype) {
descendant.prototype[m] = parent.prototype[m];
}
}