Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/defenseManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/defenseManager.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/defenseManager.js @@ -1,10 +1,11 @@ PETRA.DefenseManager = function(Config) { - this.armies = []; // array of "army" Objects + // Array of "army" Objects. + this.armies = []; this.Config = Config; this.targetList = []; this.armyMergeSize = this.Config.Defense.armyMergeSize; - // stats on how many enemies are currently attacking our allies + // Stats on how many enemies are currently attacking our allies // this.attackingArmies[enemy][ally] = number of enemy armies inside allied territory // this.attackingUnits[enemy][ally] = number of enemy units not in armies inside allied territory // this.attackedAllies[ally] = number of enemies attacking the ally @@ -21,7 +22,7 @@ this.checkEvents(gameState, events); - // Check if our potential targets are still valid + // Check if our potential targets are still valid. for (let i = 0; i < this.targetList.length; ++i) { let target = gameState.getEntityById(this.targetList[i]); @@ -29,8 +30,8 @@ this.targetList.splice(i--, 1); } - // Count the number of enemies attacking our allies in the previous turn - // We'll be more cooperative if several enemies are attacking him simultaneously + // Count the number of enemies attacking our allies in the previous turn. + // We'll be more cooperative if several enemies are attacking him simultaneously. this.attackedAllies = {}; let attackingArmies = clone(this.attackingArmies); for (let enemy in this.attackingUnits) @@ -82,7 +83,7 @@ PETRA.DefenseManager.prototype.getArmy = function(partOfArmy) { - // Find the army corresponding to this ID partOfArmy + // Find the army corresponding to this ID partOfArmy. for (let army of this.armies) if (army.ID == partOfArmy) return army; @@ -98,8 +99,8 @@ let territoryOwner = this.territoryMap.getOwner(entity.position()); if (territoryOwner != 0 && !gameState.isPlayerAlly(territoryOwner)) return false; - // check if the entity is trying to build a new base near our buildings, - // and if yes, add this base in our target list + // Check if the entity is trying to build a new base near our buildings, + // and if yes, add this base in our target list. if (entity.unitAIState() && entity.unitAIState() == "INDIVIDUAL.REPAIR.REPAIRING") { let targetId = entity.unitAIOrderData()[0].target; @@ -134,14 +135,15 @@ if (entity.attackTypes() === undefined || entity.hasClass("Support")) return false; let dist2Min = 6000; - // TODO the 30 is to take roughly into account the structure size in following checks. Can be improved + // TODO the 30 is to take roughly into account the structure size in following checks. Can be improved. if (entity.attackTypes().indexOf("Ranged") != -1) dist2Min = (entity.attackRange("Ranged").max + 30) * (entity.attackRange("Ranged").max + 30); for (let targetId of this.targetList) { let target = gameState.getEntityById(targetId); - if (!target || !target.position()) // the enemy base is either destroyed or built + // The enemy base is either destroyed or built. + if (!target || !target.position()) continue; if (API3.SquareVectorDistance(target.position(), entity.position()) < dist2Min) return true; @@ -153,9 +155,7 @@ if (!gameState.isEntityExclusiveAlly(cc) || cc.foundationProgress() == 0) continue; let cooperation = this.GetCooperationLevel(cc.owner()); - if (cooperation < 0.6 && cc.foundationProgress() !== undefined) - continue; - if (cooperation < 0.3) + if (cooperation < 0.3 || cooperation < 0.6 && !!cc.foundationProgress()) continue; if (API3.SquareVectorDistance(cc.position(), entity.position()) < dist2Min) return true; @@ -172,7 +172,7 @@ if (gameState.isPlayerMutualAlly(territoryOwner)) { - // If ally attacked by more than 2 enemies, help him not only for cc but also for structures + // If ally attacked by more than 2 enemies, help him not only for cc but also for structures. if (territoryOwner != PlayerID && this.attackedAllies[territoryOwner] && this.attackedAllies[territoryOwner] > 1 && this.GetCooperationLevel(territoryOwner) > 0.7) @@ -187,7 +187,7 @@ } } - // Update the number of enemies attacking this ally + // Update the number of enemies attacking this ally. let enemy = entity.owner(); if (this.attackingUnits[enemy] === undefined) this.attackingUnits[enemy] = {}; @@ -209,7 +209,7 @@ { if (!this.armies.length) { - // check if we can recover capture points from any of our notdecaying structures + // Check if we can recover capture points from any of our notdecaying structures. for (let ent of gameState.getOwnStructures().values()) { if (ent.decaying()) @@ -232,13 +232,12 @@ else if (!gameState.isPlayerEnemy(i)) return; - // loop through enemy units for (let ent of gameState.getEnemyUnits(i).values()) { if (ent.getMetadata(PlayerID, "PartOfArmy") !== undefined) continue; - // keep animals attacking us or our allies + // Keep animals attacking us or our allies. if (ent.hasClass("Animal")) { if (!ent.unitAIState() || ent.unitAIState().split(".")[1] != "COMBAT") @@ -255,15 +254,15 @@ if (ent.hasClass("Ship") || ent.hasClass("Trader")) continue; - // check if unit is dangerous "a priori" + // Check if unit is dangerous "a priori". if (this.isDangerous(gameState, ent)) this.makeIntoArmy(gameState, ent.id()); } if (i != 0 || this.armies.length > 1 || gameState.ai.HQ.numActiveBases() == 0) return; - // look for possible gaia buildings inside our territory (may happen when enemy resign or after structure decay) - // and attack it only if useful (and capturable) or dangereous + // Look for possible gaia buildings inside our territory (may happen when enemy resign or after structure decay) + // and attack it only if useful (and capturable) or dangereous. for (let ent of gameState.getEnemyStructures(i).values()) { if (!ent.position() || ent.getMetadata(PlayerID, "PartOfArmy") !== undefined) @@ -281,10 +280,11 @@ for (let i = 0; i < this.armies.length; ++i) { let army = this.armies[i]; - // this returns a list of IDs: the units that broke away from the army for being too far. + // This returns a list of IDs: the units that broke away from the army for being too far. let breakaways = army.update(gameState); + // Assume dangerosity. for (let breaker of breakaways) - this.makeIntoArmy(gameState, breaker); // assume dangerosity + this.makeIntoArmy(gameState, breaker); if (army.getState() == 0) { @@ -292,10 +292,9 @@ this.switchToAttack(gameState, army); army.clear(gameState); this.armies.splice(i--, 1); - continue; } } - // Check if we can't merge it with another + // Check if we can't merge it with another. for (let i = 0; i < this.armies.length - 1; ++i) { let army = this.armies[i]; @@ -307,7 +306,7 @@ if (otherArmy.getType() != "default" || API3.SquareVectorDistance(army.foePosition, otherArmy.foePosition) > this.armyMergeSize) continue; - // no need to clear here. + // No need to clear here. army.merge(gameState, otherArmy); this.armies.splice(j--, 1); } @@ -315,7 +314,7 @@ if (gameState.ai.playedTurn % 5 != 0) return; - // Check if any army is no more dangerous (possibly because it has defeated us and destroyed our base) + // Check if any army is no more dangerous (possibly because it has defeated us and destroyed our base). this.attackingArmies = {}; for (let i = 0; i < this.armies.length; ++i) { @@ -326,7 +325,7 @@ { if (gameState.isPlayerMutualAlly(owner)) { - // update the number of enemies attacking this ally + // Update the number of enemies attacking this ally. for (let id of army.foeEntities) { let ent = gameState.getEntityById(id); @@ -343,15 +342,16 @@ } continue; } - else if (owner != 0) // enemy army back in its territory + // Enemy army back in its territory. + else if (owner != 0) { army.clear(gameState); this.armies.splice(i--, 1); continue; } - // army in neutral territory - // TODO check smaller distance with all our buildings instead of only ccs with big distance + // Army in neutral territory. + // TODO check smaller distance with all our buildings instead of only ccs with big distance. let stillDangerous = false; let bases = gameState.updatingGlobalCollection("allCCs", API3.Filters.byClass("CivCentre")); for (let base of bases.values()) @@ -370,7 +370,7 @@ } if (stillDangerous) continue; - // Need to also check docks because of oversea bases + // Need to also check docks because of oversea bases. for (let dock of gameState.getOwnStructures().filter(API3.Filters.byClass("Dock")).values()) { if (API3.SquareVectorDistance(dock.position(), army.foePosition) > 10000) @@ -394,7 +394,7 @@ return; let armiesNeeding = []; - // let's add defenders + // Let's add defenders. for (let army of this.armies) { let needsDef = army.needsDefenders(gameState); @@ -419,7 +419,7 @@ if (!armiesNeeding.length) return; - // let's get our potential units + // Let's get our potential units. let potentialDefenders = []; gameState.getOwnUnits().forEach(function(ent) { if (!ent.position()) @@ -448,9 +448,9 @@ for (let ipass = 0; ipass < 2; ++ipass) { - // First pass only assign defenders with the right access - // Second pass assign all defenders - // TODO could sort them by distance + // First pass only assign defenders with the right access. + // Second pass assign all defenders. + // TODO could sort them by distance. let backup = 0; for (let i = 0; i < potentialDefenders.length; ++i) { @@ -472,7 +472,7 @@ } // If outside our territory (helping an ally or attacking a cc foundation) - // or if in another access, keep some troops in backup + // or if in another access, keep some troops in backup. if (backup < 12 && (aMin == undefined || distMin > 40000 && this.territoryMap.getOwner(armiesNeeding[aMin].army.foePosition) != PlayerID)) { @@ -495,7 +495,7 @@ } } - // If shortage of defenders, produce infantry garrisoned in nearest civil center + // If shortage of defenders, produce infantry garrisoned in nearest civil center. let armiesPos = []; for (let a = 0; a < armiesNeeding.length; ++a) armiesPos.push(armiesNeeding[a].army.foePosition); @@ -517,21 +517,23 @@ /** * If our defense structures are attacked, garrison soldiers inside when possible * and if a support unit is attacked and has less than 55% health, garrison it inside the nearest healing structure - * and if a ranged siege unit (not used for defense) is attacked, garrison it in the nearest fortress - * If our hero is attacked with regicide victory condition, the victoryManager will handle it + * and if a ranged siege unit (not used for defense) is attacked, garrison it in the nearest fortress. + * If our hero is attacked with regicide victory condition, the victoryManager will handle it. */ PETRA.DefenseManager.prototype.checkEvents = function(gameState, events) { - // must be called every turn for all armies + // Must be called every turn for all armies. for (let army of this.armies) army.checkEvents(gameState, events); - for (let evt of events.OwnershipChanged) // capture events + // Capture events. + for (let evt of events.OwnershipChanged) { if (gameState.isPlayerMutualAlly(evt.from) && evt.to > 0) { let ent = gameState.getEntityById(evt.entity); - if (ent && ent.hasClass("CivCentre")) // one of our cc has been captured + // One of our cc has been captured. + if (ent && ent.hasClass("CivCentre")) gameState.ai.HQ.attackManager.switchDefenseToAttack(gameState, ent, { "range": 150 }); } } @@ -551,7 +553,7 @@ (!target.hasClass("Structure") || target.attackRange("Ranged"))) { // If enemies are in range of one of our defensive structures, garrison it for arrow multiplier - // (enemy non-defensive structure are not considered to stay in sync with garrisonManager) + // (enemy non-defensive structure are not considered to stay in sync with garrisonManager). if (attacker.position() && attacker.isGarrisonHolder() && attacker.getArrowMultiplier() && (target.owner() != 0 || !target.hasClass("Unit") || target.unitAIState() && target.unitAIState().split(".")[1] == "COMBAT")) @@ -561,7 +563,7 @@ if (!gameState.isEntityOwn(target)) continue; - // If attacked by one of our allies (he must trying to recover capture points), do not react + // If attacked by one of our allies (he must trying to recover capture points), do not react. if (attacker && gameState.isEntityAlly(attacker)) continue; @@ -578,8 +580,9 @@ } continue; } - - if (target.hasClass("Ship")) // TODO integrate other ships later, need to be sure it is accessible + + // TODO integrate other ships later, need to be sure it is accessible. + if (target.hasClass("Ship")) continue; // If a building on a blinking tile is attacked, check if it can be defended. @@ -601,7 +604,7 @@ } - // If inside a started attack plan, let the plan deal with this unit + // If inside a started attack plan, let the plan deal with this unit. let plan = target.getMetadata(PlayerID, "plan"); if (plan !== undefined && plan >= 0) { @@ -610,8 +613,8 @@ continue; } - // Signal this attacker to our defense manager, except if we are in enemy territory - // TODO treat ship attack + // Signal this attacker to our defense manager, except if we are in enemy territory. + // TODO treat ship attack. if (attacker && attacker.position() && attacker.getMetadata(PlayerID, "PartOfArmy") === undefined && !attacker.hasClass("Structure") && !attacker.hasClass("Ship")) { @@ -626,13 +629,13 @@ if (army.getType() == "capturing") { let abort = false; - // if one of the units trying to capture a structure is attacked, + // If one of the units trying to capture a structure is attacked, // abort the army so that the unit can defend itself if (army.ownEntities.indexOf(target.id()) != -1) abort = true; else if (army.foeEntities[0] == target.id() && target.owner() == PlayerID) { - // else we may be trying to regain some capture point from one of our structure + // else we may be trying to regain some capture point from one of our structure. abort = true; let capture = target.capturePoints(); for (let j = 0; j < capture.length; ++j) @@ -691,7 +694,7 @@ if (unitAIStateOrder == "COMBAT" && !PETRA.isSiegeUnit(currentTarget) && gameState.ai.HQ.capturableTargets.has(orderData[0].target)) { - // take the nearest unit also attacking this structure to help us + // Take the nearest unit also attacking this structure to help us. let capturableTarget = gameState.ai.HQ.capturableTargets.get(orderData[0].target); let minDist; let minEnt; @@ -704,7 +707,7 @@ let ent = gameState.getEntityById(entId); if (!ent || !ent.position()) continue; - // Check that the unit is still attacking the structure (since the last played turn) + // Check that the unit is still attacking the structure (since the last played turn). let state = ent.unitAIState(); if (!state || !state.split(".")[1] || state.split(".")[1] != "COMBAT") continue; @@ -754,7 +757,7 @@ let allowMelee = gameState.ai.HQ.garrisonManager.allowMelee(target); if (allowMelee === undefined) { - // Should be kept in sync with garrisonManager to avoid garrisoning-ungarrisoning some units + // Should be kept in sync with garrisonManager to avoid garrisoning-ungarrisoning some units. if (data.attacker) allowMelee = data.attacker.hasClass("Structure") ? data.attacker.attackRange("Ranged") : !PETRA.isSiegeUnit(data.attacker); else @@ -775,7 +778,7 @@ if (ent.getMetadata(PlayerID, "plan") !== undefined && ent.getMetadata(PlayerID, "plan") >= 0) { let subrole = ent.getMetadata(PlayerID, "subrole"); - // when structure decaying (usually because we've just captured it in enemy territory), also allow units from an attack plan + // When structure decaying (usually because we've just captured it in enemy territory), also allow units from an attack plan. if (typeGarrison != "decay" && subrole && (subrole == "completing" || subrole == "walking" || subrole == "attacking")) return false; } @@ -804,7 +807,7 @@ return ret; }; -/** garrison a attacked siege ranged unit inside the nearest fortress */ +/** Garrison a attacked siege ranged unit inside the nearest fortress. */ PETRA.DefenseManager.prototype.garrisonSiegeUnit = function(gameState, unit) { let distmin = Math.min(); @@ -835,9 +838,9 @@ }; /** - * Garrison a hurt unit inside a player-owned or allied structure - * If emergency is true, the unit will be garrisoned in the closest possible structure - * Otherwise, it will garrison in the closest healing structure + * Garrison a hurt unit inside a player-owned or allied structure. + * If emergency is true, the unit will be garrisoned in the closest possible structure. + * Otherwise, it will garrison in the closest healing structure. */ PETRA.DefenseManager.prototype.garrisonAttackedUnit = function(gameState, unit, emergency = false) { @@ -882,7 +885,7 @@ }; /** - * Be more inclined to help an ally attacked by several enemies + * Be more inclined to help an ally attacked by several enemies. */ PETRA.DefenseManager.prototype.GetCooperationLevel = function(ally) { @@ -893,7 +896,7 @@ }; /** - * Switch a defense army into an attack if needed + * Switch a defense army into an attack if needed. */ PETRA.DefenseManager.prototype.switchToAttack = function(gameState, army) {