Petra: reduce the CPU time for building placement

This was SVN commit r15244.
This commit is contained in:
mimo 2014-05-29 20:39:09 +00:00
parent 7105dabca7
commit 84d799ed9f
4 changed files with 142 additions and 137 deletions

View File

@ -55,7 +55,7 @@ m.Army.prototype.recalculatePosition = function(gameState, force)
var pos = [0,0]; var pos = [0,0];
if (this.foeEntities.length !== 0) if (this.foeEntities.length !== 0)
{ {
for each (var id in this.foeEntities) for (var id of this.foeEntities)
{ {
var ent = gameState.getEntityById(id); var ent = gameState.getEntityById(id);
var epos = ent.position(); var epos = ent.position();
@ -69,7 +69,7 @@ m.Army.prototype.recalculatePosition = function(gameState, force)
this.ownPosition = [0,0]; this.ownPosition = [0,0];
var npos = 0; // same defenders may be sailing to defend us var npos = 0; // same defenders may be sailing to defend us
for each (var id in this.ownEntities) for (var id of this.ownEntities)
{ {
var ent = gameState.getEntityById(id); var ent = gameState.getEntityById(id);
if (!ent.position()) if (!ent.position())
@ -96,9 +96,9 @@ m.Army.prototype.recalculateStrengths = function (gameState)
// todo: deal with specifics. // todo: deal with specifics.
for each (var id in this.foeEntities) for (var id of this.foeEntities)
this.evaluateStrength(gameState.getEntityById(id)); this.evaluateStrength(gameState.getEntityById(id));
for each (var id in this.ownEntities) for (var id of this.ownEntities)
this.evaluateStrength(gameState.getEntityById(id), true); this.evaluateStrength(gameState.getEntityById(id), true);
} }
@ -293,10 +293,10 @@ m.Army.prototype.merge = function (gameState, otherArmy)
for (var i in otherArmy.assignedTo) for (var i in otherArmy.assignedTo)
this.assignedTo[i] = otherArmy.assignedTo[i]; this.assignedTo[i] = otherArmy.assignedTo[i];
for each (var id in otherArmy.foeEntities) for (var id of otherArmy.foeEntities)
this.addFoe(gameState, id); this.addFoe(gameState, id);
// TODO: reassign those ? // TODO: reassign those ?
for each (var id in otherArmy.ownEntities) for (var id of otherArmy.ownEntities)
this.addOwn(gameState, id); this.addOwn(gameState, id);
this.recalculatePosition(gameState, true); this.recalculatePosition(gameState, true);

View File

@ -267,28 +267,30 @@ m.BaseManager.prototype.removeDropsite = function (gameState, ent)
m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource) m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource)
{ {
var storeHousePlate = gameState.getTemplate(gameState.applyCiv("structures/{civ}_storehouse")); var template = gameState.getTemplate(gameState.applyCiv("structures/{civ}_storehouse"));
// This builds a map. The procedure is fairly simple. It adds the resource maps // This builds a map. The procedure is fairly simple. It adds the resource maps
// (which are dynamically updated and are made so that they will facilitate DP placement) // (which are dynamically updated and are made so that they will facilitate DP placement)
// Then checks for a good spot in the territory. If none, and town/city phase, checks outside // Then checks for a good spot in the territory. If none, and town/city phase, checks outside
// The AI will currently not build a CC if it wouldn't connect with an existing CC. // The AI will currently not build a CC if it wouldn't connect with an existing CC.
var obstructions = m.createObstructionMap(gameState, this.accessIndex, storeHousePlate); var obstructions = m.createObstructionMap(gameState, this.accessIndex, template);
obstructions.expandInfluences(); obstructions.expandInfluences();
var locateMap = new API3.Map(gameState.sharedScript);
var DPFoundations = gameState.getOwnFoundations().filter(API3.Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse"))); var DPFoundations = gameState.getOwnFoundations().filter(API3.Filters.byType(gameState.applyCiv("foundation|structures/{civ}_storehouse")));
var ccEnts = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); var ccEnts = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
// TODO: might be better to check dropsites someplace else. var width = obstructions.width;
// loop over this in this.terrytoryindices. It's usually a little too much, but it's always enough. var bestIdx = undefined;
var width = locateMap.width; var bestVal = undefined;
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
for (var p = 0; p < this.territoryIndices.length; ++p) for (var p = 0; p < this.territoryIndices.length; ++p)
{ {
var j = this.territoryIndices[p]; var j = this.territoryIndices[p];
if (obstructions.map[j] <= radius) // check room around
continue;
// we add 3 times the needed resource and once the other two (not food) // we add 3 times the needed resource and once the other two (not food)
var total = 0; var total = 0;
@ -355,22 +357,23 @@ m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource)
else if (dist < 6400) else if (dist < 6400)
total /= 2; total /= 2;
} }
if (total == 0)
continue;
locateMap.map[j] = total; if (bestVal !== undefined && total < bestVal)
continue;
bestVal = total;
bestIdx = j;
} }
var best = locateMap.findBestTile(2, obstructions);
var bestIdx = best[0];
if (this.Config.debug == 2) if (this.Config.debug == 2)
warn(" for dropsite best is " + best[1]); warn(" for dropsite best is " + bestVal);
var quality = best[1]; if (bestVal <= 0)
if (quality <= 0) return {"quality": bestVal, "pos": [0, 0]};
return {"quality": quality, "pos": [0, 0]};
var x = ((bestIdx % width) + 0.5) * gameState.cellSize; var x = ((bestIdx % width) + 0.5) * gameState.cellSize;
var z = (Math.floor(bestIdx / width) + 0.5) * gameState.cellSize; var z = (Math.floor(bestIdx / width) + 0.5) * gameState.cellSize;
return {"quality": quality, "pos": [x, z]}; return {"quality": bestVal, "pos": [x, z]};
}; };
m.BaseManager.prototype.getResourceLevel = function (gameState, type) m.BaseManager.prototype.getResourceLevel = function (gameState, type)

