add AI support of maps of different dimensions, see #2960
This was SVN commit r16062.
This commit is contained in:
parent
49187dd990
commit
9684bcd360
@ -6,28 +6,48 @@ var API3 = function(m)
|
||||
*/
|
||||
|
||||
// The function needs to be named too because of the copyConstructor functionality
|
||||
m.Map = function Map(sharedScript, originalMap, actualCopy)
|
||||
m.Map = function Map(sharedScript, type, originalMap, actualCopy)
|
||||
{
|
||||
// get the map to find out the correct dimensions
|
||||
var gameMap = sharedScript.passabilityMap;
|
||||
this.width = gameMap.width;
|
||||
this.height = gameMap.height;
|
||||
this.length = gameMap.data.length;
|
||||
|
||||
// get the correct dimensions according to the map type
|
||||
if (type === "territory")
|
||||
{
|
||||
var map = sharedScript.territoryMap;
|
||||
this.width = map.width;
|
||||
this.height = map.height;
|
||||
this.cellSize = map.cellSize;
|
||||
}
|
||||
else if (type === "resource")
|
||||
{
|
||||
this.cellSize = 4;
|
||||
var map = sharedScript.passabilityMap;
|
||||
this.width = map.width * map.cellSize / this.cellSize;
|
||||
this.height = map.height * map.cellSize / this.cellSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
var map = sharedScript.passabilityMap;
|
||||
this.width = map.width;
|
||||
this.height = map.height;
|
||||
this.cellSize = map.cellSize;
|
||||
}
|
||||
this.length = this.width * this.height;
|
||||
|
||||
this.maxVal = 255;
|
||||
|
||||
// sanity check
|
||||
if (originalMap && originalMap.length !== this.length)
|
||||
warn("AI map size incompatibility with type " + type + ": original " + originalMap.length + " new " + this.length);
|
||||
|
||||
if (originalMap && actualCopy)
|
||||
{
|
||||
this.map = new Uint8Array(this.length);
|
||||
for (let i = 0; i < originalMap.length; ++i)
|
||||
for (let i = 0; i < this.length; ++i)
|
||||
this.map[i] = originalMap[i];
|
||||
}
|
||||
else if (originalMap)
|
||||
this.map = originalMap;
|
||||
else
|
||||
this.map = new Uint8Array(this.length);
|
||||
|
||||
this.cellSize = 4;
|
||||
};
|
||||
|
||||
m.Map.prototype.setMaxVal = function(val)
|
||||
|
@ -26,6 +26,11 @@ m.SharedScript = function(settings)
|
||||
this._entityCollectionsByDynProp = {};
|
||||
this._entityCollectionsUID = 0;
|
||||
|
||||
// size of the map
|
||||
// TODO should be set in settings, for the time being recompute it assuming the passability cell size
|
||||
this.sizeMap = undefined;
|
||||
this.passabilityCell = 4;
|
||||
|
||||
// A few notes about these maps. They're updated by checking for "create" and "destroy" events for all resources
|
||||
// TODO: change the map when the resource amounts change for at least stone and metal mines.
|
||||
this.resourceMaps = {}; // Contains maps showing the density of wood, stone and metal
|
||||
@ -141,15 +146,19 @@ m.SharedScript.prototype.init = function(state, deserialization)
|
||||
this.ApplyTemplatesDelta(state);
|
||||
|
||||
this.passabilityClasses = state.passabilityClasses;
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.players = this._players;
|
||||
this.playersData = state.players;
|
||||
this.territoryMap = state.territoryMap;
|
||||
this.timeElapsed = state.timeElapsed;
|
||||
this.circularMap = state.circularMap;
|
||||
this.gameType = state.gameType;
|
||||
this.barterPrices = state.barterPrices;
|
||||
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.passabilityMap.cellSize = this.passabilityCell;
|
||||
this.sizeMap = this.passabilityMap.width * this.passabilityMap.cellSize;
|
||||
this.territoryMap = state.territoryMap;
|
||||
this.territoryMap.cellSize = this.sizeMap / this.territoryMap.width;
|
||||
|
||||
if (!deserialization)
|
||||
{
|
||||
this._entities = new Map();
|
||||
@ -195,11 +204,14 @@ m.SharedScript.prototype.onUpdate = function(state)
|
||||
// those are dynamic and need to be reset as the "state" object moves in memory.
|
||||
this.events = state.events;
|
||||
this.passabilityClasses = state.passabilityClasses;
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.playersData = state.players;
|
||||
this.territoryMap = state.territoryMap;
|
||||
this.timeElapsed = state.timeElapsed;
|
||||
this.barterPrices = state.barterPrices;
|
||||
|
||||
this.passabilityMap = state.passabilityMap;
|
||||
this.passabilityMap.cellSize = this.sizeMap / this.passabilityMap.width;
|
||||
this.territoryMap = state.territoryMap;
|
||||
this.territoryMap.cellSize = this.sizeMap / this.territoryMap.width;
|
||||
|
||||
for (var i in this.gameState)
|
||||
this.gameState[i].update(this,state);
|
||||
|
@ -17,7 +17,7 @@ var API3 = function(m)
|
||||
m.aStarPath = function(gameState, onWater, disregardEntities, targetTerritory)
|
||||
{
|
||||
// get the terrain analyzer map as a reference.
|
||||
this.Map(gameState.ai, gameState.ai.terrainAnalyzer.map);
|
||||
this.Map(gameState.ai, "passability", gameState.ai.terrainAnalyzer.map);
|
||||
// get the accessibility as a reference
|
||||
this.accessibility = gameState.ai.accessibility;
|
||||
this.terrainAnalyzer = gameState.ai.terrainAnalyzer;
|
||||
|
@ -17,8 +17,7 @@ var API3 = function(m)
|
||||
|
||||
m.TerrainAnalysis = function()
|
||||
{
|
||||
this.cellSize = 4;
|
||||
}
|
||||
};
|
||||
|
||||
m.copyPrototype(m.TerrainAnalysis, m.Map);
|
||||
|
||||
@ -27,11 +26,12 @@ m.TerrainAnalysis.prototype.init = function(sharedScript,rawState)
|
||||
var passabilityMap = rawState.passabilityMap;
|
||||
this.width = passabilityMap.width;
|
||||
this.height = passabilityMap.height;
|
||||
this.cellSize = passabilityMap.cellSize;
|
||||
|
||||
// the first two won't change, the third is a reference to a value updated by C++
|
||||
this.obstructionMaskLand = rawState.passabilityClasses["default"];
|
||||
this.obstructionMaskWater = rawState.passabilityClasses["ship"];
|
||||
this.obstructionMask = rawState.passabilityClasses["pathfinderObstruction"];
|
||||
var obstructionMaskLand = rawState.passabilityClasses["default"];
|
||||
var obstructionMaskWater = rawState.passabilityClasses["ship"];
|
||||
var obstructionMask = rawState.passabilityClasses["pathfinderObstruction"];
|
||||
|
||||
var obstructionTiles = new Uint8Array(passabilityMap.data.length);
|
||||
|
||||
@ -48,11 +48,11 @@ m.TerrainAnalysis.prototype.init = function(sharedScript,rawState)
|
||||
for (var i = 0; i < passabilityMap.data.length; ++i)
|
||||
{
|
||||
// If impassable for land units, set to 0, else to 255.
|
||||
obstructionTiles[i] = (passabilityMap.data[i] & this.obstructionMaskLand) ? 0 : 255;
|
||||
obstructionTiles[i] = (passabilityMap.data[i] & obstructionMaskLand) ? 0 : 255;
|
||||
|
||||
if (!(passabilityMap.data[i] & this.obstructionMaskWater) && obstructionTiles[i] === 0)
|
||||
if (!(passabilityMap.data[i] & obstructionMaskWater) && obstructionTiles[i] === 0)
|
||||
obstructionTiles[i] = 200; // if navigable and not walkable (ie basic water), set to 200.
|
||||
else if (!(passabilityMap.data[i] & this.obstructionMaskWater) && obstructionTiles[i] === 255)
|
||||
else if (!(passabilityMap.data[i] & obstructionMaskWater) && obstructionTiles[i] === 255)
|
||||
obstructionTiles[i] = 201; // navigable and walkable.
|
||||
}
|
||||
|
||||
@ -102,14 +102,7 @@ m.TerrainAnalysis.prototype.init = function(sharedScript,rawState)
|
||||
}
|
||||
}
|
||||
// Okay now we have a pretty good knowledge of the map.
|
||||
this.Map(rawState, obstructionTiles);
|
||||
|
||||
this.obstructionMaskLand = null;
|
||||
this.obstructionMaskWater = null;
|
||||
this.obstructionMask = null;
|
||||
delete this.obstructionMaskLand;
|
||||
delete this.obstructionMaskWater;
|
||||
delete this.obstructionMask;
|
||||
this.Map(rawState, "passability", obstructionTiles);
|
||||
};
|
||||
|
||||
// Returns the (approximately) closest point which is passable by searching in a spiral pattern
|
||||
@ -255,7 +248,7 @@ m.copyPrototype(m.Accessibility, m.TerrainAnalysis);
|
||||
|
||||
m.Accessibility.prototype.init = function(rawState, terrainAnalyser)
|
||||
{
|
||||
this.Map(rawState, terrainAnalyser.map);
|
||||
this.Map(rawState, "passability", terrainAnalyser.map);
|
||||
this.landPassMap = new Uint8Array(terrainAnalyser.length);
|
||||
this.navalPassMap = new Uint8Array(terrainAnalyser.length);
|
||||
|
||||
@ -696,18 +689,17 @@ m.SharedScript.prototype.createResourceMaps = function(sharedScript) {
|
||||
{
|
||||
// We're creting them 8-bit. Things could go above 255 if there are really tons of resources
|
||||
// But at that point the precision is not really important anyway. And it saves memory.
|
||||
this.resourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));
|
||||
this.resourceMaps[resource].setMaxVal(255);
|
||||
this.CCResourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));
|
||||
this.CCResourceMaps[resource].setMaxVal(255);
|
||||
this.resourceMaps[resource] = new m.Map(sharedScript, "resource");
|
||||
this.CCResourceMaps[resource] = new m.Map(sharedScript, "resource");
|
||||
}
|
||||
}
|
||||
var cellSize = this.resourceMaps["food"].cellSize;
|
||||
for (let ent of sharedScript._entities.values())
|
||||
{
|
||||
if (ent && ent.position() && ent.resourceSupplyType() && ent.resourceSupplyType().generic !== "treasure") {
|
||||
var resource = ent.resourceSupplyType().generic;
|
||||
var x = Math.floor(ent.position()[0] / 4);
|
||||
var z = Math.floor(ent.position()[1] / 4);
|
||||
var x = Math.floor(ent.position()[0] / cellSize);
|
||||
var z = Math.floor(ent.position()[1] / cellSize);
|
||||
var strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]);
|
||||
if (resource === "wood" || resource === "food")
|
||||
{
|
||||
@ -740,13 +732,11 @@ m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events)
|
||||
{
|
||||
// We're creting them 8-bit. Things could go above 255 if there are really tons of resources
|
||||
// But at that point the precision is not really important anyway. And it saves memory.
|
||||
this.resourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));
|
||||
this.resourceMaps[resource].setMaxVal(255);
|
||||
this.CCResourceMaps[resource] = new m.Map(sharedScript, new Uint8Array(sharedScript.passabilityMap.data.length));
|
||||
this.CCResourceMaps[resource].setMaxVal(255);
|
||||
this.resourceMaps[resource] = new m.Map(sharedScript, "resource");
|
||||
this.CCResourceMaps[resource] = new m.Map(sharedScript, "resource");
|
||||
}
|
||||
}
|
||||
|
||||
var cellSize = this.resourceMaps["food"].cellSize;
|
||||
// Look for destroy events and subtract the entities original influence from the resourceMap
|
||||
// TODO: perhaps do something when dropsites appear/disappear.
|
||||
let destEvents = events["Destroy"];
|
||||
@ -760,8 +750,8 @@ m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events)
|
||||
if (ent && ent.position() && ent.resourceSupplyType() && ent.resourceSupplyType().generic !== "treasure")
|
||||
{
|
||||
let resource = ent.resourceSupplyType().generic;
|
||||
let x = Math.floor(ent.position()[0] / 4);
|
||||
let z = Math.floor(ent.position()[1] / 4);
|
||||
let x = Math.floor(ent.position()[0] / cellSize);
|
||||
let z = Math.floor(ent.position()[1] / cellSize);
|
||||
let strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]);
|
||||
if (resource === "wood" || resource === "food")
|
||||
{
|
||||
@ -786,8 +776,8 @@ m.SharedScript.prototype.updateResourceMaps = function(sharedScript, events)
|
||||
if (ent && ent.position() && ent.resourceSupplyType() && ent.resourceSupplyType().generic !== "treasure")
|
||||
{
|
||||
let resource = ent.resourceSupplyType().generic;
|
||||
let x = Math.floor(ent.position()[0] / 4);
|
||||
let z = Math.floor(ent.position()[1] / 4);
|
||||
let x = Math.floor(ent.position()[0] / cellSize);
|
||||
let z = Math.floor(ent.position()[1] / cellSize);
|
||||
let strength = Math.floor(ent.resourceSupplyMax()/this.decreaseFactor[resource]);
|
||||
if (resource === "wood" || resource === "food")
|
||||
{
|
||||
|
@ -301,7 +301,7 @@ m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource)
|
||||
var width = obstructions.width;
|
||||
var bestIdx = undefined;
|
||||
var bestVal = undefined;
|
||||
var radius = Math.ceil(template.obstructionRadius() / gameState.cellSize);
|
||||
var radius = Math.ceil(template.obstructionRadius() / obstructions.cellSize);
|
||||
|
||||
for (var p = 0; p < this.territoryIndices.length; ++p)
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ m.HQ.prototype.init = function(gameState, queues, deserializing)
|
||||
{
|
||||
this.territoryMap = m.createTerritoryMap(gameState);
|
||||
// initialize base map. Each pixel is a base ID, or 0 if not or not accessible
|
||||
this.basesMap = new API3.Map(gameState.sharedScript);
|
||||
this.basesMap = new API3.Map(gameState.sharedScript, "territory");
|
||||
// area of 10 cells on the border of the map : 0=inside map, 1=border map, 2=outside map
|
||||
this.borderMap = m.createBorderMap(gameState);
|
||||
// initialize frontier map. Each cell is 2 if on the near frontier, 1 on the frontier and 0 otherwise
|
||||
@ -287,7 +287,7 @@ m.HQ.prototype.start = function(gameState, deserializing)
|
||||
if (deserializing)
|
||||
{
|
||||
// Rebuild the base maps from the territory indices of each base
|
||||
this.basesMap = new API3.Map(gameState.sharedScript);
|
||||
this.basesMap = new API3.Map(gameState.sharedScript, "territory");
|
||||
for each (let base in this.baseManagers)
|
||||
for (let j of base.territoryIndices)
|
||||
this.basesMap.map[j] = base.ID;
|
||||
|
@ -115,7 +115,7 @@ m.createObstructionMap = function(gameState, accessIndex, template)
|
||||
}
|
||||
}
|
||||
|
||||
var map = new API3.Map(gameState.sharedScript, obstructionTiles);
|
||||
var map = new API3.Map(gameState.sharedScript, "passability", obstructionTiles);
|
||||
map.setMaxVal(255);
|
||||
|
||||
if (template && template.buildDistance())
|
||||
@ -143,8 +143,8 @@ m.createObstructionMap = function(gameState, accessIndex, template)
|
||||
m.createTerritoryMap = function(gameState)
|
||||
{
|
||||
var map = gameState.ai.territoryMap;
|
||||
|
||||
var ret = new API3.Map(gameState.sharedScript, map.data);
|
||||
|
||||
var ret = new API3.Map(gameState.sharedScript, "territory", map.data);
|
||||
ret.getOwner = function(p) { return this.point(p) & m.TERRITORY_PLAYER_MASK; };
|
||||
ret.getOwnerIndex = function(p) { return this.map[p] & m.TERRITORY_PLAYER_MASK; };
|
||||
return ret;
|
||||
@ -153,9 +153,9 @@ m.createTerritoryMap = function(gameState)
|
||||
// TODO check if not already done in obstruction maps
|
||||
m.createBorderMap = function(gameState)
|
||||
{
|
||||
var map = new API3.Map(gameState.sharedScript);
|
||||
var map = new API3.Map(gameState.sharedScript, "territory");
|
||||
var width = map.width;
|
||||
var border = 15;
|
||||
var border = Math.round(60 / map.cellSize);
|
||||
if (gameState.ai.circularMap)
|
||||
{
|
||||
var ic = (width - 1) / 2;
|
||||
@ -198,10 +198,10 @@ m.createFrontierMap = function(gameState, borderMap)
|
||||
var territoryMap = gameState.ai.HQ.territoryMap;
|
||||
const around = [ [-0.7,0.7], [0,1], [0.7,0.7], [1,0], [0.7,-0.7], [0,-1], [-0.7,-0.7], [-1,0] ];
|
||||
|
||||
var map = new API3.Map(gameState.sharedScript);
|
||||
var map = new API3.Map(gameState.sharedScript, "territory");
|
||||
var width = map.width;
|
||||
var insideSmall = 10;
|
||||
var insideLarge = 15;
|
||||
var insideSmall = Math.round(40 / map.cellSize);
|
||||
var insideLarge = Math.round(60 / map.cellSize);
|
||||
|
||||
for (var j = 0; j < territoryMap.length; ++j)
|
||||
{
|
||||
@ -248,9 +248,8 @@ m.getFrontierProximity = function(gameState, j, borderMap)
|
||||
var territoryMap = gameState.ai.HQ.territoryMap;
|
||||
const around = [ [-0.7,0.7], [0,1], [0.7,0.7], [1,0], [0.7,-0.7], [0,-1], [-0.7,-0.7], [-1,0] ];
|
||||
|
||||
var map = new API3.Map(gameState.sharedScript);
|
||||
var width = territoryMap.width;
|
||||
const step = 3;
|
||||
var step = Math.round(16 / territoryMap.cellSize);
|
||||
|
||||
if (gameState.isPlayerAlly(territoryMap.getOwnerIndex(j)))
|
||||
return 0;
|
||||
|
@ -146,7 +146,7 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState)
|
||||
|
||||
// Compute each tile's closeness to friendly structures:
|
||||
|
||||
var friendlyTiles = new API3.Map(gameState.sharedScript);
|
||||
var friendlyTiles = new API3.Map(gameState.sharedScript, "passability");
|
||||
|
||||
var alreadyHasHouses = false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user