diff --git a/binaries/data/mods/public/simulation/ai/aegis/aegis.js b/binaries/data/mods/public/simulation/ai/aegis/aegis.js index 0975f92344..5692eb4872 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/aegis.js +++ b/binaries/data/mods/public/simulation/ai/aegis/aegis.js @@ -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)); diff --git a/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js b/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js index 460509fb92..610cd8599f 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js +++ b/binaries/data/mods/public/simulation/ai/aegis/attack_plan.js @@ -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; }; diff --git a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js index dc0aadc8fa..ad3071d127 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/base-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/base-manager.js @@ -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()); diff --git a/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js b/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js index 382d454188..749cc4b8a2 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js +++ b/binaries/data/mods/public/simulation/ai/aegis/defence-helper.js @@ -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]; } diff --git a/binaries/data/mods/public/simulation/ai/aegis/defence.js b/binaries/data/mods/public/simulation/ai/aegis/defence.js index 86c13c58b8..04ad40372f 100755 --- a/binaries/data/mods/public/simulation/ai/aegis/defence.js +++ b/binaries/data/mods/public/simulation/ai/aegis/defence.js @@ -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); diff --git a/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js b/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js deleted file mode 100755 index 873ca49527..0000000000 --- a/binaries/data/mods/public/simulation/ai/aegis/enemy-watcher.js +++ /dev/null @@ -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); diff --git a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js index e03c8207eb..de59034411 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/aegis/headquarters.js @@ -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(); diff --git a/binaries/data/mods/public/simulation/ai/aegis/map-module.js b/binaries/data/mods/public/simulation/ai/aegis/map-module.js index a62bce4003..3f3da6a90a 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/map-module.js +++ b/binaries/data/mods/public/simulation/ai/aegis/map-module.js @@ -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; diff --git a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js index fd3a359a27..c63dc40350 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/naval-manager.js @@ -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(); diff --git a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js index eb95196aa2..cb212e8188 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js +++ b/binaries/data/mods/public/simulation/ai/aegis/queue-manager.js @@ -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(); diff --git a/binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js b/binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js index 6d197dfb2a..7128c9d256 100644 --- a/binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js +++ b/binaries/data/mods/public/simulation/ai/aegis/queueplan-building.js @@ -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'); } } }); diff --git a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js index 7b5c43bb9d..920ac4e666 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/gamestate.js +++ b/binaries/data/mods/public/simulation/ai/common-api/gamestate.js @@ -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;