mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-07-04 05:55:47 -07:00
Fix a few bugs.
Improve the AI gamestate to make better use of entity collections, should be very slightly faster, and it's cleaner. Remove enemy watchers that were no longer used. This was SVN commit r14574.
This commit is contained in:
parent
8195e767ef
commit
9d02495a96
12 changed files with 279 additions and 527 deletions
|
|
@ -146,7 +146,7 @@ m.AegisBot.prototype.OnUpdate = function(sharedScript) {
|
|||
// TODO: softcode this.
|
||||
if (this.gameState.canResearch(townPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.townPhase*1000) && this.gameState.getPopulation() > 40
|
||||
&& this.gameState.findResearchers(townPhase,true).length != 0 && this.queues.majorTech.length() === 0
|
||||
&& this.gameState.getOwnEntities().filter(API3.Filters.byClass("Village")).length > 5)
|
||||
&& this.gameState.getOwnStructures().filter(API3.Filters.byClass("Village")).length > 5)
|
||||
{
|
||||
this.queueManager.pauseQueue("villager", true);
|
||||
this.queueManager.pauseQueue("citizenSoldier", true);
|
||||
|
|
@ -155,7 +155,7 @@ m.AegisBot.prototype.OnUpdate = function(sharedScript) {
|
|||
m.debug ("Trying to reach town phase");
|
||||
}
|
||||
else if (this.gameState.canResearch(cityPhase,true) && this.gameState.getTimeElapsed() > (this.Config.Economy.cityPhase*1000)
|
||||
&& this.gameState.getOwnEntitiesByRole("worker").length > 85
|
||||
&& this.gameState.getOwnEntitiesByRole("worker", true).length > 85
|
||||
&& this.gameState.findResearchers(cityPhase, true).length != 0 && this.queues.majorTech.length() === 0) {
|
||||
m.debug ("Trying to reach city phase");
|
||||
this.queues.majorTech.addItem(new m.ResearchPlan(this.gameState, cityPhase));
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m.CityAttack = function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy,
|
|||
return false;
|
||||
}
|
||||
|
||||
var CCs = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre"));
|
||||
var CCs = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
|
||||
if (CCs.length === 0)
|
||||
{
|
||||
this.failed = true;
|
||||
|
|
@ -125,7 +125,7 @@ m.CityAttack = function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy,
|
|||
};*/
|
||||
|
||||
var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID));
|
||||
this.unitCollection = gameState.getOwnEntities().filter(filter);
|
||||
this.unitCollection = gameState.getOwnUnits().filter(filter);
|
||||
this.unitCollection.registerUpdates();
|
||||
this.unitCollection.length;
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ m.CityAttack = function CityAttack(gameState, HQ, Config, uniqueID, targetEnemy,
|
|||
var Unit = this.unitStat[cat];
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)));
|
||||
this.unit[cat] = gameState.getOwnEntities().filter(filter);
|
||||
this.unit[cat] = gameState.getOwnUnits().filter(filter);
|
||||
this.unit[cat].registerUpdates();
|
||||
this.unit[cat].length;
|
||||
this.buildOrder.push([0, Unit["classes"], this.unit[cat], Unit, cat]);
|
||||
|
|
@ -321,7 +321,7 @@ m.CityAttack.prototype.addBuildOrder = function(gameState, name, unitStats, rese
|
|||
this.unitStat[name] = unitStats;
|
||||
var Unit = this.unitStat[name];
|
||||
var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)));
|
||||
this.unit[name] = gameState.getOwnEntities().filter(filter);
|
||||
this.unit[name] = gameState.getOwnUnits().filter(filter);
|
||||
this.unit[name].registerUpdates();
|
||||
this.buildOrder.push([0, Unit["classes"], this.unit[name], Unit, name]);
|
||||
if (resetQueue)
|
||||
|
|
@ -592,9 +592,9 @@ m.CityAttack.prototype.assignUnits = function(gameState){
|
|||
|
||||
// TODO: assign myself units that fit only, right now I'm getting anything.
|
||||
// Assign all no-roles that fit (after a plan aborts, for example).
|
||||
var NoRole = gameState.getOwnEntitiesByRole(undefined);
|
||||
var NoRole = gameState.getOwnEntitiesByRole(undefined, false);
|
||||
if (this.type === "rush")
|
||||
NoRole = gameState.getOwnEntitiesByRole("worker");
|
||||
NoRole = gameState.getOwnEntitiesByRole("worker", true);
|
||||
NoRole.forEach(function(ent) {
|
||||
if (ent.hasClass("Unit") && ent.attackTypes() !== undefined)
|
||||
{
|
||||
|
|
@ -641,20 +641,20 @@ m.CityAttack.prototype.AllToRallyPoint = function(gameState, evenWorkers) {
|
|||
m.CityAttack.prototype.defaultTargetFinder = function(gameState, HQ){
|
||||
var targets = undefined;
|
||||
|
||||
targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "CivCentre",true);
|
||||
targets = gameState.getEnemyStructures(this.targetPlayer).filter(m.Filters.byClass("CivCentre"));
|
||||
if (targets.length == 0) {
|
||||
targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "ConquestCritical");
|
||||
targets = gameState.getEnemyStructures(this.targetPlayer).filter(m.Filters.byClass("ConquestCritical"));
|
||||
}
|
||||
// If there's nothing, attack anything else that's less critical
|
||||
if (targets.length == 0) {
|
||||
targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "Town",true);
|
||||
targets = gameState.getEnemyStructures(this.targetPlayer).filter(m.Filters.byClass("Town"));
|
||||
}
|
||||
if (targets.length == 0) {
|
||||
targets = HQ.enemyWatchers[this.targetPlayer].getEnemyBuildings(gameState, "Village",true);
|
||||
targets = gameState.getEnemyStructures(this.targetPlayer).filter(m.Filters.byClass("Village"));
|
||||
}
|
||||
// no buildings, attack anything conquest critical, even units (it's assuming it won't move).
|
||||
if (targets.length == 0) {
|
||||
targets = gameState.getEnemyEntities().filter(API3.Filters.and( API3.Filters.byOwner(this.targetPlayer),API3.Filters.byClass("ConquestCritical")));
|
||||
targets = gameState.getEnemyEntities(this.targetPlayer).filter(m.Filters.byClass("ConquestCritical"));
|
||||
}
|
||||
return targets;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ m.BaseManager = function(Config) {
|
|||
m.BaseManager.prototype.init = function(gameState, events, unconstructed){
|
||||
this.constructing = unconstructed;
|
||||
// entitycollections
|
||||
this.units = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Unit"),API3.Filters.byMetadata(PlayerID, "base", this.ID)));
|
||||
this.buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byMetadata(PlayerID, "base", this.ID)));
|
||||
this.units = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "base", this.ID));
|
||||
this.buildings = gameState.getOwnStructures().filter(API3.Filters.byMetadata(PlayerID, "base", this.ID));
|
||||
|
||||
this.workers = this.units.filter(API3.Filters.byMetadata(PlayerID,"role","worker"));
|
||||
|
||||
|
|
@ -623,7 +623,7 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState,queues) {
|
|||
queues.field.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_field", { "base" : this.ID }));
|
||||
// TODO: refine count to only count my base.
|
||||
}
|
||||
} else if (queues.dropsites.length() === 0 && gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_storehouse")) === 0) {
|
||||
} else if (queues.dropsites.length() === 0 && gameState.countFoundationsByType(gameState.applyCiv("structures/{civ}_storehouse")) === 0) {
|
||||
var wantedDPs = Math.ceil(this.gatherersByType(gameState, type).length / 12.0);
|
||||
var need = wantedDPs - this.getResourceLevel(gameState,type, "dropsites-dpcount",2000);
|
||||
if (need > 0)
|
||||
|
|
@ -947,7 +947,7 @@ m.BaseManager.prototype.update = function(gameState, queues, events) {
|
|||
|
||||
/*Engine.ProfileStart("Swap Workers");
|
||||
var gathererGroups = {};
|
||||
gameState.getOwnEntitiesByRole("worker").forEach(function(ent){ }){
|
||||
gameState.getOwnEntitiesByRole("worker", true).forEach(function(ent){ }){
|
||||
if (ent.hasClass("Cavalry"))
|
||||
return;
|
||||
var key = uneval(ent.resourceGatherRates());
|
||||
|
|
|
|||
|
|
@ -140,6 +140,8 @@ m.Army.prototype.recalculatePosition = function(gameState, force)
|
|||
{
|
||||
var ent = gameState.getEntityById(this.entities[i]);
|
||||
var epos = ent.position();
|
||||
if (epos == undefined)
|
||||
continue;
|
||||
pos[0] += epos[0];
|
||||
pos[1] += epos[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,13 +60,11 @@ m.Defence.prototype.isDangerous = function(gameState, entity)
|
|||
if (this.territoryMap.getOwner(entity.position()) === entity.owner() || entity.attackTypes() === undefined)
|
||||
return false;
|
||||
|
||||
// TODO: use global collections.
|
||||
var myBuildings = gameState.getOwnEntities().filter(API3.Filters.byClass("Structure"));
|
||||
var myBuildings = gameState.getOwnStructures();
|
||||
for (var i in myBuildings._entities)
|
||||
{
|
||||
if (API3.SquareVectorDistance(myBuildings._entities[i].position(), entity.position()) < 6000)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -186,12 +184,12 @@ m.Defence.prototype.assignDefenders = function(gameState, events)
|
|||
API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "DefManagerArmy"))),
|
||||
API3.Filters.and(API3.Filters.not(API3.Filters.byMetadata(PlayerID,"subrole","walking")),
|
||||
API3.Filters.not(API3.Filters.byMetadata(PlayerID,"subrole","attacking"))));
|
||||
var potentialDefendersOne = gameState.getOwnEntities().filter(filter).toIdArray();
|
||||
var potentialDefendersOne = gameState.getOwnUnits().filter(filter).toIdArray();
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.and(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan")),
|
||||
API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "DefManagerArmy"))),
|
||||
API3.Filters.byClassesOr(["Infantry","Cavalry"]));
|
||||
var potentialDefendersTwo = gameState.getOwnEntities().filter(filter).toIdArray();
|
||||
var potentialDefendersTwo = gameState.getOwnUnits().filter(filter).toIdArray();
|
||||
|
||||
var potDefs = this.releasedDefenders.concat(potentialDefendersOne).concat(potentialDefendersTwo);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,222 +0,0 @@
|
|||
var AEGIS = function(m)
|
||||
{
|
||||
|
||||
/*
|
||||
* A class that keeps track of enemy buildings, units, and pretty much anything I can think of (still a LOT TODO here)
|
||||
* Only watches one enemy, you'll need one per enemy.
|
||||
* Note: pretty much unused in the current version.
|
||||
*/
|
||||
|
||||
m.enemyWatcher = function(gameState, playerToWatch) {
|
||||
|
||||
this.watched = playerToWatch;
|
||||
|
||||
// using global entity collections, shared by any AI that knows the name of this.
|
||||
|
||||
var filter = API3.Filters.and(API3.Filters.byClass("Structure"), API3.Filters.byOwner(this.watched));
|
||||
this.enemyBuildings = gameState.updatingGlobalCollection("player-" +this.watched + "-structures", filter);
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClass("Unit"), API3.Filters.byOwner(this.watched));
|
||||
this.enemyUnits = gameState.updatingGlobalCollection("player-" +this.watched + "-units", filter);
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched));
|
||||
this.enemyCivilians = gameState.updatingGlobalCollection("player-" +this.watched + "-civilians", filter);
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched));
|
||||
this.enemySoldiers = gameState.updatingGlobalCollection("player-" +this.watched + "-soldiers", filter);
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClass("Worker"), API3.Filters.byOwner(this.watched));
|
||||
this.enemyCivilians = gameState.getEnemyEntities().filter(filter);
|
||||
this.enemyCivilians.registerUpdates();
|
||||
|
||||
filter = API3.Filters.and(API3.Filters.byClassesOr(["CitizenSoldier", "Hero", "Champion", "Siege"]), API3.Filters.byOwner(this.watched));
|
||||
this.enemySoldiers = gameState.getEnemyEntities().filter(filter);
|
||||
this.enemySoldiers.registerUpdates();
|
||||
|
||||
// entity collections too.
|
||||
this.armies = {};
|
||||
|
||||
this.enemyBuildingClass = {};
|
||||
this.totalNBofArmies = 0;
|
||||
|
||||
// this is an array of integers, refering to "this.armies[ XX ]"
|
||||
this.dangerousArmies = [];
|
||||
|
||||
};
|
||||
m.enemyWatcher.prototype.getAllEnemySoldiers = function() {
|
||||
return this.enemySoldiers;
|
||||
};
|
||||
m.enemyWatcher.prototype.getAllEnemyBuildings = function() {
|
||||
return this.enemyBuildings;
|
||||
};
|
||||
|
||||
m.enemyWatcher.prototype.getEnemyBuildings = function(gameState, specialClass, OneTime) {
|
||||
var filter = API3.Filters.byClass(specialClass);
|
||||
|
||||
if (OneTime && gameState.getGEC("player-" +this.watched + "-structures-" +specialClass))
|
||||
return gameState.getGEC("player-" +this.watched + "-structures-" +specialClass);
|
||||
else if (OneTime)
|
||||
return this.enemyBuildings.filter(filter);
|
||||
|
||||
return gameState.updatingGlobalCollection("player-" +this.watched + "-structures-" +specialClass, filter, gameState.getGEC("player-" +this.watched + "-structures"));
|
||||
};
|
||||
m.enemyWatcher.prototype.getDangerousArmies = function() {
|
||||
var toreturn = {};
|
||||
for (var i in this.dangerousArmies)
|
||||
toreturn[this.dangerousArmies[i]] = this.armies[this.dangerousArmies[i]];
|
||||
return toreturn;
|
||||
};
|
||||
m.enemyWatcher.prototype.getSafeArmies = function() {
|
||||
var toreturn = {};
|
||||
for (var i in this.armies)
|
||||
if (this.dangerousArmies.indexOf(i) == -1)
|
||||
toreturn[i] = this.armies[i];
|
||||
return toreturn;
|
||||
};
|
||||
m.enemyWatcher.prototype.resetDangerousArmies = function() {
|
||||
this.dangerousArmies = [];
|
||||
};
|
||||
m.enemyWatcher.prototype.setAsDangerous = function(armyID) {
|
||||
if (this.dangerousArmies.indexOf(armyID) === -1)
|
||||
this.dangerousArmies.push(armyID);
|
||||
};
|
||||
m.enemyWatcher.prototype.isDangerous = function(armyID) {
|
||||
if (this.dangerousArmies.indexOf(armyID) === -1)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
// returns [id, army]
|
||||
m.enemyWatcher.prototype.getArmyFromMember = function(memberID) {
|
||||
for (var i in this.armies) {
|
||||
if (this.armies[i].toIdArray().indexOf(memberID) !== -1)
|
||||
return [i,this.armies[i]];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
m.enemyWatcher.prototype.isPartOfDangerousArmy = function(memberID) {
|
||||
var armyID = this.getArmyFromMember(memberID)[0];
|
||||
if (this.isDangerous(armyID))
|
||||
return true;
|
||||
return false;
|
||||
};
|
||||
m.enemyWatcher.prototype.cleanDebug = function() {
|
||||
for (var armyID in this.armies) {
|
||||
var army = this.armies[armyID];
|
||||
m.debug ("Army " +armyID);
|
||||
m.debug (army.length +" members, centered around " +army.getCentrePosition());
|
||||
}
|
||||
}
|
||||
|
||||
// this will monitor any unmonitored soldier.
|
||||
m.enemyWatcher.prototype.detectArmies = function(gameState){
|
||||
//this.cleanDebug();
|
||||
|
||||
var self = this;
|
||||
if (gameState.ai.playedTurn % 4 === 0) {
|
||||
Engine.ProfileStart("Looking for new soldiers");
|
||||
// let's loop through unmonitored enemy soldiers
|
||||
this.unmonitoredEnemySoldiers.forEach( function (enemy) { //}){
|
||||
if (enemy.position() === undefined)
|
||||
return;
|
||||
|
||||
// this was an unmonitored unit, we do not know any army associated with it. We assign it a new army (we'll merge later if needed)
|
||||
enemy.setMetadata(PlayerID, "monitored","true");
|
||||
var armyID = gameState.player + "" + self.totalNBofArmies;
|
||||
self.totalNBofArmies++,
|
||||
enemy.setMetadata(PlayerID, "EnemyWatcherArmy",armyID);
|
||||
var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",armyID);
|
||||
var army = self.enemySoldiers.filter(filter);
|
||||
self.armies[armyID] = army;
|
||||
self.armies[armyID].registerUpdates();
|
||||
self.armies[armyID].length;
|
||||
});
|
||||
Engine.ProfileStop();
|
||||
} else if (gameState.ai.playedTurn % 16 === 3) {
|
||||
Engine.ProfileStart("Merging");
|
||||
this.mergeArmies(); // calls "scrap empty armies"
|
||||
Engine.ProfileStop();
|
||||
} else if (gameState.ai.playedTurn % 16 === 7) {
|
||||
Engine.ProfileStart("Splitting");
|
||||
this.splitArmies(gameState);
|
||||
Engine.ProfileStop();
|
||||
}
|
||||
};
|
||||
// this will merge any two army who are too close together. The distance for "army" is fairly big.
|
||||
// note: this doesn't actually merge two entity collections... It simply changes the unit metadatas, and will clear the empty entity collection
|
||||
m.enemyWatcher.prototype.mergeArmies = function(){
|
||||
for (var army in this.armies) {
|
||||
var firstArmy = this.armies[army];
|
||||
if (firstArmy.length !== 0) {
|
||||
var firstAPos = firstArmy.getApproximatePosition(4);
|
||||
for (var otherArmy in this.armies) {
|
||||
if (otherArmy !== army && this.armies[otherArmy].length !== 0) {
|
||||
var secondArmy = this.armies[otherArmy];
|
||||
// we're not self merging, so we check if the two armies are close together
|
||||
if (m.inRange(firstAPos,secondArmy.getApproximatePosition(4), 4000 ) ) {
|
||||
// okay so we merge the two together
|
||||
|
||||
// if the other one was dangerous and we weren't, we're now.
|
||||
if (this.dangerousArmies.indexOf(otherArmy) !== -1 && this.dangerousArmies.indexOf(army) === -1)
|
||||
this.dangerousArmies.push(army);
|
||||
|
||||
secondArmy.forEach( function(ent) {
|
||||
ent.setMetadata(PlayerID, "EnemyWatcherArmy",army);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.ScrapEmptyArmies();
|
||||
};
|
||||
m.enemyWatcher.prototype.ScrapEmptyArmies = function(){
|
||||
var removelist = [];
|
||||
for (var army in this.armies) {
|
||||
if (this.armies[army].length === 0) {
|
||||
removelist.push(army);
|
||||
// if the army was dangerous, we remove it from the list
|
||||
if (this.dangerousArmies.indexOf(army) !== -1)
|
||||
this.dangerousArmies.splice(this.dangerousArmies.indexOf(army),1);
|
||||
}
|
||||
}
|
||||
for each (var toRemove in removelist) {
|
||||
delete this.armies[toRemove];
|
||||
}
|
||||
};
|
||||
// splits any unit too far from the centerposition
|
||||
m.enemyWatcher.prototype.splitArmies = function(gameState){
|
||||
var self = this;
|
||||
|
||||
var map = m.createTerritoryMap(gameState);
|
||||
|
||||
for (var armyID in this.armies) {
|
||||
var army = this.armies[armyID];
|
||||
var centre = army.getApproximatePosition(4);
|
||||
|
||||
if (map.getOwner(centre) === gameState.player)
|
||||
continue;
|
||||
|
||||
army.forEach( function (enemy) {
|
||||
if (enemy.position() === undefined)
|
||||
return;
|
||||
|
||||
if (!m.inRange(enemy.position(),centre, 3500) ) {
|
||||
var newArmyID = gameState.player + "" + self.totalNBofArmies;
|
||||
if (self.dangerousArmies.indexOf(armyID) !== -1)
|
||||
self.dangerousArmies.push(newArmyID);
|
||||
|
||||
self.totalNBofArmies++,
|
||||
enemy.setMetadata(PlayerID, "EnemyWatcherArmy",newArmyID);
|
||||
var filter = API3.Filters.byMetadata(PlayerID, "EnemyWatcherArmy",newArmyID);
|
||||
var newArmy = self.enemySoldiers.filter(filter);
|
||||
self.armies[newArmyID] = newArmy;
|
||||
self.armies[newArmyID].registerUpdates();
|
||||
self.armies[newArmyID].length;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return m;
|
||||
}(AEGIS);
|
||||
|
|
@ -74,7 +74,7 @@ m.HQ.prototype.init = function(gameState, events, queues){
|
|||
if (ents.filter(API3.Filters.byClass("Cavalry")).length > 0)
|
||||
hasScout = true;
|
||||
|
||||
// tODO: take multiple CCs into account.
|
||||
// TODO: take multiple CCs into account.
|
||||
if (hasCC)
|
||||
{
|
||||
var CC = ents.filter(API3.Filters.byClass("CivCentre")).toEntityArray()[0];
|
||||
|
|
@ -121,10 +121,9 @@ m.HQ.prototype.init = function(gameState, events, queues){
|
|||
|
||||
//this.reassignIdleWorkers(gameState);
|
||||
|
||||
|
||||
this.navalManager.init(gameState, events, queues);
|
||||
|
||||
// TODO: change that.
|
||||
// TODO: change that to something dynamic.
|
||||
var civ = gameState.playerData.civ;
|
||||
|
||||
// load units and buildings from the config files
|
||||
|
|
@ -153,27 +152,6 @@ m.HQ.prototype.init = function(gameState, events, queues){
|
|||
for (var i in this.bFort){
|
||||
this.bFort[i] = gameState.applyCiv(this.bFort[i]);
|
||||
}
|
||||
|
||||
// TODO: figure out how to make this generic
|
||||
for (var i in this.attackManagers){
|
||||
this.availableAttacks[i] = new this.attackManagers[i](gameState, this);
|
||||
}
|
||||
|
||||
var enemies = gameState.getEnemyEntities();
|
||||
var filter = API3.Filters.byClassesOr(["CitizenSoldier", "Champion", "Hero", "Siege"]);
|
||||
this.enemySoldiers = enemies.filter(filter); // TODO: cope with diplomacy changes
|
||||
this.enemySoldiers.registerUpdates();
|
||||
|
||||
// each enemy watchers keeps a list of entity collections about the enemy it watches
|
||||
// It also keeps track of enemy armies, merging/splitting as needed
|
||||
// TODO: remove those.
|
||||
this.enemyWatchers = {};
|
||||
this.ennWatcherIndex = [];
|
||||
for (var i = 1; i <= 8; i++)
|
||||
if (PlayerID != i && gameState.isPlayerEnemy(i)) {
|
||||
this.enemyWatchers[i] = new m.enemyWatcher(gameState, i);
|
||||
this.ennWatcherIndex.push(i);
|
||||
}
|
||||
};
|
||||
|
||||
m.HQ.prototype.checkEvents = function (gameState, events, queues) {
|
||||
|
|
@ -244,14 +222,16 @@ m.HQ.prototype.checkEvents = function (gameState, events, queues) {
|
|||
// TODO: This should probably be changed to favor a more mixed approach for better defense.
|
||||
// (or even to adapt based on estimated enemy strategy).
|
||||
// TODO: this should probably set which base it wants them in.
|
||||
m.HQ.prototype.trainMoreWorkers = function(gameState, queues) {
|
||||
m.HQ.prototype.trainMoreWorkers = function(gameState, queues)
|
||||
{
|
||||
// Get some data.
|
||||
// Count the workers in the world and in progress
|
||||
var numFemales = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("units/{civ}_support_female_citizen"));
|
||||
numFemales += queues.villager.countQueuedUnitsWithClass("Support");
|
||||
|
||||
// counting the workers that aren't part of a plan
|
||||
var numWorkers = 0;
|
||||
gameState.getOwnEntities().forEach (function (ent) {
|
||||
gameState.getOwnunits().forEach (function (ent) {
|
||||
if (ent.getMetadata(PlayerID, "role") == "worker" && ent.getMetadata(PlayerID, "plan") == undefined)
|
||||
numWorkers++;
|
||||
});
|
||||
|
|
@ -273,12 +253,12 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues) {
|
|||
var template = gameState.applyCiv("units/{civ}_support_female_citizen");
|
||||
|
||||
var size = Math.min(5, Math.ceil(numTotal / 10));
|
||||
|
||||
if (numFemales/numTotal > this.femaleRatio && (numTotal > 20 || (this.fastStart && numTotal > 10))) {
|
||||
if (numTotal < 100)
|
||||
template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["cost",1], ["speed",0.5], ["costsResource", 0.5, "stone"], ["costsResource", 0.5, "metal"]]);
|
||||
else
|
||||
template = this.findBestTrainableUnit(gameState, ["CitizenSoldier", "Infantry"], [ ["strength",1] ]);
|
||||
|
||||
if (!template)
|
||||
template = gameState.applyCiv("units/{civ}_support_female_citizen");
|
||||
if (gameState.currentPhase() === 1)
|
||||
|
|
@ -286,10 +266,10 @@ m.HQ.prototype.trainMoreWorkers = function(gameState, queues) {
|
|||
}
|
||||
|
||||
// TODO: improve that logic.
|
||||
if (numFemales/numTotal > this.femaleRatio * 1.3 && numTotal > 25)
|
||||
if (numFemales/numTotal > this.femaleRatio * 1.3 && numWorkers > 25)
|
||||
queues.villager.paused = true;
|
||||
else if ((numFemales/numTotal < this.femaleRatio * 1.1) || gameState.ai.queueManager.getAvailableResources(gameState)["food"] > 250
|
||||
|| numTotal <= 25)
|
||||
|| numWorkers <= 25)
|
||||
queues.villager.paused = false;
|
||||
|
||||
// TODO: perhaps assign them a default resource and check the base according to that.
|
||||
|
|
@ -557,8 +537,8 @@ m.HQ.prototype.findBestEcoCCLocation = function(gameState, resource){
|
|||
// copy the resource map as initialization.
|
||||
var friendlyTiles = new API3.Map(gameState.sharedScript, gameState.sharedScript.CCResourceMaps[resource].map, true);
|
||||
friendlyTiles.setMaxVal(255);
|
||||
var ents = gameState.getOwnEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
var eEnts = gameState.getEnemyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
var ents = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
var eEnts = gameState.getEnemyStructures().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
|
||||
|
||||
var dps = gameState.getOwnDropsites().toEntityArray();
|
||||
|
||||
|
|
@ -806,10 +786,10 @@ m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) {
|
|||
for (var type in count)
|
||||
{
|
||||
if (count[type] === 0 || need[type]
|
||||
|| capacity[type] < gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byMetadata(PlayerID, "subrole", "gatherer"), API3.Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05)
|
||||
|| capacity[type] < gameState.getOwnUnits().filter(API3.Filters.and(API3.Filters.byMetadata(PlayerID, "subrole", "gatherer"), API3.Filters.byMetadata(PlayerID, "gather-type", type))).length * 1.05)
|
||||
{
|
||||
// plan a new base.
|
||||
if (gameState.countFoundationsWithType(gameState.applyCiv("structures/{civ}_civil_centre")) === 0 && queues.civilCentre.length() === 0) {
|
||||
if (gameState.countFoundationsByType(gameState.applyCiv("structures/{civ}_civil_centre")) === 0 && queues.civilCentre.length() === 0) {
|
||||
if (this.outOf[type] && gameState.ai.playedTurn % 10 !== 0)
|
||||
continue;
|
||||
var pos = this.findBestEcoCCLocation(gameState, type);
|
||||
|
|
@ -831,7 +811,7 @@ m.HQ.prototype.checkBasesRessLevel = function(gameState,queues) {
|
|||
// TODO: Fortresses are placed randomly atm.
|
||||
m.HQ.prototype.buildDefences = function(gameState, queues){
|
||||
|
||||
var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan"))).length;
|
||||
var workersNumber = gameState.getOwnEntitiesByRole("worker", true).filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID,"plan"))).length;
|
||||
|
||||
if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv('structures/{civ}_defense_tower'))
|
||||
+ queues.defenceBuilding.length() < gameState.getEntityLimits()["DefenseTower"] && queues.defenceBuilding.length() < 4 && gameState.currentPhase() > 1) {
|
||||
|
|
@ -904,7 +884,7 @@ m.HQ.prototype.buildBlacksmith = function(gameState, queues){
|
|||
// TODO: building placement is bad. Choice of buildings is also fairly dumb.
|
||||
m.HQ.prototype.constructTrainingBuildings = function(gameState, queues) {
|
||||
Engine.ProfileStart("Build buildings");
|
||||
var workersNumber = gameState.getOwnEntitiesByRole("worker").filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "plan"))).length;
|
||||
var workersNumber = gameState.getOwnEntitiesByRole("worker", true).filter(API3.Filters.not(API3.Filters.byHasMetadata(PlayerID, "plan"))).length;
|
||||
|
||||
if (workersNumber > this.Config.Military.popForBarracks1) {
|
||||
if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bModerate[0])) + queues.militaryBuilding.length() < 1) {
|
||||
|
|
@ -931,7 +911,7 @@ m.HQ.prototype.constructTrainingBuildings = function(gameState, queues) {
|
|||
if (queues.militaryBuilding.length() === 0){
|
||||
var inConst = 0;
|
||||
for (var i in this.bAdvanced)
|
||||
inConst += gameState.countFoundationsWithType(gameState.applyCiv(this.bAdvanced[i]));
|
||||
inConst += gameState.countFoundationsByType(gameState.applyCiv(this.bAdvanced[i]));
|
||||
if (inConst == 0 && this.bAdvanced && this.bAdvanced.length !== 0) {
|
||||
var i = Math.floor(Math.random() * this.bAdvanced.length);
|
||||
if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i])) < 1){
|
||||
|
|
@ -960,8 +940,8 @@ m.HQ.prototype.constructTrainingBuildings = function(gameState, queues) {
|
|||
|
||||
// TODO: use pop(). Currently unused as this is too gameable.
|
||||
m.HQ.prototype.garrisonAllFemales = function(gameState) {
|
||||
var buildings = gameState.getOwnEntities().filter(API3.Filters.byCanGarrison()).toEntityArray();
|
||||
var females = gameState.getOwnEntities().filter(API3.Filters.byClass("Support"));
|
||||
var buildings = gameState.getOwnStructures().filter(API3.Filters.byCanGarrison()).toEntityArray();
|
||||
var females = gameState.getOwnUnits().filter(API3.Filters.byClass("Support"));
|
||||
|
||||
var cache = {};
|
||||
|
||||
|
|
@ -986,7 +966,7 @@ m.HQ.prototype.garrisonAllFemales = function(gameState) {
|
|||
};
|
||||
m.HQ.prototype.ungarrisonAll = function(gameState) {
|
||||
this.hasGarrisonedFemales = false;
|
||||
var buildings = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byCanGarrison())).toEntityArray();
|
||||
var buildings = gameState.getOwnStructures().filter(API3.Filters.and(API3.Filters.byClass("Structure"),API3.Filters.byCanGarrison())).toEntityArray();
|
||||
buildings.forEach( function (struct) {
|
||||
if (struct.garrisoned() && struct.garrisoned().length)
|
||||
struct.unloadAll();
|
||||
|
|
|
|||
|
|
@ -116,14 +116,14 @@ m.createObstructionMap = function(gameState, accessIndex, template){
|
|||
var minDist = template.buildDistance().MinDistance;
|
||||
var category = template.buildDistance().FromCategory;
|
||||
if (minDist !== undefined && category !== undefined){
|
||||
gameState.getOwnEntities().forEach(function(ent) {
|
||||
if (ent.buildCategory() === category && ent.position()){
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / gameState.cellSize);
|
||||
var z = Math.round(pos[1] / gameState.cellSize);
|
||||
map.addInfluence(x, z, minDist/gameState.cellSize, -255, 'constant');
|
||||
}
|
||||
});
|
||||
gameState.getOwnStructures().forEach(function(ent) {
|
||||
if (ent.buildCategory() === category && ent.position()){
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / gameState.cellSize);
|
||||
var z = Math.round(pos[1] / gameState.cellSize);
|
||||
map.addInfluence(x, z, minDist/gameState.cellSize, -255, 'constant');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return map;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ m.NavalManager = function() {
|
|||
// More initialisation for stuff that needs the gameState
|
||||
m.NavalManager.prototype.init = function(gameState, events, queues) {
|
||||
// finished docks
|
||||
this.docks = gameState.getOwnEntities().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation())));
|
||||
this.docks = gameState.getOwnStructures().filter(API3.Filters.and(API3.Filters.byClass("Dock"), API3.Filters.not(API3.Filters.isFoundation())));
|
||||
this.docks.allowQuickIter();
|
||||
this.docks.registerUpdates();
|
||||
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ m.QueueManager.prototype.update = function(gameState) {
|
|||
|
||||
Engine.ProfileStop();
|
||||
|
||||
if (gameState.ai.playedTurn % 10 === 5)
|
||||
if (gameState.ai.playedTurn % 30 === 5)
|
||||
this.HTMLprintQueues(gameState);
|
||||
|
||||
Engine.ProfileStop();
|
||||
|
|
|
|||
|
|
@ -118,56 +118,54 @@ m.ConstructionPlan.prototype.findGoodPosition = function(gameState) {
|
|||
friendlyTiles.addInfluence(x, z, 255);
|
||||
} else {
|
||||
// No position was specified so try and find a sensible place to build
|
||||
gameState.getOwnEntities().forEach(function(ent) {
|
||||
if (ent.hasClass("Structure")) {
|
||||
var infl = 32;
|
||||
if (ent.hasClass("CivCentre"))
|
||||
infl *= 4;
|
||||
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
|
||||
if (ent.buildCategory() == "Wall") { // no real blockers, but can't build where they are
|
||||
friendlyTiles.addInfluence(x, z, 2,-1000);
|
||||
return;
|
||||
}
|
||||
gameState.getOwnStructures().forEach(function(ent) {
|
||||
var infl = 32;
|
||||
if (ent.hasClass("CivCentre"))
|
||||
infl *= 4;
|
||||
|
||||
if (template._template.BuildRestrictions.Category === "Field"){
|
||||
if (ent.resourceDropsiteTypes() && ent.resourceDropsiteTypes().indexOf("food") !== -1){
|
||||
if (ent.hasClass("CivCentre"))
|
||||
friendlyTiles.addInfluence(x, z, infl/4, infl);
|
||||
else
|
||||
friendlyTiles.addInfluence(x, z, infl, infl);
|
||||
|
||||
}
|
||||
}else{
|
||||
if (template.genericName() == "House" && ent.genericName() == "House") {
|
||||
friendlyTiles.addInfluence(x, z, 15.0,20,'linear'); // houses are close to other houses
|
||||
alreadyHasHouses = true;
|
||||
} else if (template.hasClass("GarrisonFortress") && ent.genericName() == "House")
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, 30, -50);
|
||||
} else if (template.genericName() == "House") {
|
||||
friendlyTiles.addInfluence(x, z, Math.ceil(infl/4.0),-infl/2.0); // houses are farther away from other buildings but houses
|
||||
} else if (template.hasClass("GarrisonFortress"))
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, 20, 10);
|
||||
friendlyTiles.addInfluence(x, z, 10, -40, 'linear');
|
||||
} else if (ent.genericName() != "House") // houses have no influence on other buildings
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, infl);
|
||||
//avoid building too close to each other if possible.
|
||||
friendlyTiles.addInfluence(x, z, 5, -5, 'linear');
|
||||
}
|
||||
// If this is not a field add a negative influence near the CivCentre because we want to leave this
|
||||
// area for fields.
|
||||
if (ent.hasClass("CivCentre") && template.genericName() != "House"){
|
||||
friendlyTiles.addInfluence(x, z, Math.floor(infl/8), Math.floor(-infl/2));
|
||||
} else if (ent.hasClass("CivCentre")) {
|
||||
friendlyTiles.addInfluence(x, z, infl/3.0, infl + 1);
|
||||
friendlyTiles.addInfluence(x, z, Math.ceil(infl/5.0), -(infl/2.0), 'linear');
|
||||
}
|
||||
var pos = ent.position();
|
||||
var x = Math.round(pos[0] / cellSize);
|
||||
var z = Math.round(pos[1] / cellSize);
|
||||
|
||||
if (ent.buildCategory() == "Wall") { // no real blockers, but can't build where they are
|
||||
friendlyTiles.addInfluence(x, z, 2,-1000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (template._template.BuildRestrictions.Category === "Field"){
|
||||
if (ent.resourceDropsiteTypes() && ent.resourceDropsiteTypes().indexOf("food") !== -1){
|
||||
if (ent.hasClass("CivCentre"))
|
||||
friendlyTiles.addInfluence(x, z, infl/4, infl);
|
||||
else
|
||||
friendlyTiles.addInfluence(x, z, infl, infl);
|
||||
|
||||
}
|
||||
}else{
|
||||
if (template.genericName() == "House" && ent.genericName() == "House") {
|
||||
friendlyTiles.addInfluence(x, z, 15.0,20,'linear'); // houses are close to other houses
|
||||
alreadyHasHouses = true;
|
||||
} else if (template.hasClass("GarrisonFortress") && ent.genericName() == "House")
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, 30, -50);
|
||||
} else if (template.genericName() == "House") {
|
||||
friendlyTiles.addInfluence(x, z, Math.ceil(infl/4.0),-infl/2.0); // houses are farther away from other buildings but houses
|
||||
} else if (template.hasClass("GarrisonFortress"))
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, 20, 10);
|
||||
friendlyTiles.addInfluence(x, z, 10, -40, 'linear');
|
||||
} else if (ent.genericName() != "House") // houses have no influence on other buildings
|
||||
{
|
||||
friendlyTiles.addInfluence(x, z, infl);
|
||||
//avoid building too close to each other if possible.
|
||||
friendlyTiles.addInfluence(x, z, 5, -5, 'linear');
|
||||
}
|
||||
// If this is not a field add a negative influence near the CivCentre because we want to leave this
|
||||
// area for fields.
|
||||
if (ent.hasClass("CivCentre") && template.genericName() != "House"){
|
||||
friendlyTiles.addInfluence(x, z, Math.floor(infl/8), Math.floor(-infl/2));
|
||||
} else if (ent.hasClass("CivCentre")) {
|
||||
friendlyTiles.addInfluence(x, z, infl/3.0, infl + 1);
|
||||
friendlyTiles.addInfluence(x, z, Math.ceil(infl/5.0), -(infl/2.0), 'linear');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,9 +44,9 @@ m.GameState.prototype.update = function(SharedScript, state) {
|
|||
};
|
||||
|
||||
m.GameState.prototype.updatingCollection = function(id, filter, collection, allowQuick){
|
||||
// automatically add the player ID
|
||||
// automatically add the player ID in front.
|
||||
id = this.player + "-" + id;
|
||||
if (!this.EntCollecNames[id]){
|
||||
if (!this.EntCollecNames[id]) {
|
||||
if (collection !== undefined)
|
||||
this.EntCollecNames[id] = collection.filter(filter);
|
||||
else {
|
||||
|
|
@ -106,6 +106,30 @@ m.GameState.prototype.getGEC = function(id)
|
|||
return undefined;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getTimeElapsed = function()
|
||||
{
|
||||
return this.timeElapsed;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getTemplate = function(type)
|
||||
{
|
||||
if (this.techTemplates[type] !== undefined)
|
||||
return new m.Technology(this.techTemplates, type);
|
||||
|
||||
if (!this.templates[type])
|
||||
return null;
|
||||
|
||||
return new m.EntityTemplate(this.templates[type], this.techModifications);
|
||||
};
|
||||
|
||||
m.GameState.prototype.applyCiv = function(str) {
|
||||
return str.replace(/\{civ\}/g, this.playerData.civ);
|
||||
};
|
||||
|
||||
m.GameState.prototype.civ = function() {
|
||||
return this.playerData.civ;
|
||||
};
|
||||
|
||||
m.GameState.prototype.currentPhase = function()
|
||||
{
|
||||
if (this.isResearched("phase_city"))
|
||||
|
|
@ -133,13 +157,14 @@ m.GameState.prototype.isResearched = function(template)
|
|||
{
|
||||
return this.playerData.researchedTechs[template] !== undefined;
|
||||
};
|
||||
|
||||
// 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 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)
|
||||
{
|
||||
var template = this.getTemplate(techTemplateName);
|
||||
|
|
@ -232,42 +257,21 @@ m.GameState.prototype.checkTechRequirements = function (reqs)
|
|||
return false;
|
||||
};
|
||||
|
||||
|
||||
m.GameState.prototype.getTimeElapsed = function()
|
||||
{
|
||||
return this.timeElapsed;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getTemplate = function(type)
|
||||
{
|
||||
if (this.techTemplates[type] !== undefined)
|
||||
return new m.Technology(this.techTemplates, type);
|
||||
|
||||
if (!this.templates[type])
|
||||
return null;
|
||||
|
||||
return new m.EntityTemplate(this.templates[type], this.techModifications);
|
||||
};
|
||||
|
||||
m.GameState.prototype.applyCiv = function(str) {
|
||||
return str.replace(/\{civ\}/g, this.playerData.civ);
|
||||
};
|
||||
|
||||
m.GameState.prototype.civ = function() {
|
||||
return this.playerData.civ;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {Resources}
|
||||
*/
|
||||
m.GameState.prototype.getResources = function() {
|
||||
return new m.Resources(this.playerData.resourceCounts);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getMap = function() {
|
||||
return this.sharedScript.passabilityMap;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getPassabilityClassMask = function(name) {
|
||||
if (!(name in this.sharedScript.passabilityClasses)){
|
||||
error("Tried to use invalid passability class name '" + name + "'");
|
||||
}
|
||||
return this.sharedScript.passabilityClasses[name];
|
||||
};
|
||||
|
||||
m.GameState.prototype.getResources = function() {
|
||||
return new m.Resources(this.playerData.resourceCounts);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getPopulation = function() {
|
||||
return this.playerData.popCount;
|
||||
};
|
||||
|
|
@ -280,13 +284,6 @@ m.GameState.prototype.getPopulationMax = function() {
|
|||
return this.playerData.popMax;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getPassabilityClassMask = function(name) {
|
||||
if (!(name in this.sharedScript.passabilityClasses)){
|
||||
error("Tried to use invalid passability class name '" + name + "'");
|
||||
}
|
||||
return this.sharedScript.passabilityClasses[name];
|
||||
};
|
||||
|
||||
m.GameState.prototype.getPlayerID = function() {
|
||||
return this.player;
|
||||
};
|
||||
|
|
@ -336,80 +333,89 @@ m.GameState.prototype.isEntityOwn = function(ent) {
|
|||
return false;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnEntities = function() {
|
||||
return this.updatingCollection("own-entities", m.Filters.byOwner(this.player));
|
||||
};
|
||||
m.GameState.prototype.getEntityById = function(id){
|
||||
if (this.entities._entities[id])
|
||||
return this.entities._entities[id];
|
||||
|
||||
m.GameState.prototype.getEnemyEntities = function() {
|
||||
var diplomacyChange = false;
|
||||
var enemies = this.getEnemies();
|
||||
if (this.enemies){
|
||||
if (this.enemies.length != enemies.length){
|
||||
diplomacyChange = true;
|
||||
}else{
|
||||
for (var i = 0; i < enemies.length; i++){
|
||||
if (enemies[i] !== this.enemies[i]){
|
||||
diplomacyChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (diplomacyChange || !this.enemies){
|
||||
return this.updatingCollection("enemy-entities", m.Filters.byOwners(enemies));
|
||||
this.enemies = enemies;
|
||||
}
|
||||
return this.getEC("enemy-entities");
|
||||
return undefined;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntities = function() {
|
||||
return this.entities;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntityById = function(id){
|
||||
if (this.entities._entities[id]) {
|
||||
return this.entities._entities[id];
|
||||
}else{
|
||||
//debug("Entity " + id + " requested does not exist");
|
||||
}
|
||||
return undefined;
|
||||
m.GameState.prototype.getOwnEntities = function() {
|
||||
return this.updatingGlobalCollection("" + this.player + "-entities", m.Filters.byOwner(this.player));
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnStructures = function() {
|
||||
return this.updatingGlobalCollection("" + this.player + "-structures", m.Filters.byClass("Structure"), this.getOwnEntities());
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnUnits = function() {
|
||||
return this.updatingGlobalCollection("" + this.player + "-units", m.Filters.byClass("Unit"), this.getOwnEntities());
|
||||
};
|
||||
|
||||
// Try to use a parameter for those three, it'll be a lot faster.
|
||||
m.GameState.prototype.getEnemyEntities = function(enemyID) {
|
||||
if (enemyID === undefined)
|
||||
return this.entities.filter(m.Filters.byOwners(this.getEnemies()));
|
||||
|
||||
return this.updatingGlobalCollection("" + enemyID + "-entities", m.Filters.byOwner(enemyID));
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEnemyStructures = function(enemyID) {
|
||||
if (enemyID === undefined)
|
||||
return this.getEnemyEntities().filter(m.Filters.byClass("Structure"));
|
||||
|
||||
return this.updatingGlobalCollection("" + enemyID + "-structures", m.Filters.byClass("Structure"), this.getEnemyEntities(enemyID));
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEnemyUnits = function(enemyID) {
|
||||
if (enemyID === undefined)
|
||||
return this.getEnemyEntities().filter(m.Filters.byClass("Unit"));
|
||||
|
||||
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.
|
||||
m.GameState.prototype.getOwnEntitiesByMetadata = function(key, value, maintain){
|
||||
if (maintain === true)
|
||||
return this.updatingCollection(key + "-" + value, m.Filters.byMetadata(this.player, key, value),this.getOwnEntities());
|
||||
return this.getOwnEntities().filter(m.Filters.byMetadata(this.player, key, value));
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnEntitiesByRole = function(role){
|
||||
return this.getOwnEntitiesByMetadata("role", role, true);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnTrainingFacilities = function(){
|
||||
return this.updatingCollection("own-training-facilities", m.Filters.byTrainingQueue(), this.getOwnEntities(), true);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnResearchFacilities = function(){
|
||||
return this.updatingCollection("own-research-facilities", m.Filters.byResearchAvailable(), this.getOwnEntities(), true);
|
||||
m.GameState.prototype.getOwnEntitiesByRole = function(role, maintain){
|
||||
return this.getOwnEntitiesByMetadata("role", role, maintain);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnEntitiesByType = function(type, maintain){
|
||||
var filter = m.Filters.byType(type);
|
||||
if (maintain === true)
|
||||
return this.updatingCollection("own-by-type-" + type, filter, this.getOwnEntities());
|
||||
return this.updatingCollection("type-" + type, filter, this.getOwnEntities());
|
||||
return this.getOwnEntities().filter(filter);
|
||||
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnTrainingFacilities = function(){
|
||||
return this.updatingGlobalCollection("" + this.player + "-training-facilities", m.Filters.byTrainingQueue(), this.getOwnEntities(), true);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnResearchFacilities = function(){
|
||||
return this.updatingGlobalCollection("" + this.player + "-research-facilities", m.Filters.byResearchAvailable(), this.getOwnEntities(), true);
|
||||
};
|
||||
|
||||
|
||||
m.GameState.prototype.countEntitiesByType = function(type, maintain) {
|
||||
return this.getOwnEntitiesByType(type, maintain).length;
|
||||
};
|
||||
|
||||
m.GameState.prototype.countEntitiesAndQueuedByType = function(type) {
|
||||
var count = this.countEntitiesByType(type, true);
|
||||
m.GameState.prototype.countEntitiesAndQueuedByType = function(type, maintain) {
|
||||
var count = this.countEntitiesByType(type, maintain);
|
||||
|
||||
// Count building foundations
|
||||
if (this.getTemplate(type).hasClass("Structure") === true)
|
||||
count += this.countEntitiesByType("foundation|" + type, true);
|
||||
count += this.countFoundationsByType(type, true);
|
||||
else if (this.getTemplate(type).resourceSupplyType() !== undefined) // animal resources
|
||||
count += this.countEntitiesByType("resource|" + type, true);
|
||||
else
|
||||
|
|
@ -428,10 +434,14 @@ m.GameState.prototype.countEntitiesAndQueuedByType = function(type) {
|
|||
return count;
|
||||
};
|
||||
|
||||
m.GameState.prototype.countFoundationsWithType = function(type) {
|
||||
m.GameState.prototype.countFoundationsByType = function(type, maintain) {
|
||||
var foundationType = "foundation|" + type;
|
||||
|
||||
if (maintain === true)
|
||||
return this.updatingCollection("foundation-type-" + type, m.Filters.byType(foundationType), this.getOwnFoundations());
|
||||
|
||||
var count = 0;
|
||||
this.getOwnEntities().forEach(function(ent) {
|
||||
this.getOwnStructures().forEach(function(ent) {
|
||||
var t = ent.templateName();
|
||||
if (t == foundationType)
|
||||
++count;
|
||||
|
|
@ -468,126 +478,43 @@ m.GameState.prototype.countOwnQueuedEntitiesWithMetadata = function(data, value)
|
|||
return count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find buildings that are capable of training the given unit type, and aren't
|
||||
* already too busy.
|
||||
*/
|
||||
m.GameState.prototype.findTrainers = function(template) {
|
||||
var maxQueueLength = 3; // avoid tying up resources in giant training queues
|
||||
|
||||
return this.getOwnTrainingFacilities().filter(function(ent) {
|
||||
|
||||
var trainable = ent.trainableEntities();
|
||||
if (!trainable || trainable.indexOf(template) == -1)
|
||||
return false;
|
||||
|
||||
var queue = ent.trainingQueue();
|
||||
if (queue) {
|
||||
if (queue.length >= maxQueueLength)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Find units that are capable of constructing the given building type.
|
||||
*/
|
||||
m.GameState.prototype.findBuilders = function(template) {
|
||||
return this.getOwnEntities().filter(function(ent) {
|
||||
|
||||
var buildable = ent.buildableEntities();
|
||||
if (!buildable || buildable.indexOf(template) == -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Find buildings that are capable of researching the given tech, and aren't
|
||||
* already too busy.
|
||||
*/
|
||||
m.GameState.prototype.findResearchers = function(templateName, noRequirementCheck) {
|
||||
// let's check we can research the tech.
|
||||
if (!this.canResearch(templateName, noRequirementCheck))
|
||||
return [];
|
||||
|
||||
var template = this.getTemplate(templateName);
|
||||
var self = this;
|
||||
|
||||
return this.getOwnResearchFacilities().filter(function(ent) { //}){
|
||||
var techs = ent.researchableTechs();
|
||||
for (var i in techs)
|
||||
{
|
||||
var thisTemp = self.getTemplate(techs[i]);
|
||||
if (thisTemp.pairDef())
|
||||
{
|
||||
var pairedTechs = thisTemp.getPairedTechs();
|
||||
if (pairedTechs[0]._templateName == templateName || pairedTechs[1]._templateName == templateName)
|
||||
return true;
|
||||
} else {
|
||||
if (techs[i] == templateName)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnFoundations = function() {
|
||||
return this.updatingCollection("ownFoundations", m.Filters.isFoundation(), this.getOwnEntities());
|
||||
return this.updatingGlobalCollection("" + this.player + "-foundations", m.Filters.isFoundation(), this.getOwnStructures());
|
||||
};
|
||||
|
||||
m.GameState.prototype.getOwnDropsites = function(resource){
|
||||
if (resource !== undefined)
|
||||
return this.updatingCollection("dropsite-own-" + resource, m.Filters.isDropsite(resource), this.getOwnEntities(), true);
|
||||
return this.updatingCollection("dropsite-own", m.Filters.isDropsite(), this.getOwnEntities(), true);
|
||||
return this.updatingCollection("dropsite-" + resource, m.Filters.isDropsite(resource), this.getOwnEntities(), true);
|
||||
return this.updatingCollection("dropsite-all", m.Filters.isDropsite(), this.getOwnEntities(), true);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getResourceSupplies = function(resource){
|
||||
return this.updatingGlobalCollection("resource-" + resource, m.Filters.byResource(resource), this.getEntities(), true);
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntityLimits = function() {
|
||||
return this.playerData.entityLimits;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntityCounts = function() {
|
||||
return this.playerData.entityCounts;
|
||||
};
|
||||
|
||||
// Checks whether the maximum number of buildings have been cnstructed for a certain catergory
|
||||
m.GameState.prototype.isEntityLimitReached = function(category) {
|
||||
if(this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined)
|
||||
return false;
|
||||
return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]);
|
||||
};
|
||||
|
||||
// This returns only units from buildings.
|
||||
m.GameState.prototype.findTrainableUnits = function(classes){
|
||||
var allTrainable = [];
|
||||
this.getOwnEntities().forEach(function(ent) {
|
||||
this.getOwnStructures().forEach(function(ent) {
|
||||
var trainable = ent.trainableEntities();
|
||||
if (ent.hasClass("Structure"))
|
||||
for (var i in trainable){
|
||||
if (allTrainable.indexOf(trainable[i]) === -1){
|
||||
allTrainable.push(trainable[i]);
|
||||
}
|
||||
for (var i in trainable){
|
||||
if (allTrainable.indexOf(trainable[i]) === -1){
|
||||
allTrainable.push(trainable[i]);
|
||||
}
|
||||
}
|
||||
});
|
||||
var ret = [];
|
||||
for (var i in allTrainable) {
|
||||
var template = this.getTemplate(allTrainable[i]);
|
||||
var okay = true;
|
||||
|
||||
if (template.hasClass("Hero")) // disabling heroes for now
|
||||
continue;
|
||||
|
||||
var okay = true;
|
||||
for (var o in classes)
|
||||
if (!template.hasClass(classes[o]))
|
||||
okay = false;
|
||||
|
||||
if (template.hasClass("Hero")) // disabling heroes for now
|
||||
okay = false;
|
||||
|
||||
|
||||
if (okay)
|
||||
ret.push( [allTrainable[i], template] );
|
||||
}
|
||||
|
|
@ -628,6 +555,75 @@ m.GameState.prototype.findAvailableTech = function() {
|
|||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find buildings that are capable of training said template.
|
||||
* Getting the best is up to the AI.
|
||||
*/
|
||||
m.GameState.prototype.findTrainers = function(template) {
|
||||
return this.getOwnTrainingFacilities().filter(function(ent) {
|
||||
var trainable = ent.trainableEntities();
|
||||
if (!trainable || trainable.indexOf(template) == -1)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Find units that are capable of constructing the given building type.
|
||||
*/
|
||||
m.GameState.prototype.findBuilders = function(template) {
|
||||
return this.getOwnUnits().filter(function(ent) {
|
||||
var buildable = ent.buildableEntities();
|
||||
if (!buildable || buildable.indexOf(template) == -1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
// Find buildings that are capable of researching the given tech
|
||||
m.GameState.prototype.findResearchers = function(templateName, noRequirementCheck) {
|
||||
// let's check we can research the tech.
|
||||
if (!this.canResearch(templateName, noRequirementCheck))
|
||||
return [];
|
||||
|
||||
var template = this.getTemplate(templateName);
|
||||
var self = this;
|
||||
|
||||
return this.getOwnResearchFacilities().filter(function(ent) {
|
||||
var techs = ent.researchableTechs();
|
||||
for (var i in techs)
|
||||
{
|
||||
var thisTemp = self.getTemplate(techs[i]);
|
||||
if (thisTemp.pairDef())
|
||||
{
|
||||
var pairedTechs = thisTemp.getPairedTechs();
|
||||
if (pairedTechs[0]._templateName == templateName || pairedTechs[1]._templateName == templateName)
|
||||
return true;
|
||||
} else {
|
||||
if (techs[i] == templateName)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntityLimits = function() {
|
||||
return this.playerData.entityLimits;
|
||||
};
|
||||
|
||||
m.GameState.prototype.getEntityCounts = function() {
|
||||
return this.playerData.entityCounts;
|
||||
};
|
||||
|
||||
// Checks whether the maximum number of buildings have been cnstructed for a certain catergory
|
||||
m.GameState.prototype.isEntityLimitReached = function(category) {
|
||||
if(this.playerData.entityLimits[category] === undefined || this.playerData.entityCounts[category] === undefined)
|
||||
return false;
|
||||
return (this.playerData.entityCounts[category] >= this.playerData.entityLimits[category]);
|
||||
};
|
||||
|
||||
// defcon utilities
|
||||
m.GameState.prototype.timeSinceDefconChange = function() {
|
||||
return this.getTimeElapsed()-this.ai.defconChangeTime;
|
||||
|
|
|
|||
Loading…
Reference in a new issue