Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/army.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/army.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/army.js @@ -89,6 +89,9 @@ /** adds or remove the strength of the entity either to the enemy or to our units. */ m.Army.prototype.evaluateStrength = function (ent, isOwn, remove) { + if (!ent) + return; + let entStrength; if (ent.hasClass("Structure")) { @@ -279,7 +282,7 @@ m.Army.prototype.clear = function (gameState) { while (this.foeEntities.length > 0) - this.removeFoe(gameState,this.foeEntities[0]); + this.removeFoe(gameState, this.foeEntities[0]); // Go back to our territory, using the nearest (defensive if any) structure. let armyPos = [0, 0]; 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 @@ -503,6 +503,54 @@ this.raidNumber++; }; +/** + * Response to the capture of one of our structure: + * transform all defense armies around into a new attack army and target this structure + */ +m.AttackManager.prototype.counterAttack = function(gameState, ent, range=150) +{ + if (!ent || !ent.position()) + return false; + let pos = ent.position(); + let attackType = "Attack"; + let attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber, attackType); + if (attackPlan.failed) + return false; + this.totalNumber++; + attackPlan.init(gameState); + this.startedAttacks[attackType].push(attackPlan); + + for (let i = 0; i < gameState.ai.HQ.defenseManager.armies.length; ++i) + { + let army = gameState.ai.HQ.defenseManager.armies[i]; + army.recalculatePosition(gameState); + if (API3.SquareVectorDistance(pos, army.foePosition) > range*range) + continue; + while (army.ownEntities.length > 0) + { + let unitId = army.ownEntities[0]; + army.removeOwn(gameState, unitId); + let unit = gameState.getEntityById(unitId); + if (unit && attackPlan.isAvailableUnit(gameState, unit)) + { + unit.setMetadata(PlayerID, "plan", attackPlan.name); + attackPlan.unitCollection.updateEnt(unit); + } + } + gameState.ai.HQ.defenseManager.armies.splice(i--, 1); + } + if (!attackPlan.unitCollection.hasEntities()) + { + attackPlan.Abort(gameState); + return false; + } + attackPlan.targetPlayer = ent.owner(); + attackPlan.targetPos = pos; + attackPlan.target = ent; + attackPlan.state = "arrived"; + return true; +}; + m.AttackManager.prototype.Serialize = function() { let properties = { Index: ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js =================================================================== --- ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ ps/trunk/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -213,6 +213,14 @@ for (let evt of events.OwnershipChanged) // capture events { + 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 + this.attackManager.counterAttack(gameState, ent); + continue; + } + if (evt.to !== PlayerID) continue; let ent = gameState.getEntityById(evt.entity);