Adds territory map to AI GameState, based on patch from quantumstate. Fixes #969.
Updates testbot and Jubot to support basic build restrictions. This was SVN commit r10408.
This commit is contained in:
parent
c73c0870f1
commit
1c081135ad
@ -79,11 +79,12 @@ BaseAI.prototype.HandleMessage = function(state)
|
||||
|
||||
this.entities = new EntityCollection(this, this._rawEntities);
|
||||
this.events = state.events;
|
||||
this.map = state.map;
|
||||
this.passabilityClasses = state.passabilityClasses;
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.player = this._player;
|
||||
this.playerData = state.players[this._player];
|
||||
this.templates = this._templates;
|
||||
this.territoryMap = state.territoryMap;
|
||||
this.timeElapsed = state.timeElapsed;
|
||||
|
||||
Engine.ProfileStop();
|
||||
@ -93,11 +94,12 @@ BaseAI.prototype.HandleMessage = function(state)
|
||||
// Clean up temporary properties, so they don't disturb the serializer
|
||||
delete this.entities;
|
||||
delete this.events;
|
||||
delete this.map;
|
||||
delete this.passabilityClasses;
|
||||
delete this.passabilityMap;
|
||||
delete this.player;
|
||||
delete this.playerData;
|
||||
delete this.templates;
|
||||
delete this.territoryMap;
|
||||
delete this.timeElapsed;
|
||||
};
|
||||
|
||||
|
@ -43,9 +43,9 @@ var GameState = Class({
|
||||
return new Resources(this.playerData.resourceCounts);
|
||||
},
|
||||
|
||||
getMap: function()
|
||||
getPassabilityMap: function()
|
||||
{
|
||||
return this.ai.map;
|
||||
return this.ai.passabilityMap;
|
||||
},
|
||||
|
||||
getPassabilityClassMask: function(name)
|
||||
@ -55,6 +55,11 @@ var GameState = Class({
|
||||
return this.ai.passabilityClasses[name];
|
||||
},
|
||||
|
||||
getTerritoryMap: function()
|
||||
{
|
||||
return this.ai.territoryMap;
|
||||
},
|
||||
|
||||
getOwnEntities: (function()
|
||||
{
|
||||
return new EntityCollection(this.ai, this.ai._ownEntities);
|
||||
|
@ -146,25 +146,56 @@ var BuildingConstructionPlan = Class({
|
||||
|
||||
var cellSize = 4; // size of each tile
|
||||
|
||||
// First, find all tiles that are far enough away from obstructions:
|
||||
|
||||
var map = gameState.getMap();
|
||||
var template = gameState.getTemplate(this.type);
|
||||
|
||||
// Find all tiles in valid territory that are far enough away from obstructions:
|
||||
var passabilityMap = gameState.getPassabilityMap();
|
||||
var territoryMap = gameState.getTerritoryMap();
|
||||
const TERRITORY_PLAYER_MASK = 0x7F;
|
||||
var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
|
||||
// Only accept valid land tiles (we don't handle docks yet)
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
|
||||
var obstructionTiles = new Uint16Array(map.data.length);
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
|
||||
if (passabilityMap.data.length != territoryMap.data.length)
|
||||
error("passability and territory data are not matched!");
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
|
||||
// See BuildRestrictions.js
|
||||
switch(template.buildPlacementType())
|
||||
{
|
||||
case "shore":
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-shore");
|
||||
break;
|
||||
case "land":
|
||||
default:
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
}
|
||||
|
||||
this.expandInfluences(obstructionTiles, map.width, map.height);
|
||||
var playerID = gameState.getPlayerID();
|
||||
var buildOwn = template.hasBuildTerritory("own");
|
||||
var buildAlly = template.hasBuildTerritory("ally");
|
||||
var buildNeutral = template.hasBuildTerritory("neutral");
|
||||
var buildEnemy = template.hasBuildTerritory("enemy");
|
||||
|
||||
var obstructionTiles = new Uint16Array(passabilityMap.data.length);
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
|
||||
var invalidTerritory = (
|
||||
(!buildOwn && tilePlayer == playerID) ||
|
||||
(!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) ||
|
||||
(!buildNeutral && tilePlayer == 0) ||
|
||||
(!buildEnemy && gameState.isPlayerEnemy(tilePlayer) && tilePlayer !=0)
|
||||
);
|
||||
obstructionTiles[i] = (invalidTerritory || (passabilityMap.data[i] & obstructionMask)) ? 0 : 65535;
|
||||
}
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
|
||||
|
||||
this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
|
||||
|
||||
// TODO: handle distance restrictions for e.g. CivCentres
|
||||
|
||||
// Compute each tile's closeness to friendly structures:
|
||||
|
||||
var friendlyTiles = new Uint16Array(map.data.length);
|
||||
var friendlyTiles = new Uint16Array(passabilityMap.data.length);
|
||||
|
||||
gameState.getOwnEntities().forEach(function(ent) {
|
||||
if (ent.hasClass("Structure"))
|
||||
@ -176,7 +207,7 @@ var BuildingConstructionPlan = Class({
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
|
||||
self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
}
|
||||
});
|
||||
|
||||
@ -190,20 +221,19 @@ var BuildingConstructionPlan = Class({
|
||||
// var pos = ent.position();
|
||||
// var x = Math.round(pos[0] / cellSize);
|
||||
// var z = Math.round(pos[1] / cellSize);
|
||||
// self.subtractInfluence(friendlyTiles, map.width, map.height, x, z, infl);
|
||||
// self.subtractInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
// Find target building's approximate obstruction radius,
|
||||
// and expand by a bit to make sure we're not too close
|
||||
var template = gameState.getTemplate(this.type);
|
||||
var radius = Math.ceil(template.obstructionRadius() / cellSize) + 1;
|
||||
|
||||
// Find the best non-obstructed tile
|
||||
var bestIdx = 0;
|
||||
var bestVal = -1;
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
if (obstructionTiles[i] > radius)
|
||||
{
|
||||
@ -220,11 +250,13 @@ var BuildingConstructionPlan = Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
var x = ((bestIdx % map.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
|
||||
var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
|
||||
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
|
||||
|
||||
// TODO: special dock placement requirements
|
||||
|
||||
// Fixed angle to match fixed starting cam
|
||||
var angle = 0.75*Math.PI;
|
||||
|
@ -148,30 +148,61 @@ var BuildingConstructionPlanEcon = Class({
|
||||
|
||||
var cellSize = 4; // size of each tile
|
||||
|
||||
// First, find all tiles that are far enough away from obstructions:
|
||||
|
||||
var map = gameState.getMap();
|
||||
var template = gameState.getTemplate(this.type);
|
||||
|
||||
// Find all tiles in valid territory that are far enough away from obstructions:
|
||||
var passabilityMap = gameState.getPassabilityMap();
|
||||
var territoryMap = gameState.getTerritoryMap();
|
||||
const TERRITORY_PLAYER_MASK = 0x7F;
|
||||
var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
|
||||
// Only accept valid land tiles (we don't handle docks yet)
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
|
||||
var obstructionTiles = new Uint16Array(map.data.length);
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
|
||||
if (passabilityMap.data.length != territoryMap.data.length)
|
||||
error("passability and territory data are not matched!");
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
|
||||
// See BuildRestrictions.js
|
||||
switch(template.buildPlacementType())
|
||||
{
|
||||
case "shore":
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-shore");
|
||||
break;
|
||||
case "land":
|
||||
default:
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
}
|
||||
|
||||
this.expandInfluences(obstructionTiles, map.width, map.height);
|
||||
var playerID = gameState.getPlayerID();
|
||||
var buildOwn = template.hasBuildTerritory("own");
|
||||
var buildAlly = template.hasBuildTerritory("ally");
|
||||
var buildNeutral = template.hasBuildTerritory("neutral");
|
||||
var buildEnemy = template.hasBuildTerritory("enemy");
|
||||
|
||||
var obstructionTiles = new Uint16Array(passabilityMap.data.length);
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
|
||||
var invalidTerritory = (
|
||||
(!buildOwn && tilePlayer == playerID) ||
|
||||
(!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) ||
|
||||
(!buildNeutral && tilePlayer == 0) ||
|
||||
(!buildEnemy && gameState.isPlayerEnemy(tilePlayer) && tilePlayer !=0)
|
||||
);
|
||||
obstructionTiles[i] = (invalidTerritory || (passabilityMap.data[i] & obstructionMask)) ? 0 : 65535;
|
||||
}
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
|
||||
|
||||
this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
|
||||
|
||||
// TODO: handle distance restrictions for e.g. CivCentres
|
||||
|
||||
// Compute each tile's closeness to friendly structures:
|
||||
|
||||
var friendlyTiles = new Uint16Array(map.data.length);
|
||||
var friendlyTiles = new Uint16Array(passabilityMap.data.length);
|
||||
var infl = 100;
|
||||
var pos = this.resourceposition;
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
|
||||
self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
|
||||
//Look at making sure we're a long way from enemy civ centres as well.
|
||||
|
||||
@ -184,7 +215,7 @@ var BuildingConstructionPlanEcon = Class({
|
||||
// Find the best non-obstructed tile
|
||||
var bestIdx = 0;
|
||||
var bestVal = -1;
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
if (obstructionTiles[i] > radius)
|
||||
{
|
||||
@ -201,11 +232,11 @@ var BuildingConstructionPlanEcon = Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
var x = ((bestIdx % map.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
|
||||
var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
|
||||
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
|
||||
|
||||
// Fixed angle to match fixed starting cam
|
||||
var angle = 0.75*Math.PI;
|
||||
@ -225,23 +256,23 @@ var BuildingConstructionPlanEcon = Class({
|
||||
|
||||
// First, find all tiles that are far enough away from obstructions:
|
||||
|
||||
var map = gameState.getMap();
|
||||
var passabilityMap = gameState.getPassabilityMap();
|
||||
|
||||
var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
|
||||
// Only accept valid land tiles (we don't handle docks yet)
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
|
||||
var obstructionTiles = new Uint16Array(map.data.length);
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
|
||||
var obstructionTiles = new Uint16Array(passabilityMap.data.length);
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
obstructionTiles[i] = (passabilityMap.data[i] & obstructionMask) ? 0 : 65535;
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
|
||||
|
||||
this.expandInfluences(obstructionTiles, map.width, map.height);
|
||||
this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
|
||||
|
||||
// Compute each tile's closeness to friendly structures:
|
||||
|
||||
var friendlyTiles = new Uint16Array(map.data.length);
|
||||
var friendlyTiles = new Uint16Array(passabilityMap.data.length);
|
||||
|
||||
gameState.getOwnEntities().forEach(function(ent) {
|
||||
if (ent.hasClass("Structure"))
|
||||
@ -253,13 +284,13 @@ var BuildingConstructionPlanEcon = Class({
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
|
||||
self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
}
|
||||
});
|
||||
|
||||
//Look at making sure we're a long way from enemy civ centres as well.
|
||||
|
||||
// var enemyTiles = new Uint16Array(map.data.length);
|
||||
// var enemyTiles = new Uint16Array(passabilityMap.data.length);
|
||||
//
|
||||
// var foetargets = gameState.entities.filter(function(ent) {
|
||||
// return (ent.isEnemy());
|
||||
@ -271,7 +302,7 @@ var BuildingConstructionPlanEcon = Class({
|
||||
// var pos = ent.position();
|
||||
// var x = Math.round(pos[0] / cellSize);
|
||||
// var z = Math.round(pos[1] / cellSize);
|
||||
// self.addInfluence(enemyTiles, map.width, map.height, x, z, infl);
|
||||
// self.addInfluence(enemyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
// }
|
||||
// });
|
||||
|
||||
@ -284,7 +315,7 @@ var BuildingConstructionPlanEcon = Class({
|
||||
// Find the best non-obstructed tile
|
||||
var bestIdx = 0;
|
||||
var bestVal = -1;
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
if (obstructionTiles[i] > radius)
|
||||
{
|
||||
@ -301,11 +332,11 @@ var BuildingConstructionPlanEcon = Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
var x = ((bestIdx % map.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
|
||||
var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
|
||||
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
|
||||
|
||||
// Randomise the angle a little, to look less artificial
|
||||
//var angle = Math.PI + (Math.random()*2-1) * Math.PI/24;
|
||||
|
@ -38,9 +38,9 @@ var GameState = Class({
|
||||
return new Resources(this.playerData.resourceCounts);
|
||||
},
|
||||
|
||||
getMap: function()
|
||||
getPassabilityMap: function()
|
||||
{
|
||||
return this.ai.map;
|
||||
return this.ai.passabilityMap;
|
||||
},
|
||||
|
||||
getPassabilityClassMask: function(name)
|
||||
@ -50,6 +50,11 @@ var GameState = Class({
|
||||
return this.ai.passabilityClasses[name];
|
||||
},
|
||||
|
||||
getTerritoryMap: function()
|
||||
{
|
||||
return this.ai.territoryMap;
|
||||
},
|
||||
|
||||
getOwnEntities: (function()
|
||||
{
|
||||
return new EntityCollection(this.ai, this.ai._ownEntities);
|
||||
|
@ -124,25 +124,56 @@ var BuildingConstructionPlan = Class({
|
||||
|
||||
var cellSize = 4; // size of each tile
|
||||
|
||||
// First, find all tiles that are far enough away from obstructions:
|
||||
|
||||
var map = gameState.getMap();
|
||||
var template = gameState.getTemplate(this.type);
|
||||
|
||||
// Find all tiles in valid territory that are far enough away from obstructions:
|
||||
var passabilityMap = gameState.getPassabilityMap();
|
||||
var territoryMap = gameState.getTerritoryMap();
|
||||
const TERRITORY_PLAYER_MASK = 0x7F;
|
||||
var obstructionMask = gameState.getPassabilityClassMask("foundationObstruction");
|
||||
// Only accept valid land tiles (we don't handle docks yet)
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
|
||||
var obstructionTiles = new Uint16Array(map.data.length);
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
obstructionTiles[i] = (map.data[i] & obstructionMask) ? 0 : 65535;
|
||||
if (passabilityMap.data.length != territoryMap.data.length)
|
||||
error("passability and territory data are not matched!");
|
||||
|
||||
// Engine.DumpImage("tiles0.png", obstructionTiles, map.width, map.height, 64);
|
||||
// See BuildRestrictions.js
|
||||
switch(template.buildPlacementType())
|
||||
{
|
||||
case "shore":
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-shore");
|
||||
break;
|
||||
case "land":
|
||||
default:
|
||||
obstructionMask |= gameState.getPassabilityClassMask("building-land");
|
||||
}
|
||||
|
||||
this.expandInfluences(obstructionTiles, map.width, map.height);
|
||||
var playerID = gameState.getPlayerID();
|
||||
var buildOwn = template.hasBuildTerritory("own");
|
||||
var buildAlly = template.hasBuildTerritory("ally");
|
||||
var buildNeutral = template.hasBuildTerritory("neutral");
|
||||
var buildEnemy = template.hasBuildTerritory("enemy");
|
||||
|
||||
var obstructionTiles = new Uint16Array(passabilityMap.data.length);
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK);
|
||||
var invalidTerritory = (
|
||||
(!buildOwn && tilePlayer == playerID) ||
|
||||
(!buildAlly && gameState.isPlayerAlly(tilePlayer) && tilePlayer != playerID) ||
|
||||
(!buildNeutral && tilePlayer == 0) ||
|
||||
(!buildEnemy && gameState.isPlayerEnemy(tilePlayer) && tilePlayer !=0)
|
||||
);
|
||||
obstructionTiles[i] = (invalidTerritory || (passabilityMap.data[i] & obstructionMask)) ? 0 : 65535;
|
||||
}
|
||||
|
||||
// Engine.DumpImage("obstruction"+playerID+".png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64);
|
||||
|
||||
this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height);
|
||||
|
||||
// TODO: handle distance restrictions for e.g. CivCentres
|
||||
|
||||
// Compute each tile's closeness to friendly structures:
|
||||
|
||||
var friendlyTiles = new Uint16Array(map.data.length);
|
||||
var friendlyTiles = new Uint16Array(passabilityMap.data.length);
|
||||
|
||||
gameState.getOwnEntities().forEach(function(ent) {
|
||||
if (ent.hasClass("Structure"))
|
||||
@ -154,19 +185,18 @@ var BuildingConstructionPlan = Class({
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
self.addInfluence(friendlyTiles, map.width, map.height, x, z, infl);
|
||||
self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl);
|
||||
}
|
||||
});
|
||||
|
||||
// Find target building's approximate obstruction radius,
|
||||
// and expand by a bit to make sure we're not too close
|
||||
var template = gameState.getTemplate(this.type);
|
||||
var radius = Math.ceil(template.obstructionRadius() / cellSize) + 2;
|
||||
|
||||
// Find the best non-obstructed tile
|
||||
var bestIdx = 0;
|
||||
var bestVal = -1;
|
||||
for (var i = 0; i < map.data.length; ++i)
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
if (obstructionTiles[i] > radius)
|
||||
{
|
||||
@ -178,12 +208,14 @@ var BuildingConstructionPlan = Class({
|
||||
}
|
||||
}
|
||||
}
|
||||
var x = ((bestIdx % map.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / map.width) + 0.5) * cellSize;
|
||||
var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize;
|
||||
var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize;
|
||||
|
||||
// Engine.DumpImage("tiles1.png", obstructionTiles, map.width, map.height, 32);
|
||||
// Engine.DumpImage("tiles2.png", friendlyTiles, map.width, map.height, 256);
|
||||
// Engine.DumpImage("influences"+playerID+".png", obstructionTiles, passabilityMap.width, passabilityMap.height, 32);
|
||||
// Engine.DumpImage("friendly"+playerID+".png", friendlyTiles, passabilityMap.width, passabilityMap.height, 256);
|
||||
|
||||
// TODO: special dock placement requirements
|
||||
|
||||
// Fixed angle to match fixed starting cam
|
||||
var angle = 0.75*Math.PI;
|
||||
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "simulation2/components/ICmpObstructionManager.h"
|
||||
#include "simulation2/components/ICmpRangeManager.h"
|
||||
#include "simulation2/components/ICmpTemplateManager.h"
|
||||
#include "simulation2/components/ICmpTerritoryManager.h"
|
||||
#include "simulation2/helpers/Grid.h"
|
||||
#include "simulation2/serialization/DebugSerializer.h"
|
||||
#include "simulation2/serialization/StdDeserializer.h"
|
||||
@ -272,7 +273,8 @@ public:
|
||||
m_PlayerMetadata.clear();
|
||||
m_Players.clear();
|
||||
m_GameState.reset();
|
||||
m_GameStateMapVal = CScriptValRooted();
|
||||
m_PassabilityMapVal = CScriptValRooted();
|
||||
m_TerritoryMapVal = CScriptValRooted();
|
||||
}
|
||||
|
||||
bool AddPlayer(const std::wstring& aiName, player_id_t player, bool callConstructor)
|
||||
@ -286,18 +288,26 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
void StartComputation(const shared_ptr<ScriptInterface::StructuredClone>& gameState, const Grid<u16>& map)
|
||||
void StartComputation(const shared_ptr<ScriptInterface::StructuredClone>& gameState, const Grid<u16>& passabilityMap, const Grid<u8>& territoryMap, bool territoryMapDirty)
|
||||
{
|
||||
ENSURE(m_CommandsComputed);
|
||||
|
||||
m_GameState = gameState;
|
||||
|
||||
if (map.m_DirtyID != m_GameStateMap.m_DirtyID)
|
||||
if (passabilityMap.m_DirtyID != m_PassabilityMap.m_DirtyID)
|
||||
{
|
||||
m_GameStateMap = map;
|
||||
m_PassabilityMap = passabilityMap;
|
||||
|
||||
JSContext* cx = m_ScriptInterface.GetContext();
|
||||
m_GameStateMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_GameStateMap));
|
||||
m_PassabilityMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_PassabilityMap));
|
||||
}
|
||||
|
||||
if (territoryMapDirty)
|
||||
{
|
||||
m_TerritoryMap = territoryMap;
|
||||
|
||||
JSContext* cx = m_ScriptInterface.GetContext();
|
||||
m_TerritoryMapVal = CScriptValRooted(cx, ScriptInterface::ToJSVal(cx, m_TerritoryMap));
|
||||
}
|
||||
|
||||
m_CommandsComputed = false;
|
||||
@ -432,7 +442,8 @@ private:
|
||||
{
|
||||
PROFILE("AI compute read state");
|
||||
state = m_ScriptInterface.ReadStructuredClone(m_GameState);
|
||||
m_ScriptInterface.SetProperty(state.get(), "map", m_GameStateMapVal, true);
|
||||
m_ScriptInterface.SetProperty(state.get(), "passabilityMap", m_PassabilityMapVal, true);
|
||||
m_ScriptInterface.SetProperty(state.get(), "territoryMap", m_TerritoryMapVal, true);
|
||||
}
|
||||
|
||||
// It would be nice to do
|
||||
@ -467,8 +478,10 @@ private:
|
||||
std::vector<shared_ptr<CAIPlayer> > m_Players; // use shared_ptr just to avoid copying
|
||||
|
||||
shared_ptr<ScriptInterface::StructuredClone> m_GameState;
|
||||
Grid<u16> m_GameStateMap;
|
||||
CScriptValRooted m_GameStateMapVal;
|
||||
Grid<u16> m_PassabilityMap;
|
||||
CScriptValRooted m_PassabilityMapVal;
|
||||
Grid<u8> m_TerritoryMap;
|
||||
CScriptValRooted m_TerritoryMapVal;
|
||||
|
||||
bool m_CommandsComputed;
|
||||
};
|
||||
@ -568,16 +581,28 @@ public:
|
||||
// Get the game state from AIInterface
|
||||
CScriptVal state = cmpAIInterface->GetRepresentation();
|
||||
|
||||
// Get the map data
|
||||
// Get the passability data
|
||||
Grid<u16> dummyGrid;
|
||||
const Grid<u16>* map = &dummyGrid;
|
||||
const Grid<u16>* passabilityMap = &dummyGrid;
|
||||
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSimContext(), SYSTEM_ENTITY);
|
||||
if (!cmpPathfinder.null())
|
||||
map = &cmpPathfinder->GetPassabilityGrid();
|
||||
passabilityMap = &cmpPathfinder->GetPassabilityGrid();
|
||||
|
||||
// Get the territory data
|
||||
// Since getting the territory grid can trigger a recalculation, we check NeedUpdate first
|
||||
bool territoryMapDirty = false;
|
||||
Grid<u8> dummyGrid2;
|
||||
const Grid<u8>* territoryMap = &dummyGrid2;
|
||||
CmpPtr<ICmpTerritoryManager> cmpTerritoryManager(GetSimContext(), SYSTEM_ENTITY);
|
||||
if (!cmpTerritoryManager.null() && cmpTerritoryManager->NeedUpdate(&m_TerritoriesDirtyID))
|
||||
{
|
||||
territoryMap = &cmpTerritoryManager->GetTerritoryGrid();
|
||||
territoryMapDirty = true;
|
||||
}
|
||||
|
||||
LoadPathfinderClasses(state);
|
||||
|
||||
m_Worker.StartComputation(scriptInterface.WriteStructuredClone(state.get()), *map);
|
||||
m_Worker.StartComputation(scriptInterface.WriteStructuredClone(state.get()), *passabilityMap, *territoryMap, territoryMapDirty);
|
||||
}
|
||||
|
||||
virtual void PushCommands()
|
||||
@ -605,6 +630,7 @@ private:
|
||||
std::vector<std::string> m_TemplateNames;
|
||||
size_t m_TemplateLoadedIdx;
|
||||
std::vector<std::pair<std::string, const CParamNode*> > m_Templates;
|
||||
size_t m_TerritoriesDirtyID;
|
||||
|
||||
void StartLoadEntityTemplates()
|
||||
{
|
||||
|
@ -236,3 +236,30 @@ template<> jsval ScriptInterface::ToJSVal<Grid<u16> >(JSContext* cx, const Grid<
|
||||
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
||||
template<> jsval ScriptInterface::ToJSVal<Grid<u8> >(JSContext* cx, const Grid<u8>& val)
|
||||
{
|
||||
JSObject* obj = JS_NewObject(cx, NULL, NULL, NULL);
|
||||
if (!obj)
|
||||
return JSVAL_VOID;
|
||||
|
||||
jsuint len = val.m_W * val.m_H;
|
||||
JSObject *darray = js_CreateTypedArray(cx, js::TypedArray::TYPE_UINT8, len);
|
||||
if (!darray)
|
||||
return JSVAL_VOID;
|
||||
|
||||
js::TypedArray *tdest = js::TypedArray::fromJSObject(darray);
|
||||
ENSURE(tdest->byteLength == len*sizeof(u8));
|
||||
|
||||
memcpy(tdest->data, val.m_Data, tdest->byteLength);
|
||||
|
||||
jsval w = ToJSVal(cx, val.m_W);
|
||||
jsval h = ToJSVal(cx, val.m_H);
|
||||
jsval data = OBJECT_TO_JSVAL(darray);
|
||||
|
||||
JS_SetProperty(cx, obj, "width", &w);
|
||||
JS_SetProperty(cx, obj, "height", &h);
|
||||
JS_SetProperty(cx, obj, "data", &data);
|
||||
|
||||
return OBJECT_TO_JSVAL(obj);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user