diff --git a/binaries/data/mods/public/simulation/ai/aegis/aegis.js b/binaries/data/mods/public/simulation/ai/aegis/aegis.js
index 5692eb4872..d7c3a12322 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/aegis.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/aegis.js
@@ -45,7 +45,7 @@ m.AegisBot.prototype.CustomInit = function(gameState, sharedScript) {
m.playerGlobals[PlayerID].uniqueIDTPlans = 1; // transport plans. starts at 1 because 0 might be used as none.
m.playerGlobals[PlayerID].uniqueIDDefManagerArmy = 0;
- this.HQ.init(gameState,sharedScript.events,this.queues);
+ this.HQ.init(gameState,this.queues);
m.debug ("Initialized with the difficulty " + this.Config.difficulty);
var ents = gameState.getEntities().filter(API3.Filters.byOwner(this.player));
diff --git a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js
index e497dc4be7..f1fb4eb5c6 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js
@@ -34,7 +34,7 @@ m.BaseManager = function(Config) {
this.territoryIndices = [];
};
-m.BaseManager.prototype.init = function(gameState, events, unconstructed){
+m.BaseManager.prototype.init = function(gameState, unconstructed){
this.constructing = unconstructed;
// entitycollections
this.units = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "base", this.ID));
@@ -584,7 +584,7 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) {
{
if (this.willGather[type] === 0)
continue;
- if (type !== "food" && gameState.playedTurn % 10 === 4 && this.getResourceLevel(gameState,type, "all") < 200)
+ if (type !== "food" && gameState.ai.playedTurn % 10 === 4 && this.getResourceLevel(gameState,type, "all") < 200)
this.willGather[type] = 0; // won't gather at all
if (this.willGather[type] === 2)
continue;
@@ -901,13 +901,13 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) {
continue;
var assigned = gameState.getOwnEntitiesByMetadata("target-foundation", target.id()).length;
- if (assigned < this.targetNumBuilders/3) {
- if (builderWorkers.length + addedWorkers < this.targetNumBuilders*2) {
+ if (assigned < targetNB/3) {
+ if (builderWorkers.length + addedWorkers < targetNB*2) {
var nonBuilderWorkers = workers.filter(function(ent) { return (ent.getMetadata(PlayerID, "subrole") !== "builder" && ent.position() !== undefined); });
if (gameState.defcon() < 5)
nonBuilderWorkers = workers.filter(function(ent) { return (ent.getMetadata(PlayerID, "subrole") !== "builder" && ent.hasClass("Female") && ent.position() !== undefined); });
- var nearestNonBuilders = nonBuilderWorkers.filterNearest(target.position(), this.targetNumBuilders/3 - assigned);
+ var nearestNonBuilders = nonBuilderWorkers.filterNearest(target.position(), targetNB/3 - assigned);
nearestNonBuilders.forEach(function(ent) {
ent.stopMoving();
diff --git a/binaries/data/mods/public/simulation/ai/aegis/config.js b/binaries/data/mods/public/simulation/ai/aegis/config.js
index 44c77f8a4e..72d3662d32 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/config.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/config.js
@@ -10,7 +10,7 @@ m.Config = function() {
"defenceBuildingTime" : 600, // Time to wait before building towers or fortresses
"attackPlansStartTime" : 0, // time to wait before attacking. Start as soon as possible (first barracks)
"techStartTime" : 120, // time to wait before teching. Will only start after town phase so it's irrelevant.
- "popForBarracks1" : 15,
+ "popForBarracks1" : 20,
"popForBarracks2" : 95,
"timeForBlacksmith" : 900,
};
@@ -63,21 +63,20 @@ m.Config = function() {
}
};
- // qbot
this.priorities =
- { // Note these are dynamic, you are only setting the initial values
- "house" : 350,
- "villager" : 40,
+ {
+ "villager" : 30, // should be slightly lower than the citizen soldier one because otherwise they get all the food
"citizenSoldier" : 60,
"ships" : 70,
- "economicBuilding" : 90,
+ "house" : 350,
"dropsites" : 120,
"field" : 500,
- "militaryBuilding" : 110,
+ "economicBuilding" : 90,
+ "militaryBuilding" : 140, // TODO: set to a lower value after the first barracks.
"defenceBuilding" : 70,
+ "civilCentre" : 400,
"majorTech" : 700,
- "minorTech" : 50,
- "civilCentre" : 400
+ "minorTech" : 40
};
};
diff --git a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js
index 486111aece..3590e77228 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js
@@ -30,6 +30,9 @@ m.HQ = function(Config) {
this.baseManagers = {};
+ // cache the rates currently want for resource gathering.
+ this.wantedRates = {};
+
// this means we'll have about a big third of women, and thus we can maximize resource gathering rates.
this.femaleRatio = this.Config.Economy.femaleRatio;
@@ -47,7 +50,7 @@ m.HQ = function(Config) {
};
// More initialisation for stuff that needs the gameState
-m.HQ.prototype.init = function(gameState, events, queues){
+m.HQ.prototype.init = function(gameState, queues){
// initialize base map. Each pixel is a base ID, or 0 if none
this.basesMap = new API3.Map(gameState.sharedScript, new Uint8Array(gameState.getMap().data.length));
this.basesMap.setMaxVal(255);
@@ -84,7 +87,7 @@ m.HQ.prototype.init = function(gameState, events, queues){
treasureAmount[i] += ent.resourceSupplyMax();
});
this.baseManagers[1] = new m.BaseManager(this.Config);
- this.baseManagers[1].init(gameState, events);
+ this.baseManagers[1].init(gameState);
this.baseManagers[1].setAnchor(CC);
this.baseManagers[1].initTerritory(this, gameState);
this.baseManagers[1].initGatheringFunctions(this, gameState);
@@ -121,7 +124,7 @@ m.HQ.prototype.init = function(gameState, events, queues){
//this.reassignIdleWorkers(gameState);
- this.navalManager.init(gameState, events, queues);
+ this.navalManager.init(gameState, queues);
// TODO: change that to something dynamic.
var civ = gameState.playerData.civ;
@@ -214,20 +217,14 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues) {
}
};
-// okay, so here we'll create both females and male workers.
-// We'll try to keep close to the "ratio" defined atop.
-// Choice of citizen soldier is a bit messy.
-// Before having 100 workers it focuses on speed, cost, and won't choose units that cost stone/metal
-// After 100 it just picks the strongest;
-// TODO: This should probably be changed to favor a more mixed approach for better defense.
-// (or even to adapt based on estimated enemy strategy).
-// TODO: this should probably set which base it wants them in.
+// This code trains females and citizen workers, trying to keep close to a ratio of females/CS
+// TODO: this should choose a base depending on which base need workers
+// TODO: also there are several things that could be greatly improved here.
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
{
// Get some data.
// Count the workers in the world and in progress
var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen"), true);
- numFemales += queues.villager.countQueuedUnitsWithClass("Support");
// counting the workers that aren't part of a plan
var numWorkers = 0;
@@ -243,43 +240,50 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
numInTraining += item.count;
});
});
- var numQueued = queues.villager.countQueuedUnits() + queues.citizenSoldier.countQueuedUnits();
+ var numQueuedF = queues.villager.countQueuedUnits();
+ var numQueuedS = queues.citizenSoldier.countQueuedUnits();
+ var numQueued = numQueuedS + numQueuedF;
var numTotal = numWorkers + numQueued;
// If we have too few, train more
// should plan enough to always have females…
// TODO: 15 here should be changed to something more sensible, such as nb of producing buildings.
- if (numTotal < this.targetNumWorkers && numQueued < 50 && (queues.villager.length() + queues.citizenSoldier.length()) < 120 && numInTraining < 15) {
- var template = gameState.applyCiv("units/{civ}_support_female_citizen");
-
- var size = Math.min(5, Math.ceil(numTotal / 10));
- if (numFemales/numTotal > this.femaleRatio && (numTotal > 20 || (this.fastStart && numTotal > 10))) {
- if (numTotal < 100)
- template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["cost",1], ["speed",0.5], ["costsResource", 0.5, "stone"], ["costsResource", 0.5, "metal"]]);
- else
- template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["strength",1] ]);
+ if (numTotal > this.targetNumWorkers || numQueued > 50 || (numQueuedF > 20 && numQueuedS > 20) || numInTraining > 15)
+ return;
- if (!template)
- template = gameState.applyCiv("units/{civ}_support_female_citizen");
- if (gameState.currentPhase() === 1)
- size = 2;
- }
-
- // TODO: improve that logic.
- if (numFemales/numTotal > this.femaleRatio * 1.3 && numWorkers > 25)
- queues.villager.paused = true;
- else if ((numFemales/numTotal < this.femaleRatio * 1.1) || gameState.ai.queueManager.getAvailableResources(gameState)["food"] > 250
- || numWorkers <= 25)
- queues.villager.paused = false;
-
- // TODO: perhaps assign them a default resource and check the base according to that.
-
- // base "0" means "auto"
- if (template === gameState.applyCiv("units/{civ}_support_female_citizen"))
- queues.villager.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size ));
+ // default template and size
+ var template = gameState.applyCiv("units/{civ}_support_female_citizen");
+ var size = Math.min(5, Math.ceil(numTotal / 10));
+
+ // Choose whether we want soldiers instead.
+ // TODO: we might want to adjust our female ratio.
+ if ((numFemales+numQueuedF)/numTotal > this.femaleRatio && numQueuedS < 20) {
+ if (numTotal < 35)
+ template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["cost",1], ["speed",0.5], ["costsResource", 0.5, "stone"], ["costsResource", 0.5, "metal"]]);
else
- queues.citizenSoldier.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size));
+ template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["strength",1] ]);
+
+ if (!template)
+ template = gameState.applyCiv("units/{civ}_support_female_citizen");
+ else
+ size = Math.min(5, Math.ceil(numTotal / 12));
}
+
+ // TODO: improve that logic.
+ /*
+ if (numFemales/numWorkers > this.femaleRatio && numQueuedS > 0 && numWorkers > 25)
+ queues.villager.paused = true;
+ else
+ queues.villager.paused = false;
+ */
+
+ // TODO: perhaps assign them a default resource and check the base according to that.
+
+ // base "0" means "auto"
+ if (template === gameState.applyCiv("units/{civ}_support_female_citizen"))
+ queues.villager.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size ));
+ else
+ queues.citizenSoldier.addItem(new m.TrainingPlan(gameState, template, { "role" : "worker", "base" : 0 }, size, 0, -1, size));
};
// picks the best template based on parameters and classes
@@ -457,7 +461,13 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState) {
};
-// Pick the resource which most needs another worker
+/* Pick the resource which most needs another worker
+ * How this works:
+ * We get the rates we would want to have to be able to deal with our plans
+ * We get our current rates
+ * We compare; we pick the one where the discrepancy is highest.
+ * Need to balance long-term needs and possible short-term needs.
+ */
m.HQ.prototype.pickMostNeededResources = function(gameState) {
var self = this;
@@ -491,7 +501,7 @@ m.HQ.prototype.pickMostNeededResources = function(gameState) {
var va = (Math.max(0,self.wantedRates[a] - currentRates[a]))/ (currentRates[a]+1);
var vb = (Math.max(0,self.wantedRates[b] - currentRates[b]))/ (currentRates[b]+1);
- // If they happen to be equal (generally this means "0" aka no need), make it equitable.
+ // If they happen to be equal (generally this means "0" aka no need), make it fair.
if (va === vb)
return (self.wantedRates[b]/(currentRates[b]+1)) - (self.wantedRates[a]/(currentRates[a]+1));
return vb-va;
@@ -1054,7 +1064,7 @@ m.HQ.prototype.update = function(gameState, queues, events) {
this.GetCurrentGatherRates(gameState);
- if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2)
+ if (gameState.getTimeElapsed() > this.techStartTime && gameState.currentPhase() > 2 )
this.tryResearchTechs(gameState,queues);
if (this.Config.difficulty > 1)
diff --git a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js
index c63dc40350..4c22f9bf84 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js
@@ -35,7 +35,7 @@ m.NavalManager = function() {
};
// More initialisation for stuff that needs the gameState
-m.NavalManager.prototype.init = function(gameState, events, queues) {
+m.NavalManager.prototype.init = function(gameState, queues) {
// finished docks
this.docks = gameState.getOwnStructures().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation())));
this.docks.allowQuickIter();
diff --git a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
index cb212e8188..53c82ecd06 100644
--- a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
+++ b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js
@@ -111,10 +111,14 @@ m.QueueManager.prototype.futureNeeds = function(gameState) {
};
};
-// calculate the gather rates we'd want to be able to use all elements in our queues
+// calculate the gather rates we'd want to be able to start all elements in our queues
+// TODO: many things.
m.QueueManager.prototype.wantedGatherRates = function(gameState) {
+ // global rates
var rates = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 };
+ // per-queue.
var qTime = gameState.getTimeElapsed();
+ var time = gameState.getTimeElapsed();
var qCosts = { "food" : 0, "wood" : 0, "stone" : 0, "metal" : 0 };
var currentRess = this.getAvailableResources(gameState);
@@ -127,32 +131,37 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState) {
var name = this.queueArrays[i][0];
var queue = this.queueArrays[i][1];
+ // we'll move temporally along the queue.
for (var j = 0; j < queue.length(); ++j)
{
var elem = queue.queue[j];
var cost = elem.getCost();
+
if (qTime < elem.startTime)
qTime = elem.startTime;
+ // TODO: what is the else case here?
+
if (!elem.isGo(gameState))
{
- // assume 2 minutes.
- // TODO work on this.
+ // assume we'll be wanted in four minutes.
+ // TODO: work on this.
for (var type in qCosts)
- qCosts[type] += cost[type];
- qTime += 120000;
+ qCosts[type] += cost[type] / (qTime/time);
+ qTime += 240000;
break; // disregard other stuffs.
}
if (!elem.endTime)
{
- // estimate time based on priority + cost + nb
+ // Assume we want it in 30 seconds from current time.
+ // Costs are made higher based on priority and lower based on current time.
// TODO: work on this.
for (var type in qCosts)
- qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name]));
+ qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])) / (qTime/time);
qTime += 30000;
} else {
// TODO: work on this.
for (var type in qCosts)
- qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name]));
+ qCosts[type] += (cost[type] + Math.min(cost[type],this.priorities[name])) / (qTime/time);
// TODO: refine based on % completed.
qTime += (elem.endTime-elem.startTime);
}
@@ -166,6 +175,7 @@ m.QueueManager.prototype.wantedGatherRates = function(gameState) {
rates[j] += qCosts[j]/(qTime/1000);
}
}
+
return rates;
};
@@ -311,8 +321,14 @@ m.QueueManager.prototype.HTMLprintQueues = function(gameState){
if (q.queue[j].number)
qStr += q.queue[j].number + " ";
qStr += q.queue[j].type;
+ qStr += "
";
+ var costs = q.queue[j].getCost();
+ for each (var k in costs.types) {
+ qStr += costs[k] + k.substr(0,1).toUpperCase() ;
+ if (k != "metal") qStr += " / ";
+ }
+ qStr += "";
log (qStr);
- log ("");
}
log ("");
}
@@ -322,7 +338,6 @@ m.QueueManager.prototype.HTMLprintQueues = function(gameState){
{
log("
" + p + ": " + uneval(this.accounts[p]) + "
"); }*/ - log ("Needed Resources:" + uneval(this.futureNeeds(gameState,false)) + "
"); log ("Wanted Gather Rate:" + uneval(this.wantedGatherRates(gameState)) + "
"); log ("Current Resources:" + uneval(gameState.getResources()) + "
"); log ("Available Resources:" + uneval(this.getAvailableResources(gameState)) + "
"); diff --git a/binaries/data/mods/public/simulation/ai/common-api/map-module.js b/binaries/data/mods/public/simulation/ai/common-api/map-module.js index 44e85c152a..f3d0258768 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/map-module.js +++ b/binaries/data/mods/public/simulation/ai/common-api/map-module.js @@ -45,8 +45,8 @@ m.Map.prototype.addInfluence = function(cx, cy, maxDist, strength, type) { var x0 = Math.max(0, cx - maxDist); var y0 = Math.max(0, cy - maxDist); - var x1 = Math.min(this.width, cx + maxDist); - var y1 = Math.min(this.height, cy + maxDist); + var x1 = Math.min(this.width-1, cx + maxDist); + var y1 = Math.min(this.height-1, cy + maxDist); var maxDist2 = maxDist * maxDist; var str = 0.0; @@ -70,11 +70,11 @@ m.Map.prototype.addInfluence = function(cx, cy, maxDist, strength, type) { var dx = x - cx; var dy = y - cy; var r2 = dx*dx + dy*dy; - if (r2 < maxDist2){ + if (r2 < maxDist2) { var quant = 0; var r = Math.sqrt(r2); quant = str * (maxDist - r); - + if (this.map[x + y * this.width] + quant < 0) this.map[x + y * this.width] = 0; else if (this.map[x + y * this.width] + quant > this.maxVal) diff --git a/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis-pathfinder.js b/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis-pathfinder.js index 292cca59c4..794b764f22 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis-pathfinder.js +++ b/binaries/data/mods/public/simulation/ai/common-api/terrain-analysis-pathfinder.js @@ -205,7 +205,7 @@ m.aStarPath.prototype.continuePath = function(gamestate) { var index = 0 + this.currentSquare +positions[i][0]*this.Sampling +w*this.Sampling*positions[i][1]; if (this.widthMap[index] >= this.minWidth || (this.onWater && this.map[index] > 0 && this.map[index] !== 200 && this.map[index] !== 201) - || (!this.onWater && this.map[this.index] === 200)) + || (!this.onWater && this.map[index] === 200)) { if(this.isOpened[index] === undefined) {