181 lines
4.8 KiB
JavaScript
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];
|
|
}
|
|
}
|