Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackManager.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackManager.js @@ -362,24 +362,27 @@ } else if (gameState.getGameType() === "capture_the_relic") { - // Target the player with the most relics + // Target the player with the most relics (including gaia) + let allRelics = gameState.updatingGlobalCollection("allRelics", API3.Filters.byClass("Relic")); let maxRelicsOwned = 0; - // TODO: target gaia relics - for (let i = 1; i < gameState.sharedScript.playersData.length; ++i) + for (let i = 0; i < gameState.sharedScript.playersData.length; ++i) { - if (!gameState.isPlayerEnemy(i) || this.defeated[i]) + if (!gameState.isPlayerEnemy(i) || this.defeated[i] || i === 0 && + !gameState.ai.HQ.gameTypeManager.tryCaptureGaiaRelic) continue; - let relicsCount = gameState.getEnemyUnits(i).filter(API3.Filters.byClass("Relic")).length; + let relicsCount = allRelics.filter(relic => relic.owner() === i).length; if (relicsCount <= maxRelicsOwned) continue; maxRelicsOwned = relicsCount; enemyPlayer = i; } - if (enemyPlayer) + if (enemyPlayer !== undefined) { if (attack.targetPlayer === undefined) this.currentEnemyPlayer = enemyPlayer; + if (enemyPlayer === 0) + gameState.ai.HQ.gameTypeManager.tryCaptureGaiaRelic = false; return enemyPlayer; } } @@ -479,7 +482,7 @@ }; /** f.e. if we have changed diplomacy with another player. */ -m.AttackManager.prototype.cancelAttacksAgainstPlayer = function(player) +m.AttackManager.prototype.cancelAttacksAgainstPlayer = function(gameState, player) { for (let attackType in this.upcomingAttacks) for (let attack of this.upcomingAttacks[attackType]) Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackPlan.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackPlan.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackPlan.js @@ -798,6 +798,8 @@ let minDist = Math.min(); for (let ent of targets.values()) { + if (this.targetPlayer === 0 && gameState.getGameType() === "capture_the_relic" && !ent.hasClass("Relic")) + continue; if (!ent.position()) continue; if (sameLand && gameState.ai.accessibility.getAccessValue(ent.position()) !== land) @@ -835,7 +837,7 @@ else if (gameState.getGameType() === "regicide") targets = gameState.getEnemyUnits(playerEnemy).filter(API3.Filters.byClass("Hero")); else if (gameState.getGameType() === "capture_the_relic") - targets = gameState.getEnemyUnits(playerEnemy).filter(API3.Filters.byClass("Relic")); + targets = gameState.updatingGlobalCollection("allRelics", API3.Filters.byClass("Relic")).filter(relic => relic.owner() === playerEnemy); if (targets && targets.hasEntities()) return targets; Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/diplomacyManager.js @@ -322,7 +322,7 @@ m.DiplomacyManager.prototype.changePlayerDiplomacy = function(gameState, player, newDiplomaticStance) { if (gameState.isPlayerEnemy(player) && (newDiplomaticStance === "ally" || newDiplomaticStance === "neutral")) - gameState.ai.HQ.attackManager.cancelAttacksAgainstPlayer(player); + gameState.ai.HQ.attackManager.cancelAttacksAgainstPlayer(gameState, player); Engine.PostCommand(PlayerID, { "type": "diplomacy", "player": player, "to": newDiplomaticStance }); if (this.Config.debug > 1) API3.warn("diplomacy stance with player " + player + " is now " + newDiplomaticStance); Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/gameTypeManager.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/gameTypeManager.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/gameTypeManager.js @@ -13,6 +13,8 @@ // Holds ids of all ents who are (or can be) guarding and if the ent is currently guarding this.guardEnts = new Map(); this.healersPerCriticalEnt = 2 + Math.round(this.Config.personality.defensive * 2); + this.tryCaptureGaiaRelic = false; + this.tryCaptureGaiaRelicLapseTime = -1; }; /** @@ -244,7 +246,11 @@ this.criticalEnts.set(ent.id(), { "guardsAssigned": 0, "guards": new Map() }); // Move captured relics to the closest base if (ent.hasClass("Unit")) + { this.pickCriticalEntRetreatLocation(gameState, ent, false); + if (evt.from === 0) + gameState.ai.HQ.attackManager.cancelAttacksAgainstPlayer(gameState, evt.from); + } } } }; @@ -399,7 +405,8 @@ return; // Couldn't find a place to garrison, so the ent will flee from attacks - criticalEnt.setStance("passive"); + if (!criticalEnt.hasClass("Relic")) + criticalEnt.setStance("passive"); let accessIndex = gameState.ai.accessibility.getAccessValue(criticalEnt.position()); let basePos = m.getBestBase(gameState, criticalEnt, true); if (basePos && basePos.accessIndex == accessIndex) @@ -516,7 +523,15 @@ } if (gameState.getGameType() === "capture_the_relic" && gameState.ai.playedTurn % 10 === 0) + { this.manageCriticalEntGuards(gameState); + // Do not capture gaia relics frequently, as the ai has access to the entire map + if (gameState.ai.elapsedTime > this.tryCaptureGaiaRelicLapseTime && !this.tryCaptureGaiaRelic) + { + this.tryCaptureGaiaRelic = true; + this.tryCaptureGaiaRelicLapseTime = gameState.ai.elapsedTime + (5 - 0.5 * (this.Config.difficulty - 3) * 60); + } + } }; m.GameTypeManager.prototype.Serialize = function() @@ -524,7 +539,9 @@ return { "criticalEnts": this.criticalEnts, "guardEnts": this.guardEnts, - "healersPerCriticalEnt": this.healersPerCriticalEnt + "healersPerCriticalEnt": this.healersPerCriticalEnt, + "tryCaptureGaiaRelic": this.tryCaptureGaiaRelic, + "tryCaptureGaiaRelicLapseTime": this.tryCaptureGaiaRelicLapseTime }; };