1
0
forked from 0ad/0ad

Let PetraAI check for different templates when finding the best dropsite.

Loops buildable templates to find the best.

Differential revision: https://code.wildfiregames.com/D3876
Comments by: @Angen, @Stan, @wraitii
This was SVN commit r25514.
This commit is contained in:
Freagarach 2021-05-22 07:53:47 +00:00
parent 494d12fb9c
commit 0dfebc8d2b
4 changed files with 60 additions and 27 deletions

View File

@ -245,12 +245,37 @@ PETRA.BaseManager.prototype.removeDropsite = function(gameState, ent)
};
/**
* Returns the position of the best place to build a new dropsite for the specified resource
* @return {Object} - The position of the best place to build a new dropsite for the specified resource,
* its quality and its template name.
*/
PETRA.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource)
PETRA.BaseManager.prototype.findBestDropsiteAndLocation = function(gameState, resource)
{
let bestResult = {
"quality": 0,
"pos": [0, 0]
};
for (const templateName of gameState.ai.HQ.buildManager.findStructuresByFilter(gameState, API3.Filters.isDropsite(resource)))
{
const dp = this.findBestDropsiteLocation(gameState, resource, templateName);
if (dp.quality < bestResult.quality)
continue;
bestResult = dp;
bestResult.templateName = templateName;
}
return bestResult;
};
/**
* Returns the position of the best place to build a new dropsite for the specified resource and dropsite template.
*/
PETRA.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource, templateName)
{
const template = gameState.getTemplate(gameState.applyCiv(templateName));
// CCs and Docks are handled elsewhere.
if (template.hasClass("CivCentre") || template.hasClass("Dock"))
return { "quality": 0, "pos": [0, 0] };
let template = gameState.getTemplate(gameState.applyCiv("structures/{civ}/storehouse"));
let halfSize = 0;
if (template.get("Footprint/Square"))
halfSize = Math.max(+template.get("Footprint/Square/@depth"), +template.get("Footprint/Square/@width")) / 2;
@ -430,17 +455,17 @@ PETRA.BaseManager.prototype.checkResourceLevels = function(gameState, queues)
let ratio = this.gatherers[type].lost / total;
if (ratio > 0.15)
{
let newDP = this.findBestDropsiteLocation(gameState, type);
if (newDP.quality > 50 && gameState.ai.HQ.canBuild(gameState, "structures/{civ}/storehouse"))
queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, "structures/{civ}/storehouse", { "base": this.ID, "type": type }, newDP.pos));
const newDP = this.findBestDropsiteAndLocation(gameState, type);
if (newDP.quality > 50 && gameState.ai.HQ.canBuild(gameState, newDP.templateName))
queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, newDP.templateName, { "base": this.ID, "type": type }, newDP.pos));
else if (!gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")).hasEntities() && !queues.civilCentre.hasQueuedUnits())
{
// No good dropsite, try to build a new base if no base already planned,
// and if not possible, be less strict on dropsite quality.
if ((!gameState.ai.HQ.canExpand || !gameState.ai.HQ.buildNewBase(gameState, queues, type)) &&
newDP.quality > Math.min(25, 50*0.15/ratio) &&
gameState.ai.HQ.canBuild(gameState, "structures/{civ}/storehouse"))
queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, "structures/{civ}/storehouse", { "base": this.ID, "type": type }, newDP.pos));
gameState.ai.HQ.canBuild(gameState, newDP.templateName))
queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, newDP.templateName, { "base": this.ID, "type": type }, newDP.pos));
}
}
this.gatherers[type].nextCheck = gameState.ai.playedTurn + 20;

View File

@ -97,23 +97,32 @@ PETRA.BuildManager.prototype.checkEvents = function(gameState, events)
};
/**
* Get the buildable structures passing a filter.
*/
PETRA.BuildManager.prototype.findStructuresByFilter = function(gameState, filter)
{
const result = [];
for (let [templateName, count] of this.builderCounters)
{
if (!count || gameState.isTemplateDisabled(templateName))
continue;
let template = gameState.getTemplate(templateName);
if (!template || !template.available(gameState))
continue;
if (filter.func(template))
result.push(templateName);
}
return result;
};
/**
* Get the first buildable structure with a given class
* TODO when several available, choose the best one
*/
PETRA.BuildManager.prototype.findStructureWithClass = function(gameState, classes)
{
for (let [templateName, count] of this.builderCounters)
{
if (count == 0 || gameState.isTemplateDisabled(templateName))
continue;
let template = gameState.getTemplate(templateName);
if (!template || !template.available(gameState))
continue;
if (MatchesClassList(template.classes(), classes))
return templateName;
}
return undefined;
return this.findStructuresByFilter(gameState, API3.Filters.byClassesOr(classes))[0];
};
PETRA.BuildManager.prototype.hasBuilder = function(template)

View File

@ -119,7 +119,7 @@ PETRA.ConstructionPlan.prototype.findGoodPosition = function(gameState)
// recompute the best dropsite location in case some conditions have changed
let base = HQ.getBaseByID(this.metadata.base);
let type = this.metadata.type ? this.metadata.type : "wood";
let newpos = base.findBestDropsiteLocation(gameState, type);
const newpos = base.findBestDropsiteLocation(gameState, type, template._templateName);
if (newpos && newpos.quality > 0)
{
let pos = newpos.pos;

View File

@ -545,11 +545,10 @@ PETRA.HQ.prototype.configFirstBase = function(gameState)
}
// immediatly build a wood dropsite if possible.
let template = gameState.applyCiv("structures/{civ}/storehouse");
if (!gameState.getOwnEntitiesByClass("Storehouse", true).hasEntities() && this.canBuild(gameState, template))
if (!gameState.getOwnEntitiesByClass("DropsiteWood", true).hasEntities())
{
let newDP = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood");
if (newDP.quality > 40)
const newDP = this.baseManagers[1].findBestDropsiteAndLocation(gameState, "wood");
if (newDP.quality > 40 && this.canBuild(gameState, newDP.templateName))
{
// if we start with enough workers, put our available resources in this first dropsite
// same thing if our pop exceed the allowed one, as we will need several houses
@ -557,16 +556,16 @@ PETRA.HQ.prototype.configFirstBase = function(gameState)
if (numWorkers > 12 && newDP.quality > 60 ||
gameState.getPopulation() > gameState.getPopulationLimit() + 20)
{
let cost = new API3.Resources(gameState.getTemplate(template).cost());
const cost = new API3.Resources(gameState.getTemplate(newDP.templateName).cost());
gameState.ai.queueManager.setAccounts(gameState, cost, "dropsites");
}
gameState.ai.queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, template, { "base": this.baseManagers[1].ID }, newDP.pos));
gameState.ai.queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, newDP.templateName, { "base": this.baseManagers[1].ID }, newDP.pos));
}
}
// and build immediately a corral if needed
if (this.needCorral)
{
template = gameState.applyCiv("structures/{civ}/corral");
const template = gameState.applyCiv("structures/{civ}/corral");
if (!gameState.getOwnEntitiesByClass("Corral", true).hasEntities() && this.canBuild(gameState, template))
gameState.ai.queues.corral.addPlan(new PETRA.ConstructionPlan(gameState, template, { "base": this.baseManagers[1].ID }));
}