1
0
forked from 0ad/0ad

Improve some building placement. May improve dropsite usage slightly.

Should fix #1964

This was SVN commit r14639.
This commit is contained in:
wraitii 2014-01-22 20:26:45 +00:00
parent 1fedf11e9e
commit ad8fa37f17
6 changed files with 113 additions and 34 deletions

View File

@ -51,7 +51,7 @@ m.BaseManager.prototype.init = function(gameState, unconstructed){
this.workers.registerUpdates();
// array of entity IDs, with each being
// { "food" : [close entities, semi-close entities, faraway entities, closeAmount, medianAmount, assignedWorkers collection ] … } (one per resource)
// { "food" : [close entities, semi-close entities, faraway entities, closeAmount, medianAmount, assignedWorkers collection, Rebuilt ] … } (one per resource)
// note that "median amount" also counts the closeAmount.
this.dropsites = { };
@ -269,6 +269,16 @@ m.BaseManager.prototype.assignResourceToDP = function (gameState, supply, specif
supply.setMetadata(PlayerID, "linked-dropsite-nearby", (dist < this.medRadius[type]) );
supply.setMetadata(PlayerID, "linked-dropsite", closest );
supply.setMetadata(PlayerID, "linked-dropsite-dist", +dist);
if (m.DebugEnabled())
{
if (type == "food" && dist < this.smallRadius[type])
Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [supply.id()], "rgb": [10,0,0]});
else if (type == "food" && dist < this.medRadius[type])
Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [supply.id()], "rgb": [2,0,0]});
else
Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [supply.id()], "rgb": [0.5,0,0]});
}
}
}
// TODO: ought to recount immediatly.
@ -319,7 +329,7 @@ m.BaseManager.prototype.initializeDropsite = function (gameState, ent, type) {
if (!self.dropsites[ent.id()])
self.dropsites[ent.id()] = {};
self.dropsites[ent.id()][type] = [collection2,collection3, collection, count, farCount, WkCollection];
self.dropsites[ent.id()][type] = [collection2,collection3, collection, count, farCount, WkCollection, false];
// TODO: flag us on the SharedScript "type" map.
// TODO: get workers on those resources and do something with them.
@ -483,18 +493,41 @@ m.BaseManager.prototype.updateDropsite = function (gameState, ent, type) {
return undefined; // should initialize it first.
var count = 0, farCount = 0;
var resources = gameState.getResourceSupplies(type);
this.dropsites[ent.id()][type][1].forEach( function (supply) { //}){
var dropsite = this.dropsites[ent.id()][type];
var medianPositionX = 0;
var medianPositionY = 0;
var divider = 0;
dropsite[1].forEach( function (supply) { //}){
farCount += supply.resourceSupplyAmount();
medianPositionX += supply.position()[0];
medianPositionY += supply.position()[1];
++divider;
});
this.dropsites[ent.id()][type][0].forEach( function (supply) { //}){
dropsite[0].forEach( function (supply) { //}){
count += supply.resourceSupplyAmount();
medianPositionX += supply.position()[0];
medianPositionY += supply.position()[1];
++divider;
});
this.dropsites[ent.id()][type][3] = count;
this.dropsites[ent.id()][type][4] = farCount;
// once per dropsite, if the average wood resource is too far away, try to build a closer one.
if (type === "wood" && divider !== 0 && !dropsite[6] && count < 300 && farCount > 700
&& gameState.ai.queues.dropsites.length() === 0 && gameState.countFoundationsByType(gameState.applyCiv("structures/{civ}_storehouse"), true) === 0)
{
medianPositionX /= divider;
medianPositionY /= divider;
if (API3.SquareVectorDistance([medianPositionX,medianPositionY], ent.position()) > 1800)
{
dropsite[6] = true;
gameState.ai.queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse", { "base" : this.ID }, [medianPositionX,medianPositionY]));
}
}
dropsite[3] = count;
dropsite[4] = farCount;
return true;
};
@ -512,31 +545,41 @@ m.BaseManager.prototype.updateDropsites = function (gameState) {
};
// TODO: ought to be cached or something probably
// Returns the number of slots available for workers here.
// we're assuming Max - 3 for metal/stone mines, and 20 for any dropsite that has wood.
// TODO: for wood might want to count the trees too.
// TODO: this returns "future" worker capacity, might want to have a current one.
m.BaseManager.prototype.getWorkerCapacity = function (gameState, type) {
// Returns the number of slots available for workers on this dropsite.
m.BaseManager.prototype.getDpWorkerCapacity = function (gameState, entID, type, faraway) {
if (this.dropsites[entID] === undefined || this.dropsites[entID][type] === undefined)
return undefined; // should initialize it first.
var dropsite = this.dropsites[entID];
var count = 0;
if (type == "food")
return 1000000; // TODO: perhaps return something sensible here.
if (type === "stone" || type === "metal")
return (dropsite["food"] !== undefined ? 10000 : 0);
if ((type === "stone" && dropsite["stone"])|| (type === "metal" && dropsite["metal"]))
{
for (var id in this.dropsites)
if (this.dropsites[id][type])
this.dropsites[id][type][1].forEach(function (ent) {// }){
if (ent.resourceSupplyAmount() > 500)
count += ent.maxGatherers() - 3;
});
var slot = dropsite[type][0];
if (faraway === true)
dropsite[type][1];
slot.forEach(function (ent) {
if (ent.resourceSupplyAmount() > 500)
count += ent.maxGatherers();
});
} else if (type === "wood")
{
for (var id in this.dropsites)
if (this.dropsites[id][type] && (this.dropsites[id][type][4]) > 1000)
count += Math.min(15, this.dropsites[id][type][4] / 200);
count = (faraway === true) ? dropsite[type][4] / 250 : dropsite[type][3] / 200;
}
return count;
};
// TODO: ought to be cached or something probably
// Returns the number of slots available for workers here.
m.BaseManager.prototype.getWorkerCapacity = function (gameState, type, faraway) {
var count = 0;
for (var i in this.dropsites)
count += this.getDpWorkerCapacity(gameState,i,type, faraway);
return count;
};
// TODO: ought to be cached or something probably
// Returns the amount of resource left
m.BaseManager.prototype.getResourceLevel = function (gameState, type, searchType, threshold) {
@ -588,10 +631,13 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) {
{
if (this.willGather[type] === 0)
continue;
// not enough resources on the map, tell us we've stopped.
if (type !== "food" && gameState.ai.playedTurn % 10 === 4 && this.getResourceLevel(gameState,type, "all") < 200)
this.willGather[type] = 0; // won't gather at all
// we're waiting for a new dropsite.
if (this.willGather[type] === 2)
continue;
var count = this.getResourceLevel(gameState,type, "dropsites");
if (type == "food")
{
@ -624,14 +670,14 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) {
// let's see if we need to push new farms.
var maxGatherers = gameState.getTemplate(gameState.applyCiv("structures/{civ}_field")).maxGatherers();
if (numFd < 2)
if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / (maxGatherers*0.9)) || numFarms < Math.round(this.workers.length / (maxGatherers*4)))
if (numFarms < Math.round(this.gatherersByType(gameState, "food").length / (maxGatherers*0.9)))
queues.field.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }));
// TODO: refine count to only count my base.
}
} else if (queues.dropsites.length() === 0 && gameState.countFoundationsByType(gameState.applyCiv("structures/{civ}_storehouse"), true) === 0) {
var wantedDPs = Math.ceil(this.gatherersByType(gameState, type).length / 12.0);
var need = wantedDPs - this.getResourceLevel(gameState,type, "dropsites-dpcount",2000);
if (need > 0)
var workerCapacity = this.getWorkerCapacity(gameState, type); // only close;
var wantDropsite = (this.gatherersByType(gameState, type).length / workerCapacity) > 0.9;
if (wantDropsite)
{
var pos = this.findBestDropsiteLocation(gameState, type);
if (!pos)
@ -859,7 +905,7 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) {
}
var addedWorkers = 0;
var maxTotalBuilders = Math.ceil(workers.length * 0.15);
var maxTotalBuilders = Math.ceil(workers.length * 0.33);
if (this.constructing == true && maxTotalBuilders < 15)
maxTotalBuilders = 15;

View File

@ -73,7 +73,7 @@ m.Config = function() {
"economicBuilding" : 90,
"militaryBuilding" : 240, // set to something lower after the first barracks.
"defenceBuilding" : 70,
"civilCentre" : 400,
"civilCentre" : 750,
"majorTech" : 700,
"minorTech" : 40
};

View File

@ -233,6 +233,15 @@ m.HQ.prototype.OnTownPhase = function(gameState)
this.femaleRatio = 0.4;
gameState.ai.queues["villager"].empty();
gameState.ai.queues["citizenSoldier"].empty();
for (var i in this.baseManagers)
{
if (this.baseManagers[i].willGather["wood"] === 2)
this.baseManagers[i].willGather["wood"] = 1; // retry.
if (this.baseManagers[i].willGather["stone"] === 2)
this.baseManagers[i].willGather["stone"] = 1; // retry.
if (this.baseManagers[i].willGather["metal"] === 2)
this.baseManagers[i].willGather["metal"] = 1; // retry.
}
}
}
@ -382,14 +391,16 @@ m.HQ.prototype.tryResearchTechs = function(gameState, queues) {
// TODO: improve choice alogrithm
m.HQ.prototype.switchWorkerBase = function(gameState, worker, type) {
var bestBase = 0;
var bestBaseState = -1;
for (var i in this.baseManagers)
{
if (this.baseManagers[i].willGather[type] >= 1)
if (this.baseManagers[i].willGather[type] === 1 || (this.baseManagers[i].willGather[type] === 2 && bestBaseState !== 1))
{
if (this.baseManagers[i].accessIndex === this.baseManagers[worker.getMetadata(PlayerID,"base")].accessIndex
|| this.navalManager.canReach(gameState, this.baseManagers[i].accessIndex, this.baseManagers[worker.getMetadata(PlayerID,"base")].accessIndex))
{
bestBaseState = this.baseManagers[i].willGather[type]
bestBase = i;
break;
}
@ -845,10 +856,10 @@ m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) {
var base = this.baseManagers[i];
for (var type in count)
{
if (base.getResourceLevel(gameState, type, "all") > 1500*Math.max(this.Config.difficulty,2))
if (base.getResourceLevel(gameState, type, "all") > 2200*Math.max(this.Config.difficulty,2))
count[type]++;
capacity[type] += base.getWorkerCapacity(gameState, type);
if (base.willGather[type] !== 2)
capacity[type] += base.getWorkerCapacity(gameState, type, true);
if (base.willGather[type] === 1)
need[type] = false;
}
}
@ -867,6 +878,7 @@ m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) {
// Okay so we'll set us as out of this.
this.outOf[type] = true;
} else {
warn ("planning new base ");
// base "-1" means new base.
queues.civilCentre.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_civil_centre",{ "base" : -1 }, pos));
}

View File

@ -106,6 +106,9 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState) {
friendlyTiles.addInfluence(x, z, 255);
} else {
// No position was specified so try and find a sensible place to build
if (this.metadata && this.metadata.base !== undefined)
for each (var px in gameState.ai.HQ.baseManagers[this.metadata.base].territoryIndices)
friendlyTiles.map[px] = 20;
gameState.getOwnStructures().forEach(function(ent) {
var pos = ent.position();
var x = Math.round(pos[0] / cellSize);
@ -122,6 +125,9 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState) {
} else {
friendlyTiles.addInfluence(x, z, 15, -40); // and further away from other stuffs
}
} else if (template.hasClass("Farmstead")) {
// move farmsteads away to make room.
friendlyTiles.addInfluence(x, z, 25, -25);
} else {
if (template.hasClass("GarrisonFortress") && ent.genericName() == "House")
friendlyTiles.addInfluence(x, z, 30, -50);
@ -134,6 +140,16 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState) {
friendlyTiles.addInfluence(x, z, 20, -20);
}
});
if (template.hasClass("Farmstead"))
{
for (var j = 0; j < gameState.sharedScript.resourceMaps["wood"].map.length; ++j)
{
var value = friendlyTiles.map[j] - (gameState.sharedScript.resourceMaps["wood"].map[j])/3;
friendlyTiles.map[j] = value >= 0 ? value : 0;
}
}
if (this.metadata && this.metadata.base !== undefined)
for (var base in gameState.ai.HQ.baseManagers)
if (base != this.metadata.base)

View File

@ -61,6 +61,8 @@ m.Template = m.Class({
},
available: function(gameState) {
if (this.requiredTech() === undefined)
return true;
return gameState.isResearched(this.get("Identity/RequiredTechnology"));
},

View File

@ -507,7 +507,7 @@ m.GameState.prototype.findTrainableUnits = function(classes){
this.getOwnStructures().forEach(function(ent) {
var trainable = ent.trainableEntities();
for (var i in trainable){
if (allTrainable.indexOf(trainable[i]) === -1){
if (allTrainable.indexOf(trainable[i]) === -1) {
allTrainable.push(trainable[i]);
}
}
@ -518,6 +518,9 @@ m.GameState.prototype.findTrainableUnits = function(classes){
if (template.hasClass("Hero")) // disabling heroes for now
continue;
if (!template.available(this))
continue;
var okay = true;
for (var o in classes)