mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-19 14:53:56 -07:00
Petra: first step of base management rework needed for nomad maps
This was SVN commit r16122.
This commit is contained in:
parent
bb6003ea0c
commit
9b79b5b844
13 changed files with 478 additions and 307 deletions
|
|
@ -578,7 +578,7 @@ m.Entity = m.Class({
|
|||
return this._entity.idle;
|
||||
},
|
||||
|
||||
unitAIState: function() { return this._entity.unitAIState; },
|
||||
unitAIState: function() { if (this._entity.unitAIState) return this._entity.unitAIState; return undefined; },
|
||||
unitAIOrderData: function() { return this._entity.unitAIOrderData; },
|
||||
|
||||
// TODO understand why we have sometimes rounding problems with maxHitpoints ? making wrongly isHurt=true
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ m.PetraBot.prototype.CustomInit = function(gameState, sharedScript)
|
|||
this.turn = this.data.turn;
|
||||
this.playedTurn = this.data.playedTurn;
|
||||
this.elapsedTime = this.data.elapsedTime;
|
||||
this.myIndex = this.data.myIndex;
|
||||
this.savedEvents = this.data.savedEvents;
|
||||
for (let key in this.savedEvents)
|
||||
{
|
||||
|
|
@ -84,11 +83,6 @@ m.PetraBot.prototype.CustomInit = function(gameState, sharedScript)
|
|||
|
||||
this.HQ = new m.HQ(this.Config);
|
||||
|
||||
var myKeyEntities = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre"));
|
||||
if (myKeyEntities.length == 0)
|
||||
myKeyEntities = gameState.getOwnEntities();
|
||||
this.myIndex = this.accessibility.getAccessValue(myKeyEntities.toEntityArray()[0].position());
|
||||
|
||||
this.HQ.init(gameState, this.queues);
|
||||
|
||||
this.HQ.start(gameState);
|
||||
|
|
@ -161,7 +155,6 @@ m.PetraBot.prototype.Serialize = function()
|
|||
"turn": this.turn,
|
||||
"playedTurn": this.playedTurn,
|
||||
"elapsedTime": this.elapsedTime,
|
||||
"myIndex": this.myIndex,
|
||||
"savedEvents": savedEvents,
|
||||
"config": this.Config.Serialize(),
|
||||
"queueManager": this.queueManager.Serialize(),
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
|||
|
||||
// get a starting rallyPoint ... will be improved later
|
||||
var rallyPoint = undefined;
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
|
|
@ -413,7 +413,7 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events)
|
|||
var rallySame = undefined;
|
||||
var distminDiff = Math.min();
|
||||
var rallyDiff = undefined;
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
var anchor = base.anchor;
|
||||
if (!anchor || !anchor.position())
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ m.BaseManager.prototype.setAnchor = function(gameState, anchorEntity)
|
|||
this.anchor.setMetadata(PlayerID, "baseAnchor", true);
|
||||
this.buildings.updateEnt(this.anchor);
|
||||
this.accessIndex = gameState.ai.accessibility.getAccessValue(this.anchor.position());
|
||||
// in case all our other bases were destroyed, reaffect these destroyed bases to this base
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
// in case some of our other bases were destroyed, reaffect these destroyed bases to this base
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.anchor || base.newbase)
|
||||
if (base.anchor || base.newbaseID)
|
||||
continue;
|
||||
base.newbase = this.ID;
|
||||
base.newbaseID = this.ID;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
|
@ -108,31 +108,13 @@ m.BaseManager.prototype.checkEvents = function (gameState, events, queues)
|
|||
// sounds like we lost our anchor. Let's reaffect our units and buildings
|
||||
this.anchor = undefined;
|
||||
this.anchorId = undefined;
|
||||
var distmin = Math.min();
|
||||
var basemin = undefined;
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (!base.anchor)
|
||||
continue;
|
||||
var dist = API3.SquareVectorDistance(base.anchor.position(), ent.position());
|
||||
if (base.accessIndex != this.accessIndex)
|
||||
dist += 100000000;
|
||||
if (dist > distmin)
|
||||
continue;
|
||||
distmin = dist;
|
||||
basemin = base;
|
||||
}
|
||||
if (!basemin)
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn(" base " + this.ID + " destroyed and no other bases found");
|
||||
continue;
|
||||
}
|
||||
this.newbase = basemin.ID;
|
||||
this.units.forEach( function (ent) { ent.setMetadata(PlayerID, "base", basemin.ID); });
|
||||
this.buildings.forEach( function (ent) { ent.setMetadata(PlayerID, "base", basemin.ID); });
|
||||
}
|
||||
|
||||
let bestbase = m.getBestBase(ent, gameState);
|
||||
this.newbaseID = bestbase.ID;
|
||||
for (let entity of this.units.values())
|
||||
bestbase.assignEntity(entity);
|
||||
for (let entity of this.buildings.values())
|
||||
bestbase.assignEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -538,14 +520,14 @@ m.BaseManager.prototype.getGatherRates = function(gameState, currentRates)
|
|||
m.BaseManager.prototype.assignRolelessUnits = function(gameState)
|
||||
{
|
||||
// TODO: make this cleverer.
|
||||
var roleless = this.units.filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "role")));
|
||||
var self = this;
|
||||
roleless.forEach(function(ent) {
|
||||
var roleless = this.units.filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "role"))).values();
|
||||
for (var ent of roleless)
|
||||
{
|
||||
if (ent.hasClass("Worker") || ent.hasClass("CitizenSoldier") || ent.hasClass("FishingBoat"))
|
||||
ent.setMetadata(PlayerID, "role", "worker");
|
||||
else if (ent.hasClass("Support") && ent.hasClass("Elephant"))
|
||||
ent.setMetadata(PlayerID, "role", "worker");
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// If the numbers of workers on the resources is unbalanced then set some of workers to idle so
|
||||
|
|
@ -754,7 +736,7 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
|||
|
||||
if (workers.length < 2)
|
||||
{
|
||||
var noobs = gameState.ai.HQ.bulkPickWorkers(gameState, this.ID, 2);
|
||||
var noobs = gameState.ai.HQ.bulkPickWorkers(gameState, this, 2);
|
||||
if(noobs)
|
||||
{
|
||||
noobs.forEach(function (worker) {
|
||||
|
|
@ -919,19 +901,42 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair)
|
|||
|
||||
m.BaseManager.prototype.update = function(gameState, queues, events)
|
||||
{
|
||||
if (!this.anchor) // this base has been destroyed
|
||||
if (this.ID === gameState.ai.HQ.baseManagers[0].ID) // base for unaffected units
|
||||
{
|
||||
// transfer possible remaining units (probably they were in training during previous transfers)
|
||||
if (this.newbase)
|
||||
// if some active base, reassigns the workers/buildings
|
||||
// otherwise look for anything useful to do, i.e. treasures to gather
|
||||
if (gameState.ai.HQ.numActiveBase() > 0)
|
||||
{
|
||||
var newbase = this.newbase;
|
||||
this.units.forEach( function (ent) { ent.setMetadata(PlayerID, "base", newbase); });
|
||||
this.buildings.forEach( function (ent) { ent.setMetadata(PlayerID, "base", newbase); });
|
||||
for (var ent of this.units.values())
|
||||
m.getBestBase(ent, gameState).assignEntity(ent, gameState);
|
||||
for (var ent of this.buildings.values())
|
||||
m.getBestBase(ent, gameState).assignEntity(ent, gameState);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.assignRolelessUnits(gameState);
|
||||
this.reassignIdleWorkers(gameState);
|
||||
for (var ent of this.workers.values())
|
||||
this.workerObject.update(ent, gameState);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.anchor && this.anchor.getMetadata(PlayerID, "access") != this.accessIndex)
|
||||
if (!this.anchor) // this base has been destroyed
|
||||
{
|
||||
// transfer possible remaining units (probably they were in training during previous transfers)
|
||||
if (this.newbaseID)
|
||||
{
|
||||
var newbaseID = this.newbaseID;
|
||||
for (let ent of this.units.values())
|
||||
ent.setMetadata(PlayerID, "base", newbaseID);
|
||||
for (let ent of this.buildings.values())
|
||||
ent.setMetadata(PlayerID, "base", newbaseID);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.anchor.getMetadata(PlayerID, "access") != this.accessIndex)
|
||||
API3.warn("Petra baseManager " + this.ID + " problem with accessIndex " + this.accessIndex
|
||||
+ " while metadata access is " + this.anchor.getMetadata(PlayerID, "access"));
|
||||
|
||||
|
|
@ -940,7 +945,7 @@ m.BaseManager.prototype.update = function(gameState, queues, events)
|
|||
this.checkResourceLevels(gameState, queues);
|
||||
this.assignToFoundations(gameState);
|
||||
|
||||
if (this.constructing && this.anchor)
|
||||
if (this.constructing)
|
||||
{
|
||||
var owner = gameState.ai.HQ.territoryMap.getOwner(this.anchor.position());
|
||||
if(owner !== 0 && !gameState.isPlayerAlly(owner))
|
||||
|
|
@ -963,13 +968,10 @@ m.BaseManager.prototype.update = function(gameState, queues, events)
|
|||
this.setWorkersIdleByPriority(gameState);
|
||||
|
||||
this.assignRolelessUnits(gameState);
|
||||
|
||||
// should probably be last to avoid reallocations of units that would have done stuffs otherwise.
|
||||
this.reassignIdleWorkers(gameState);
|
||||
|
||||
// TODO: do this incrementally a la defense.js
|
||||
var self = this;
|
||||
this.workers.forEach(function(ent) { self.workerObject.update(ent, gameState); });
|
||||
// check if workers can find something useful to do
|
||||
for (var ent of this.workers.values())
|
||||
this.workerObject.update(ent, gameState);
|
||||
|
||||
Engine.ProfileStop();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ m.Config = function(difficulty)
|
|||
"targetNumTraders" : 4, // Target number of traders
|
||||
"targetNumFishers" : 1, // Target number of fishers per sea
|
||||
"femaleRatio" : 0.5, // fraction of females among the workforce
|
||||
"provisionFields" : 3
|
||||
"provisionFields" : 2
|
||||
};
|
||||
|
||||
this.distUnitGain = 110*110; // TODO take it directly from helpers/TraderGain.js
|
||||
|
|
@ -136,7 +136,7 @@ m.Config.prototype.setConfig = function(gameState)
|
|||
this.Economy.cityPhase = 1800;
|
||||
this.Economy.popForMarket = 80;
|
||||
this.Economy.femaleRatio = 0.6;
|
||||
this.Economy.provisionFields = 2;
|
||||
this.Economy.provisionFields = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -94,6 +94,43 @@ m.returnResources = function(ent, gameState)
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* get the best base (in terms of distance and accessIndex) for an entity
|
||||
*/
|
||||
m.getBestBase = function(ent, gameState)
|
||||
{
|
||||
var pos = ent.position();
|
||||
if (!pos)
|
||||
{
|
||||
var holder = m.getHolder(ent, gameState);
|
||||
if (!holder || !holder.position())
|
||||
{
|
||||
API3.warn("Petra error: entity without position, but not garrisoned");
|
||||
m.dumpEntity(ent);
|
||||
return gameState.ai.HQ.baseManagers[0];
|
||||
}
|
||||
pos = holder.position();
|
||||
}
|
||||
var distmin = Math.min();
|
||||
var bestbase = undefined;
|
||||
var accessIndex = gameState.ai.accessibility.getAccessValue(pos);
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (!base.anchor)
|
||||
continue;
|
||||
var dist = API3.SquareVectorDistance(base.anchor.position(), pos);
|
||||
if (base.accessIndex !== accessIndex)
|
||||
dist += 100000000;
|
||||
if (dist > distmin)
|
||||
continue;
|
||||
distmin = dist;
|
||||
bestbase = base;
|
||||
}
|
||||
if (!bestbase)
|
||||
bestbase = gameState.ai.HQ.baseManagers[0];
|
||||
return bestbase;
|
||||
};
|
||||
|
||||
m.getHolder = function(ent, gameState)
|
||||
{
|
||||
var found = undefined;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m.HQ = function(Config)
|
|||
this.fortressStartTime = 0;
|
||||
this.fortressLapseTime = this.Config.Military.fortressLapseTime;
|
||||
|
||||
this.baseManagers = {};
|
||||
this.baseManagers = [];
|
||||
this.attackManager = new m.AttackManager(this.Config);
|
||||
this.defenseManager = new m.DefenseManager(this.Config);
|
||||
this.tradeManager = new m.TradeManager(this.Config);
|
||||
|
|
@ -58,46 +58,10 @@ m.HQ.prototype.init = function(gameState, queues, deserializing)
|
|||
// initialize frontier map. Each cell is 2 if on the near frontier, 1 on the frontier and 0 otherwise
|
||||
this.frontierMap = m.createFrontierMap(gameState);
|
||||
// list of allowed regions
|
||||
this.allowedRegions = {};
|
||||
|
||||
this.landRegions = {};
|
||||
// try to determine if we have a water map
|
||||
this.navalMap = false;
|
||||
this.navalRegions = [];
|
||||
|
||||
var passabilityMap = gameState.getMap();
|
||||
var totalSize = passabilityMap.width * passabilityMap.width;
|
||||
var minLandSize = Math.floor(0.2*totalSize);
|
||||
var minWaterSize = Math.floor(0.3*totalSize);
|
||||
var cellArea = passabilityMap.cellSize * passabilityMap.cellSize;
|
||||
for (var i = 0; i < gameState.ai.accessibility.regionSize.length; ++i)
|
||||
{
|
||||
if (i == gameState.ai.myIndex)
|
||||
this.allowedRegions[i] = true;
|
||||
else if (gameState.ai.accessibility.regionType[i] === "land" && cellArea*gameState.ai.accessibility.regionSize[i] > 320)
|
||||
{
|
||||
var seaIndex = this.getSeaIndex(gameState, gameState.ai.myIndex, i);
|
||||
if (!seaIndex)
|
||||
continue;
|
||||
this.allowedRegions[i] = true;
|
||||
if (gameState.ai.accessibility.regionSize[i] > minLandSize)
|
||||
{
|
||||
this.navalMap = true;
|
||||
if (this.navalRegions.indexOf(seaIndex) == -1)
|
||||
this.navalRegions.push(seaIndex);
|
||||
}
|
||||
}
|
||||
else if (gameState.ai.accessibility.regionType[i] === "water" && gameState.ai.accessibility.regionSize[i] > minWaterSize)
|
||||
{
|
||||
this.navalMap = true;
|
||||
if (this.navalRegions.indexOf(i) == -1)
|
||||
this.navalRegions.push(i);
|
||||
}
|
||||
}
|
||||
if (this.Config.debug > 2)
|
||||
{
|
||||
for (var region in this.allowedRegions)
|
||||
API3.warn(" >>> zone " + region + " taille " + cellArea*gameState.ai.accessibility.regionSize[region]);
|
||||
}
|
||||
this.navalRegions = {};
|
||||
|
||||
if (this.Config.difficulty < 2)
|
||||
this.targetNumWorkers = Math.max(1, Math.min(40, Math.floor(gameState.getPopulationMax())));
|
||||
|
|
@ -117,6 +81,86 @@ m.HQ.prototype.init = function(gameState, queues, deserializing)
|
|||
if (deserializing)
|
||||
return;
|
||||
|
||||
// determine the main land Index (or water index if none)
|
||||
let landIndex = undefined;
|
||||
let seaIndex = undefined;
|
||||
var ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
for (let cc of ccEnts.values())
|
||||
{
|
||||
let land = gameState.ai.accessibility.getAccessValue(cc.position());
|
||||
if (land > 1)
|
||||
{
|
||||
landIndex = land;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!landIndex)
|
||||
{
|
||||
for (let ent of gameState.getOwnEntities().values())
|
||||
{
|
||||
if (!ent.position() || (!ent.hasClass("Unit") && !ent.trainableEntities()))
|
||||
continue;
|
||||
let land = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
if (land > 1)
|
||||
{
|
||||
landIndex = land;
|
||||
break;
|
||||
}
|
||||
let sea = gameState.ai.accessibility.getAccessValue(ent.position(), true);
|
||||
if (!seaIndex && sea > 1)
|
||||
seaIndex = sea;
|
||||
}
|
||||
}
|
||||
if (!landIndex && !seaIndex)
|
||||
API3.warn("Petra error: it does not know how to interpret this map");
|
||||
|
||||
var passabilityMap = gameState.getMap();
|
||||
var totalSize = passabilityMap.width * passabilityMap.width;
|
||||
var minLandSize = Math.floor(0.1*totalSize);
|
||||
var minWaterSize = Math.floor(0.3*totalSize);
|
||||
var cellArea = passabilityMap.cellSize * passabilityMap.cellSize;
|
||||
for (var i = 0; i < gameState.ai.accessibility.regionSize.length; ++i)
|
||||
{
|
||||
if (landIndex && i == landIndex)
|
||||
this.landRegions[i] = true;
|
||||
else if (gameState.ai.accessibility.regionType[i] === "land" && cellArea*gameState.ai.accessibility.regionSize[i] > 320)
|
||||
{
|
||||
if (landIndex)
|
||||
{
|
||||
var sea = this.getSeaIndex(gameState, landIndex, i);
|
||||
if (sea && (gameState.ai.accessibility.regionSize[i] > minLandSize || gameState.ai.accessibility.regionSize[sea] > minWaterSize))
|
||||
{
|
||||
this.navalMap = true;
|
||||
this.landRegions[i] = true;
|
||||
this.navalRegions[sea] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var traject = gameState.ai.accessibility.getTrajectToIndex(seaIndex, i);
|
||||
if (traject && traject.length === 2)
|
||||
{
|
||||
this.navalMap = true;
|
||||
this.landRegions[i] = true;
|
||||
this.navalRegions[seaIndex] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gameState.ai.accessibility.regionType[i] === "water" && gameState.ai.accessibility.regionSize[i] > minWaterSize)
|
||||
{
|
||||
this.navalMap = true;
|
||||
this.navalRegions[i] = true;
|
||||
}
|
||||
}
|
||||
if (this.Config.debug > 2)
|
||||
{
|
||||
for (var region in this.landRegions)
|
||||
API3.warn(" >>> zone " + region + " taille " + cellArea*gameState.ai.accessibility.regionSize[region]);
|
||||
API3.warn(" navalMap " + this.navalMap);
|
||||
API3.warn(" landRegions " + uneval(this.landRegions));
|
||||
API3.warn(" navalRegions " + uneval(this.navalRegions));
|
||||
}
|
||||
|
||||
// TODO: change that to something dynamic.
|
||||
var civ = gameState.playerData.civ;
|
||||
// load units and buildings from the config files
|
||||
|
|
@ -135,67 +179,104 @@ m.HQ.prototype.init = function(gameState, queues, deserializing)
|
|||
this.bAdvanced[i] = gameState.applyCiv(this.bAdvanced[i]);
|
||||
|
||||
// Let's get our initial situation here.
|
||||
var b0 = gameState.ai.uniqueIDs.bases;
|
||||
var ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
for (let i = 0; i < ccEnts.length; ++i)
|
||||
let nobase = new m.BaseManager(gameState, this.Config);
|
||||
nobase.init(gameState);
|
||||
nobase.accessIndex = 0;
|
||||
this.baseManagers.push(nobase); // baseManager[0] will deal with unit/structure witout bases
|
||||
var ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
for (let cc of ccEnts.values())
|
||||
{
|
||||
this.baseManagers[i+b0] = new m.BaseManager(gameState, this.Config);
|
||||
this.baseManagers[i+b0].init(gameState);
|
||||
this.baseManagers[i+b0].setAnchor(gameState, ccEnts[i]);
|
||||
let newbase = new m.BaseManager(gameState, this.Config);
|
||||
newbase.init(gameState);
|
||||
newbase.setAnchor(gameState, cc);
|
||||
this.baseManagers.push(newbase);
|
||||
}
|
||||
this.updateTerritories(gameState);
|
||||
|
||||
if (this.baseManagers[b0]) // Assign entities in the different bases
|
||||
// Assign entities in the different bases
|
||||
var defaultbase = (this.numActiveBase() > 0) ? 1 : 0;
|
||||
var width = gameState.getMap().width;
|
||||
for (var ent of gameState.getOwnEntities().values())
|
||||
{
|
||||
var self = this;
|
||||
var width = gameState.getMap().width;
|
||||
gameState.getOwnEntities().forEach( function (ent) {
|
||||
// do not affect merchant ship immediately to trade as they may-be useful for transport
|
||||
if (ent.hasClass("Trader") && !ent.hasClass("Ship"))
|
||||
self.tradeManager.assignTrader(ent);
|
||||
var pos = ent.position();
|
||||
if (!pos)
|
||||
{
|
||||
// TODO temporarily assigned to base 1. Certainly a garrisoned unit,
|
||||
// should assign it to the base of the garrison holder
|
||||
self.baseManagers[b0].assignEntity(ent);
|
||||
return;
|
||||
}
|
||||
ent.setMetadata(PlayerID, "access", gameState.ai.accessibility.getAccessValue(ent.position()));
|
||||
var x = Math.round(pos[0] / gameState.cellSize);
|
||||
var z = Math.round(pos[1] / gameState.cellSize);
|
||||
var id = x + width*z;
|
||||
for each (var base in self.baseManagers)
|
||||
{
|
||||
if (base.territoryIndices.indexOf(id) == -1)
|
||||
continue;
|
||||
base.assignEntity(ent);
|
||||
if (ent.resourceDropsiteTypes() && !ent.hasClass("Elephant"))
|
||||
base.assignResourceToDropsite(gameState, ent);
|
||||
return;
|
||||
}
|
||||
// entity outside our territory, assign it to base b0
|
||||
self.baseManagers[b0].assignEntity(ent);
|
||||
// make sure we have not rejected small regions with units (TODO should probably also check with other non-gaia units)
|
||||
if (ent.position())
|
||||
{
|
||||
let pos = gameState.ai.accessibility.gamePosToMapPos(ent.position());
|
||||
let index = pos[0] + pos[1]*gameState.ai.accessibility.width;
|
||||
let land = gameState.ai.accessibility.landPassMap[index];
|
||||
if (land > 1 && !this.landRegions[land])
|
||||
API3.warn("entity " + ent.genericName() + " in a not allowed land region " + land);
|
||||
if (land > 1 && !this.landRegions[land])
|
||||
this.landRegions[land] = true;
|
||||
let sea = gameState.ai.accessibility.navalPassMap[index];
|
||||
if (sea > 1 && !this.navalRegions[sea])
|
||||
API3.warn("entity " + ent.genericName() + " in a not allowed sea region " + sea);
|
||||
if (sea > 1 && !this.navalRegions[sea])
|
||||
this.navalRegions[sea] = true;
|
||||
}
|
||||
// if garrisoned units inside, ungarrison them except if a ship in which case we make a transport
|
||||
if (ent.isGarrisonHolder() && ent.garrisoned().length)
|
||||
{
|
||||
API3.warn(">>>>>>>>>>>>>>>> ent " + ent.id() + " name " + ent.genericName());
|
||||
m.dumpEntity(ent);
|
||||
API3.warn(" garrisoned " + uneval(ent.garrisoned()));
|
||||
if (!ent.hasClass("Ship"))
|
||||
for (let id of ent.garrisoned())
|
||||
ent.unload(id);
|
||||
else
|
||||
warn(" ship garrisoned >>> create a transport");
|
||||
}
|
||||
// do not affect merchant ship immediately to trade as they may-be useful for transport
|
||||
if (ent.hasClass("Trader") && !ent.hasClass("Ship"))
|
||||
this.tradeManager.assignTrader(ent);
|
||||
var pos = ent.position();
|
||||
if (!pos)
|
||||
continue;
|
||||
ent.setMetadata(PlayerID, "access", gameState.ai.accessibility.getAccessValue(pos));
|
||||
var x = Math.round(pos[0] / gameState.cellSize);
|
||||
var z = Math.round(pos[1] / gameState.cellSize);
|
||||
var id = x + width*z;
|
||||
var bestbase = undefined;
|
||||
for (var i = 1; i < this.baseManagers.length; ++i)
|
||||
{
|
||||
var base = this.baseManagers[i];
|
||||
if (base.territoryIndices.indexOf(id) == -1)
|
||||
continue;
|
||||
base.assignEntity(ent);
|
||||
if (ent.resourceDropsiteTypes() && !ent.hasClass("Elephant"))
|
||||
self.baseManagers[b0].assignResourceToDropsite(gameState, ent);
|
||||
});
|
||||
base.assignResourceToDropsite(gameState, ent);
|
||||
bestbase = base;
|
||||
break;
|
||||
}
|
||||
if (!bestbase)
|
||||
{
|
||||
// entity outside our territory
|
||||
var bestbase = m.getBestBase(ent, gameState);
|
||||
bestbase.assignEntity(ent);
|
||||
if (bestbase.ID !== this.baseManagers[0].ID && ent.resourceDropsiteTypes() && !ent.hasClass("Elephant"))
|
||||
bestbase.assignResourceToDropsite(gameState, ent);
|
||||
}
|
||||
// now assign entities garrisoned inside this entity
|
||||
if (ent.isGarrisonHolder() && ent.garrisoned().length)
|
||||
for (let id of ent.garrisoned())
|
||||
bestBase.assignEntity(gameState.getEntityByID(id));
|
||||
}
|
||||
|
||||
// we now have enough data to decide on a few things.
|
||||
|
||||
// immediatly build a wood dropsite if possible.
|
||||
if (this.baseManagers[1] && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_storehouse"), true) == 0)
|
||||
if (this.baseManagers.length > 1 && gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_storehouse"), true) == 0)
|
||||
{
|
||||
var newDP = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood");
|
||||
if (newDP.quality > 40 && this.canBuild(gameState, "structures/{civ}_storehouse"))
|
||||
queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse", { "base": 1 }, newDP.pos));
|
||||
queues.dropsites.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse", { "base": this.baseManagers[1].ID }, newDP.pos));
|
||||
}
|
||||
|
||||
// Check if we will ever be able to produce units
|
||||
this.canBuildUnits = true;
|
||||
if (!gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).length)
|
||||
{
|
||||
var template = gameState.getTemplate(this.bBase[0]);
|
||||
var template = gameState.getTemplate(gameState.applyCiv("structures/{civ}_civil_centre"));
|
||||
if (!template.available(gameState))
|
||||
{
|
||||
if (this.Config.debug > 1)
|
||||
|
|
@ -290,26 +371,26 @@ m.HQ.prototype.start = function(gameState, deserializing)
|
|||
{
|
||||
// Rebuild the base maps from the territory indices of each base
|
||||
this.basesMap = new API3.Map(gameState.sharedScript, "territory");
|
||||
for each (let base in this.baseManagers)
|
||||
for (let base of this.baseManagers)
|
||||
for (let j of base.territoryIndices)
|
||||
this.basesMap.map[j] = base.ID;
|
||||
|
||||
var self = this;
|
||||
gameState.getOwnEntities().forEach( function (ent) {
|
||||
for (let ent of gameState.getOwnEntities().values())
|
||||
{
|
||||
if (!ent.resourceDropsiteTypes() || ent.hasClass("Elephant"))
|
||||
return;
|
||||
let base = self.baseManagers[ent.getMetadata(PlayerID, "base")];
|
||||
continue;
|
||||
let base = this.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
base.assignResourceToDropsite(gameState, ent);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// adapt our starting strategy to the available resources
|
||||
// - if on a small island, favor fishing and require less fields to save room for buildings
|
||||
var startingSize = 0;
|
||||
for (var region in this.allowedRegions)
|
||||
for (let region in this.landRegions)
|
||||
{
|
||||
for each (var base in this.baseManagers)
|
||||
for (let base of this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || base.accessIndex != +region)
|
||||
continue;
|
||||
|
|
@ -332,7 +413,7 @@ m.HQ.prototype.start = function(gameState, deserializing)
|
|||
var check = {};
|
||||
for (var proxim of ["nearby", "medium", "faraway"])
|
||||
{
|
||||
for each (var base in this.baseManagers)
|
||||
for (let base of this.baseManagers)
|
||||
{
|
||||
for (var supply of base.dropsiteSupplies["wood"][proxim])
|
||||
{
|
||||
|
|
@ -385,17 +466,16 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
|||
if (ent.getMetadata(PlayerID, "base") == -1)
|
||||
{
|
||||
// Okay so let's try to create a new base around this.
|
||||
var bID = gameState.ai.uniqueIDs.bases;
|
||||
this.baseManagers[bID] = new m.BaseManager(gameState, this.Config);
|
||||
this.baseManagers[bID].init(gameState, true);
|
||||
this.baseManagers[bID].setAnchor(gameState, ent);
|
||||
|
||||
// Let's get a few units out there to build this.
|
||||
var builders = this.bulkPickWorkers(gameState, bID, 10);
|
||||
let newbase = new m.BaseManager(gameState, this.Config);
|
||||
newbase.init(gameState, true);
|
||||
newbase.setAnchor(gameState, ent);
|
||||
this.baseManagers.push(newbase);
|
||||
// Let's get a few units from other bases there to build this.
|
||||
var builders = this.bulkPickWorkers(gameState, newbase, 10);
|
||||
if (builders !== false)
|
||||
{
|
||||
builders.forEach(function (worker) {
|
||||
worker.setMetadata(PlayerID, "base", bID);
|
||||
worker.setMetadata(PlayerID, "base", newbase.ID);
|
||||
worker.setMetadata(PlayerID, "subrole", "builder");
|
||||
worker.setMetadata(PlayerID, "target-foundation", ent.id());
|
||||
});
|
||||
|
|
@ -403,15 +483,13 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
|||
}
|
||||
else if (ent.hasClass("Wonder") && gameState.getGameType() === "wonder")
|
||||
{
|
||||
var base = ent.getMetadata(PlayerID, "base");
|
||||
if (!base)
|
||||
API3.warn("Petra: wonder foundation without base ???");
|
||||
// Let's get a few units out there to build this.
|
||||
// Let's get a few units from other bases there to build this.
|
||||
var base = this.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
var builders = this.bulkPickWorkers(gameState, base, 10);
|
||||
if (builders !== false)
|
||||
{
|
||||
builders.forEach(function (worker) {
|
||||
worker.setMetadata(PlayerID, "base", base);
|
||||
worker.setMetadata(PlayerID, "base", baseID);
|
||||
worker.setMetadata(PlayerID, "subrole", "builder");
|
||||
worker.setMetadata(PlayerID, "target-foundation", ent.id());
|
||||
});
|
||||
|
|
@ -432,12 +510,12 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
|||
|
||||
if (ent.getMetadata(PlayerID, "baseAnchor") == true)
|
||||
{
|
||||
var base = ent.getMetadata(PlayerID, "base");
|
||||
if (this.baseManagers[base].constructing)
|
||||
this.baseManagers[base].constructing = false;
|
||||
this.baseManagers[base].anchor = ent;
|
||||
this.baseManagers[base].anchorId = evt.newentity;
|
||||
this.baseManagers[base].buildings.updateEnt(ent);
|
||||
let base = this.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
if (base.constructing)
|
||||
base.constructing = false;
|
||||
base.anchor = ent;
|
||||
base.anchorId = evt.newentity;
|
||||
base.buildings.updateEnt(ent);
|
||||
this.updateTerritories(gameState);
|
||||
// let us hope this new base will fix our resource shortage
|
||||
this.saveResources = undefined;
|
||||
|
|
@ -691,13 +769,13 @@ m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements
|
|||
|
||||
// returns an entity collection of workers through BaseManager.pickBuilders
|
||||
// TODO: when same accessIndex, sort by distance
|
||||
m.HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number)
|
||||
m.HQ.prototype.bulkPickWorkers = function(gameState, baseRef, number)
|
||||
{
|
||||
var accessIndex = this.baseManagers[newBaseID].accessIndex;
|
||||
var accessIndex = baseRef.accessIndex;
|
||||
if (!accessIndex)
|
||||
return false;
|
||||
// sorting bases by whether they are on the same accessindex or not.
|
||||
var baseBest = API3.AssocArraytoArray(this.baseManagers).sort(function (a,b) {
|
||||
var baseBest = this.baseManagers.slice().sort(function (a,b) {
|
||||
if (a.accessIndex == accessIndex && b.accessIndex != accessIndex)
|
||||
return -1;
|
||||
else if (b.accessIndex == accessIndex && a.accessIndex != accessIndex)
|
||||
|
|
@ -709,7 +787,7 @@ m.HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number)
|
|||
var workers = new API3.EntityCollection(gameState.sharedScript);
|
||||
for (let base of baseBest)
|
||||
{
|
||||
if (base.ID === newBaseID)
|
||||
if (base.ID === baseRef.ID)
|
||||
continue;
|
||||
base.pickBuilders(gameState, workers, needed);
|
||||
if (workers.length < number)
|
||||
|
|
@ -725,7 +803,7 @@ m.HQ.prototype.bulkPickWorkers = function(gameState, newBaseID, number)
|
|||
m.HQ.prototype.getTotalResourceLevel = function(gameState)
|
||||
{
|
||||
var total = { "food": 0, "wood": 0, "stone": 0, "metal": 0 };
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
for (var type in total)
|
||||
total[type] += base.getResourceLevel(gameState, type);
|
||||
|
||||
|
|
@ -739,7 +817,7 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState)
|
|||
for (var type in this.wantedRates)
|
||||
this.currentRates[type] = 0;
|
||||
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
base.getGatherRates(gameState, this.currentRates);
|
||||
|
||||
return this.currentRates;
|
||||
|
|
@ -755,8 +833,6 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState)
|
|||
*/
|
||||
m.HQ.prototype.pickMostNeededResources = function(gameState)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
this.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState);
|
||||
var currentRates = this.GetCurrentGatherRates(gameState);
|
||||
|
||||
|
|
@ -813,7 +889,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
|||
continue;
|
||||
// We require that it is accessible
|
||||
var index = gameState.ai.accessibility.landPassMap[j];
|
||||
if (!this.allowedRegions[index])
|
||||
if (!this.landRegions[index])
|
||||
continue;
|
||||
// and with enough room around to build the cc
|
||||
var i = API3.getMaxMapIndex(j, this.territoryMap, obstructions);
|
||||
|
|
@ -847,7 +923,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
|||
}
|
||||
if (norm == 0)
|
||||
continue;
|
||||
if (minDist > 170000 && !this.navalMap) // Reject if too far from any allied cc (-> not connected)
|
||||
/* rototo if (minDist > 170000 && !this.navalMap) // Reject if too far from any allied cc (-> not connected)
|
||||
{
|
||||
norm = 0;
|
||||
continue;
|
||||
|
|
@ -863,7 +939,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
|||
}
|
||||
else
|
||||
norm *= 0.5;
|
||||
}
|
||||
} */
|
||||
|
||||
for (var dp of dpList)
|
||||
{
|
||||
|
|
@ -911,7 +987,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
|||
|
||||
// Define a minimal number of wanted ships in the seas reaching this new base
|
||||
var index = gameState.ai.accessibility.landPassMap[i];
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || base.accessIndex === index)
|
||||
continue;
|
||||
|
|
@ -966,7 +1042,7 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
|
|||
continue;
|
||||
// We require that it is accessible
|
||||
var index = gameState.ai.accessibility.landPassMap[j];
|
||||
if (!this.allowedRegions[index])
|
||||
if (!this.landRegions[index])
|
||||
continue;
|
||||
// and with enough room around to build the cc
|
||||
var i = API3.getMaxMapIndex(j, this.territoryMap, obstructions);
|
||||
|
|
@ -1046,7 +1122,7 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
|
|||
|
||||
// Define a minimal number of wanted ships in the seas reaching this new base
|
||||
var index = gameState.ai.accessibility.landPassMap[i];
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || base.accessIndex === index)
|
||||
continue;
|
||||
|
|
@ -1095,7 +1171,7 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
|
|||
if (obstructions.map[i] <= radius)
|
||||
continue;
|
||||
var index = gameState.ai.accessibility.landPassMap[i];
|
||||
if (!this.allowedRegions[index])
|
||||
if (!this.landRegions[index])
|
||||
continue;
|
||||
|
||||
var pos = [cellSize * (j%width+0.5), cellSize * (Math.floor(j/width)+0.5)];
|
||||
|
|
@ -1397,7 +1473,13 @@ m.HQ.prototype.checkBaseExpansion = function(gameState, queues)
|
|||
{
|
||||
if (queues.civilCentre.length() > 0)
|
||||
return;
|
||||
// first expand if we have not enough room available for buildings
|
||||
// first build one cc if none already available
|
||||
if (this.numActiveBase() < 1)
|
||||
{
|
||||
this.buildNewBase(gameState, queues);
|
||||
return;
|
||||
}
|
||||
// then expand if we have not enough room available for buildings
|
||||
if (this.stopBuilding.length > 1)
|
||||
{
|
||||
if (this.Config.debug > 2)
|
||||
|
|
@ -1413,24 +1495,25 @@ m.HQ.prototype.checkBaseExpansion = function(gameState, queues)
|
|||
if (Math.floor(numUnits/popForBase) >= gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).length)
|
||||
{
|
||||
if (this.Config.debug > 2)
|
||||
API3.warn("try to build a new base because of population " + numUnits + " for " + numCCs + " CCs");
|
||||
API3.warn("try to build a new base because of population " + numUnits + " for " + this.numActiveBase() + " CCs");
|
||||
this.buildNewBase(gameState, queues);
|
||||
}
|
||||
};
|
||||
|
||||
m.HQ.prototype.buildNewBase = function(gameState, queues, type)
|
||||
{
|
||||
if (gameState.currentPhase() == 1 && !gameState.isResearching(gameState.townPhase()))
|
||||
if (this.numActiveBase() > 0 && gameState.currentPhase() == 1 && !gameState.isResearching(gameState.townPhase()))
|
||||
return false;
|
||||
if (gameState.countFoundationsByType(this.bBase[0], true) > 0 || queues.civilCentre.length() > 0)
|
||||
var template = (this.numActiveBase() > 0) ? this.bBase[0] : gameState.applyCiv("structures/{civ}_civil_centre");
|
||||
if (gameState.countFoundationsByType(template, true) > 0 || queues.civilCentre.length() > 0)
|
||||
return false;
|
||||
if (!this.canBuild(gameState, this.bBase[0]))
|
||||
if (!this.canBuild(gameState, template))
|
||||
return false;
|
||||
|
||||
// base "-1" means new base.
|
||||
if (this.Config.debug > 1)
|
||||
API3.warn("new base planned with type " + type);
|
||||
queues.civilCentre.addItem(new m.ConstructionPlan(gameState, this.bBase[0], { "base": -1, "type": type }));
|
||||
queues.civilCentre.addItem(new m.ConstructionPlan(gameState, template, { "base": -1, "type": type }));
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -1634,7 +1717,7 @@ m.HQ.prototype.trainEmergencyUnits = function(gameState, positions)
|
|||
{
|
||||
var access = gameState.ai.accessibility.getAccessValue(pos);
|
||||
// check nearest base anchor
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
|
|
@ -1801,14 +1884,14 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
|||
{
|
||||
if (this.basesMap.map[j] == 0)
|
||||
continue;
|
||||
var baseID = this.basesMap.map[j];
|
||||
var index = this.baseManagers[baseID].territoryIndices.indexOf(j);
|
||||
var base = this.getBaseByID(this.basesMap.map[j]);
|
||||
var index = base.territoryIndices.indexOf(j);
|
||||
if (index == -1)
|
||||
{
|
||||
API3.warn(" problem in headquarters::updateTerritories for base " + baseID);
|
||||
API3.warn(" problem in headquarters::updateTerritories for base " + this.basesMap.map[j]);
|
||||
continue;
|
||||
}
|
||||
this.baseManagers[baseID].territoryIndices.splice(index, 1);
|
||||
base.territoryIndices.splice(index, 1);
|
||||
this.basesMap.map[j] = 0;
|
||||
}
|
||||
else if (this.basesMap.map[j] == 0)
|
||||
|
|
@ -1818,7 +1901,7 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
|||
var access;
|
||||
for (var k of ind)
|
||||
{
|
||||
if (!this.allowedRegions[gameState.ai.accessibility.landPassMap[k]])
|
||||
if (!this.landRegions[gameState.ai.accessibility.landPassMap[k]])
|
||||
continue;
|
||||
landPassable = true;
|
||||
access = gameState.ai.accessibility.landPassMap[k];
|
||||
|
|
@ -1829,7 +1912,7 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
|||
var distmin = Math.min();
|
||||
var baseID = undefined;
|
||||
var pos = [cellSize * (j%width+0.5), cellSize * (Math.floor(j/width)+0.5)];
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
{
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
|
|
@ -1843,7 +1926,7 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
|||
}
|
||||
if (!baseID)
|
||||
continue;
|
||||
this.baseManagers[baseID].territoryIndices.push(j);
|
||||
this.getBaseByID(baseID).territoryIndices.push(j);
|
||||
this.basesMap.map[j] = baseID;
|
||||
expansion++;
|
||||
}
|
||||
|
|
@ -1861,11 +1944,37 @@ m.HQ.prototype.updateTerritories = function(gameState)
|
|||
this.tradeManager.routeProspection = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the base corresponding to baseID
|
||||
*/
|
||||
m.HQ.prototype.getBaseByID = function(baseID)
|
||||
{
|
||||
for (let base of this.baseManagers)
|
||||
if (base.ID === baseID)
|
||||
return base;
|
||||
|
||||
API3.warn("Petra error: no base found with ID " + baseID);
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* returns the number of active (i.e. with one cc) bases
|
||||
* TODO should be cached
|
||||
*/
|
||||
m.HQ.prototype.numActiveBase = function()
|
||||
{
|
||||
let num = 0;
|
||||
for (let base of this.baseManagers)
|
||||
if (base.anchor)
|
||||
++num;
|
||||
return num;
|
||||
};
|
||||
|
||||
// Count gatherers returning resources in the number of gatherers of resourceSupplies
|
||||
// to prevent the AI always reaffecting idle workers to these resourceSupplies (specially in naval maps).
|
||||
m.HQ.prototype.assignGatherers = function(gameState)
|
||||
{
|
||||
for each (var base in this.baseManagers)
|
||||
for (var base of this.baseManagers)
|
||||
{
|
||||
base.workers.forEach( function (worker) {
|
||||
if (worker.unitAIState().split(".")[1] !== "RETURNRESOURCE")
|
||||
|
|
@ -1933,7 +2042,7 @@ m.HQ.prototype.update = function(gameState, queues, events)
|
|||
if (gameState.getGameType() === "wonder")
|
||||
this.buildWonder(gameState, queues);
|
||||
|
||||
if (this.baseManagers[1])
|
||||
if (this.numActiveBase() > 0)
|
||||
{
|
||||
this.trainMoreWorkers(gameState, queues);
|
||||
|
||||
|
|
@ -1947,12 +2056,12 @@ m.HQ.prototype.update = function(gameState, queues, events)
|
|||
this.researchManager.update(gameState, queues);
|
||||
}
|
||||
|
||||
if (this.numActiveBase() < 1 ||
|
||||
(this.Config.difficulty > 0 && gameState.ai.playedTurn % 10 == 7 && gameState.currentPhase() > 1))
|
||||
this.checkBaseExpansion(gameState, queues);
|
||||
|
||||
if (gameState.currentPhase() > 1)
|
||||
{
|
||||
// sandbox doesn't expand
|
||||
if (this.Config.difficulty > 0 && gameState.ai.playedTurn % 10 == 7)
|
||||
this.checkBaseExpansion(gameState, queues);
|
||||
|
||||
if (!this.saveResources)
|
||||
{
|
||||
this.buildMarket(gameState, queues);
|
||||
|
|
@ -1974,15 +2083,17 @@ m.HQ.prototype.update = function(gameState, queues, events)
|
|||
this.buildDefenses(gameState, queues);
|
||||
|
||||
this.assignGatherers(gameState);
|
||||
for (var i in this.baseManagers)
|
||||
for (let i = 0; i < this.baseManagers.length; ++i)
|
||||
{
|
||||
this.baseManagers[i].checkEvents(gameState, events, queues);
|
||||
if (((+i + gameState.ai.playedTurn)%(gameState.ai.uniqueIDs.bases - 1)) == 0)
|
||||
if (((i + gameState.ai.playedTurn)%this.baseManagers.length) === 0)
|
||||
this.baseManagers[i].update(gameState, queues, events);
|
||||
}
|
||||
|
||||
this.navalManager.update(gameState, queues, events);
|
||||
|
||||
|
||||
var rototo = false;
|
||||
if (rototo)
|
||||
if (this.Config.difficulty > 0)
|
||||
this.attackManager.update(gameState, queues, events);
|
||||
|
||||
|
|
@ -2011,12 +2122,15 @@ m.HQ.prototype.Serialize = function()
|
|||
"bAdvanced": this.bAdvanced,
|
||||
"saveResources": this.saveResources,
|
||||
"saveSpace": this.saveSpace,
|
||||
"canBuildUnits": this.canBuildUnits
|
||||
"canBuildUnits": this.canBuildUnits,
|
||||
"navalMap": this.navalMap,
|
||||
"landRegions": this.landRegions,
|
||||
"navalRegions": this.navalRegions
|
||||
};
|
||||
|
||||
let baseManagers = {};
|
||||
for (let base in this.baseManagers)
|
||||
baseManagers[base] = this.baseManagers[base].Serialize();
|
||||
let baseManagers = [];
|
||||
for (let base of this.baseManagers)
|
||||
baseManagers.push(base.Serialize());
|
||||
|
||||
if (this.Config.debug == -100)
|
||||
{
|
||||
|
|
@ -2051,14 +2165,15 @@ m.HQ.prototype.Deserialize = function(gameState, data)
|
|||
for (let key in data.properties)
|
||||
this[key] = data.properties[key];
|
||||
|
||||
this.baseManagers = {};
|
||||
for (let base in data.baseManagers)
|
||||
this.baseManagers = [];
|
||||
for (let base of data.baseManagers)
|
||||
{
|
||||
// the first call to deserialize set the ID base needed by entitycollections
|
||||
this.baseManagers[base] = new m.BaseManager(gameState, this.Config);
|
||||
this.baseManagers[base].Deserialize(gameState, data.baseManagers[base]);
|
||||
this.baseManagers[base].init(gameState);
|
||||
this.baseManagers[base].Deserialize(gameState, data.baseManagers[base]);
|
||||
var newbase = new m.BaseManager(gameState, this.Config);
|
||||
newbase.Deserialize(gameState, base);
|
||||
newbase.init(gameState);
|
||||
newbase.Deserialize(gameState, base);
|
||||
this.baseManagers.push(newbase);
|
||||
}
|
||||
|
||||
this.attackManager = new m.AttackManager(this.Config);
|
||||
|
|
|
|||
|
|
@ -43,11 +43,6 @@ m.createObstructionMap = function(gameState, accessIndex, template)
|
|||
var iter = xter + yter*territoryMap.width;
|
||||
var tilePlayer = (territoryMap.data[iter] & m.TERRITORY_PLAYER_MASK);
|
||||
|
||||
//if (gameState.ai.myIndex !== gameState.ai.accessibility.landPassMap[i])
|
||||
//{
|
||||
// obstructionTiles[i] = 0;
|
||||
// continue;
|
||||
//}
|
||||
if (gameState.isPlayerEnemy(tilePlayer) && tilePlayer !== 0)
|
||||
{
|
||||
obstructionTiles[i] = 0;
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ m.NavalManager.prototype.init = function(gameState, deserializing)
|
|||
|
||||
for (var i = 0; i < gameState.ai.accessibility.regionSize.length; ++i)
|
||||
{
|
||||
if (gameState.ai.HQ.navalRegions.indexOf(i) === -1)
|
||||
if (!gameState.ai.HQ.navalRegions[i])
|
||||
{
|
||||
// push dummies
|
||||
this.seaShips.push(undefined);
|
||||
|
|
@ -162,9 +162,11 @@ m.NavalManager.prototype.init = function(gameState, deserializing)
|
|||
if (deserializing)
|
||||
return;
|
||||
|
||||
// Assign our docks
|
||||
var self = this;
|
||||
this.docks.forEach(function(dock) { self.assignDock(gameState, dock); });
|
||||
// Assign our initial docks and ships
|
||||
for (let ship of this.ships.values())
|
||||
this.setShipIndex(gameState, ship);
|
||||
for (let dock of this.docks.values())
|
||||
this.setDockIndex(gameState, dock);
|
||||
};
|
||||
|
||||
m.NavalManager.prototype.resetFishingBoats = function(gameState)
|
||||
|
|
@ -173,7 +175,13 @@ m.NavalManager.prototype.resetFishingBoats = function(gameState)
|
|||
this.wantedFishShips[i] = 0;
|
||||
};
|
||||
|
||||
m.NavalManager.prototype.assignDock = function(gameState, dock)
|
||||
m.NavalManager.prototype.setShipIndex = function(gameState, ship)
|
||||
{
|
||||
let sea = gameState.ai.accessibility.getAccessValue(ship.position(), true);
|
||||
ship.setMetadata(PlayerID, "sea", sea);
|
||||
};
|
||||
|
||||
m.NavalManager.prototype.setDockIndex = function(gameState, dock)
|
||||
{
|
||||
var land = dock.getMetadata(PlayerID, "access");
|
||||
if (land === undefined)
|
||||
|
|
@ -238,7 +246,7 @@ m.NavalManager.prototype.checkEvents = function(gameState, queues, events)
|
|||
continue;
|
||||
var entity = gameState.getEntityById(evt.newentity);
|
||||
if (entity && entity.hasClass("Dock") && entity.isOwn(PlayerID))
|
||||
this.assignDock(gameState, entity);
|
||||
this.setDockIndex(gameState, entity);
|
||||
}
|
||||
|
||||
var evts = events["TrainingFinished"];
|
||||
|
|
@ -251,10 +259,7 @@ m.NavalManager.prototype.checkEvents = function(gameState, queues, events)
|
|||
var entity = gameState.getEntityById(entId);
|
||||
if (!entity || !entity.hasClass("Ship") || !entity.isOwn(PlayerID))
|
||||
continue;
|
||||
var pos = gameState.ai.accessibility.gamePosToMapPos(entity.position());
|
||||
var index = pos[0] + pos[1]*gameState.ai.accessibility.width;
|
||||
var sea = gameState.ai.accessibility.navalPassMap[index];
|
||||
entity.setMetadata(PlayerID, "sea", sea);
|
||||
this.setShipIndex(gameState, entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -533,7 +538,7 @@ m.NavalManager.prototype.buildNavalStructures = function(gameState, queues)
|
|||
&& gameState.ai.HQ.canBuild(gameState, "structures/{civ}_dock"))
|
||||
{
|
||||
var dockStarted = false;
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (dockStarted)
|
||||
break;
|
||||
|
|
@ -542,7 +547,7 @@ m.NavalManager.prototype.buildNavalStructures = function(gameState, queues)
|
|||
var remaining = this.getUnconnectedSeas(gameState, base.accessIndex);
|
||||
for (var sea of remaining)
|
||||
{
|
||||
if (gameState.ai.HQ.navalRegions.indexOf(sea) === -1)
|
||||
if (!gameState.ai.HQ.navalRegions[sea])
|
||||
continue;
|
||||
queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_dock", { "land": base.accessIndex, "sea": sea }));
|
||||
dockStarted = true;
|
||||
|
|
|
|||
|
|
@ -374,14 +374,13 @@ m.ConstructionPlan.prototype.findDockPosition = function(gameState)
|
|||
var baseIndex = gameState.ai.HQ.basesMap.map[bestIdx];
|
||||
if (!baseIndex)
|
||||
{
|
||||
for (let i in gameState.ai.HQ.baseManagers)
|
||||
for (let base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
let base = gameState.ai.HQ.baseManagers[i];
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
if (base.accessIndex !== access)
|
||||
continue;
|
||||
baseIndex = i;
|
||||
baseIndex = base.ID;
|
||||
break;
|
||||
}
|
||||
if (!baseIndex)
|
||||
|
|
|
|||
|
|
@ -85,16 +85,16 @@ m.TrainingPlan.prototype.start = function(gameState)
|
|||
let bBase = b.getMetadata(PlayerID, "base");
|
||||
if (wantedIndex)
|
||||
{
|
||||
if (!aBase || gameState.ai.HQ.baseManagers[aBase].accessIndex != wantedIndex)
|
||||
if (!aBase || gameState.ai.HQ.getBaseByID(aBase).accessIndex != wantedIndex)
|
||||
aa += 30;
|
||||
if (!bBase || gameState.ai.HQ.baseManagers[bBase].accessIndex != wantedIndex)
|
||||
if (!bBase || gameState.ai.HQ.getBaseByID(bBase).accessIndex != wantedIndex)
|
||||
bb += 30;
|
||||
}
|
||||
// then, if worker, small preference for bases with less workers
|
||||
if (workerUnit && aBase && bBase && aBase != bBase)
|
||||
{
|
||||
let apop = gameState.ai.HQ.baseManagers[aBase].workers.length;
|
||||
let bpop = gameState.ai.HQ.baseManagers[bBase].workers.length;
|
||||
let apop = gameState.ai.HQ.getBaseByID(aBase).workers.length;
|
||||
let bpop = gameState.ai.HQ.getBaseByID(bBase).workers.length;
|
||||
if (apop > bpop)
|
||||
aa++;
|
||||
else if (bpop > apop)
|
||||
|
|
|
|||
|
|
@ -184,22 +184,21 @@ m.TransportPlan.prototype.releaseAll = function()
|
|||
m.TransportPlan.prototype.cancelTransport = function(gameState)
|
||||
{
|
||||
var ent = this.units.toEntityArray()[0];
|
||||
var base = gameState.ai.HQ.baseManagers[ent.getMetadata(PlayerID, "base")];
|
||||
var base = gameState.ai.HQ.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
{
|
||||
for (var i in gameState.ai.HQ.baseManagers)
|
||||
for (let newbase of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
base = gameState.ai.HQ.baseManagers[i];
|
||||
if (base.anchor && base.anchor.position())
|
||||
{
|
||||
ent.setMetadata(PlayerID, "base", +i);
|
||||
break;
|
||||
}
|
||||
if (!newbase.anchor || !newbase.anchor.position())
|
||||
continue;
|
||||
ent.setMetadata(PlayerID, "base", newbase.ID);
|
||||
base = newbase;
|
||||
break;
|
||||
}
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
return false;
|
||||
this.units.forEach(function (ent) {
|
||||
ent.setMetadata(PlayerID, "base", base);
|
||||
ent.setMetadata(PlayerID, "base", base.ID);
|
||||
});
|
||||
}
|
||||
this.endIndex = this.startIndex;
|
||||
|
|
@ -401,7 +400,7 @@ m.TransportPlan.prototype.onSailing = function(gameState)
|
|||
API3.warn(">>> transport " + this.ID + " reloading failed ... <<<");
|
||||
// destroy the unit if inaccessible otherwise leave it there
|
||||
var index = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
if (gameState.ai.HQ.allowedRegions[index])
|
||||
if (gameState.ai.HQ.landRegions[index])
|
||||
{
|
||||
if (this.debug > 1)
|
||||
API3.warn(" recovered entity kept " + ent.id());
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ var PETRA = function(m)
|
|||
* This class makes a worker do as instructed by the economy manager
|
||||
*/
|
||||
|
||||
m.Worker = function(baseManager)
|
||||
m.Worker = function(base)
|
||||
{
|
||||
this.ent = undefined;
|
||||
this.baseManager = baseManager
|
||||
this.baseID = baseManager.ID;
|
||||
this.base = base
|
||||
this.baseID = base.ID;
|
||||
};
|
||||
|
||||
m.Worker.prototype.update = function(ent, gameState)
|
||||
|
|
@ -22,6 +22,12 @@ m.Worker.prototype.update = function(ent, gameState)
|
|||
return;
|
||||
|
||||
this.ent = ent;
|
||||
// base 0 for unassigned entities has no accessIndex, so take the one from the entity
|
||||
if (this.baseID === gameState.ai.HQ.baseManagers[0].ID)
|
||||
this.accessIndex = gameState.ai.accessibility.getAccessValue(ent.position());
|
||||
else
|
||||
this.accessIndex = this.base.accessIndex;
|
||||
|
||||
var subrole = this.ent.getMetadata(PlayerID, "subrole");
|
||||
|
||||
// Check for inaccessible targets (in RMS maps, we quite often have chicken or bushes inside obstruction of other entities).
|
||||
|
|
@ -77,7 +83,7 @@ m.Worker.prototype.update = function(ent, gameState)
|
|||
else
|
||||
{
|
||||
var gatherType = this.ent.getMetadata(PlayerID, "gather-type");
|
||||
var nearby = this.baseManager.dropsiteSupplies[gatherType]["nearby"];
|
||||
var nearby = this.base.dropsiteSupplies[gatherType]["nearby"];
|
||||
var isNearby = nearby.some(function(sup) {
|
||||
if (sup.id === supplyId)
|
||||
return true;
|
||||
|
|
@ -152,9 +158,8 @@ m.Worker.prototype.update = function(ent, gameState)
|
|||
{
|
||||
// nothing to hunt around. Try another region if any
|
||||
var nowhereToHunt = true;
|
||||
for (var i in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
var base = gameState.ai.HQ.baseManagers[i];
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
continue;
|
||||
var basePos = base.anchor.position();
|
||||
|
|
@ -222,40 +227,8 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
var access = gameState.ai.accessibility.getAccessValue(this.ent.position());
|
||||
|
||||
// First look for possible treasure if any
|
||||
var treasureFound = undefined;
|
||||
var distmin = Math.min();
|
||||
gameState.ai.HQ.treasures.forEach(function (treasure) {
|
||||
var treasureAccess = treasure.getMetadata(PlayerID, "access");
|
||||
if (!treasureAccess)
|
||||
{
|
||||
treasureAccess = gameState.ai.accessibility.getAccessValue(treasure.position());
|
||||
treasure.setMetadata(PlayerID, "access", treasureAccess);
|
||||
}
|
||||
if (treasureAccess !== access)
|
||||
return;
|
||||
var territoryOwner = gameState.ai.HQ.territoryMap.getOwner(treasure.position());
|
||||
if (territoryOwner !== 0 && !gameState.isPlayerAlly(territoryOwner))
|
||||
return;
|
||||
var lastGathered = treasure.getMetadata(PlayerID, "lastGathered");
|
||||
// let some time for the previous gatherer to reach the treasure
|
||||
if (lastGathered && gameState.ai.elapsedTime - lastGathered < 20)
|
||||
return;
|
||||
var dist = API3.SquareVectorDistance(self.ent.position(), treasure.position());
|
||||
if (territoryOwner !== PlayerID && dist > 14000) // AI has no LOS, so restrict it a bit
|
||||
return;
|
||||
if (dist > distmin)
|
||||
return;
|
||||
distmin = dist;
|
||||
treasureFound = treasure;
|
||||
});
|
||||
if (treasureFound)
|
||||
{
|
||||
treasureFound.setMetadata(PlayerID, "lastGathered", gameState.ai.elapsedTime);
|
||||
this.ent.gather(treasureFound);
|
||||
m.AddTCGatherer(gameState, treasureFound.id());
|
||||
this.ent.setMetadata(PlayerID, "supply", treasureFound.id());
|
||||
if (this.gatherTreasure(gameState))
|
||||
return true;
|
||||
}
|
||||
|
||||
var resource = this.ent.getMetadata(PlayerID, "gather-type");
|
||||
|
||||
|
|
@ -300,9 +273,9 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
var supply;
|
||||
|
||||
// first look in our own base if accessible from our present position
|
||||
if (this.baseManager.accessIndex === access)
|
||||
if (this.base.accessIndex === access)
|
||||
{
|
||||
if ((supply = findSupply(this.ent, this.baseManager.dropsiteSupplies[resource]["nearby"])))
|
||||
if ((supply = findSupply(this.ent, this.base.dropsiteSupplies[resource]["nearby"])))
|
||||
{
|
||||
this.ent.gather(supply);
|
||||
return true;
|
||||
|
|
@ -321,7 +294,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
if ((supply = findSupply(this.ent, this.baseManager.dropsiteSupplies[resource]["medium"])))
|
||||
if ((supply = findSupply(this.ent, this.base.dropsiteSupplies[resource]["medium"])))
|
||||
{
|
||||
this.ent.gather(supply);
|
||||
return true;
|
||||
|
|
@ -329,7 +302,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
}
|
||||
// So if we're here we have checked our whole base for a proper resource (or it was not accessible)
|
||||
// --> check other bases directly accessible
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.ID === this.baseID)
|
||||
continue;
|
||||
|
|
@ -344,7 +317,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
}
|
||||
if (resource === "food") // --> for food, try to gather from fields if any, otherwise build one if any
|
||||
{
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.ID === this.baseID)
|
||||
continue;
|
||||
|
|
@ -364,7 +337,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
}
|
||||
}
|
||||
}
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.ID === this.baseID)
|
||||
continue;
|
||||
|
|
@ -398,7 +371,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
return true;
|
||||
|
||||
// Still nothing ... try bases which need a transport
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.accessIndex === access)
|
||||
continue;
|
||||
|
|
@ -412,7 +385,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
}
|
||||
if (resource === "food") // --> for food, try to gather from fields if any, otherwise build one if any
|
||||
{
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.accessIndex === access)
|
||||
continue;
|
||||
|
|
@ -432,7 +405,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
}
|
||||
}
|
||||
}
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.accessIndex === access)
|
||||
continue;
|
||||
|
|
@ -463,15 +436,15 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
return true;
|
||||
|
||||
// Still nothing, we look now for faraway resources, first in the accessible ones, then in the others
|
||||
if (this.baseManager.accessIndex === access)
|
||||
if (this.accessIndex === access)
|
||||
{
|
||||
if ((supply = findSupply(this.ent, this.baseManager.dropsiteSupplies[resource]["faraway"])))
|
||||
if ((supply = findSupply(this.ent, this.base.dropsiteSupplies[resource]["faraway"])))
|
||||
{
|
||||
this.ent.gather(supply);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.ID === this.baseID)
|
||||
continue;
|
||||
|
|
@ -484,7 +457,7 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
return true;
|
||||
}
|
||||
}
|
||||
for each (var base in gameState.ai.HQ.baseManagers)
|
||||
for (var base of gameState.ai.HQ.baseManagers)
|
||||
{
|
||||
if (base.accessIndex === access)
|
||||
continue;
|
||||
|
|
@ -505,10 +478,16 @@ m.Worker.prototype.startGathering = function(gameState)
|
|||
return false;
|
||||
};
|
||||
|
||||
// if position is given, we only check if we could hunt from this position but do nothing
|
||||
// otherwise the position of the entity is taken, and if something is found, we directly start the hunt
|
||||
/**
|
||||
* if position is given, we only check if we could hunt from this position but do nothing
|
||||
* otherwise the position of the entity is taken, and if something is found, we directly start the hunt
|
||||
*/
|
||||
m.Worker.prototype.startHunting = function(gameState, position)
|
||||
{
|
||||
// First look for possible treasure if any
|
||||
if (!position && this.gatherTreasure(gameState))
|
||||
return true;
|
||||
|
||||
var resources = gameState.getHuntableSupplies();
|
||||
if (resources.length === 0)
|
||||
return false;
|
||||
|
|
@ -748,11 +727,58 @@ m.Worker.prototype.buildAnyField = function(gameState, baseID)
|
|||
return bestFarmEnt;
|
||||
};
|
||||
|
||||
// Workers elephant should move away from the buildings they've built to avoid being trapped in between constructions
|
||||
// For the time being, we move towards the nearest gatherer (providing him a dropsite)
|
||||
/**
|
||||
* Look for some treasure to gather
|
||||
*/
|
||||
m.Worker.prototype.gatherTreasure = function(gameState)
|
||||
{
|
||||
var rates = this.ent.resourceGatherRates();
|
||||
if (!rates || !rates["treasure"] || rates["treasure"] <= 0)
|
||||
return false;
|
||||
var treasureFound = undefined;
|
||||
var distmin = Math.min();
|
||||
var access = gameState.ai.accessibility.getAccessValue(this.ent.position());
|
||||
for (var treasure of gameState.ai.HQ.treasures.values())
|
||||
{
|
||||
// let some time for the previous gatherer to reach the treasure befor trying again
|
||||
var lastGathered = treasure.getMetadata(PlayerID, "lastGathered");
|
||||
if (lastGathered && gameState.ai.elapsedTime - lastGathered < 20)
|
||||
continue;
|
||||
var treasureAccess = treasure.getMetadata(PlayerID, "access");
|
||||
if (!treasureAccess)
|
||||
{
|
||||
treasureAccess = gameState.ai.accessibility.getAccessValue(treasure.position());
|
||||
treasure.setMetadata(PlayerID, "access", treasureAccess);
|
||||
}
|
||||
if (treasureAccess !== access)
|
||||
continue;
|
||||
var territoryOwner = gameState.ai.HQ.territoryMap.getOwner(treasure.position());
|
||||
if (territoryOwner !== 0 && !gameState.isPlayerAlly(territoryOwner))
|
||||
continue;
|
||||
var dist = API3.SquareVectorDistance(this.ent.position(), treasure.position());
|
||||
if (territoryOwner !== PlayerID && dist > 14000) // AI has no LOS, so restrict it a bit
|
||||
continue;
|
||||
if (dist > distmin)
|
||||
continue;
|
||||
distmin = dist;
|
||||
treasureFound = treasure;
|
||||
}
|
||||
if (!treasureFound)
|
||||
return false;
|
||||
treasureFound.setMetadata(PlayerID, "lastGathered", gameState.ai.elapsedTime);
|
||||
this.ent.gather(treasureFound);
|
||||
m.AddTCGatherer(gameState, treasureFound.id());
|
||||
this.ent.setMetadata(PlayerID, "supply", treasureFound.id());
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Workers elephant should move away from the buildings they've built to avoid being trapped in between constructions
|
||||
* For the time being, we move towards the nearest gatherer (providing him a dropsite)
|
||||
*/
|
||||
m.Worker.prototype.moveAway = function(gameState)
|
||||
{
|
||||
var gatherers = this.baseManager.workersBySubrole(gameState, "gatherer");
|
||||
var gatherers = this.base.workersBySubrole(gameState, "gatherer");
|
||||
var pos = this.ent.position();
|
||||
var dist = Math.min();
|
||||
var destination = pos;
|
||||
|
|
|
|||
Loading…
Reference in a new issue