LCOV - code coverage report
Current view: top level - simulation/ai/petra - startingStrategy.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 310 0.0 %
Date: 2023-04-02 12:52:40 Functions: 0 10 0.0 %

          Line data    Source code
       1             : /**
       2             :  * Determines the strategy to adopt when starting a new game,
       3             :  * depending on the initial conditions
       4             :  */
       5             : 
       6           0 : PETRA.HQ.prototype.gameAnalysis = function(gameState)
       7             : {
       8             :         // Analysis of the terrain and the different access regions
       9           0 :         if (!this.regionAnalysis(gameState))
      10           0 :                 return;
      11             : 
      12           0 :         this.attackManager.init(gameState);
      13           0 :         this.buildManager.init(gameState);
      14           0 :         this.navalManager.init(gameState);
      15           0 :         this.tradeManager.init(gameState);
      16           0 :         this.diplomacyManager.init(gameState);
      17             : 
      18             :         // Make a list of buildable structures from the config file
      19           0 :         this.structureAnalysis(gameState);
      20             : 
      21             :         // Let's get our initial situation here.
      22           0 :         this.basesManager.init(gameState);
      23           0 :         this.updateTerritories(gameState);
      24             : 
      25             :         // Assign entities and resources in the different bases
      26           0 :         this.assignStartingEntities(gameState);
      27             : 
      28             : 
      29             :         // Sandbox difficulty should not try to expand
      30           0 :         this.canExpand = this.Config.difficulty != PETRA.DIFFICULTY_SANDBOX;
      31             :         // If no base yet, check if we can construct one. If not, dispatch our units to possible tasks/attacks
      32           0 :         this.canBuildUnits = true;
      33           0 :         if (!gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).hasEntities())
      34             :         {
      35           0 :                 let template = gameState.applyCiv("structures/{civ}/civil_centre");
      36           0 :                 if (!gameState.isTemplateAvailable(template) || !gameState.getTemplate(template).available(gameState))
      37             :                 {
      38           0 :                         if (this.Config.debug > 1)
      39           0 :                                 API3.warn(" this AI is unable to produce any units");
      40           0 :                         this.canBuildUnits = false;
      41           0 :                         this.dispatchUnits(gameState);
      42             :                 }
      43             :                 else
      44           0 :                         this.buildFirstBase(gameState);
      45             :         }
      46             : 
      47             :         // configure our first base strategy
      48           0 :         if (this.hasPotentialBase())
      49           0 :                 this.configFirstBase(gameState);
      50             : };
      51             : 
      52             : /**
      53             :  * Assign the starting entities to the different bases
      54             :  */
      55           0 : PETRA.HQ.prototype.assignStartingEntities = function(gameState)
      56             : {
      57           0 :         for (let ent of gameState.getOwnEntities().values())
      58             :         {
      59             :                 // do not affect merchant ship immediately to trade as they may-be useful for transport
      60           0 :                 if (ent.hasClasses(["Trader+!Ship"]))
      61           0 :                         this.tradeManager.assignTrader(ent);
      62             : 
      63           0 :                 let pos = ent.position();
      64           0 :                 if (!pos)
      65             :                 {
      66             :                         // TODO should support recursive garrisoning. Make a warning for now
      67           0 :                         if (ent.isGarrisonHolder() && ent.garrisoned().length)
      68           0 :                                 API3.warn("Petra warning: support for garrisoned units inside garrisoned holders not yet implemented");
      69           0 :                         continue;
      70             :                 }
      71             : 
      72             :                 // make sure we have not rejected small regions with units (TODO should probably also check with other non-gaia units)
      73           0 :                 let gamepos = gameState.ai.accessibility.gamePosToMapPos(pos);
      74           0 :                 let index = gamepos[0] + gamepos[1]*gameState.ai.accessibility.width;
      75           0 :                 let land = gameState.ai.accessibility.landPassMap[index];
      76           0 :                 if (land > 1 && !this.landRegions[land])
      77           0 :                         this.landRegions[land] = true;
      78           0 :                 let sea = gameState.ai.accessibility.navalPassMap[index];
      79           0 :                 if (sea > 1 && !this.navalRegions[sea])
      80           0 :                         this.navalRegions[sea] = true;
      81             : 
      82             :                 // if garrisoned units inside, ungarrison them except if a ship in which case we will make a transport
      83             :                 // when a construction will start (see createTransportIfNeeded)
      84           0 :                 if (ent.isGarrisonHolder() && ent.garrisoned().length && !ent.hasClass("Ship"))
      85           0 :                         for (let id of ent.garrisoned())
      86           0 :                                 ent.unload(id);
      87             : 
      88           0 :                 let territorypos = this.territoryMap.gamePosToMapPos(pos);
      89           0 :                 let territoryIndex = territorypos[0] + territorypos[1]*this.territoryMap.width;
      90             : 
      91           0 :                 this.basesManager.assignEntity(gameState, ent, territoryIndex);
      92             :         }
      93             : };
      94             : 
      95             : /**
      96             :  * determine the main land Index (or water index if none)
      97             :  * as well as the list of allowed (land andf water) regions
      98             :  */
      99           0 : PETRA.HQ.prototype.regionAnalysis = function(gameState)
     100             : {
     101           0 :         let accessibility = gameState.ai.accessibility;
     102             :         let landIndex;
     103             :         let seaIndex;
     104           0 :         let ccEnts = gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre"));
     105           0 :         for (let cc of ccEnts.values())
     106             :         {
     107           0 :                 let land = accessibility.getAccessValue(cc.position());
     108           0 :                 if (land > 1)
     109             :                 {
     110           0 :                         landIndex = land;
     111           0 :                         break;
     112             :                 }
     113             :         }
     114           0 :         if (!landIndex)
     115             :         {
     116           0 :                 let civ = gameState.getPlayerCiv();
     117           0 :                 for (let ent of gameState.getOwnEntities().values())
     118             :                 {
     119           0 :                         if (!ent.position() || !ent.hasClass("Unit") && !ent.trainableEntities(civ))
     120           0 :                                 continue;
     121           0 :                         let land = accessibility.getAccessValue(ent.position());
     122           0 :                         if (land > 1)
     123             :                         {
     124           0 :                                 landIndex = land;
     125           0 :                                 break;
     126             :                         }
     127           0 :                         let sea = accessibility.getAccessValue(ent.position(), true);
     128           0 :                         if (!seaIndex && sea > 1)
     129           0 :                                 seaIndex = sea;
     130             :                 }
     131             :         }
     132           0 :         if (!landIndex && !seaIndex)
     133             :         {
     134           0 :                 API3.warn("Petra error: it does not know how to interpret this map");
     135           0 :                 return false;
     136             :         }
     137             : 
     138           0 :         let passabilityMap = gameState.getPassabilityMap();
     139           0 :         let totalSize = passabilityMap.width * passabilityMap.width;
     140           0 :         let minLandSize = Math.floor(0.1*totalSize);
     141           0 :         let minWaterSize = Math.floor(0.2*totalSize);
     142           0 :         let cellArea = passabilityMap.cellSize * passabilityMap.cellSize;
     143           0 :         for (let i = 0; i < accessibility.regionSize.length; ++i)
     144             :         {
     145           0 :                 if (landIndex && i == landIndex)
     146           0 :                         this.landRegions[i] = true;
     147           0 :                 else if (accessibility.regionType[i] === "land" && cellArea*accessibility.regionSize[i] > 320)
     148             :                 {
     149           0 :                         if (landIndex)
     150             :                         {
     151           0 :                                 let sea = this.getSeaBetweenIndices(gameState, landIndex, i);
     152           0 :                                 if (sea && (accessibility.regionSize[i] > minLandSize || accessibility.regionSize[sea] > minWaterSize))
     153             :                                 {
     154           0 :                                         this.navalMap = true;
     155           0 :                                         this.landRegions[i] = true;
     156           0 :                                         this.navalRegions[sea] = true;
     157             :                                 }
     158             :                         }
     159             :                         else
     160             :                         {
     161           0 :                                 let traject = accessibility.getTrajectToIndex(seaIndex, i);
     162           0 :                                 if (traject && traject.length === 2)
     163             :                                 {
     164           0 :                                         this.navalMap = true;
     165           0 :                                         this.landRegions[i] = true;
     166           0 :                                         this.navalRegions[seaIndex] = true;
     167             :                                 }
     168             :                         }
     169             :                 }
     170           0 :                 else if (accessibility.regionType[i] === "water" && accessibility.regionSize[i] > minWaterSize)
     171             :                 {
     172           0 :                         this.navalMap = true;
     173           0 :                         this.navalRegions[i] = true;
     174             :                 }
     175           0 :                 else if (accessibility.regionType[i] === "water" && cellArea*accessibility.regionSize[i] > 3600)
     176           0 :                         this.navalRegions[i] = true;
     177             :         }
     178             : 
     179           0 :         if (this.Config.debug < 3)
     180           0 :                 return true;
     181           0 :         for (let region in this.landRegions)
     182           0 :                 API3.warn(" >>> zone " + region + " taille " + cellArea*gameState.ai.accessibility.regionSize[region]);
     183           0 :         API3.warn(" navalMap " + this.navalMap);
     184           0 :         API3.warn(" landRegions " + uneval(this.landRegions));
     185           0 :         API3.warn(" navalRegions " + uneval(this.navalRegions));
     186           0 :         return true;
     187             : };
     188             : 
     189             : /**
     190             :  * load units and buildings from the config files
     191             :  * TODO: change that to something dynamic
     192             :  */
     193           0 : PETRA.HQ.prototype.structureAnalysis = function(gameState)
     194             : {
     195           0 :         let civref = gameState.playerData.civ;
     196           0 :         let civ = civref in this.Config.buildings ? civref : 'default';
     197           0 :         this.bAdvanced = [];
     198           0 :         for (let building of this.Config.buildings[civ])
     199           0 :                 if (gameState.isTemplateAvailable(gameState.applyCiv(building)))
     200           0 :                         this.bAdvanced.push(gameState.applyCiv(building));
     201             : };
     202             : 
     203             : /**
     204             :  * build our first base
     205             :  * if not enough resource, try first to do a dock
     206             :  */
     207           0 : PETRA.HQ.prototype.buildFirstBase = function(gameState)
     208             : {
     209           0 :         if (gameState.ai.queues.civilCentre.hasQueuedUnits())
     210           0 :                 return;
     211           0 :         let templateName = gameState.applyCiv("structures/{civ}/civil_centre");
     212           0 :         if (gameState.isTemplateDisabled(templateName))
     213           0 :                 return;
     214           0 :         let template = gameState.getTemplate(templateName);
     215           0 :         if (!template)
     216           0 :                 return;
     217           0 :         let total = gameState.getResources();
     218           0 :         let goal = "civil_centre";
     219           0 :         if (!total.canAfford(new API3.Resources(template.cost())))
     220             :         {
     221           0 :                 let totalExpected = gameState.getResources();
     222             :                 // Check for treasures around available in some maps at startup
     223           0 :                 for (let ent of gameState.getOwnUnits().values())
     224             :                 {
     225           0 :                         if (!ent.position())
     226           0 :                                 continue;
     227             :                         // If we can get a treasure around, just do it
     228           0 :                         if (ent.isIdle())
     229           0 :                                 PETRA.gatherTreasure(gameState, ent);
     230             :                         // Then count the resources from the treasures being collected
     231           0 :                         let treasureId = ent.getMetadata(PlayerID, "treasure");
     232           0 :                         if (!treasureId)
     233           0 :                                 continue;
     234           0 :                         let treasure = gameState.getEntityById(treasureId);
     235           0 :                         if (!treasure)
     236           0 :                                 continue;
     237           0 :                         let types = treasure.treasureResources();
     238           0 :                         for (let type in types)
     239           0 :                                 if (type in totalExpected)
     240           0 :                                         totalExpected[type] += types[type];
     241             :                         // If we can collect enough resources from these treasures, wait for them.
     242           0 :                         if (totalExpected.canAfford(new API3.Resources(template.cost())))
     243           0 :                                 return;
     244             :                 }
     245             : 
     246             :                 // not enough resource to build a cc, try with a dock to accumulate resources if none yet
     247           0 :                 if (!this.navalManager.docks.filter(API3.Filters.byClass("Dock")).hasEntities())
     248             :                 {
     249           0 :                         if (gameState.ai.queues.dock.hasQueuedUnits())
     250           0 :                                 return;
     251           0 :                         templateName = gameState.applyCiv("structures/{civ}/dock");
     252           0 :                         if (gameState.isTemplateDisabled(templateName))
     253           0 :                                 return;
     254           0 :                         template = gameState.getTemplate(templateName);
     255           0 :                         if (!template || !total.canAfford(new API3.Resources(template.cost())))
     256           0 :                                 return;
     257           0 :                         goal = "dock";
     258             :                 }
     259             :         }
     260           0 :         if (!this.canBuild(gameState, templateName))
     261           0 :                 return;
     262             : 
     263             :         // We first choose as startingPoint the point where we have the more units
     264           0 :         let startingPoint = [];
     265           0 :         for (let ent of gameState.getOwnUnits().values())
     266             :         {
     267           0 :                 if (!ent.hasClass("Worker"))
     268           0 :                         continue;
     269           0 :                 if (PETRA.isFastMoving(ent))
     270           0 :                         continue;
     271           0 :                 let pos = ent.position();
     272           0 :                 if (!pos)
     273             :                 {
     274           0 :                         let holder = PETRA.getHolder(gameState, ent);
     275           0 :                         if (!holder || !holder.position())
     276           0 :                                 continue;
     277           0 :                         pos = holder.position();
     278             :                 }
     279           0 :                 let gamepos = gameState.ai.accessibility.gamePosToMapPos(pos);
     280           0 :                 let index = gamepos[0] + gamepos[1] * gameState.ai.accessibility.width;
     281           0 :                 let land = gameState.ai.accessibility.landPassMap[index];
     282           0 :                 let sea = gameState.ai.accessibility.navalPassMap[index];
     283           0 :                 let found = false;
     284           0 :                 for (let point of startingPoint)
     285             :                 {
     286           0 :                         if (land !== point.land || sea !== point.sea)
     287           0 :                                 continue;
     288           0 :                         if (API3.SquareVectorDistance(point.pos, pos) > 2500)
     289           0 :                                 continue;
     290           0 :                         point.weight += 1;
     291           0 :                         found = true;
     292           0 :                         break;
     293             :                 }
     294           0 :                 if (!found)
     295           0 :                         startingPoint.push({ "pos": pos, "land": land, "sea": sea, "weight": 1 });
     296             :         }
     297           0 :         if (!startingPoint.length)
     298           0 :                 return;
     299             : 
     300           0 :         let imax = 0;
     301           0 :         for (let i = 1; i < startingPoint.length; ++i)
     302           0 :                 if (startingPoint[i].weight > startingPoint[imax].weight)
     303           0 :                         imax = i;
     304             : 
     305           0 :         if (goal == "dock")
     306             :         {
     307           0 :                 let sea = startingPoint[imax].sea > 1 ? startingPoint[imax].sea : undefined;
     308           0 :                 gameState.ai.queues.dock.addPlan(new PETRA.ConstructionPlan(gameState, "structures/{civ}/dock", { "sea": sea, "proximity": startingPoint[imax].pos }));
     309             :         }
     310             :         else
     311           0 :                 gameState.ai.queues.civilCentre.addPlan(new PETRA.ConstructionPlan(gameState, "structures/{civ}/civil_centre", { "base": -1, "resource": "wood", "proximity": startingPoint[imax].pos }));
     312             : };
     313             : 
     314             : /**
     315             :  * set strategy if game without construction:
     316             :  *   - if one of our allies has a cc, affect a small fraction of our army for his defense, the rest will attack
     317             :  *   - otherwise all units will attack
     318             :  */
     319           0 : PETRA.HQ.prototype.dispatchUnits = function(gameState)
     320             : {
     321           0 :         let allycc = gameState.getExclusiveAllyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray();
     322           0 :         if (allycc.length)
     323             :         {
     324           0 :                 if (this.Config.debug > 1)
     325           0 :                         API3.warn(" We have allied cc " + allycc.length + " and " + gameState.getOwnUnits().length + " units ");
     326           0 :                 let units = gameState.getOwnUnits();
     327           0 :                 let num = Math.max(Math.min(Math.round(0.08*(1+this.Config.personality.cooperative)*units.length), 20), 5);
     328           0 :                 let num1 = Math.floor(num / 2);
     329           0 :                 let num2 = num1;
     330             :                 // first pass to affect ranged infantry
     331           0 :                 units.filter(API3.Filters.byClasses(["Infantry+Ranged"])).forEach(ent => {
     332           0 :                         if (!num || !num1)
     333           0 :                                 return;
     334           0 :                         if (ent.getMetadata(PlayerID, "allied"))
     335           0 :                                 return;
     336           0 :                         let access = PETRA.getLandAccess(gameState, ent);
     337           0 :                         for (let cc of allycc)
     338             :                         {
     339           0 :                                 if (!cc.position() || PETRA.getLandAccess(gameState, cc) != access)
     340           0 :                                         continue;
     341           0 :                                 --num;
     342           0 :                                 --num1;
     343           0 :                                 ent.setMetadata(PlayerID, "allied", true);
     344           0 :                                 let range = 1.5 * cc.footprintRadius();
     345           0 :                                 ent.moveToRange(cc.position()[0], cc.position()[1], range, range + 5);
     346           0 :                                 break;
     347             :                         }
     348             :                 });
     349             :                 // second pass to affect melee infantry
     350           0 :                 units.filter(API3.Filters.byClasses(["Infantry+Melee"])).forEach(ent => {
     351           0 :                         if (!num || !num2)
     352           0 :                                 return;
     353           0 :                         if (ent.getMetadata(PlayerID, "allied"))
     354           0 :                                 return;
     355           0 :                         let access = PETRA.getLandAccess(gameState, ent);
     356           0 :                         for (let cc of allycc)
     357             :                         {
     358           0 :                                 if (!cc.position() || PETRA.getLandAccess(gameState, cc) != access)
     359           0 :                                         continue;
     360           0 :                                 --num;
     361           0 :                                 --num2;
     362           0 :                                 ent.setMetadata(PlayerID, "allied", true);
     363           0 :                                 let range = 1.5 * cc.footprintRadius();
     364           0 :                                 ent.moveToRange(cc.position()[0], cc.position()[1], range, range + 5);
     365           0 :                                 break;
     366             :                         }
     367             :                 });
     368             :                 // and now complete the affectation, including all support units
     369           0 :                 units.forEach(ent => {
     370           0 :                         if (!num && !ent.hasClass("Support"))
     371           0 :                                 return;
     372           0 :                         if (ent.getMetadata(PlayerID, "allied"))
     373           0 :                                 return;
     374           0 :                         let access = PETRA.getLandAccess(gameState, ent);
     375           0 :                         for (let cc of allycc)
     376             :                         {
     377           0 :                                 if (!cc.position() || PETRA.getLandAccess(gameState, cc) != access)
     378           0 :                                         continue;
     379           0 :                                 if (!ent.hasClass("Support"))
     380           0 :                                         --num;
     381           0 :                                 ent.setMetadata(PlayerID, "allied", true);
     382           0 :                                 let range = 1.5 * cc.footprintRadius();
     383           0 :                                 ent.moveToRange(cc.position()[0], cc.position()[1], range, range + 5);
     384           0 :                                 break;
     385             :                         }
     386             :                 });
     387             :         }
     388             : };
     389             : 
     390             : /**
     391             :  * configure our first base expansion
     392             :  *   - if on a small island, favor fishing
     393             :  *   - count the available wood resource, and allow rushes only if enough (we should otherwise favor expansion)
     394             :  */
     395           0 : PETRA.HQ.prototype.configFirstBase = function(gameState)
     396             : {
     397           0 :         if (!this.hasPotentialBase())
     398           0 :                 return;
     399             : 
     400           0 :         this.firstBaseConfig = true;
     401             : 
     402           0 :         let startingSize = 0;
     403           0 :         let startingLand = [];
     404           0 :         for (let region in this.landRegions)
     405             :         {
     406           0 :                 for (const base of this.baseManagers())
     407             :                 {
     408           0 :                         if (!base.anchor || base.accessIndex != +region)
     409           0 :                                 continue;
     410           0 :                         startingSize += gameState.ai.accessibility.regionSize[region];
     411           0 :                         startingLand.push(base.accessIndex);
     412           0 :                         break;
     413             :                 }
     414             :         }
     415           0 :         let cell = gameState.getPassabilityMap().cellSize;
     416           0 :         startingSize = startingSize * cell * cell;
     417           0 :         if (this.Config.debug > 1)
     418           0 :                 API3.warn("starting size " + startingSize + "(cut at 24000 for fish pushing)");
     419           0 :         if (startingSize < 25000)
     420             :         {
     421           0 :                 this.saveSpace = true;
     422           0 :                 this.Config.Economy.popForDock = Math.min(this.Config.Economy.popForDock, 16);
     423           0 :                 let num = Math.max(this.Config.Economy.targetNumFishers, 2);
     424           0 :                 for (let land of startingLand)
     425             :                 {
     426           0 :                         for (let sea of gameState.ai.accessibility.regionLinks[land])
     427           0 :                                 if (gameState.ai.HQ.navalRegions[sea])
     428           0 :                                         this.navalManager.updateFishingBoats(sea, num);
     429             :                 }
     430           0 :                 this.maxFields = 1;
     431           0 :                 this.needCorral = true;
     432             :         }
     433           0 :         else if (startingSize < 60000)
     434           0 :                 this.maxFields = 2;
     435             :         else
     436           0 :                 this.maxFields = false;
     437             : 
     438             :         // - count the available food resource, and react accordingly
     439           0 :         let startingFood = gameState.getResources().food;
     440           0 :         startingFood += this.getTotalResourceLevel(gameState, ["food"], ["nearby", "medium", "faraway"]).food;
     441             : 
     442           0 :         if (startingFood < 800)
     443             :         {
     444           0 :                 if (startingSize < 25000)
     445             :                 {
     446           0 :                         this.needFish = true;
     447           0 :                         this.Config.Economy.popForDock = 1;
     448             :                 }
     449             :                 else
     450           0 :                         this.needFarm = true;
     451             :         }
     452             :         // - count the available wood resource, and allow rushes only if enough (we should otherwise favor expansion)
     453           0 :         let startingWood = gameState.getResources().wood;
     454           0 :         startingWood += this.getTotalResourceLevel(gameState, ["wood"], ["nearby", "medium", "faraway"]).wood;
     455             : 
     456           0 :         if (this.Config.debug > 1)
     457           0 :                 API3.warn("startingWood: " + startingWood + " (cut at 8500 for no rush and 6000 for saveResources)");
     458           0 :         if (startingWood < 6000)
     459             :         {
     460           0 :                 this.saveResources = true;
     461           0 :                 this.Config.Economy.popPhase2 = Math.floor(0.75 * this.Config.Economy.popPhase2);       // Switch to town phase sooner to be able to expand
     462             : 
     463           0 :                 if (startingWood < 2000 && this.needFarm)
     464             :                 {
     465           0 :                         this.needCorral = true;
     466           0 :                         this.needFarm = false;
     467             :                 }
     468             :         }
     469           0 :         if (startingWood > 8500 && this.canBuildUnits)
     470             :         {
     471           0 :                 let allowed = Math.ceil((startingWood - 8500) / 3000);
     472             :                 // Not useful to prepare rushing if too long ceasefire
     473           0 :                 if (gameState.isCeasefireActive())
     474             :                 {
     475           0 :                         if (gameState.ceasefireTimeRemaining > 900)
     476           0 :                                 allowed = 0;
     477           0 :                         else if (gameState.ceasefireTimeRemaining > 600 && allowed > 1)
     478           0 :                                 allowed = 1;
     479             :                 }
     480           0 :                 this.attackManager.setRushes(allowed);
     481             :         }
     482             : 
     483             :         // immediatly build a wood dropsite if possible.
     484           0 :         if (!gameState.getOwnEntitiesByClass("DropsiteWood", true).hasEntities())
     485             :         {
     486           0 :                 const newDP = this.baseManagers()[0].findBestDropsiteAndLocation(gameState, "wood");
     487           0 :                 if (newDP.quality > 40 && this.canBuild(gameState, newDP.templateName))
     488             :                 {
     489             :                         // if we start with enough workers, put our available resources in this first dropsite
     490             :                         // same thing if our pop exceed the allowed one, as we will need several houses
     491           0 :                         let numWorkers = gameState.getOwnUnits().filter(API3.Filters.byClass("Worker")).length;
     492           0 :                         if (numWorkers > 12 && newDP.quality > 60 ||
     493             :                                 gameState.getPopulation() > gameState.getPopulationLimit() + 20)
     494             :                         {
     495           0 :                                 const cost = new API3.Resources(gameState.getTemplate(newDP.templateName).cost());
     496           0 :                                 gameState.ai.queueManager.setAccounts(gameState, cost, "dropsites");
     497             :                         }
     498           0 :                         gameState.ai.queues.dropsites.addPlan(new PETRA.ConstructionPlan(gameState, newDP.templateName, { "base": this.baseManagers()[0].ID }, newDP.pos));
     499             :                 }
     500             :         }
     501             :         // and build immediately a corral if needed
     502           0 :         if (this.needCorral)
     503             :         {
     504           0 :                 const template = gameState.applyCiv("structures/{civ}/corral");
     505           0 :                 if (!gameState.getOwnEntitiesByClass("Corral", true).hasEntities() && this.canBuild(gameState, template))
     506           0 :                         gameState.ai.queues.corral.addPlan(new PETRA.ConstructionPlan(gameState, template, { "base": this.baseManagers()[0].ID }));
     507             :         }
     508             : };

Generated by: LCOV version 1.14