mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
ai cleanup
This was SVN commit r18290.
This commit is contained in:
parent
d9caf157e2
commit
5be948019b
11 changed files with 176 additions and 163 deletions
|
|
@ -6,21 +6,17 @@ var API3 = function(m)
|
|||
*/
|
||||
m.Class = function(data)
|
||||
{
|
||||
var ctor;
|
||||
let ctor;
|
||||
if (data._init)
|
||||
ctor = data._init;
|
||||
else
|
||||
ctor = function() { };
|
||||
|
||||
if (data._super)
|
||||
{
|
||||
ctor.prototype = { "__proto__": data._super.prototype };
|
||||
}
|
||||
|
||||
for (var key in data)
|
||||
{
|
||||
for (let key in data)
|
||||
ctor.prototype[key] = data[key];
|
||||
}
|
||||
|
||||
return ctor;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
var API3 = function(m)
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* Provides an API for the rest of the AI scripts to query the world state at a
|
||||
* higher level than the raw data.
|
||||
|
|
@ -183,14 +182,14 @@ m.GameState.prototype.isResearched = function(template)
|
|||
return this.playerData.researchedTechs[template] !== undefined;
|
||||
};
|
||||
|
||||
// true if started or queued
|
||||
/** true if started or queued */
|
||||
m.GameState.prototype.isResearching = function(template)
|
||||
{
|
||||
return this.playerData.researchStarted[template] !== undefined ||
|
||||
this.playerData.researchQueued[template] !== undefined;
|
||||
};
|
||||
|
||||
// this is an "in-absolute" check that doesn't check if we have a building to research from.
|
||||
/** this is an "in-absolute" check that doesn't check if we have a building to research from. */
|
||||
m.GameState.prototype.canResearch = function(techTemplateName, noRequirementCheck)
|
||||
{
|
||||
let template = this.getTemplate(techTemplateName);
|
||||
|
|
@ -227,8 +226,10 @@ m.GameState.prototype.canResearch = function(techTemplateName, noRequirementChec
|
|||
return this.checkTechRequirements(template.requirements());
|
||||
};
|
||||
|
||||
// Private function for checking a set of requirements is met
|
||||
// basically copies TechnologyManager's
|
||||
/**
|
||||
* Private function for checking a set of requirements is met
|
||||
* basically copies TechnologyManager
|
||||
*/
|
||||
m.GameState.prototype.checkTechRequirements = function(reqs)
|
||||
{
|
||||
// If there are no requirements then all requirements are met
|
||||
|
|
@ -447,7 +448,7 @@ m.GameState.prototype.getEnemyUnits = function(enemyID)
|
|||
return this.updatingGlobalCollection("" + enemyID + "-units", m.Filters.byClass("Unit"), this.getEnemyEntities(enemyID));
|
||||
};
|
||||
|
||||
// if maintain is true, this will be stored. Otherwise it's one-shot.
|
||||
/** if maintain is true, this will be stored. Otherwise it's one-shot. */
|
||||
m.GameState.prototype.getOwnEntitiesByMetadata = function(key, value, maintain)
|
||||
{
|
||||
if (maintain === true)
|
||||
|
|
@ -599,7 +600,7 @@ m.GameState.prototype.getFishableSupplies = function()
|
|||
return this.updatingGlobalCollection("resource-fish", m.Filters.isFishable(), this.getEntities());
|
||||
};
|
||||
|
||||
// This returns only units from buildings.
|
||||
/** This returns only units from buildings. */
|
||||
m.GameState.prototype.findTrainableUnits = function(classes, anticlasses)
|
||||
{
|
||||
let allTrainable = [];
|
||||
|
|
@ -653,9 +654,11 @@ m.GameState.prototype.findTrainableUnits = function(classes, anticlasses)
|
|||
return ret;
|
||||
};
|
||||
|
||||
// Return all techs which can currently be researched
|
||||
// Does not factor cost.
|
||||
// If there are pairs, both techs are returned.
|
||||
/**
|
||||
* Return all techs which can currently be researched
|
||||
* Does not factor cost.
|
||||
* If there are pairs, both techs are returned.
|
||||
*/
|
||||
m.GameState.prototype.findAvailableTech = function()
|
||||
{
|
||||
let allResearchable = [];
|
||||
|
|
@ -790,7 +793,7 @@ m.GameState.prototype.isDisabledTemplates = function(template)
|
|||
return this.playerData.disabledTemplates[template];
|
||||
};
|
||||
|
||||
// Checks whether the maximum number of buildings have been cnstructed for a certain catergory
|
||||
/** Checks whether the maximum number of buildings have been constructed for a certain catergory */
|
||||
m.GameState.prototype.isEntityLimitReached = function(category)
|
||||
{
|
||||
if (this.playerData.entityLimits[category] === undefined ||
|
||||
|
|
|
|||
|
|
@ -231,12 +231,12 @@ m.SharedScript.prototype.ApplyEntitiesDelta = function(state)
|
|||
{
|
||||
Engine.ProfileStart("Shared ApplyEntitiesDelta");
|
||||
|
||||
var foundationFinished = {};
|
||||
let foundationFinished = {};
|
||||
|
||||
// by order of updating:
|
||||
// we "Destroy" last because we want to be able to switch Metadata first.
|
||||
|
||||
var CreateEvents = state.events.Create;
|
||||
let CreateEvents = state.events.Create;
|
||||
for (let i = 0; i < CreateEvents.length; ++i)
|
||||
{
|
||||
let evt = CreateEvents[i];
|
||||
|
|
@ -289,7 +289,7 @@ m.SharedScript.prototype.ApplyEntitiesDelta = function(state)
|
|||
this.setMetadata(evt.owner, this._entities.get(evt.id), key, evt.metadata[key]);
|
||||
}
|
||||
|
||||
var DestroyEvents = state.events.Destroy;
|
||||
let DestroyEvents = state.events.Destroy;
|
||||
for (let i = 0; i < DestroyEvents.length; ++i)
|
||||
{
|
||||
let evt = DestroyEvents[i];
|
||||
|
|
@ -404,7 +404,7 @@ m.SharedScript.prototype.updateEntityCollections = function(property, ent)
|
|||
|
||||
m.SharedScript.prototype.setMetadata = function(player, ent, key, value)
|
||||
{
|
||||
var metadata = this._entityMetadata[player][ent.id()];
|
||||
let metadata = this._entityMetadata[player][ent.id()];
|
||||
if (!metadata)
|
||||
metadata = this._entityMetadata[player][ent.id()] = {};
|
||||
metadata[key] = value;
|
||||
|
|
@ -415,7 +415,7 @@ m.SharedScript.prototype.setMetadata = function(player, ent, key, value)
|
|||
|
||||
m.SharedScript.prototype.getMetadata = function(player, ent, key)
|
||||
{
|
||||
var metadata = this._entityMetadata[player][ent.id()];
|
||||
let metadata = this._entityMetadata[player][ent.id()];
|
||||
|
||||
if (!metadata || !(key in metadata))
|
||||
return undefined;
|
||||
|
|
@ -424,7 +424,7 @@ m.SharedScript.prototype.getMetadata = function(player, ent, key)
|
|||
|
||||
m.SharedScript.prototype.deleteMetadata = function(player, ent, key)
|
||||
{
|
||||
var metadata = this._entityMetadata[player][ent.id()];
|
||||
let metadata = this._entityMetadata[player][ent.id()];
|
||||
|
||||
if (!metadata || !(key in metadata))
|
||||
return true;
|
||||
|
|
@ -437,8 +437,8 @@ m.SharedScript.prototype.deleteMetadata = function(player, ent, key)
|
|||
|
||||
m.copyPrototype = function(descendant, parent)
|
||||
{
|
||||
var sConstructor = parent.toString();
|
||||
var aMatch = sConstructor.match( /\s*function (.*)\(/ );
|
||||
let sConstructor = parent.toString();
|
||||
let aMatch = sConstructor.match( /\s*function (.*)\(/ );
|
||||
|
||||
if ( aMatch != null )
|
||||
descendant.prototype[aMatch[1]] = parent;
|
||||
|
|
|
|||
|
|
@ -23,8 +23,10 @@ m.SquareVectorDistance = function(a, b)
|
|||
return dx*dx + dz*dz;
|
||||
};
|
||||
|
||||
// A is the reference, B must be in "range" of A
|
||||
// this supposes the range is already squared
|
||||
/**
|
||||
* A is the reference, B must be in "range" of A
|
||||
* this supposes the range is already squared
|
||||
*/
|
||||
m.inRange = function(a, b, range)// checks for X distance
|
||||
{
|
||||
// will avoid unnecessary checking for position in some rare cases... I'm lazy
|
||||
|
|
@ -36,7 +38,7 @@ m.inRange = function(a, b, range)// checks for X distance
|
|||
return dx*dx + dz*dz < range;
|
||||
};
|
||||
|
||||
// slower than SquareVectorDistance, faster than VectorDistance but not exactly accurate.
|
||||
/** Slower than SquareVectorDistance, faster than VectorDistance but not exactly accurate. */
|
||||
m.ManhattanDistance = function(a, b)
|
||||
{
|
||||
let dx = a[0] - b[0];
|
||||
|
|
@ -61,7 +63,7 @@ m.PickRandom = function(list)
|
|||
// Utility functions for conversions of maps of different sizes
|
||||
|
||||
/**
|
||||
*return the index of map2 with max content from indices contained inside the cell i of map1
|
||||
* Returns the index of map2 with max content from indices contained inside the cell i of map1
|
||||
* map1.cellSize must be a multiple of map2.cellSize
|
||||
*/
|
||||
m.getMaxMapIndex = function(i, map1, map2)
|
||||
|
|
@ -78,7 +80,7 @@ m.getMaxMapIndex = function(i, map1, map2)
|
|||
};
|
||||
|
||||
/**
|
||||
* return the list of indices of map2 contained inside the cell i of map1
|
||||
* Returns the list of indices of map2 contained inside the cell i of map1
|
||||
* map1.cellSize must be a multiple of map2.cellSize
|
||||
*/
|
||||
m.getMapIndices = function(i, map1, map2)
|
||||
|
|
@ -94,7 +96,7 @@ m.getMapIndices = function(i, map1, map2)
|
|||
};
|
||||
|
||||
/**
|
||||
* return the list of points of map2 contained inside the cell i of map1
|
||||
* Returns the list of points of map2 contained inside the cell i of map1
|
||||
* map1.cellSize must be a multiple of map2.cellSize
|
||||
*/
|
||||
m.getMapPoints = function(i, map1, map2)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
var PETRA = function(m)
|
||||
{
|
||||
|
||||
// Specialization of Armies used by the defense manager.
|
||||
/** Specialization of Armies used by the defense manager. */
|
||||
m.DefenseArmy = function(gameState, ownEntities, foeEntities)
|
||||
{
|
||||
if (!m.Army.call(this, gameState, ownEntities, foeEntities))
|
||||
|
|
@ -17,17 +17,17 @@ m.DefenseArmy.prototype.assignUnit = function (gameState, entID)
|
|||
// we'll assume this defender is ours already.
|
||||
// we'll also override any previous assignment
|
||||
|
||||
var ent = gameState.getEntityById(entID);
|
||||
let ent = gameState.getEntityById(entID);
|
||||
if (!ent || !ent.position())
|
||||
return false;
|
||||
|
||||
// try to return its resources, and if any, the attack order will be queued
|
||||
var queued = m.returnResources(gameState, ent);
|
||||
let queued = m.returnResources(gameState, ent);
|
||||
|
||||
var idMin;
|
||||
var distMin;
|
||||
var idMinAll;
|
||||
var distMinAll;
|
||||
let idMin;
|
||||
let distMin;
|
||||
let idMinAll;
|
||||
let distMinAll;
|
||||
for (let id of this.foeEntities)
|
||||
{
|
||||
let eEnt = gameState.getEntityById(id);
|
||||
|
|
@ -84,7 +84,6 @@ m.DefenseArmy.prototype.assignUnit = function (gameState, entID)
|
|||
return true;
|
||||
};
|
||||
|
||||
// TODO: this should return cleverer results ("needs anti-elephant"…)
|
||||
m.DefenseArmy.prototype.needsDefenders = function (gameState)
|
||||
{
|
||||
// some preliminary checks because we don't update for tech so entStrength removed can be > entStrength added
|
||||
|
|
|
|||
|
|
@ -397,34 +397,34 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues)
|
|||
}
|
||||
};
|
||||
|
||||
// Called by the "town phase" research plan once it's started
|
||||
/** Called by the "town phase" research plan once it's started */
|
||||
m.HQ.prototype.OnTownPhase = function(gameState)
|
||||
{
|
||||
var phaseName = gameState.getTemplate(gameState.townPhase()).name();
|
||||
let phaseName = gameState.getTemplate(gameState.townPhase()).name();
|
||||
m.chatNewPhase(gameState, phaseName, true);
|
||||
};
|
||||
|
||||
// Called by the "city phase" research plan once it's started
|
||||
/** Called by the "city phase" research plan once it's started */
|
||||
m.HQ.prototype.OnCityPhase = function(gameState)
|
||||
{
|
||||
// increase the priority of defense buildings to free this queue for our first fortress
|
||||
gameState.ai.queueManager.changePriority("defenseBuilding", 2*this.Config.priorities.defenseBuilding);
|
||||
|
||||
var phaseName = gameState.getTemplate(gameState.cityPhase()).name();
|
||||
let phaseName = gameState.getTemplate(gameState.cityPhase()).name();
|
||||
m.chatNewPhase(gameState, phaseName, true);
|
||||
};
|
||||
|
||||
// This code trains citizen workers, trying to keep close to a ratio of worker/soldiers
|
||||
/** This code trains citizen workers, trying to keep close to a ratio of worker/soldiers */
|
||||
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
{
|
||||
// default template
|
||||
var requirementsDef = [["cost", 1], ["costsResource", 1, "food"]];
|
||||
var classesDef = ["Support", "Worker"];
|
||||
var templateDef = this.findBestTrainableUnit(gameState, classesDef, requirementsDef);
|
||||
let requirementsDef = [["cost", 1], ["costsResource", 1, "food"]];
|
||||
let classesDef = ["Support", "Worker"];
|
||||
let templateDef = this.findBestTrainableUnit(gameState, classesDef, requirementsDef);
|
||||
|
||||
// counting the workers that aren't part of a plan
|
||||
var numberOfWorkers = 0; // all workers
|
||||
var numberOfSupports = 0; // only support workers (i.e. non fighting)
|
||||
let numberOfWorkers = 0; // all workers
|
||||
let numberOfSupports = 0; // only support workers (i.e. non fighting)
|
||||
gameState.getOwnUnits().forEach (function (ent) {
|
||||
if (ent.getMetadata(PlayerID, "role") === "worker" && ent.getMetadata(PlayerID, "plan") === undefined)
|
||||
{
|
||||
|
|
@ -433,9 +433,10 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
|||
++numberOfSupports;
|
||||
}
|
||||
});
|
||||
var numberInTraining = 0;
|
||||
let numberInTraining = 0;
|
||||
gameState.getOwnTrainingFacilities().forEach(function(ent) {
|
||||
ent.trainingQueue().forEach(function(item) {
|
||||
for (let item of ent.trainingQueue())
|
||||
{
|
||||
numberInTraining += item.count;
|
||||
if (item.metadata && item.metadata.role && item.metadata.role === "worker" && item.metadata.plan === undefined)
|
||||
{
|
||||
|
|
@ -443,14 +444,14 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
|||
if (item.metadata.support)
|
||||
numberOfSupports += item.count;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Anticipate the optimal batch size when this queue will start
|
||||
// and adapt the batch size of the first and second queued workers to the present population
|
||||
// to ease a possible recovery if our population was drastically reduced by an attack
|
||||
// (need to go up to second queued as it is accounted in queueManager)
|
||||
var size = numberOfWorkers < 12 ? 1 : Math.min(5, Math.ceil(numberOfWorkers / 10));
|
||||
let size = numberOfWorkers < 12 ? 1 : Math.min(5, Math.ceil(numberOfWorkers / 10));
|
||||
if (queues.villager.plans[0])
|
||||
{
|
||||
queues.villager.plans[0].number = Math.min(queues.villager.plans[0].number, size);
|
||||
|
|
@ -464,10 +465,10 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
|||
queues.citizenSoldier.plans[1].number = Math.min(queues.citizenSoldier.plans[1].number, size);
|
||||
}
|
||||
|
||||
var numberOfQueuedSupports = queues.villager.countQueuedUnits();
|
||||
var numberOfQueuedSoldiers = queues.citizenSoldier.countQueuedUnits();
|
||||
var numberQueued = numberOfQueuedSupports + numberOfQueuedSoldiers;
|
||||
var numberTotal = numberOfWorkers + numberQueued;
|
||||
let numberOfQueuedSupports = queues.villager.countQueuedUnits();
|
||||
let numberOfQueuedSoldiers = queues.citizenSoldier.countQueuedUnits();
|
||||
let numberQueued = numberOfQueuedSupports + numberOfQueuedSoldiers;
|
||||
let numberTotal = numberOfWorkers + numberQueued;
|
||||
|
||||
if (this.saveResources && numberTotal > this.Config.Economy.popForTown + 10)
|
||||
return;
|
||||
|
|
@ -510,7 +511,7 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
|||
queues.citizenSoldier.addPlan(new m.TrainingPlan(gameState, template, { "role": "worker", "base": 0 }, size, size));
|
||||
};
|
||||
|
||||
// picks the best template based on parameters and classes
|
||||
/** picks the best template based on parameters and classes */
|
||||
m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements)
|
||||
{
|
||||
var units;
|
||||
|
|
@ -595,8 +596,10 @@ m.HQ.prototype.findBestTrainableUnit = function(gameState, classes, requirements
|
|||
return units[0][0];
|
||||
};
|
||||
|
||||
// returns an entity collection of workers through BaseManager.pickBuilders
|
||||
// TODO: when same accessIndex, sort by distance
|
||||
/**
|
||||
* returns an entity collection of workers through BaseManager.pickBuilders
|
||||
* TODO: when same accessIndex, sort by distance
|
||||
*/
|
||||
m.HQ.prototype.bulkPickWorkers = function(gameState, baseRef, number)
|
||||
{
|
||||
var accessIndex = baseRef.accessIndex;
|
||||
|
|
@ -630,7 +633,7 @@ m.HQ.prototype.bulkPickWorkers = function(gameState, baseRef, number)
|
|||
|
||||
m.HQ.prototype.getTotalResourceLevel = function(gameState)
|
||||
{
|
||||
var total = { "food": 0, "wood": 0, "stone": 0, "metal": 0 };
|
||||
let total = { "food": 0, "wood": 0, "stone": 0, "metal": 0 };
|
||||
for (let base of this.baseManagers)
|
||||
for (let type in total)
|
||||
total[type] += base.getResourceLevel(gameState, type);
|
||||
|
|
@ -665,8 +668,8 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState)
|
|||
return this.currentRates;
|
||||
};
|
||||
|
||||
|
||||
/* Pick the resource which most needs another worker
|
||||
/**
|
||||
* Pick the resource which most needs another worker
|
||||
* How this works:
|
||||
* We get the rates we would want to have to be able to deal with our plans
|
||||
* We get our current rates
|
||||
|
|
@ -676,9 +679,9 @@ m.HQ.prototype.GetCurrentGatherRates = function(gameState)
|
|||
m.HQ.prototype.pickMostNeededResources = function(gameState)
|
||||
{
|
||||
this.wantedRates = gameState.ai.queueManager.wantedGatherRates(gameState);
|
||||
var currentRates = this.GetCurrentGatherRates(gameState);
|
||||
let currentRates = this.GetCurrentGatherRates(gameState);
|
||||
|
||||
var needed = [];
|
||||
let needed = [];
|
||||
for (let res in this.wantedRates)
|
||||
needed.push({ "type": res, "wanted": this.wantedRates[res], "current": currentRates[res] });
|
||||
|
||||
|
|
@ -693,8 +696,10 @@ m.HQ.prototype.pickMostNeededResources = function(gameState)
|
|||
return needed;
|
||||
};
|
||||
|
||||
// Returns the best position to build a new Civil Centre
|
||||
// Whose primary function would be to reach new resources of type "resource".
|
||||
/**
|
||||
* Returns the best position to build a new Civil Centre
|
||||
* Whose primary function would be to reach new resources of type "resource".
|
||||
*/
|
||||
m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource, proximity, fromStrategic)
|
||||
{
|
||||
// This builds a map. The procedure is fairly simple. It adds the resource maps
|
||||
|
|
@ -868,8 +873,10 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource,
|
|||
return [x, z];
|
||||
};
|
||||
|
||||
// Returns the best position to build a new Civil Centre
|
||||
// Whose primary function would be to assure territorial continuity with our allies
|
||||
/**
|
||||
* Returns the best position to build a new Civil Centre
|
||||
* Whose primary function would be to assure territorial continuity with our allies
|
||||
*/
|
||||
m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
|
||||
{
|
||||
// This builds a map. The procedure is fairly simple.
|
||||
|
|
@ -1008,10 +1015,12 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template)
|
|||
return [x, z];
|
||||
};
|
||||
|
||||
// Returns the best position to build a new market: if the allies already have a market, build it as far as possible
|
||||
// from it, although not in our border to be able to defend it easily. If no allied market, our second market will
|
||||
// follow the same logic
|
||||
// TODO check that it is on same accessIndex
|
||||
/**
|
||||
* Returns the best position to build a new market: if the allies already have a market, build it as far as possible
|
||||
* from it, although not in our border to be able to defend it easily. If no allied market, our second market will
|
||||
* follow the same logic
|
||||
* TODO check that it is on same accessIndex
|
||||
*/
|
||||
m.HQ.prototype.findMarketLocation = function(gameState, template)
|
||||
{
|
||||
var markets = gameState.updatingCollection("ExclusiveAllyMarkets", API3.Filters.byClass("Market"), gameState.getExclusiveAllyEntities()).toEntityArray();
|
||||
|
|
@ -1105,8 +1114,10 @@ m.HQ.prototype.findMarketLocation = function(gameState, template)
|
|||
return [x, z, this.basesMap.map[bestJdx], expectedGain];
|
||||
};
|
||||
|
||||
// Returns the best position to build defensive buildings (fortress and towers)
|
||||
// Whose primary function is to defend our borders
|
||||
/**
|
||||
* Returns the best position to build defensive buildings (fortress and towers)
|
||||
* Whose primary function is to defend our borders
|
||||
*/
|
||||
m.HQ.prototype.findDefensiveLocation = function(gameState, template)
|
||||
{
|
||||
// We take the point in our territory which is the nearest to any enemy cc
|
||||
|
|
@ -1273,12 +1284,12 @@ m.HQ.prototype.buildMarket = function(gameState, queues)
|
|||
return;
|
||||
|
||||
gameState.ai.queueManager.changePriority("economicBuilding", 3*this.Config.priorities.economicBuilding);
|
||||
var plan = new m.ConstructionPlan(gameState, "structures/{civ}_market");
|
||||
let plan = new m.ConstructionPlan(gameState, "structures/{civ}_market");
|
||||
plan.onStart = function(gameState) { gameState.ai.queueManager.changePriority("economicBuilding", gameState.ai.Config.priorities.economicBuilding); };
|
||||
queues.economicBuilding.addPlan(plan);
|
||||
};
|
||||
|
||||
// Build a farmstead
|
||||
/** Build a farmstead */
|
||||
m.HQ.prototype.buildFarmstead = function(gameState, queues)
|
||||
{
|
||||
// Only build one farmstead for the time being ("DropsiteFood" does not refer to CCs)
|
||||
|
|
@ -1297,7 +1308,7 @@ m.HQ.prototype.buildFarmstead = function(gameState, queues)
|
|||
queues.economicBuilding.addPlan(new m.ConstructionPlan(gameState, "structures/{civ}_farmstead"));
|
||||
};
|
||||
|
||||
// Build a corral, and train animals there
|
||||
/** Build a corral, and train animals there */
|
||||
m.HQ.prototype.manageCorral = function(gameState, queues)
|
||||
{
|
||||
if (queues.corral.hasQueuedUnits())
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
var PETRA = function(m)
|
||||
{
|
||||
/*
|
||||
/**
|
||||
* Common functions and variables to all queue plans.
|
||||
* has a "--" suffix because it needs to be loaded before the other queueplan files.
|
||||
*/
|
||||
|
||||
m.QueuePlan = function(gameState, type, metadata)
|
||||
|
|
@ -25,25 +24,25 @@ m.QueuePlan = function(gameState, type, metadata)
|
|||
return true;
|
||||
};
|
||||
|
||||
// Check the content of this queue
|
||||
/** Check the content of this queue */
|
||||
m.QueuePlan.prototype.isInvalid = function(gameState)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
// if true, the queue manager will begin increasing this plan's account.
|
||||
/** if true, the queue manager will begin increasing this plan's account. */
|
||||
m.QueuePlan.prototype.isGo = function(gameState)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
// can we start this plan immediately?
|
||||
/** can we start this plan immediately? */
|
||||
m.QueuePlan.prototype.canStart = function(gameState)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
// process the plan.
|
||||
/** process the plan. */
|
||||
m.QueuePlan.prototype.start = function(gameState)
|
||||
{
|
||||
// should call onStart.
|
||||
|
|
@ -51,17 +50,19 @@ m.QueuePlan.prototype.start = function(gameState)
|
|||
|
||||
m.QueuePlan.prototype.getCost = function()
|
||||
{
|
||||
var costs = new API3.Resources();
|
||||
let costs = new API3.Resources();
|
||||
costs.add(this.cost);
|
||||
if (this.number !== 1)
|
||||
costs.multiply(this.number);
|
||||
return costs;
|
||||
};
|
||||
|
||||
// On Event functions.
|
||||
// Can be used to do some specific stuffs
|
||||
// Need to be updated to actually do something if you want them to.
|
||||
// this is called by "Start" if it succeeds.
|
||||
/**
|
||||
* On Event functions.
|
||||
* Can be used to do some specific stuffs
|
||||
* Need to be updated to actually do something if you want them to.
|
||||
* this is called by "Start" if it succeeds.
|
||||
*/
|
||||
m.QueuePlan.prototype.onStart = function(gameState)
|
||||
{
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ m.ResearchPlan = function(gameState, type, rush = false)
|
|||
this.category = "technology";
|
||||
|
||||
this.rush = rush;
|
||||
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ m.ResearchPlan.prototype.isInvalid = function(gameState)
|
|||
|
||||
m.ResearchPlan.prototype.start = function(gameState)
|
||||
{
|
||||
var trainers = gameState.findResearchers(this.type).toEntityArray();
|
||||
let trainers = gameState.findResearchers(this.type).toEntityArray();
|
||||
|
||||
// Prefer training buildings with short queues
|
||||
// (TODO: this should also account for units added to the queue by
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ m.TrainingPlan = function(gameState, type, metadata, number = 1, maxMerge = 5)
|
|||
|
||||
this.category = "unit";
|
||||
this.cost = new API3.Resources(this.template.cost(), +this.template._template.Cost.Population);
|
||||
|
||||
|
||||
this.number = number;
|
||||
this.maxMerge = maxMerge;
|
||||
|
||||
|
|
@ -113,10 +113,10 @@ m.TrainingPlan.prototype.addItem = function(amount = 1)
|
|||
// Find the promoted types corresponding to this.type
|
||||
m.TrainingPlan.prototype.promotedTypes = function(gameState)
|
||||
{
|
||||
var types = [];
|
||||
var promotion = this.template.promotion();
|
||||
var previous;
|
||||
var template;
|
||||
let types = [];
|
||||
let promotion = this.template.promotion();
|
||||
let previous;
|
||||
let template;
|
||||
while (promotion)
|
||||
{
|
||||
types.push(promotion);
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ m.ResearchManager.prototype.checkPhase = function(gameState, queues)
|
|||
if (queues.majorTech.hasQueuedUnits())
|
||||
return;
|
||||
|
||||
var townPhase = gameState.townPhase();
|
||||
var cityPhase = gameState.cityPhase();
|
||||
let townPhase = gameState.townPhase();
|
||||
let cityPhase = gameState.cityPhase();
|
||||
|
||||
if (gameState.canResearch(townPhase,true) && gameState.getPopulation() >= this.Config.Economy.popForTown - 10 &&
|
||||
gameState.hasResearchers(townPhase, true))
|
||||
|
|
@ -51,8 +51,8 @@ m.ResearchManager.prototype.researchPopulationBonus = function(gameState, queues
|
|||
if (queues.minorTech.hasQueuedUnits())
|
||||
return;
|
||||
|
||||
var techs = gameState.findAvailableTech();
|
||||
for (var tech of techs)
|
||||
let techs = gameState.findAvailableTech();
|
||||
for (let tech of techs)
|
||||
{
|
||||
if (!tech[1]._template.modifications)
|
||||
continue;
|
||||
|
|
@ -69,8 +69,8 @@ m.ResearchManager.prototype.researchTradeBonus = function(gameState, queues)
|
|||
if (queues.minorTech.hasQueuedUnits())
|
||||
return;
|
||||
|
||||
var techs = gameState.findAvailableTech();
|
||||
for (var tech of techs)
|
||||
let techs = gameState.findAvailableTech();
|
||||
for (let tech of techs)
|
||||
{
|
||||
if (!tech[1]._template.modifications || !tech[1]._template.affects)
|
||||
continue;
|
||||
|
|
@ -85,11 +85,11 @@ m.ResearchManager.prototype.researchTradeBonus = function(gameState, queues)
|
|||
}
|
||||
};
|
||||
|
||||
// Techs to be searched for as soon as they are available
|
||||
/** Techs to be searched for as soon as they are available */
|
||||
m.ResearchManager.prototype.researchWantedTechs = function(gameState, techs)
|
||||
{
|
||||
var available = gameState.currentPhase() === 1 ? gameState.ai.queueManager.getAvailableResources(gameState) : null;
|
||||
var numWorkers = gameState.currentPhase() === 1 ? gameState.getOwnEntitiesByRole("worker", true).length : 0;
|
||||
let available = gameState.currentPhase() === 1 ? gameState.ai.queueManager.getAvailableResources(gameState) : null;
|
||||
let numWorkers = gameState.currentPhase() === 1 ? gameState.getOwnEntitiesByRole("worker", true).length : 0;
|
||||
for (let tech of techs)
|
||||
{
|
||||
if (!tech[1]._template.modifications)
|
||||
|
|
@ -123,11 +123,11 @@ m.ResearchManager.prototype.researchWantedTechs = function(gameState, techs)
|
|||
return false;
|
||||
};
|
||||
|
||||
// Techs to be searched for as soon as they are available, but only after phase 2
|
||||
/** Techs to be searched for as soon as they are available, but only after phase 2 */
|
||||
m.ResearchManager.prototype.researchPreferredTechs = function(gameState, techs)
|
||||
{
|
||||
var available = gameState.currentPhase() === 2 ? gameState.ai.queueManager.getAvailableResources(gameState) : null;
|
||||
var numWorkers = gameState.currentPhase() === 2 ? gameState.getOwnEntitiesByRole("worker", true).length : 0;
|
||||
let available = gameState.currentPhase() === 2 ? gameState.ai.queueManager.getAvailableResources(gameState) : null;
|
||||
let numWorkers = gameState.currentPhase() === 2 ? gameState.getOwnEntitiesByRole("worker", true).length : 0;
|
||||
for (let tech of techs)
|
||||
{
|
||||
if (!tech[1]._template.modifications)
|
||||
|
|
@ -164,9 +164,9 @@ m.ResearchManager.prototype.update = function(gameState, queues)
|
|||
if (queues.minorTech.hasQueuedUnits() || queues.majorTech.hasQueuedUnits())
|
||||
return;
|
||||
|
||||
var techs = gameState.findAvailableTech();
|
||||
let techs = gameState.findAvailableTech();
|
||||
|
||||
var techName = this.researchWantedTechs(gameState, techs);
|
||||
let techName = this.researchWantedTechs(gameState, techs);
|
||||
if (techName)
|
||||
{
|
||||
queues.minorTech.addPlan(new m.ResearchPlan(gameState, techName));
|
||||
|
|
@ -208,7 +208,7 @@ m.ResearchManager.prototype.update = function(gameState, queues)
|
|||
if (!techs.length)
|
||||
return;
|
||||
// randomly pick one. No worries about pairs in that case.
|
||||
var p = Math.floor(Math.random()*techs.length);
|
||||
let p = Math.floor(Math.random()*techs.length);
|
||||
queues.minorTech.addPlan(new m.ResearchPlan(gameState, techs[p][0]));
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
var PETRA = function(m)
|
||||
{
|
||||
|
||||
/*
|
||||
Describes a transport plan
|
||||
Constructor assign units (units is an ID array), a destionation (position).
|
||||
The naval manager will try to deal with it accordingly.
|
||||
|
||||
By this I mean that the naval manager will find how to go from access point 1 to access point 2 (relying on in-game pathfinder for mvt)
|
||||
And then carry units from there.
|
||||
|
||||
Note: only assign it units currently over land, or it won't work.
|
||||
Also: destination should probably be land, otherwise the units will be lost at sea.
|
||||
|
||||
metadata for units:
|
||||
transport = this.ID
|
||||
onBoard = ship.id() when affected to a ship but not yet garrisoned
|
||||
= "onBoard" when garrisoned in a ship
|
||||
= undefined otherwise
|
||||
endPos = position of destination
|
||||
|
||||
metadata for ships
|
||||
transporter = this.ID
|
||||
*/
|
||||
/**
|
||||
* Describes a transport plan
|
||||
* Constructor assign units (units is an ID array), a destination (position).
|
||||
* The naval manager will try to deal with it accordingly.
|
||||
*
|
||||
* By this I mean that the naval manager will find how to go from access point 1 to access point 2
|
||||
* and then carry units from there.
|
||||
*
|
||||
* Note: only assign it units currently over land, or it won't work.
|
||||
* Also: destination should probably be land, otherwise the units will be lost at sea.
|
||||
*
|
||||
* metadata for units:
|
||||
* transport = this.ID
|
||||
* onBoard = ship.id() when affected to a ship but not yet garrisoned
|
||||
* = "onBoard" when garrisoned in a ship
|
||||
* = undefined otherwise
|
||||
* endPos = position of destination
|
||||
*
|
||||
* metadata for ships
|
||||
* transporter = this.ID
|
||||
*/
|
||||
|
||||
m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos, ship)
|
||||
{
|
||||
|
|
@ -89,11 +89,11 @@ m.TransportPlan.prototype.init = function(gameState)
|
|||
this.boardingRange = 18*18; // TODO compute it from the ship clearance and garrison range
|
||||
};
|
||||
|
||||
// count available slots
|
||||
/** count available slots */
|
||||
m.TransportPlan.prototype.countFreeSlots = function()
|
||||
{
|
||||
var self = this;
|
||||
var slots = 0;
|
||||
let self = this;
|
||||
let slots = 0;
|
||||
this.transportShips.forEach(function (ship) { slots += self.countFreeSlotsOnShip(ship); });
|
||||
return slots;
|
||||
};
|
||||
|
|
@ -135,7 +135,7 @@ m.TransportPlan.prototype.assignUnitToShip = function(gameState, ent)
|
|||
|
||||
m.TransportPlan.prototype.assignShip = function(gameState)
|
||||
{
|
||||
var pos;
|
||||
let pos;
|
||||
// choose a unit of this plan not yet assigned to a ship
|
||||
for (let ent of this.units.values())
|
||||
{
|
||||
|
|
@ -145,8 +145,8 @@ m.TransportPlan.prototype.assignShip = function(gameState)
|
|||
break;
|
||||
}
|
||||
// and choose the nearest available ship from this unit
|
||||
var distmin = Math.min();
|
||||
var nearest;
|
||||
let distmin = Math.min();
|
||||
let nearest;
|
||||
gameState.ai.HQ.navalManager.seaTransportShips[this.sea].forEach(function (ship) {
|
||||
if (ship.getMetadata(PlayerID, "transporter"))
|
||||
return;
|
||||
|
|
@ -171,7 +171,7 @@ m.TransportPlan.prototype.assignShip = function(gameState)
|
|||
return true;
|
||||
};
|
||||
|
||||
// add a unit to this plan
|
||||
/** add a unit to this plan */
|
||||
m.TransportPlan.prototype.addUnit = function(unit, endPos)
|
||||
{
|
||||
unit.setMetadata(PlayerID, "transport", this.ID);
|
||||
|
|
@ -199,8 +199,8 @@ m.TransportPlan.prototype.releaseAll = function()
|
|||
|
||||
m.TransportPlan.prototype.cancelTransport = function(gameState)
|
||||
{
|
||||
var ent = this.units.toEntityArray()[0];
|
||||
var base = gameState.ai.HQ.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
let ent = this.units.toEntityArray()[0];
|
||||
let base = gameState.ai.HQ.getBaseByID(ent.getMetadata(PlayerID, "base"));
|
||||
if (!base.anchor || !base.anchor.position())
|
||||
{
|
||||
for (let newbase of gameState.ai.HQ.baseManagers)
|
||||
|
|
@ -224,11 +224,11 @@ m.TransportPlan.prototype.cancelTransport = function(gameState)
|
|||
};
|
||||
|
||||
|
||||
/*
|
||||
try to move on. There are two states:
|
||||
- "boarding" means we're trying to board units onto our ships
|
||||
- "sailing" means we're moving ships and eventually unload units
|
||||
- then the plan is cleared
|
||||
/**
|
||||
* try to move on. There are two states:
|
||||
* - "boarding" means we're trying to board units onto our ships
|
||||
* - "sailing" means we're moving ships and eventually unload units
|
||||
* - then the plan is cleared
|
||||
*/
|
||||
|
||||
m.TransportPlan.prototype.update = function(gameState)
|
||||
|
|
@ -243,9 +243,9 @@ m.TransportPlan.prototype.update = function(gameState)
|
|||
|
||||
m.TransportPlan.prototype.onBoarding = function(gameState)
|
||||
{
|
||||
var ready = true;
|
||||
var self = this;
|
||||
var time = gameState.ai.elapsedTime;
|
||||
let ready = true;
|
||||
let self = this;
|
||||
let time = gameState.ai.elapsedTime;
|
||||
this.units.forEach(function (ent) {
|
||||
if (!ent.getMetadata(PlayerID, "onBoard"))
|
||||
{
|
||||
|
|
@ -342,7 +342,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState)
|
|||
this.recovered = [];
|
||||
};
|
||||
|
||||
// tell if a unit is garrisoned in one of the ships of this plan, and update its metadata if yes
|
||||
/** tell if a unit is garrisoned in one of the ships of this plan, and update its metadata if yes */
|
||||
m.TransportPlan.prototype.isOnBoard = function(ent)
|
||||
{
|
||||
for (let ship of this.transportShips.values())
|
||||
|
|
@ -355,7 +355,7 @@ m.TransportPlan.prototype.isOnBoard = function(ent)
|
|||
return false;
|
||||
};
|
||||
|
||||
// when avoidEnnemy is true, we try to not board/unboard in ennemy territory
|
||||
/** when avoidEnnemy is true, we try to not board/unboard in ennemy territory */
|
||||
m.TransportPlan.prototype.getBoardingPos = function(gameState, ship, landIndex, seaIndex, destination, avoidEnnemy)
|
||||
{
|
||||
if (!gameState.ai.HQ.navalManager.landingZones[landIndex])
|
||||
|
|
@ -369,11 +369,11 @@ m.TransportPlan.prototype.getBoardingPos = function(gameState, ship, landIndex,
|
|||
return destination;
|
||||
}
|
||||
|
||||
var startPos = ship.position();
|
||||
var distmin = Math.min();
|
||||
var posmin = destination;
|
||||
var width = gameState.getMap().width;
|
||||
var cell = gameState.getMap().cellSize;
|
||||
let startPos = ship.position();
|
||||
let distmin = Math.min();
|
||||
let posmin = destination;
|
||||
let width = gameState.getMap().width;
|
||||
let cell = gameState.getMap().cellSize;
|
||||
let alliedDocks = gameState.getAllyStructures().filter(API3.Filters.and(
|
||||
API3.Filters.byClass("Dock"), API3.Filters.byMetadata(PlayerID, "sea", seaIndex))).toEntityArray();
|
||||
for (let i of gameState.ai.HQ.navalManager.landingZones[landIndex][seaIndex])
|
||||
|
|
@ -392,8 +392,9 @@ m.TransportPlan.prototype.getBoardingPos = function(gameState, ship, landIndex,
|
|||
// require a small distance between all ships of the transport plan to avoid path finder problems
|
||||
// this is also used when the ship is blocked and we want to find a new boarding point
|
||||
for (let shipId in this.boardingPos)
|
||||
if (this.boardingPos[shipId] !== undefined && API3.SquareVectorDistance(this.boardingPos[shipId], pos) < this.boardingRange)
|
||||
dist += 1000000;
|
||||
if (this.boardingPos[shipId] !== undefined &&
|
||||
API3.SquareVectorDistance(this.boardingPos[shipId], pos) < this.boardingRange)
|
||||
dist += 1000000;
|
||||
// and not too near our allied docks to not disturb naval traffic
|
||||
for (let dock of alliedDocks)
|
||||
{
|
||||
|
|
@ -452,7 +453,7 @@ m.TransportPlan.prototype.onSailing = function(gameState)
|
|||
this.recovered = [];
|
||||
|
||||
// Check that the units unloaded on the previous turn have been really unloaded and in the right position
|
||||
var shipsToMove = {};
|
||||
let shipsToMove = {};
|
||||
for (let entId of this.unloaded)
|
||||
{
|
||||
let ent = gameState.getEntityById(entId);
|
||||
|
|
@ -529,9 +530,9 @@ m.TransportPlan.prototype.onSailing = function(gameState)
|
|||
{
|
||||
if (ship.unitAIState() === "INDIVIDUAL.WALKING")
|
||||
continue;
|
||||
var shipId = ship.id();
|
||||
var dist = API3.SquareVectorDistance(ship.position(), this.boardingPos[shipId]);
|
||||
var remaining = 0;
|
||||
let shipId = ship.id();
|
||||
let dist = API3.SquareVectorDistance(ship.position(), this.boardingPos[shipId]);
|
||||
let remaining = 0;
|
||||
for (let entId of ship.garrisoned())
|
||||
{
|
||||
let ent = gameState.getEntityById(entId);
|
||||
|
|
@ -546,7 +547,7 @@ m.TransportPlan.prototype.onSailing = function(gameState)
|
|||
}
|
||||
}
|
||||
|
||||
var recovering = 0;
|
||||
let recovering = 0;
|
||||
for (let recov of this.recovered)
|
||||
if (recov.shipId === shipId)
|
||||
recovering++;
|
||||
|
|
|
|||
Loading…
Reference in a new issue