View File

@ -643,7 +643,7 @@ m.HQ.prototype.buildNewCC= function(gameState, queues)
// Returns the best position to build a new Civil Centre // Returns the best position to build a new Civil Centre
// Whose primary function would be to reach new resources of type "resource". // Whose primary function would be to reach new resources of type "resource".
m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrategic) m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource, fromStrategic)
{ {
// This builds a map. The procedure is fairly simple. It adds the resource maps // This builds a map. The procedure is fairly simple. It adds the resource maps
// (which are dynamically updated and are made so that they will facilitate DP placement) // (which are dynamically updated and are made so that they will facilitate DP placement)
@ -652,45 +652,51 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrate
Engine.ProfileStart("findEconomicCCLocation"); Engine.ProfileStart("findEconomicCCLocation");
// create an empty map
var locateMap = new API3.Map(gameState.sharedScript);
locateMap.setMaxVal(255);
// obstruction map // obstruction map
var obstructions = m.createObstructionMap(gameState, 0); var obstructions = m.createObstructionMap(gameState, 0, template);
obstructions.expandInfluences(); obstructions.expandInfluences();
var ccEnts = gameState.getEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); var ccEnts = gameState.getEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
var dpEnts = gameState.getOwnDropsites().toEntityArray(); var dpEnts = gameState.getOwnDropsites().filter(API3.Filters.not(API3.Filters.byClassesOr(["CivCentre", "Elephant"]))).toEntityArray();
var ccList = [];
for (var cc of ccEnts)
ccList.push({"pos": cc.position(), "ally": gameState.isPlayerAlly(cc.owner())});
var dpList = [];
for (var dp of dpEnts)
dpList.push({"pos": dp.position()});
for (var j = 0; j < locateMap.length; ++j) var width = this.territoryMap.width;
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
var bestIdx = undefined;
var bestVal = undefined;
for (var j = 0; j < this.territoryMap.length; ++j)
{ {
var norm = 0.5; // TODO adjust it, knowing that we will sum 5 maps
if (this.territoryMap.getOwnerIndex(j) !== 0 || this.borderMap.map[j] === 2) if (this.territoryMap.getOwnerIndex(j) !== 0 || this.borderMap.map[j] === 2)
{
norm = 0;
continue; continue;
}
// We require that it is accessible from our starting position // We require that it is accessible from our starting position
var index = gameState.ai.accessibility.landPassMap[j]; var index = gameState.ai.accessibility.landPassMap[j];
if (!this.allowedRegions[index]) if (!this.allowedRegions[index])
{
norm = 0;
continue; continue;
} // and with enough room around to build the cc
if (obstructions.map[j] <= radius)
continue;
var norm = 0.5; // TODO adjust it, knowing that we will sum 5 maps
// checking distance to other cc // checking distance to other cc
var pos = [j%locateMap.width+0.5, Math.floor(j/locateMap.width)+0.5]; var pos = [j%width+0.5, Math.floor(j/width)+0.5];
pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]]; pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]];
var minDist = Math.min(); var minDist = Math.min();
for (var cc of ccEnts)
for (var cc of ccList)
{ {
var dist = API3.SquareVectorDistance(cc.position(), pos); var dist = API3.SquareVectorDistance(cc.pos, pos);
if (dist < 14000) // Reject if too near from any cc if (dist < 14000) // Reject if too near from any cc
{ {
norm = 0 norm = 0
break; break;
} }
if (!gameState.isPlayerAlly(cc.owner())) if (!cc.ally)
continue; continue;
if (dist < 20000) // Reject if too near from an allied cc if (dist < 20000) // Reject if too near from an allied cc
{ {
@ -722,15 +728,13 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrate
norm *= 0.5; norm *= 0.5;
} }
for (var dp of dpEnts) for (var dp of dpList)
{ {
if (dp.hasClass("Elephant") || dp.hasClass("CivCentre")) // CivCentre are already taken into account var dist = API3.SquareVectorDistance(dp.pos, pos);
continue;
var dist = API3.SquareVectorDistance(dp.position(), pos);
if (dist < 3600) if (dist < 3600)
{ {
norm = 0; norm = 0;
continue; break;
} }
else if (dist < 6400) else if (dist < 6400)
norm *= 0.5; norm *= 0.5;
@ -746,16 +750,15 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrate
+ gameState.sharedScript.CCResourceMaps["stone"].map[j] + gameState.sharedScript.CCResourceMaps["stone"].map[j]
+ gameState.sharedScript.CCResourceMaps["metal"].map[j]; + gameState.sharedScript.CCResourceMaps["metal"].map[j];
val *= norm; val *= norm;
if (val > 255)
val = 255; if (bestVal !== undefined && val < bestVal)
locateMap.map[j] = val; continue;
bestVal = val;
bestIdx = j;
} }
Engine.ProfileStop(); Engine.ProfileStop();
var best = locateMap.findBestTile(6, obstructions);
var bestIdx = best[0];
/* if (m.DebugEnabled()) /* if (m.DebugEnabled())
{ {
gameState.sharedScript.CCResourceMaps["wood"].dumpIm("woodMap.png", 300); gameState.sharedScript.CCResourceMaps["wood"].dumpIm("woodMap.png", 300);
@ -769,14 +772,13 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrate
if (fromStrategic) // be less restrictive if (fromStrategic) // be less restrictive
cut = 30; cut = 30;
if (this.Config.debug) if (this.Config.debug)
warn("on a trouve une base avec best (cut=" + cut + ") = " + best[1]); warn("on a trouve une base avec best (cut=" + cut + ") = " + bestVal);
// not good enough. // not good enough.
if (best[1] < cut) if (bestVal < cut)
return false; return false;
var bestIdx = best[0]; var x = (bestIdx%width + 0.5) * gameState.cellSize;
var x = ((bestIdx % locateMap.width) + 0.5) * gameState.cellSize; var z = (Math.floor(bestIdx/width) + 0.5) * gameState.cellSize;
var z = (Math.floor(bestIdx / locateMap.width) + 0.5) * gameState.cellSize;
// Define a minimal number of wanted ships in the seas reaching this new base // Define a minimal number of wanted ships in the seas reaching this new base
var index = gameState.ai.accessibility.landPassMap[bestIdx]; var index = gameState.ai.accessibility.landPassMap[bestIdx];
@ -795,30 +797,39 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, resource, fromStrate
// Returns the best position to build a new Civil Centre // Returns the best position to build a new Civil Centre
// Whose primary function would be to assure territorial continuity with our allies // Whose primary function would be to assure territorial continuity with our allies
m.HQ.prototype.findStrategicCCLocation = function(gameState) m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
{ {
// This builds a map. The procedure is fairly simple. // This builds a map. The procedure is fairly simple.
// We minimize the Sum((dist-300)**2) where the sum is on all allied CC // We minimize the Sum((dist-300)**2) where the sum is on the three nearest allied CC
// with the constraints that all CC have dist > 200 and at least one have dist < 400 // with the constraints that all CC have dist > 200 and at least one have dist < 400
// This needs at least 2 CC. Otherwise, go back to economic CC. // This needs at least 2 CC. Otherwise, go back to economic CC.
// TODO add CC foundations (needed for allied) // TODO add CC foundations (needed for allied)
var ccEnts = gameState.getEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); var ccEnts = gameState.getEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
var ccList = [];
var numAllyCC = 0; var numAllyCC = 0;
for (var cc of ccEnts) for (var cc of ccEnts)
if (gameState.isPlayerAlly(cc.owner())) {
numAllyCC += 1; var ally = gameState.isPlayerAlly(cc.owner());
ccList.push({"pos": cc.position(), "ally": ally});
if (ally)
++numAllyCC;
}
if (numAllyCC < 2) if (numAllyCC < 2)
return this.findEconomicCCLocation(gameState, "wood", true); return this.findEconomicCCLocation(gameState, template, "wood", true);
Engine.ProfileStart("findStrategicCCLocation"); Engine.ProfileStart("findStrategicCCLocation");
// obstruction map // obstruction map
var obstructions = m.createObstructionMap(gameState, 0); var obstructions = m.createObstructionMap(gameState, 0, template);
obstructions.expandInfluences(); obstructions.expandInfluences();
var map = {};
var width = this.territoryMap.width; var width = this.territoryMap.width;
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
var bestIdx = undefined;
var bestVal = undefined;
var currentVal, delta;
var distcc0, distcc1, distcc2;
for (var j = 0; j < this.territoryMap.length; ++j) for (var j = 0; j < this.territoryMap.length; ++j)
{ {
@ -828,56 +839,68 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState)
var index = gameState.ai.accessibility.landPassMap[j]; var index = gameState.ai.accessibility.landPassMap[j];
if (!this.allowedRegions[index]) if (!this.allowedRegions[index])
continue; continue;
// and with enough room around to build the cc
if (obstructions.map[j] <= radius)
continue;
// checking distances to other cc // checking distances to other cc
var pos = [j%width+0.5, Math.floor(j/width)+0.5]; var pos = [j%width+0.5, Math.floor(j/width)+0.5];
pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]]; pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]];
var minDist = Math.min(); var minDist = Math.min();
var sumDelta = 0; distcc0 = undefined;
for (var cc of ccEnts)
for (var cc of ccList)
{ {
var ccPos = cc.position(); var dist = API3.SquareVectorDistance(cc.pos, pos);
var dist = API3.SquareVectorDistance(ccPos, pos);
if (dist < 14000) // Reject if too near from any cc if (dist < 14000) // Reject if too near from any cc
{ {
minDist = 0; minDist = 0;
break; break;
} }
if (!gameState.isPlayerAlly(cc.owner())) if (!cc.ally)
continue; continue;
if (dist < 40000) // Reject if quite near from ally cc if (dist < 40000) // Reject if quite near from ally cc
{ {
minDist = 0; minDist = 0;
break; break;
} }
var delta = Math.sqrt(dist) - 300;
if (cc.owner === PlayerID) // small preference territory continuity with our territory
delta = 1.05*delta; // rather than ally one
sumDelta += delta*delta;
if (dist < minDist) if (dist < minDist)
minDist = dist; minDist = dist;
if (!distcc0 || dist < distcc0)
{
distcc2 = distcc1;
distcc1 = distcc0;
distcc0 = dist;
}
else if (!distcc1 || dist < distcc1)
{
distcc2 = distcc1;
distcc1 = dist;
}
else if (!distcc2 || dist < distcc2)
distcc2 = dist;
} }
if (minDist < 1 || (minDist > 170000 && !this.navalMap)) if (minDist < 1 || (minDist > 170000 && !this.navalMap))
continue; continue;
map[j] = 10 + sumDelta; delta = Math.sqrt(distcc0) - 300; // favor a distance of 300
currentVal = delta*delta;
delta = Math.sqrt(distcc1) - 300;
currentVal += delta*delta;
if (distcc2)
{
delta = Math.sqrt(distcc2) - 300;
currentVal += delta*delta;
}
// disfavor border of the map // disfavor border of the map
if (this.borderMap.map[j] === 1) if (this.borderMap.map[j] === 1)
map[j] = map[j] + 10000; currentVal += 10000;
}
var bestIdx = undefined; if (bestVal !== undefined && currentVal > bestVal)
var bestVal = undefined;
var radius = 6;
for (var i in map)
{
if (obstructions.map[+i] <= radius)
continue; continue;
var v = map[i]; bestVal = currentVal;
if (bestVal !== undefined && v > bestVal) bestIdx = j;
continue;
bestVal = v;
bestIdx = i;
} }
if (this.Config.debug > 0) if (this.Config.debug > 0)
@ -923,8 +946,10 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
var obstructions = m.createObstructionMap(gameState, 0); var obstructions = m.createObstructionMap(gameState, 0);
obstructions.expandInfluences(); obstructions.expandInfluences();
var map = {};
var width = this.territoryMap.width; var width = this.territoryMap.width;
var bestIdx = undefined;
var bestVal = undefined;
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
for (var j = 0; j < this.territoryMap.length; ++j) for (var j = 0; j < this.territoryMap.length; ++j)
{ {
@ -933,13 +958,12 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
continue; continue;
if (this.basesMap.map[j] === 0) // inaccessible cell if (this.basesMap.map[j] === 0) // inaccessible cell
continue; continue;
if (obstructions.map[j] <= radius) // check room around
continue;
var ix = j%width; var index = gameState.ai.accessibility.landPassMap[j];
var iy = Math.floor(j/width); var pos = [j%width+0.5, Math.floor(j/width)+0.5];
var pos = [ix+0.5, iy+0.5];
pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]]; pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]];
var index = gameState.ai.accessibility.getAccessValue(pos);
// checking distances to other markets // checking distances to other markets
var maxDist = 0; var maxDist = 0;
for (var market of markets) for (var market of markets)
@ -956,22 +980,10 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
} }
if (maxDist == 0) if (maxDist == 0)
continue; continue;
if (bestVal !== undefined && maxDist < bestVal)
map[j] = maxDist;
}
var bestIdx = undefined;
var bestVal = undefined;
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
for (var i in map)
{
if (obstructions.map[+i] <= radius)
continue; continue;
var v = map[i]; bestVal = maxDist;
if (bestVal !== undefined && v < bestVal) bestIdx = j;
continue;
bestVal = v;
bestIdx = i;
} }
if (this.Config.debug > 0) if (this.Config.debug > 0)
@ -997,11 +1009,17 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template)
var enemyStructures = gameState.getEnemyStructures().filter(API3.Filters.byClassesOr(["CivCentre", "Fortress", "Tower"])).toEntityArray(); var enemyStructures = gameState.getEnemyStructures().filter(API3.Filters.byClassesOr(["CivCentre", "Fortress", "Tower"])).toEntityArray();
// obstruction map // obstruction map
var obstructions = m.createObstructionMap(gameState, 0); var obstructions = m.createObstructionMap(gameState, 0, template);
obstructions.expandInfluences(); obstructions.expandInfluences();
var map = {};
var width = this.territoryMap.width; var width = this.territoryMap.width;
var bestIdx = undefined;
var bestVal = undefined;
if (template.hasClass("Fortress"))
var radius = Math.floor(template.obstructionRadius() / gameState.cellSize) + 2;
else
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
for (var j = 0; j < this.territoryMap.length; ++j) for (var j = 0; j < this.territoryMap.length; ++j)
{ {
// do not try if well inside or outside territory // do not try if well inside or outside territory
@ -1011,10 +1029,10 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template)
continue; continue;
if (this.basesMap.map[j] === 0) // inaccessible cell if (this.basesMap.map[j] === 0) // inaccessible cell
continue; continue;
if (obstructions.map[j] <= radius) // check room around
continue;
var ix = j%width; var pos = [j%width+0.5, Math.floor(j/width)+0.5];
var iy = Math.floor(j/width);
var pos = [ix+0.5, iy+0.5];
pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]]; pos = [gameState.cellSize*pos[0], gameState.cellSize*pos[1]];
// checking distances to other structures // checking distances to other structures
var minDist = Math.min(); var minDist = Math.min();
@ -1055,25 +1073,9 @@ m.HQ.prototype.findDefensiveLocation = function(gameState, template)
} }
if (minDist < 0) if (minDist < 0)
continue; continue;
if (bestVal !== undefined && minDist > bestVal)
map[j] = minDist;
}
var bestIdx = undefined;
var bestVal = undefined;
if (template.hasClass("Fortress"))
var radius = Math.floor(template.obstructionRadius() / gameState.cellSize) + 2;
else
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
for (var j in map)
{
if (obstructions.map[+j] <= radius)
continue; continue;
var v = map[j]; bestVal = minDist;
if (bestVal !== undefined && v > bestVal)
continue;
bestVal = v;
bestIdx = j; bestIdx = j;
} }
@ -1538,7 +1540,7 @@ m.HQ.prototype.updateTerritories = function(gameState)
else if (this.basesMap.map[j] === 0) else if (this.basesMap.map[j] === 0)
{ {
var index = gameState.ai.accessibility.landPassMap[j]; var index = gameState.ai.accessibility.landPassMap[j];
if (!gameState.ai.HQ.allowedRegions[index]) if (!this.allowedRegions[index])
continue; continue;
var distmin = Math.min(); var distmin = Math.min();
var baseID = undefined; var baseID = undefined;

View File

@ -94,9 +94,9 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
if (template.hasClass("CivCentre")) if (template.hasClass("CivCentre"))
{ {
if (this.metadata.type) if (this.metadata.type)
var pos = gameState.ai.HQ.findEconomicCCLocation(gameState, this.metadata.type); var pos = gameState.ai.HQ.findEconomicCCLocation(gameState, template, this.metadata.type);
else else
var pos = gameState.ai.HQ.findStrategicCCLocation(gameState); var pos = gameState.ai.HQ.findStrategicCCLocation(gameState, template);
if (pos) if (pos)
return { "x": pos[0], "z": pos[1], "angle": 3*Math.PI/4, "xx": pos[0], "zz": pos[1], "base": 0 }; return { "x": pos[0], "z": pos[1], "angle": 3*Math.PI/4, "xx": pos[0], "zz": pos[1], "base": 0 };