From d5dcb0c61ecb762c3c40cb68adca48e0bc9933f0 Mon Sep 17 00:00:00 2001 From: mimo Date: Thu, 25 May 2017 20:26:22 +0000 Subject: [PATCH] Petra: fix a case where the AI loose control of its units (they become only driven by UnitAI) Reviewed By: Sandarac Differential Revision: https://code.wildfiregames.com/D545 This was SVN commit r19655. --- .../mods/public/simulation/ai/petra/army.js | 63 ++++++++++++++++++- .../simulation/ai/petra/defenseManager.js | 17 +++-- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/binaries/data/mods/public/simulation/ai/petra/army.js b/binaries/data/mods/public/simulation/ai/petra/army.js index e0e2ff981b..296f97402b 100644 --- a/binaries/data/mods/public/simulation/ai/petra/army.js +++ b/binaries/data/mods/public/simulation/ai/petra/army.js @@ -280,8 +280,69 @@ m.Army.prototype.clear = function (gameState) { while (this.foeEntities.length > 0) this.removeFoe(gameState,this.foeEntities[0]); + + // Go back to our territory, using the nearest (defensive if any) structure. + let armyPos = [0, 0]; + let npos = 0; + for (let entId of this.ownEntities) + { + let ent = gameState.getEntityById(entId); + if (!ent) + continue; + let pos = ent.position(); + if (!pos || gameState.ai.HQ.territoryMap.getOwner(pos) === PlayerID) + continue; + armyPos[0] += pos[0]; + armyPos[1] += pos[1]; + ++npos; + } + let nearestStructurePos; + let defensiveFound; + let distmin; + let radius; + if (npos > 0) + { + armyPos[0] /= npos; + armyPos[1] /= npos; + let armyAccess = gameState.ai.accessibility.getAccessValue(armyPos); + for (let struct of gameState.getOwnStructures().values()) + { + let pos = struct.position(); + if (!pos || gameState.ai.HQ.territoryMap.getOwner(pos) !== PlayerID) + continue; + if (m.getLandAccess(gameState, struct) !== armyAccess) + continue; + let defensiveStruct = struct.hasDefensiveFire(); + if (defensiveFound && !defensiveStruct) + continue; + let dist = API3.SquareVectorDistance(armyPos, pos); + if (distmin && dist > distmin && (defensiveFound || !defensiveStruct)) + continue; + if (defensiveStruct) + defensiveFound = true; + distmin = dist; + nearestStructurePos = pos; + radius = struct.obstructionRadius(); + } + } while (this.ownEntities.length > 0) - this.removeOwn(gameState,this.ownEntities[0]); + { + let entId = this.ownEntities[0]; + this.removeOwn(gameState, entId); + let ent = gameState.getEntityById(entId); + if (ent) + { + if (!ent.position() || + ent.healthLevel() < this.Config.garrisonHealthLevel.low && + gameState.ai.HQ.defenseManager.garrisonAttackedUnit(gameState, ent)) + continue; + + if (nearestStructurePos && gameState.ai.HQ.territoryMap.getOwner(ent.position()) !== PlayerID) + ent.moveToRange(nearestStructurePos[0], nearestStructurePos[1], radius, radius+5); + else + ent.stopMoving(); + } + } this.assignedAgainst = {}; this.assignedTo = {}; diff --git a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js index 34f6aa28ee..31f4d4a475 100644 --- a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js @@ -566,18 +566,18 @@ m.DefenseManager.prototype.garrisonUnitsInside = function(gameState, target, dat let minGarrison = data.min ? data.min : target.garrisonMax(); let typeGarrison = data.type ? data.type : "protection"; if (gameState.ai.HQ.garrisonManager.numberOfGarrisonedUnits(target) >= minGarrison) - return; + return false; if (target.hitpoints() < target.garrisonEjectHealth() * target.maxHitpoints()) - return; + return false; if (data.attacker) { let attackTypes = target.attackTypes(); if (!attackTypes || attackTypes.indexOf("Ranged") === -1) - return; + return false; let dist = API3.SquareVectorDistance(data.attacker.position(), target.position()); let range = target.attackRange("Ranged").max; if (dist >= range*range) - return; + return false; } let index = gameState.ai.accessibility.getAccessValue(target.position()); let garrisonManager = gameState.ai.HQ.garrisonManager; @@ -592,6 +592,7 @@ m.DefenseManager.prototype.garrisonUnitsInside = function(gameState, target, dat else allowMelee = true; } + let ret = false; for (let ent of units.values()) { if (garrisonManager.numberOfGarrisonedUnits(target) >= minGarrison) @@ -623,7 +624,9 @@ m.DefenseManager.prototype.garrisonUnitsInside = function(gameState, target, dat if (army) army.removeOwn(gameState, ent.id()); garrisonManager.garrison(gameState, ent, target, typeGarrison); + ret = true; } + return ret; }; /** garrison a attacked siege ranged unit inside the nearest fortress */ @@ -650,6 +653,7 @@ m.DefenseManager.prototype.garrisonSiegeUnit = function(gameState, unit) }); if (nearest) garrisonManager.garrison(gameState, unit, nearest, "protection"); + return nearest !== undefined; }; /** @@ -683,17 +687,18 @@ m.DefenseManager.prototype.garrisonAttackedUnit = function(gameState, unit, emer nearest = ent; } if (!nearest) - return; + return false; if (!emergency) { garrisonManager.garrison(gameState, unit, nearest, "protection"); - return; + return true; } if (garrisonManager.numberOfGarrisonedUnits(nearest) >= nearest.garrisonMax()) // make room for this ent nearest.unload(nearest.garrisoned()[0]); garrisonManager.garrison(gameState, unit, nearest, nearest.buffHeal() ? "protection" : "emergency"); + return true; }; /**