forked from 0ad/0ad
petra: better AI recovery after its economy is badly damaged + some fixes
This was SVN commit r15989.
This commit is contained in:
parent
3589aa39b9
commit
da1af993f7
@ -632,7 +632,9 @@ m.BaseManager.prototype.reassignIdleWorkers = function(gameState)
|
||||
|
||||
if (ent.hasClass("Worker"))
|
||||
{
|
||||
if (self.anchor && self.anchor.needsRepair() === true)
|
||||
// Just emergency repairing here. It is better managed in assignToFoundations
|
||||
if (self.anchor && self.anchor.needsRepair() === true
|
||||
&& gameState.getOwnEntitiesByMetadata("target-foundation", self.anchor.id()).length < 2)
|
||||
ent.repair(self.anchor);
|
||||
else
|
||||
{
|
||||
@ -732,7 +734,7 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
||||
}
|
||||
var workers = this.workers.filter(API3.Filters.not(API3.Filters.or(API3.Filters.byClass("Cavalry"), API3.Filters.byClass("Ship"))));
|
||||
var builderWorkers = this.workersBySubrole(gameState, "builder");
|
||||
var idleBuilderWorkers = this.workersBySubrole(gameState, "builder").filter(API3.Filters.isIdle());
|
||||
var idleBuilderWorkers = builderWorkers.filter(API3.Filters.isIdle());
|
||||
|
||||
// if we're constructing and we have the foundations to our base anchor, only try building that.
|
||||
if (this.constructing == true && this.buildings.filter(API3.Filters.and(API3.Filters.isFoundation(), API3.Filters.byMetadata(PlayerID, "baseAnchor", true))).length !== 0)
|
||||
@ -763,11 +765,8 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
||||
});
|
||||
}
|
||||
}
|
||||
var addedWorkers = 0;
|
||||
|
||||
var maxTotalBuilders = Math.ceil(workers.length * 0.2);
|
||||
if (this.constructing == true && maxTotalBuilders < 15)
|
||||
maxTotalBuilders = 15;
|
||||
|
||||
var builderTot = builderWorkers.length - idleBuilderWorkers.length;
|
||||
|
||||
for (var target of foundations)
|
||||
{
|
||||
@ -775,94 +774,36 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
||||
continue; // we do not build fields
|
||||
|
||||
if (gameState.ai.HQ.isDangerousLocation(target.position()))
|
||||
if (!target.hasClass("CivCentre") && !target.hasClass("StoneWall"))
|
||||
if (!target.hasClass("CivCentre") && !target.hasClass("StoneWall") && (!target.hasClass("Wonder") || gameState.getGameType() !== "wonder"))
|
||||
continue;
|
||||
|
||||
var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length;
|
||||
var targetNB = this.Config.Economy.targetNumBuilders; // TODO: dynamic that.
|
||||
var maxTotalBuilders = Math.ceil(workers.length * 0.2);
|
||||
var targetNB = 2;
|
||||
if (target.hasClass("House") || target.hasClass("Market"))
|
||||
targetNB *= 2;
|
||||
targetNB = 3;
|
||||
else if (target.hasClass("Barracks") || target.hasClass("Tower"))
|
||||
targetNB = 4;
|
||||
else if (target.hasClass("Fortress"))
|
||||
targetNB = 7;
|
||||
if (target.getMetadata(PlayerID, "baseAnchor") == true || (target.hasClass("Wonder") && gameState.getGameType() === "wonder"))
|
||||
{
|
||||
targetNB = 15;
|
||||
maxTotalBuilders = Math.max(maxTotalBuilders, 15);
|
||||
}
|
||||
|
||||
if (assigned < targetNB)
|
||||
{
|
||||
if (builderWorkers.length - idleBuilderWorkers.length + addedWorkers < maxTotalBuilders) {
|
||||
|
||||
var addedToThis = 0;
|
||||
|
||||
idleBuilderWorkers.forEach(function(ent) {
|
||||
if (ent.position() && API3.SquareVectorDistance(ent.position(), target.position()) < 10000 && assigned + addedToThis < targetNB)
|
||||
{
|
||||
addedWorkers++;
|
||||
addedToThis++;
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
}
|
||||
});
|
||||
if (assigned + addedToThis < targetNB)
|
||||
{
|
||||
var nonBuilderWorkers = workers.filter(function(ent) {
|
||||
if (ent.getMetadata(PlayerID, "subrole") === "builder")
|
||||
return false;
|
||||
if (!ent.position())
|
||||
return false;
|
||||
if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3)
|
||||
return false;
|
||||
if (ent.getMetadata(PlayerID, "transport"))
|
||||
return false;
|
||||
return true;
|
||||
}).toEntityArray();
|
||||
var time = target.buildTime();
|
||||
nonBuilderWorkers.sort(function (workerA,workerB)
|
||||
{
|
||||
var coeffA = API3.SquareVectorDistance(target.position(),workerA.position());
|
||||
// elephant moves slowly, so when far away they are only useful if build time is long
|
||||
if (workerA.hasClass("Elephant"))
|
||||
coeffA *= 0.5 * (1 + (Math.sqrt(coeffA)/150)*(30/time));
|
||||
else if (workerA.getMetadata(PlayerID, "gather-type") === "food")
|
||||
coeffA *= 3;
|
||||
var coeffB = API3.SquareVectorDistance(target.position(),workerB.position());
|
||||
if (workerB.hasClass("Elephant"))
|
||||
coeffB *= 0.5 * (1 + (Math.sqrt(coeffB)/150)*(30/time));
|
||||
else if (workerB.getMetadata(PlayerID, "gather-type") === "food")
|
||||
coeffB *= 3;
|
||||
return (coeffA - coeffB);
|
||||
});
|
||||
var current = 0;
|
||||
while (assigned + addedToThis < targetNB && current < nonBuilderWorkers.length)
|
||||
{
|
||||
addedWorkers++;
|
||||
addedToThis++;
|
||||
var ent = nonBuilderWorkers[current++];
|
||||
ent.stopMoving();
|
||||
ent.setMetadata(PlayerID, "subrole", "builder");
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// don't repair if we're still under attack, unless it's like a vital (civcentre or wall) building that's getting destroyed.
|
||||
for (var target of damagedBuildings)
|
||||
{
|
||||
if (gameState.ai.HQ.isDangerousLocation(target.position()))
|
||||
if (target.healthLevel() > 0.5 || (!target.hasClass("CivCentre") && !target.hasClass("StoneWall")))
|
||||
continue;
|
||||
else if (noRepair && !target.hasClass("CivCentre"))
|
||||
continue;
|
||||
|
||||
if (target.decaying())
|
||||
continue;
|
||||
|
||||
var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length;
|
||||
if (assigned < targetNB/3)
|
||||
{
|
||||
if (builderWorkers.length + addedWorkers < targetNB*2)
|
||||
idleBuilderWorkers.forEach(function(ent) {
|
||||
if (ent.getMetadata(PlayerID, "target-foundation") !== undefined)
|
||||
return;
|
||||
if (assigned >= targetNB || !ent.position() || API3.SquareVectorDistance(ent.position(), target.position()) > 40000)
|
||||
return;
|
||||
assigned++;
|
||||
builderTot++;
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
});
|
||||
if (assigned < targetNB && builderTot < maxTotalBuilders)
|
||||
{
|
||||
var nonBuilderWorkers = workers.filter(function(ent) {
|
||||
if (ent.getMetadata(PlayerID, "subrole") === "builder")
|
||||
@ -874,12 +815,99 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
||||
if (ent.getMetadata(PlayerID, "transport"))
|
||||
return false;
|
||||
return true;
|
||||
}).toEntityArray();
|
||||
var time = target.buildTime();
|
||||
nonBuilderWorkers.sort(function (workerA,workerB)
|
||||
{
|
||||
let coeffA = API3.SquareVectorDistance(target.position(),workerA.position());
|
||||
// elephant moves slowly, so when far away they are only useful if build time is long
|
||||
if (workerA.hasClass("Elephant"))
|
||||
coeffA *= 0.5 * (1 + (Math.sqrt(coeffA)/150)*(30/time));
|
||||
else if (workerA.getMetadata(PlayerID, "gather-type") === "food")
|
||||
coeffA *= 3;
|
||||
let coeffB = API3.SquareVectorDistance(target.position(),workerB.position());
|
||||
if (workerB.hasClass("Elephant"))
|
||||
coeffB *= 0.5 * (1 + (Math.sqrt(coeffB)/150)*(30/time));
|
||||
else if (workerB.getMetadata(PlayerID, "gather-type") === "food")
|
||||
coeffB *= 3;
|
||||
return (coeffA - coeffB);
|
||||
});
|
||||
var nearestNonBuilders = nonBuilderWorkers.filterNearest(target.position(), targetNB/3 - assigned);
|
||||
let current = 0;
|
||||
let nonBuilderTot = nonBuilderWorkers.length;
|
||||
while (assigned < targetNB && builderTot < maxTotalBuilders && current < nonBuilderTot)
|
||||
{
|
||||
assigned++;
|
||||
builderTot++;
|
||||
var ent = nonBuilderWorkers[current++];
|
||||
ent.stopMoving();
|
||||
ent.setMetadata(PlayerID, "subrole", "builder");
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var target of damagedBuildings)
|
||||
{
|
||||
// don't repair if we're still under attack, unless it's a vital (civcentre or wall) building that's getting destroyed.
|
||||
if (gameState.ai.HQ.isDangerousLocation(target.position()))
|
||||
if (target.healthLevel() > 0.5 ||
|
||||
(!target.hasClass("CivCentre") && !target.hasClass("StoneWall") && (!target.hasClass("Wonder") || gameState.getGameType() !== "wonder")))
|
||||
continue;
|
||||
else if (noRepair && !target.hasClass("CivCentre"))
|
||||
continue;
|
||||
|
||||
if (target.decaying())
|
||||
continue;
|
||||
|
||||
var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length;
|
||||
var maxTotalBuilders = Math.ceil(workers.length * 0.2);
|
||||
var targetNB = 1;
|
||||
if (target.hasClass("Fortress"))
|
||||
targetNB = 3;
|
||||
if (target.getMetadata(PlayerID, "baseAnchor") == true || (target.hasClass("Wonder") && gameState.getGameType() === "wonder"))
|
||||
{
|
||||
maxTotalBuilders = Math.ceil(workers.length * 0.3);
|
||||
targetNB = 5;
|
||||
if (target.healthLevel() < 0.3)
|
||||
{
|
||||
maxTotalBuilders = Math.ceil(workers.length * 0.6);
|
||||
targetNB = 7;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (assigned < targetNB)
|
||||
{
|
||||
idleBuilderWorkers.forEach(function(ent) {
|
||||
if (ent.getMetadata(PlayerID, "target-foundation") !== undefined)
|
||||
return;
|
||||
if (assigned >= targetNB || !ent.position() || API3.SquareVectorDistance(ent.position(), target.position()) > 40000)
|
||||
return;
|
||||
assigned++;
|
||||
builderTot++;
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
});
|
||||
if (assigned < targetNB && builderTot < maxTotalBuilders)
|
||||
{
|
||||
let nonBuilderWorkers = workers.filter(function(ent) {
|
||||
if (ent.getMetadata(PlayerID, "subrole") === "builder")
|
||||
return false;
|
||||
if (!ent.position())
|
||||
return false;
|
||||
if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3)
|
||||
return false;
|
||||
if (ent.getMetadata(PlayerID, "transport"))
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
let num = Math.min(nonBuilderWorkers.length, targetNB-assigned);
|
||||
let nearestNonBuilders = nonBuilderWorkers.filterNearest(target.position(), num);
|
||||
|
||||
nearestNonBuilders.forEach(function(ent) {
|
||||
assigned++;
|
||||
builderTot++;
|
||||
ent.stopMoving();
|
||||
addedWorkers++;
|
||||
ent.setMetadata(PlayerID, "subrole", "builder");
|
||||
ent.setMetadata(PlayerID, "target-foundation", target.id());
|
||||
});
|
||||
|
@ -25,7 +25,6 @@ m.Config = function(difficulty)
|
||||
"cityPhase" : 840, // time to start trying to reach city phase
|
||||
"popForMarket" : 50,
|
||||
"popForDock" : 25,
|
||||
"targetNumBuilders" : 1.5, // Base number of builders per foundation.
|
||||
"targetNumTraders" : 4, // Target number of traders
|
||||
"targetNumFishers" : 1, // Target number of fishers per sea
|
||||
"femaleRatio" : 0.5, // percent of females among the workforce.
|
||||
|
@ -18,8 +18,6 @@ m.HQ = function(Config)
|
||||
{
|
||||
this.Config = Config;
|
||||
|
||||
this.targetNumBuilders = this.Config.Economy.targetNumBuilders; // number of workers we want building stuff
|
||||
|
||||
this.econState = "growth"; // existing values: growth, townPhasing.
|
||||
this.phaseStarted = undefined;
|
||||
|
||||
@ -534,16 +532,25 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
});
|
||||
});
|
||||
|
||||
// Adapt the batch size of the first queued workers and females to the present population
|
||||
// Adapt the batch size of the first and second queued workers and females to the present population
|
||||
// to ease a possible recovery if our population was drastically reduced by an attack
|
||||
// (need to go up to second queued as it is accounted in queueManager)
|
||||
if (numWorkers < 12)
|
||||
var size = 1;
|
||||
else
|
||||
var size = Math.min(5, Math.ceil(numWorkers / 10));
|
||||
if (queues.villager.queue[0])
|
||||
{
|
||||
queues.villager.queue[0].number = Math.min(queues.villager.queue[0].number, size);
|
||||
if (queues.villager.queue[1])
|
||||
queues.villager.queue[1].number = Math.min(queues.villager.queue[1].number, size);
|
||||
}
|
||||
if (queues.citizenSoldier.queue[0])
|
||||
{
|
||||
queues.citizenSoldier.queue[0].number = Math.min(queues.citizenSoldier.queue[0].number, size);
|
||||
if (queues.citizenSoldier.queue[1])
|
||||
queues.citizenSoldier.queue[1].number = Math.min(queues.citizenSoldier.queue[1].number, size);
|
||||
}
|
||||
|
||||
var numQueuedF = queues.villager.countQueuedUnits();
|
||||
var numQueuedS = queues.citizenSoldier.countQueuedUnits();
|
||||
@ -1633,26 +1640,18 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
if (gameState.isDisabledTemplates(trainable))
|
||||
continue;
|
||||
var template = gameState.getTemplate(trainable);
|
||||
if (!template.hasClass("Infantry") || !template.hasClass("Ranged")
|
||||
|| !template.hasClass("CitizenSoldier"))
|
||||
if (!template.hasClass("Infantry") || !template.hasClass("CitizenSoldier"))
|
||||
continue;
|
||||
// Keep non-ranged units only as long as no ranged one found
|
||||
if (rangedUnit && !template.hasClass("Ranged"))
|
||||
continue;
|
||||
if (!total.canAfford(new API3.Resources(template.cost())))
|
||||
{
|
||||
if (rangedUnit)
|
||||
continue;
|
||||
// if we still have no ranged units, but can afford a melee unit, let's try it
|
||||
var template = gameState.getTemplate(trainable);
|
||||
if (!template.hasClass("Infantry") || !template.hasClass("Melee")
|
||||
|| !template.hasClass("CitizenSoldier"))
|
||||
continue;
|
||||
if (!total.canAfford(new API3.Resources(template.cost())))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
rangedUnit = true;
|
||||
continue;
|
||||
templateFound = [trainable, template];
|
||||
if (rangedUnit)
|
||||
break;
|
||||
if (!template.hasClass("Ranged"))
|
||||
continue;
|
||||
rangedUnit = true;
|
||||
break;
|
||||
}
|
||||
if (!templateFound)
|
||||
continue;
|
||||
@ -1698,8 +1697,8 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check first if we can afford it without touching other the accounts
|
||||
// and if not, take some of ther accounted resources
|
||||
// Check first if we can afford it without touching the other accounts
|
||||
// and if not, take some of other accounted resources
|
||||
// TODO sort the queues to be substracted
|
||||
var cost = new API3.Resources(templateAnchor[1].cost());
|
||||
if (!gameState.ai.queueManager.accounts["emergency"].canAfford(cost))
|
||||
@ -2000,7 +1999,6 @@ m.HQ.prototype.update = function(gameState, queues, events)
|
||||
m.HQ.prototype.Serialize = function()
|
||||
{
|
||||
let properties = {
|
||||
"targetNumBuilders": this.targetNumBuilders,
|
||||
"econState": this.econState,
|
||||
"phaseStarted": this.phaseStarted,
|
||||
"wantedRates": this.wantedRates,
|
||||
|
@ -423,6 +423,9 @@ m.QueueManager.prototype.update = function(gameState)
|
||||
this.priorities[i] = 1; // TODO: make the Queue Manager not die when priorities are zero.
|
||||
}
|
||||
|
||||
// Pause or unpause queues depending on the situation
|
||||
this.checkPausedQueues(gameState);
|
||||
|
||||
// Let's assign resources to plans that need them
|
||||
this.distributeResources(gameState);
|
||||
|
||||
@ -435,6 +438,85 @@ m.QueueManager.prototype.update = function(gameState)
|
||||
Engine.ProfileStop();
|
||||
};
|
||||
|
||||
// Recovery system: if short of workers after an attack, pause (and reset) some queues to favor worker training
|
||||
m.QueueManager.prototype.checkPausedQueues = function(gameState)
|
||||
{
|
||||
let numWorkers = 0;
|
||||
gameState.getOwnUnits().forEach (function (ent) {
|
||||
if (ent.getMetadata(PlayerID, "role") == "worker")
|
||||
numWorkers++;
|
||||
});
|
||||
gameState.getOwnTrainingFacilities().forEach(function(ent) {
|
||||
ent.trainingQueue().forEach(function(item) {
|
||||
if (item.metadata && item.metadata.role && item.metadata.role == "worker")
|
||||
numWorkers += item.count;
|
||||
});
|
||||
});
|
||||
|
||||
if (numWorkers < 8)
|
||||
{
|
||||
for (let q in this.queues)
|
||||
{
|
||||
let queue = this.queues[q];
|
||||
if (!queue.paused
|
||||
&& q != "citizenSoldier" && q != "villager"
|
||||
&& (q != "civilCentre" || gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")) > 0))
|
||||
{
|
||||
queue.paused = true;
|
||||
this.accounts[q].reset();
|
||||
}
|
||||
else if (queue.paused)
|
||||
queue.paused = false;
|
||||
}
|
||||
}
|
||||
else if (numWorkers < 16)
|
||||
{
|
||||
for (let q in this.queues)
|
||||
{
|
||||
let queue = this.queues[q];
|
||||
if (!queue.paused
|
||||
&& (q == "economicBuilding" || q == "militaryBuilding" || q == "defenseBuilding"
|
||||
|| (q == "civilCentre" && gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")) > 0)
|
||||
|| q == "majorTech" || q == "minorTech" || q.indexOf("plan_") != -1))
|
||||
{
|
||||
queue.paused = true;
|
||||
this.accounts[q].reset();
|
||||
}
|
||||
else if (queue.paused)
|
||||
queue.paused = false;
|
||||
}
|
||||
}
|
||||
else if (numWorkers < 24)
|
||||
{
|
||||
for (let q in this.queues)
|
||||
{
|
||||
let queue = this.queues[q];
|
||||
if (!queue.paused
|
||||
&& (q == "defenseBuilding"
|
||||
|| (q == "civilCentre" && gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")) > 0)
|
||||
|| q == "majorTech" || q.indexOf("_siege") != -1 || q.indexOf("_champ") != -1))
|
||||
{
|
||||
queue.paused = true;
|
||||
this.accounts[q].reset();
|
||||
}
|
||||
else if (queue.paused)
|
||||
queue.paused = false;
|
||||
|
||||
// And reduce the batch sizes of attack queues
|
||||
if (q.indexOf("plan_") != -1 && queue.queue[0])
|
||||
{
|
||||
queue.queue[0].number = 1;
|
||||
if (queue.queue[1])
|
||||
queue.queue[1].number = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
for (let q in this.queues)
|
||||
if (this.queues[q].paused)
|
||||
this.queues[q].paused = false;
|
||||
};
|
||||
|
||||
m.QueueManager.prototype.pauseQueue = function(queue, scrapAccounts)
|
||||
{
|
||||
if (this.queues[queue])
|
||||
|
@ -476,12 +476,12 @@ m.ConstructionPlan.prototype.Deserialize = function(gameState, data)
|
||||
this.cost = cost;
|
||||
|
||||
// TODO find a way to properly serialize functions. For the time being, they are manually added
|
||||
if (this.type == "structures/{civ}_house")
|
||||
if (this.type == gameState.applyCiv("structures/{civ}_house"))
|
||||
{
|
||||
var difficulty = gameState.ai.Config.difficulty;
|
||||
// change the starting condition according to the situation.
|
||||
this.isGo = function (gameState) {
|
||||
if (!self.canBuild(gameState, "structures/{civ}_house"))
|
||||
if (!gameState.ai.HQ.canBuild(gameState, "structures/{civ}_house"))
|
||||
return false;
|
||||
if (gameState.getPopulationMax() <= gameState.getPopulationLimit())
|
||||
return false;
|
||||
@ -501,12 +501,12 @@ m.ConstructionPlan.prototype.Deserialize = function(gameState, data)
|
||||
return (freeSlots <= 10);
|
||||
};
|
||||
}
|
||||
else if (this.type == "structures/{civ}_market")
|
||||
else if (this.type == gameState.applyCiv("structures/{civ}_market"))
|
||||
{
|
||||
let priority = gameState.ai.Config.priorities.economicBuilding;
|
||||
this.onStart = function(gameState) { gameState.ai.queueManager.changePriority("economicBuilding", priority); };
|
||||
}
|
||||
else if (this.type == "structures/{civ}_barracks")
|
||||
else if (this.type == gameState.applyCiv("structures/{civ}_barracks"))
|
||||
{
|
||||
let priority = gameState.ai.Config.priorities.militaryBuilding;
|
||||
this.onStart = function(gameState) { gameState.ai.queueManager.changePriority("militaryBuilding", priority); };
|
||||
|
@ -65,10 +65,11 @@ m.TrainingPlan.prototype.start = function(gameState)
|
||||
var wantedIndex = undefined;
|
||||
if (this.metadata && this.metadata.index)
|
||||
wantedIndex = this.metadata.index;
|
||||
var workerUnit = (this.metadata && this.metadata.role && this.metadata.role == "worker");
|
||||
var supportUnit = this.template.hasClass("Support");
|
||||
trainers.sort(function(a, b) {
|
||||
var aa = a.trainingQueueTime();
|
||||
var bb = b.trainingQueueTime();
|
||||
let aa = a.trainingQueueTime();
|
||||
let bb = b.trainingQueueTime();
|
||||
if (a.hasClass("Civic") && !supportUnit)
|
||||
aa += 10;
|
||||
if (b.hasClass("Civic") && !supportUnit)
|
||||
@ -80,18 +81,28 @@ m.TrainingPlan.prototype.start = function(gameState)
|
||||
if (gameState.ai.HQ.isDangerousLocation(b.position()))
|
||||
bb += 50;
|
||||
}
|
||||
let aBase = a.getMetadata(PlayerID, "base");
|
||||
let bBase = b.getMetadata(PlayerID, "base");
|
||||
if (wantedIndex)
|
||||
{
|
||||
var aBase = a.getMetadata(PlayerID, "base");
|
||||
if (!aBase || gameState.ai.HQ.baseManagers[aBase].accessIndex !== wantedIndex)
|
||||
if (!aBase || gameState.ai.HQ.baseManagers[aBase].accessIndex != wantedIndex)
|
||||
aa += 30;
|
||||
var bBase = b.getMetadata(PlayerID, "base");
|
||||
if (!bBase || gameState.ai.HQ.baseManagers[bBase].accessIndex !== wantedIndex)
|
||||
if (!bBase || gameState.ai.HQ.baseManagers[bBase].accessIndex != wantedIndex)
|
||||
bb += 30;
|
||||
}
|
||||
// then, if worker, small preference for bases with less workers
|
||||
if (workerUnit && aBase && bBase && aBase != bBase)
|
||||
{
|
||||
let apop = gameState.ai.HQ.baseManagers[aBase].workers.length;
|
||||
let bpop = gameState.ai.HQ.baseManagers[bBase].workers.length;
|
||||
if (apop > bpop)
|
||||
aa++;
|
||||
else if (bpop > apop)
|
||||
bb++;
|
||||
}
|
||||
return (aa - bb);
|
||||
});
|
||||
if (this.metadata && this.metadata.base !== undefined && this.metadata.base === 0)
|
||||
if (this.metadata && this.metadata.base !== undefined && this.metadata.base == 0)
|
||||
this.metadata.base = trainers[0].getMetadata(PlayerID, "base");
|
||||
trainers[0].train(this.type, this.number, this.metadata, this.promotedTypes(gameState));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user