diff --git a/binaries/data/mods/public/simulation/ai/common-api/entitycollection.js b/binaries/data/mods/public/simulation/ai/common-api/entitycollection.js index df53153c5c..0fa627c521 100644 --- a/binaries/data/mods/public/simulation/ai/common-api/entitycollection.js +++ b/binaries/data/mods/public/simulation/ai/common-api/entitycollection.js @@ -138,6 +138,11 @@ m.EntityCollection.prototype.forEach = function(callback) return this; }; +m.EntityCollection.prototype.hasEntities = function() +{ + return this._entities.size !== 0; +}; + m.EntityCollection.prototype.move = function(x, z, queued) { queued = queued || false; diff --git a/binaries/data/mods/public/simulation/ai/petra/attackManager.js b/binaries/data/mods/public/simulation/ai/petra/attackManager.js index cab58954ef..19a533fccd 100644 --- a/binaries/data/mods/public/simulation/ai/petra/attackManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/attackManager.js @@ -382,7 +382,7 @@ m.AttackManager.prototype.getEnemyPlayer = function(gameState, attack) { if (attack.targetPlayer === undefined && this.currentEnemyPlayer !== undefined && !this.defeated[this.currentEnemyPlayer] && - gameState.getEnemyEntities(this.currentEnemyPlayer).length > 0) + gameState.getEnemyEntities(this.currentEnemyPlayer).hasEntities()) return this.currentEnemyPlayer; let distmin; diff --git a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js index 176feae9ae..48eddb0f5d 100644 --- a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js +++ b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js @@ -271,7 +271,7 @@ m.AttackPlan.prototype.mustStart = function() return false; if (!this.canBuildUnits) - return (this.unitCollection.length > 0); + return this.unitCollection.hasEntities(); var MaxReachedEverywhere = true; var MinReachedEverywhere = true; @@ -796,7 +796,7 @@ m.AttackPlan.prototype.getNearestTarget = function(gameState, position, sameLand targets = this.rushTargetFinder(gameState, this.targetPlayer); else targets = this.defaultTargetFinder(gameState, this.targetPlayer); - if (!targets.length) + if (!targets.hasEntities()) return undefined; var land = gameState.ai.accessibility.getAccessValue(position); @@ -834,20 +834,20 @@ m.AttackPlan.prototype.defaultTargetFinder = function(gameState, playerEnemy) if (gameState.getGameType() === "wonder") { targets = gameState.getEnemyStructures(playerEnemy).filter(API3.Filters.byClass("Wonder")); - if (targets.length) + if (targets.hasEntities()) return targets; } targets = gameState.getEnemyStructures(playerEnemy).filter(API3.Filters.byClass("CivCentre")); - if (!targets.length) + if (!targets.hasEntities()) targets = gameState.getEnemyStructures(playerEnemy).filter(API3.Filters.byClass("ConquestCritical")); // If there's nothing, attack anything else that's less critical - if (!targets.length) + if (!targets.hasEntities()) targets = gameState.getEnemyStructures(playerEnemy).filter(API3.Filters.byClass("Town")); - if (!targets.length) + if (!targets.hasEntities()) targets = gameState.getEnemyStructures(playerEnemy).filter(API3.Filters.byClass("Village")); // no buildings, attack anything conquest critical, even units - if (!targets.length) + if (!targets.hasEntities()) targets = gameState.getEnemyEntities(playerEnemy).filter(API3.Filters.byClass("ConquestCritical")); return targets; }; @@ -900,7 +900,7 @@ m.AttackPlan.prototype.rushTargetFinder = function(gameState, playerEnemy) if (target) targets.addEnt(target); - if (!targets.length) + if (!targets.hasEntities()) { if (this.type === "Attack") targets = this.defaultTargetFinder(gameState, playerEnemy); @@ -1033,7 +1033,7 @@ m.AttackPlan.prototype.StartAttack = function(gameState) // Runs every turn after the attack is executed m.AttackPlan.prototype.update = function(gameState, events) { - if (!this.unitCollection.length) + if (!this.unitCollection.hasEntities()) return 0; Engine.ProfileStart("Update Attack"); @@ -1153,7 +1153,7 @@ m.AttackPlan.prototype.update = function(gameState, events) nexttoWalls = true; }); // there are walls but we can attack - if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).length !== 0) + if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).hasEntities()) { if (this.Config.debug > 1) API3.warn("Attack Plan " + this.type + " " + this.name + " has met walls and is not happy."); @@ -1676,7 +1676,7 @@ m.AttackPlan.prototype.update = function(gameState, events) m.AttackPlan.prototype.Abort = function(gameState) { this.unitCollection.unregister(); - if (this.unitCollection.length) + if (this.unitCollection.hasEntities()) { // If the attack was started, and we are on the same land as the rallyPoint, go back there var rallyPoint = this.rallyPoint; diff --git a/binaries/data/mods/public/simulation/ai/petra/baseManager.js b/binaries/data/mods/public/simulation/ai/petra/baseManager.js index 81d21fb674..a927dfa94a 100644 --- a/binaries/data/mods/public/simulation/ai/petra/baseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/baseManager.js @@ -463,7 +463,7 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState, queues) } else if (gameState.isDisabledTemplates(gameState.applyCiv("structures/{civ}_field")) && !queues.corral.hasQueuedUnits() && - gameState.getOwnEntitiesByClass("Corral", true).length === 0 && + !gameState.getOwnEntitiesByClass("Corral", true).hasEntities() && gameState.ai.HQ.canBuild(gameState, "structures/{civ}_corral")) { let count = this.getResourceLevel(gameState, type, (gameState.currentPhase() > 1)); // animals are not accounted @@ -474,7 +474,7 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState, queues) } } } - else if (!queues.dropsites.hasQueuedUnits() && !gameState.getOwnFoundations().filter(API3.Filters.byClass("Storehouse")).length) + else if (!queues.dropsites.hasQueuedUnits() && !gameState.getOwnFoundations().filter(API3.Filters.byClass("Storehouse")).hasEntities()) { if (gameState.ai.playedTurn > this.gatherers[type].nextCheck) { @@ -495,7 +495,7 @@ m.BaseManager.prototype.checkResourceLevels = function (gameState, queues) let newDP = this.findBestDropsiteLocation(gameState, type); if (newDP.quality > 50 && gameState.ai.HQ.canBuild(gameState, "structures/{civ}_storehouse")) queues.dropsites.addPlan(new m.ConstructionPlan(gameState, "structures/{civ}_storehouse", { "base": this.ID, "type": type }, newDP.pos)); - else if (!gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")).length && !queues.civilCentre.hasQueuedUnits()) + else if (!gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")).hasEntities() && !queues.civilCentre.hasQueuedUnits()) { // No good dropsite, try to build a new base if no base already planned, // and if not possible, be less strict on dropsite quality @@ -609,10 +609,10 @@ m.BaseManager.prototype.setWorkersIdleByPriority = function(gameState) let only; // in average, females are less efficient for stone and metal, and citizenSoldiers for food let gatherers = this.gatherersByType(gameState, lessNeed.type); - if (lessNeed.type === "food" && gatherers.filter(API3.Filters.byClass("CitizenSoldier")).length) + if (lessNeed.type === "food" && gatherers.filter(API3.Filters.byClass("CitizenSoldier")).hasEntities()) only = "CitizenSoldier"; else if ((lessNeed.type === "stone" || lessNeed.type === "metal") && moreNeed.type !== "stone" && moreNeed.type !== "metal" && - gatherers.filter(API3.Filters.byClass("Female")).length) + gatherers.filter(API3.Filters.byClass("Female")).hasEntities()) only = "Female"; gatherers.forEach( function (ent) { diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index 162bdb1fc7..1e42de07b6 100644 --- a/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -1093,7 +1093,7 @@ m.HQ.prototype.findMarketLocation = function(gameState, template) API3.warn("this would give a trading gain of " + expectedGain); // do not keep it if gain is too small, except if this is our first BarterMarket if (expectedGain < this.tradeManager.minimalGain || - (expectedGain < 8 && (!template.hasClass("BarterMarket") || gameState.getOwnEntitiesByClass("BarterMarket", true).length > 0))) + (expectedGain < 8 && (!template.hasClass("BarterMarket") || gameState.getOwnEntitiesByClass("BarterMarket", true).hasEntities()))) return false; var x = (bestIdx % obstructions.width + 0.5) * obstructions.cellSize; @@ -1228,8 +1228,8 @@ m.HQ.prototype.buildTemple = function(gameState, queues) { // at least one market (which have the same queue) should be build before any temple if (gameState.currentPhase() < 3 || queues.economicBuilding.hasQueuedUnits() || - gameState.getOwnEntitiesByClass("Temple", true).length || - !gameState.getOwnEntitiesByClass("BarterMarket", true).length) + gameState.getOwnEntitiesByClass("Temple", true).hasEntities() || + !gameState.getOwnEntitiesByClass("BarterMarket", true).hasEntities()) return; if (!this.canBuild(gameState, "structures/{civ}_temple")) return; @@ -1238,7 +1238,7 @@ m.HQ.prototype.buildTemple = function(gameState, queues) m.HQ.prototype.buildMarket = function(gameState, queues) { - if (gameState.getOwnEntitiesByClass("BarterMarket", true).length > 0 || + if (gameState.getOwnEntitiesByClass("BarterMarket", true).hasEntities() || !this.canBuild(gameState, "structures/{civ}_market")) return; @@ -1277,12 +1277,12 @@ m.HQ.prototype.buildMarket = function(gameState, queues) m.HQ.prototype.buildFarmstead = function(gameState, queues) { // Only build one farmstead for the time being ("DropsiteFood" does not refer to CCs) - if (gameState.getOwnEntitiesByClass("Farmstead", true).length > 0) + if (gameState.getOwnEntitiesByClass("Farmstead", true).hasEntities()) return; // Wait to have at least one dropsite and house before the farmstead - if (gameState.getOwnEntitiesByClass("Storehouse", true).length == 0) + if (!gameState.getOwnEntitiesByClass("Storehouse", true).hasEntities()) return; - if (gameState.getOwnEntitiesByClass("House", true).length == 0) + if (!gameState.getOwnEntitiesByClass("House", true).hasEntities()) return; if (queues.economicBuilding.hasQueuedUnitsWithClass("DropsiteFood")) return; @@ -1299,7 +1299,7 @@ m.HQ.prototype.manageCorral = function(gameState, queues) return; // Only build one corral for the time being - if (gameState.getOwnEntitiesByClass("Corral", true).length === 0) + if (!gameState.getOwnEntitiesByClass("Corral", true).hasEntities()) { if (this.canBuild(gameState, "structures/{civ}_corral")) queues.corral.addPlan(new m.ConstructionPlan(gameState, "structures/{civ}_corral")); @@ -1461,7 +1461,7 @@ m.HQ.prototype.buildNewBase = function(gameState, queues, resource) { if (this.numActiveBase() > 0 && gameState.currentPhase() == 1 && !gameState.isResearching(gameState.townPhase())) return false; - if (gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")).length > 0 || queues.civilCentre.hasQueuedUnits()) + if (gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")).hasEntities() || queues.civilCentre.hasQueuedUnits()) return false; let template = (this.numActiveBase() > 0) ? this.bBase[0] : gameState.applyCiv("structures/{civ}_civil_centre"); if (!this.canBuild(gameState, template)) @@ -1531,7 +1531,7 @@ m.HQ.prototype.buildBlacksmith = function(gameState, queues) queues.militaryBuilding.hasQueuedUnits() || gameState.getOwnEntitiesByClass("Blacksmith", true).length) return; // build a market before the blacksmith - if (!gameState.getOwnEntitiesByClass("BarterMarket", true).length) + if (!gameState.getOwnEntitiesByClass("BarterMarket", true).hasEntities()) return; if (this.canBuild(gameState, "structures/{civ}_blacksmith")) @@ -1542,7 +1542,7 @@ m.HQ.prototype.buildWonder = function(gameState, queues) { if (queues.wonder && queues.wonder.hasQueuedUnits()) return; - if (gameState.getOwnEntitiesByClass("Wonder", true).length > 0) + if (gameState.getOwnEntitiesByClass("Wonder", true).hasEntities()) return; if (!this.canBuild(gameState, "structures/{civ}_wonder")) return; diff --git a/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js b/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js index c0652cb2b5..fb6b18c2b0 100644 --- a/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js +++ b/binaries/data/mods/public/simulation/ai/petra/startingStrategy.js @@ -37,7 +37,7 @@ m.HQ.prototype.gameAnalysis = function(gameState) // If no base yet, check if we can construct one. If not, dispatch our units to possible tasks/attacks this.canBuildUnits = true; - if (!gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).length) + if (!gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).hasEntities()) { let template = gameState.applyCiv("structures/{civ}_civil_centre"); if (gameState.isDisabledTemplates(template) || !gameState.getTemplate(template).available(gameState)) @@ -253,7 +253,7 @@ m.HQ.prototype.buildFirstBase = function(gameState) template = gameState.getTemplate(template); var goal = "civil_centre"; var docks = gameState.getOwnStructures().filter(API3.Filters.byClass("Dock")); - if (!total.canAfford(new API3.Resources(template.cost())) && !docks.length) + if (!total.canAfford(new API3.Resources(template.cost())) && !docks.hasEntities()) { // not enough resource to build a cc, try with a dock to accumulate resources if none yet if (gameState.ai.queues.dock.hasQueuedUnits()) @@ -502,7 +502,7 @@ m.HQ.prototype.configFirstBase = function(gameState) // immediatly build a wood dropsite if possible. var template = gameState.applyCiv("structures/{civ}_storehouse"); - if (gameState.getOwnEntitiesByClass("Storehouse", true).length === 0 && this.canBuild(gameState, template)) + if (!gameState.getOwnEntitiesByClass("Storehouse", true).hasEntities() && this.canBuild(gameState, template)) { let newDP = this.baseManagers[1].findBestDropsiteLocation(gameState, "wood"); if (newDP.quality > 40) @@ -523,7 +523,7 @@ m.HQ.prototype.configFirstBase = function(gameState) if (this.needCorral) { template = gameState.applyCiv("structures/{civ}_corral"); - if (gameState.getOwnEntitiesByClass("Corral", true).length === 0 && this.canBuild(gameState, template)) + if (!gameState.getOwnEntitiesByClass("Corral", true).hasEntities() && this.canBuild(gameState, template)) gameState.ai.queues.corral.addPlan(new m.ConstructionPlan(gameState, template, { "base": this.baseManagers[1].ID })); } }; diff --git a/binaries/data/mods/public/simulation/ai/petra/worker.js b/binaries/data/mods/public/simulation/ai/petra/worker.js index 960e2f3215..af7634ca84 100644 --- a/binaries/data/mods/public/simulation/ai/petra/worker.js +++ b/binaries/data/mods/public/simulation/ai/petra/worker.js @@ -530,7 +530,7 @@ m.Worker.prototype.startHunting = function(gameState, position) return true; var resources = gameState.getHuntableSupplies(); - if (resources.length === 0) + if (!resources.hasEntities()) return false; var nearestSupplyDist = Math.min(); @@ -622,11 +622,11 @@ m.Worker.prototype.startFishing = function(gameState) { if (!this.ent.position()) return false; - + // So here we're doing it basic. We check what we can hunt, we hunt it. No fancies. - + var resources = gameState.getFishableSupplies(); - if (resources.length === 0) + if (!resources.hasEntities()) { gameState.ai.HQ.navalManager.resetFishingBoats(gameState); this.ent.destroy();