1
0
forked from 0ad/0ad
0ad/binaries/data/mods/public/simulation/ai/qbot/gamestate.js

320 lines
8.4 KiB
JavaScript
Raw Normal View History

2011-12-02 13:44:31 +01:00
/**
* Provides an API for the rest of the AI scripts to query the world state at a
* higher level than the raw data.
*/
var GameState = function(ai) {
MemoizeInit(this);
this.ai = ai;
this.timeElapsed = ai.timeElapsed;
this.templates = ai.templates;
this.entities = ai.entities;
this.player = ai.player;
this.playerData = ai.playerData;
this.buildingsBuilt = 0;
if (!this.ai._gameStateStore){
this.ai._gameStateStore = {};
}
this.store = this.ai._gameStateStore;
2011-12-02 13:44:31 +01:00
this.cellSize = 4; // Size of each map tile
this.turnCache = {};
};
GameState.prototype.updatingCollection = function(id, filter, collection){
if (!this.store[id]){
this.store[id] = collection.filter(filter);
this.store[id].registerUpdates();
}
return this.store[id];
2011-12-02 13:44:31 +01:00
};
GameState.prototype.getTimeElapsed = function() {
return this.timeElapsed;
};
GameState.prototype.getTemplate = function(type) {
if (!this.templates[type]){
2011-12-02 13:44:31 +01:00
return null;
}
2011-12-02 13:44:31 +01:00
return new EntityTemplate(this.templates[type]);
};
GameState.prototype.applyCiv = function(str) {
return str.replace(/\{civ\}/g, this.playerData.civ);
};
/**
* @returns {Resources}
*/
GameState.prototype.getResources = function() {
return new Resources(this.playerData.resourceCounts);
};
GameState.prototype.getMap = function() {
return this.ai.passabilityMap;
};
GameState.prototype.getTerritoryMap = function() {
return this.ai.territoryMap;
};
GameState.prototype.getPopulation = function() {
return this.playerData.popCount;
};
GameState.prototype.getPopulationLimit = function() {
return this.playerData.popLimit;
};
GameState.prototype.getPopulationMax = function() {
return this.playerData.popMax;
};
GameState.prototype.getPassabilityClassMask = function(name) {
if (!(name in this.ai.passabilityClasses)){
2011-12-02 13:44:31 +01:00
error("Tried to use invalid passability class name '" + name + "'");
}
2011-12-02 13:44:31 +01:00
return this.ai.passabilityClasses[name];
};
GameState.prototype.getPlayerID = function() {
return this.player;
};
GameState.prototype.isPlayerAlly = function(id) {
return this.playerData.isAlly[id];
};
GameState.prototype.isPlayerEnemy = function(id) {
return this.playerData.isEnemy[id];
};
GameState.prototype.getEnemies = function(){
var ret = [];
for (var i in this.playerData.isEnemy){
if (this.playerData.isEnemy[i]){
ret.push(i);
}
}
return ret;
};
2011-12-02 13:44:31 +01:00
GameState.prototype.isEntityAlly = function(ent) {
if (ent && ent.owner && (typeof ent.owner) === "function"){
return this.playerData.isAlly[ent.owner()];
} else if (ent && ent.owner){
return this.playerData.isAlly[ent.owner];
}
return false;
};
GameState.prototype.isEntityEnemy = function(ent) {
if (ent && ent.owner && (typeof ent.owner) === "function"){
return this.playerData.isEnemy[ent.owner()];
} else if (ent && ent.owner){
return this.playerData.isEnemy[ent.owner];
}
return false;
};
GameState.prototype.isEntityOwn = function(ent) {
if (ent && ent.owner && (typeof ent.owner) === "function"){
return ent.owner() == this.player;
} else if (ent && ent.owner){
return ent.owner == this.player;
}
return false;
};
GameState.prototype.getOwnEntities = function() {
if (!this.store.ownEntities){
this.store.ownEntities = this.getEntities().filter(Filters.byOwner(this.player));
this.store.ownEntities.registerUpdates();
}
return this.store.ownEntities;
};
GameState.prototype.getEnemyEntities = function() {
var diplomacyChange = false;
var enemies = this.getEnemies();
if (this.store.enemies){
if (this.store.enemies.length != enemies.length){
diplomacyChange = true;
}else{
for (var i = 0; i < enemies.length; i++){
if (enemies[i] !== this.store.enemies[i]){
diplomacyChange = true;
}
}
}
}
if (diplomacyChange || !this.store.enemyEntities){
var filter = Filters.byOwners(enemies);
this.store.enemyEntities = this.getEntities().filter(filter);
this.store.enemyEntities.registerUpdates();
this.store.enemies = enemies;
}
return this.store.enemyEntities;
2011-12-02 13:44:31 +01:00
};
GameState.prototype.getEntities = function() {
return this.entities;
};
GameState.prototype.getEntityById = function(id){
if (this.entities._entities[id]) {
return this.entities._entities[id];
2011-12-02 13:44:31 +01:00
}else{
//debug("Entity " + id + " requested does not exist");
2011-12-02 13:44:31 +01:00
}
return undefined;
2011-12-02 13:44:31 +01:00
};
GameState.prototype.getOwnEntitiesByMetadata = function(key, value){
if (!this.store[key + "-" + value]){
var filter = Filters.byMetadata(key, value);
this.store[key + "-" + value] = this.getOwnEntities().filter(filter);
this.store[key + "-" + value].registerUpdates();
}
return this.store[key + "-" + value];
};
2011-12-02 13:44:31 +01:00
GameState.prototype.getOwnEntitiesByRole = function(role){
return this.getOwnEntitiesByMetadata("role", role);
2011-12-02 13:44:31 +01:00
};
// TODO: fix this so it picks up not in use training stuff
GameState.prototype.getOwnTrainingFacilities = function(){
return this.updatingCollection("own-training-facilities", Filters.byTrainingQueue(), this.getOwnEntities());
};
2011-12-02 13:44:31 +01:00
GameState.prototype.getOwnEntitiesByType = function(type){
var filter = Filters.byType(type);
return this.updatingCollection("own-by-type-" + type, filter, this.getOwnEntities());
};
2011-12-02 13:44:31 +01:00
GameState.prototype.countEntitiesByType = function(type) {
return this.getOwnEntitiesByType(type).length;
};
GameState.prototype.countEntitiesAndQueuedByType = function(type) {
var count = this.countEntitiesByType(type);
// Count building foundations
count += this.countEntitiesByType("foundation|" + type);
// Count entities in building production queues
this.getOwnTrainingFacilities().forEach(function(ent){
ent.trainingQueue().forEach(function(item) {
if (item.template == type){
count += item.count;
}
});
2011-12-02 13:44:31 +01:00
});
2011-12-02 13:44:31 +01:00
return count;
};
GameState.prototype.countFoundationsWithType = function(type) {
var foundationType = "foundation|" + type;
var count = 0;
this.getOwnEntities().forEach(function(ent) {
var t = ent.templateName();
if (t == foundationType)
++count;
});
return count;
};
GameState.prototype.countOwnEntitiesByRole = function(role) {
return this.getOwnEntitiesByRole(role).length;
};
2011-12-02 13:44:31 +01:00
GameState.prototype.countOwnEntitiesAndQueuedWithRole = function(role) {
var count = this.countOwnEntitiesByRole(role);
// Count entities in building production queues
this.getOwnTrainingFacilities().forEach(function(ent) {
ent.trainingQueue().forEach(function(item) {
if (item.metadata && item.metadata.role == role)
count += item.count;
});
2011-12-02 13:44:31 +01:00
});
return count;
};
/**
* Find buildings that are capable of training the given unit type, and aren't
* already too busy.
*/
GameState.prototype.findTrainers = function(template) {
var maxQueueLength = 2; // avoid tying up resources in giant training queues
return this.getOwnTrainingFacilities().filter(function(ent) {
2011-12-02 13:44:31 +01:00
var trainable = ent.trainableEntities();
if (!trainable || trainable.indexOf(template) == -1)
return false;
var queue = ent.trainingQueue();
if (queue) {
if (queue.length >= maxQueueLength)
return false;
}
return true;
});
};
/**
* Find units that are capable of constructing the given building type.
*/
GameState.prototype.findBuilders = function(template) {
return this.getOwnEntities().filter(function(ent) {
var buildable = ent.buildableEntities();
if (!buildable || buildable.indexOf(template) == -1)
return false;
return true;
});
};
GameState.prototype.getOwnFoundations = function() {
return this.updatingCollection("ownFoundations", Filters.isFoundation(), this.getOwnEntities());
2011-12-02 13:44:31 +01:00
};
GameState.prototype.getOwnDropsites = function(resource){
return this.updatingCollection("dropsite-own-" + resource, Filters.isDropsite(resource), this.getOwnEntities());
2011-12-02 13:44:31 +01:00
};
GameState.prototype.getResourceSupplies = function(resource){
return this.updatingCollection("resource-" + resource, Filters.byResource(resource), this.getEntities());
};
2011-12-02 13:44:31 +01:00
GameState.prototype.getBuildLimits = function() {
return this.playerData.buildLimits;
};
GameState.prototype.getBuildCounts = function() {
return this.playerData.buildCounts;
};
// Checks whether the maximum number of buildings have been cnstructed for a certain catergory
2011-12-02 13:44:31 +01:00
GameState.prototype.isBuildLimitReached = function(category) {
if(this.playerData.buildLimits[category] === undefined || this.playerData.buildCounts[category] === undefined)
return false;
if(this.playerData.buildLimits[category].LimitsPerCivCentre != undefined)
return (this.playerData.buildCounts[category] >= this.playerData.buildCounts["CivilCentre"]*this.playerData.buildLimits[category].LimitPerCivCentre);
else
return (this.playerData.buildCounts[category] >= this.playerData.buildLimits[category]);
};