1
0
forked from mirrors/0ad

petra: rework the management of siege units in attacks, to remove some civ hardcodings + some cleanup

This was SVN commit r20260.
This commit is contained in:
mimo
2017-10-04 16:29:25 +00:00
parent 862fd197d9
commit 2f24006afb
4 changed files with 56 additions and 50 deletions
@@ -701,7 +701,7 @@ m.GameState.prototype.findTrainableUnits = function(classes, anticlasses)
{
let allTrainable = [];
let civ = this.playerData.civ;
this.getOwnStructures().forEach(function(ent) {
this.getOwnTrainingFacilities().forEach(function(ent) {
let trainable = ent.trainableEntities(civ);
if (!trainable)
return;
@@ -719,28 +719,10 @@ m.GameState.prototype.findTrainableUnits = function(classes, anticlasses)
let template = this.getTemplate(trainable);
if (!template || !template.available(this))
continue;
let okay = true;
for (let clas of classes)
{
if (template.hasClass(clas))
continue;
okay = false;
break;
}
if (!okay)
if (classes.some(c => !template.hasClass(c)))
continue;
for (let clas of anticlasses)
{
if (!template.hasClass(clas))
continue;
okay = false;
break;
}
if (!okay)
if (anticlasses.some(c => template.hasClass(c)))
continue;
let category = template.trainingCategory();
if (category && limits[category] && current[category] >= limits[category])
continue;
@@ -336,8 +336,9 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
this.rushNumber++;
}
}
else if (unexecutedAttacks.Attack === 0 && unexecutedAttacks.HugeAttack === 0 &&
this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length < Math.min(2, 1 + Math.round(gameState.getPopulationMax()/100)))
else if (unexecutedAttacks.Attack == 0 && unexecutedAttacks.HugeAttack == 0 &&
this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length < Math.min(2, 1 + Math.round(gameState.getPopulationMax()/100)) &&
(this.startedAttacks.Attack.length + this.startedAttacks.HugeAttack.length == 0 || gameState.getPopulationMax() - gameState.getPopulation() > 12))
{
if (barracksNb >= 1 && (gameState.currentPhase() > 1 || gameState.isResearching(gameState.getPhaseName(2))) ||
!gameState.ai.HQ.baseManagers[1]) // if we have no base ... nothing else to do than attack
@@ -195,6 +195,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data)
// each array is [ratio, [associated classes], associated EntityColl, associated unitStat, name ]
this.buildOrders = [];
this.canBuildUnits = gameState.ai.HQ.canBuildUnits;
this.siegeState = 0; // 0 = not yet tested, 1 = not yet any siege trainer, 2 = siege added in build orders
// some variables used during the attack
this.position5TurnsAgo = [0,0];
@@ -334,18 +335,49 @@ m.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, rese
m.AttackPlan.prototype.addSiegeUnits = function(gameState)
{
if (this.unitStat.Siege || this.state !== "unexecuted")
if (this.siegeState == 2 || this.state !== "unexecuted")
return false;
let playerCiv = gameState.getPlayerCiv();
let classes = [[ "Siege", "Melee"], ["Siege", "Ranged"], ["Elephant", "Melee", "Champion"]];
let hasTrainer = [false, false, false];
for (let ent of gameState.getOwnTrainingFacilities().values())
{
let trainables = ent.trainableEntities(playerCiv);
if (!trainables)
continue;
for (let trainable of trainables)
{
if (gameState.isTemplateDisabled(trainable))
continue;
let template = gameState.getTemplate(trainable);
if (!template || !template.available(gameState))
continue;
for (let i = 0; i < classes.length; ++i)
if (classes[i].every(c => template.hasClass(c)))
hasTrainer[i] = true;
}
}
if (hasTrainer.every(e => !e))
return false;
let i = this.name % classes.length;
for (let k = 0; k < classes.length; ++k)
{
if (hasTrainer[i])
break;
i = ++i % classes.length;
}
this.siegeState = 2;
let targetSize = this.type == "HugeAttack" ? 6 : 4;
if (this.Config.difficulty < 3)
targetSize = this.Config.difficulty;
targetSize = Math.round(this.Config.popScaling * targetSize);
if (!targetSize)
return true;
// no minsize as we don't want the plan to fail at the last minute though.
let stat = { "priority": 1, "minSize": 0, "targetSize": 4, "batchSize": 2, "classes": ["Siege"],
"interests": [ ["siegeStrength", 3] ] };
if (gameState.getPlayerCiv() === "maur")
stat.classes = ["Elephant", "Champion"];
if (this.Config.difficulty < 2)
stat.targetSize = 1;
else if (this.Config.difficulty < 3)
stat.targetSize = 2;
stat.targetSize = Math.round(this.Config.popScaling * stat.targetSize);
let stat = { "priority": 1, "minSize": 0, "targetSize": targetSize, "batchSize": Math.min(targetSize, 2),
"classes": classes[i], "interests": [ ["siegeStrength", 3] ] };
this.addBuildOrder(gameState, "Siege", stat, true);
return true;
};
@@ -428,17 +460,8 @@ m.AttackPlan.prototype.updatePreparation = function(gameState)
if (this.canBuildUnits)
{
// We still have time left to recruit units and do stuffs.
if (!this.unitStat.Siege)
{
let numSiegeBuilder = 0;
let playerCiv = gameState.getPlayerCiv();
if (playerCiv !== "mace" && playerCiv !== "maur")
numSiegeBuilder += gameState.getOwnEntitiesByClass("Fortress", true).filter(API3.Filters.isBuilt()).length;
if (playerCiv === "mace" || playerCiv === "maur" || playerCiv === "rome")
numSiegeBuilder += gameState.countEntitiesByType(gameState.ai.HQ.bAdvanced[0], true);
if (numSiegeBuilder > 0)
this.addSiegeUnits(gameState);
}
if (this.siegeState == 0 || this.siegeState == 1 && gameState.ai.playedTurn % 5 == 0)
this.addSiegeUnits(gameState);
this.trainMoreUnits(gameState);
// may happen if we have no more training facilities and build orders are canceled
if (!this.buildOrders.length)
@@ -558,13 +581,12 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState)
{
// find the actual queue we want
let queue = this.queue;
if (firstOrder[3].classes.indexOf("Siege") !== -1 ||
gameState.getPlayerCiv() == "maur" && firstOrder[3].classes.indexOf("Elephant") !== -1 &&
firstOrder[3].classes.indexOf("Champion") !== -1)
if (firstOrder[3].classes.indexOf("Siege") != -1 || firstOrder[3].classes.indexOf("Elephant") != -1 &&
firstOrder[3].classes.indexOf("Melee") != -1 && firstOrder[3].classes.indexOf("Champion") != -1)
queue = this.queueSiege;
else if (firstOrder[3].classes.indexOf("Hero") !== -1)
else if (firstOrder[3].classes.indexOf("Hero") != -1)
queue = this.queueSiege;
else if (firstOrder[3].classes.indexOf("Champion") !== -1)
else if (firstOrder[3].classes.indexOf("Champion") != -1)
queue = this.queueChamp;
if (queue.length() <= 5)
@@ -2052,6 +2074,7 @@ m.AttackPlan.prototype.Serialize = function()
"maxCompletingTime": this.maxCompletingTime,
"neededShips": this.neededShips,
"unitStat": this.unitStat,
"siegeState": this.siegeState,
"position5TurnsAgo": this.position5TurnsAgo,
"lastPosition": this.lastPosition,
"position": this.position,
@@ -4,7 +4,7 @@ var PETRA = function(m)
/** returns true if this unit should be considered as a siege unit */
m.isSiegeUnit = function(ent)
{
return ent.hasClass("Siege") || ent.hasClass("Elephant") && ent.hasClass("Champion");
return ent.hasClass("Siege") || ent.hasClass("Elephant") && ent.hasClass("Melee") && ent.hasClass("Champion");
};
/** returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. */