From 032d0317291edf1740cc230ced04eff1c7602b93 Mon Sep 17 00:00:00 2001 From: mimo Date: Sat, 30 Aug 2014 20:06:48 +0000 Subject: [PATCH] Petra: revisit the attacks + several bugfixes + add some more debug printouts This was SVN commit r15695. --- .../public/simulation/ai/petra/_petrabot.js | 2 +- .../simulation/ai/petra/attackManager.js | 16 +- .../public/simulation/ai/petra/attackPlan.js | 213 ++++++++++++------ .../public/simulation/ai/petra/baseManager.js | 38 +++- .../mods/public/simulation/ai/petra/config.js | 1 + .../simulation/ai/petra/defenseManager.js | 24 +- .../simulation/ai/petra/entity-extend.js | 24 ++ .../simulation/ai/petra/garrisonManager.js | 34 ++- .../simulation/ai/petra/headquarters.js | 54 ++--- .../simulation/ai/petra/navalManager.js | 12 +- .../simulation/ai/petra/queueManager.js | 6 +- .../simulation/ai/petra/queueplan-training.js | 2 +- .../simulation/ai/petra/tradeManager.js | 14 +- .../simulation/ai/petra/transportPlan.js | 22 +- .../mods/public/simulation/ai/petra/worker.js | 4 +- 15 files changed, 291 insertions(+), 175 deletions(-) diff --git a/binaries/data/mods/public/simulation/ai/petra/_petrabot.js b/binaries/data/mods/public/simulation/ai/petra/_petrabot.js index 3cab95e257..5943cd7570 100644 --- a/binaries/data/mods/public/simulation/ai/petra/_petrabot.js +++ b/binaries/data/mods/public/simulation/ai/petra/_petrabot.js @@ -120,7 +120,7 @@ m.PetraBot.prototype.initPersonality = function() this.Config.priorities.defenseBuilding = 60; } - if (this.Config.debug == 0) + if (this.Config.debug < 2) return; API3.warn(" >>> Petra bot: personality = " + uneval(this.Config.personality)); }; diff --git a/binaries/data/mods/public/simulation/ai/petra/attackManager.js b/binaries/data/mods/public/simulation/ai/petra/attackManager.js index f31ae7dd34..0f72ed287a 100644 --- a/binaries/data/mods/public/simulation/ai/petra/attackManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/attackManager.js @@ -50,7 +50,7 @@ m.AttackManager.prototype.init = function(gameState, queues, allowRush) // Others once in a while m.AttackManager.prototype.update = function(gameState, queues, events) { - if (this.Config.debug == 2 && gameState.ai.elapsedTime > this.debugTime + 60) + if (this.Config.debug > 2 && gameState.ai.elapsedTime > this.debugTime + 60) { this.debugTime = gameState.ai.elapsedTime; API3.warn(" upcoming attacks ================="); @@ -93,7 +93,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) } else if (updateStep === 0 || updateStep === 3) { - if (this.Config.debug) + if (this.Config.debug > 1) API3.warn("Attack Manager: " + attack.getType() + " plan " + attack.getName() + " aborted."); attack.Abort(gameState, this); this.upcomingAttacks[attackType].splice(i--,1); @@ -114,7 +114,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) var chatText = "I'm starting an attack against " + targetName + "."; gameState.ai.chatTeam(chatText); - if (this.Config.debug) + if (this.Config.debug > 1) API3.warn("Attack Manager: Starting " + attack.getType() + " plan " + attack.getName()); this.startedAttacks[attackType].push(attack); } @@ -137,7 +137,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) var chatText = "I'm starting an attack against " + targetName + "."; gameState.ai.chatTeam(chatText); - if (this.Config.debug) + if (this.Config.debug > 1) API3.warn("Attack Manager: Starting " + attack.getType() + " plan " + attack.getName()); this.startedAttacks[attackType].push(attack); this.upcomingAttacks[attackType].splice(i--,1); @@ -157,7 +157,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) var remaining = attack.update(gameState, events); if (!remaining) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Military Manager: " + attack.getType() + " plan " + attack.getName() + " is finished with remaining " + remaining); attack.Abort(gameState); this.startedAttacks[attackType].splice(i--,1); @@ -176,7 +176,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) var attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber, "Rush", data); if (!attackPlan.failed) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Headquarters: Rushing plan " + this.totalNumber + " with maxRushes " + this.maxRushes); this.totalNumber++; this.upcomingAttacks["Rush"].push(attackPlan); @@ -201,7 +201,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) this.attackPlansEncounteredWater = true; // hack else { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Military Manager: Creating the plan " + type + " " + this.totalNumber); this.totalNumber++; this.upcomingAttacks[type].push(attackPlan); @@ -226,7 +226,7 @@ m.AttackManager.prototype.update = function(gameState, queues, events) var attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber, "Raid", data); if (!attackPlan.failed) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Headquarters: Raiding plan " + this.totalNumber); this.totalNumber++; this.upcomingAttacks["Raid"].push(attackPlan); diff --git a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js index 2dc1f3db1f..a5b50a05a7 100644 --- a/binaries/data/mods/public/simulation/ai/petra/attackPlan.js +++ b/binaries/data/mods/public/simulation/ai/petra/attackPlan.js @@ -376,7 +376,7 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events) return 2; } - if (this.Config.debug > 2 && gameState.ai.playedTurn % 50 === 0) + if (this.Config.debug > 3 && gameState.ai.playedTurn % 50 === 0) this.debugAttack(); // find our target @@ -388,7 +388,7 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events) var oldTargetPlayer = this.targetPlayer; // may-be all our previous enemey targets have been destroyed ? this.targetPlayer = this.getEnemyPlayer(gameState); - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(" === no more target for enemy player " + oldTargetPlayer + " let us switch against player " + this.targetPlayer); this.target = this.getNearestTarget(gameState, this.rallyPoint); } @@ -471,7 +471,7 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events) } else // Abort the plan so that its units will be reassigned to other plans. { - if (this.Config.debug > 0) + if (this.Config.debug > 1) { var am = gameState.ai.HQ.attackManager; API3.warn(" attacks upcoming: raid " + am.upcomingAttacks["Raid"].length @@ -531,7 +531,7 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events) } var index = gameState.ai.accessibility.getAccessValue(entity.position()); if (index === rallyIndex) - entity.moveToRange(rallyPoint[0], rallyPoint[1], 0, 25, queued); + entity.moveToRange(rallyPoint[0], rallyPoint[1], 0, 15, queued); else gameState.ai.HQ.navalManager.requireTransport(gameState, entity, index, rallyIndex, rallyPoint); }); @@ -569,7 +569,7 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState) return va - vb; }); - if (this.Config.debug > 0 && gameState.ai.playedTurn%50 === 0) + if (this.Config.debug > 1 && gameState.ai.playedTurn%50 === 0) { API3.warn("===================================="); API3.warn("======== build order for plan " + this.name); @@ -605,14 +605,14 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState) // effectively removing the unit from the plan. if (template === undefined) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("attack no template found " + this.buildOrder[0][1]); delete this.unitStat[this.buildOrder[0][4]]; // deleting the associated unitstat. this.buildOrder.splice(0,1); } else { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("attack template " + template + " added for plan " + this.name); var max = this.buildOrder[0][3]["batchSize"]; var specialData = "Plan_" + this.name + "_" + this.buildOrder[0][4]; @@ -622,7 +622,7 @@ m.AttackPlan.prototype.trainMoreUnits = function(gameState) var trainingPlan = new m.TrainingPlan(gameState, template, { "role": "attack", "plan": this.name, "special": specialData, "base": 0 }, max, max); if (trainingPlan.template) queue.addItem(trainingPlan); - else if (this.Config.debug > 0) + else if (this.Config.debug > 1) API3.warn("training plan canceled because no template for " + template + " build1 " + uneval(this.buildOrder[0][1]) + " build3 " + uneval(this.buildOrder[0][3]["interests"])); } @@ -930,7 +930,7 @@ m.AttackPlan.prototype.setRallyPoint = function(gameState) // If we're here, it's because we have enough units. m.AttackPlan.prototype.StartAttack = function(gameState) { - if (this.Config.debug) + if (this.Config.debug > 1) API3.warn("start attack " + this.name + " with type " + this.type); if (!this.target || !gameState.getEntityById(this.target.id())) // our target was destroyed during our preparation @@ -985,7 +985,7 @@ m.AttackPlan.prototype.StartAttack = function(gameState) { if (!this.path[0][0][0] || !this.path[0][0][1]) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("StartAttack: Problem with path " + uneval(this.path)); return false; } @@ -1034,9 +1034,9 @@ m.AttackPlan.prototype.update = function(gameState, events) { var done = true; this.unitCollection.forEach(function (entity) { - if (self.Config.debug > 0 && entity.getMetadata(PlayerID, "transport") !== undefined) + if (self.Config.debug > 1 && entity.getMetadata(PlayerID, "transport") !== undefined) Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [entity.id()], "rgb": [2,2,0]}); - else if (self.Config.debug > 0) + else if (self.Config.debug > 1) Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [entity.id()], "rgb": [1,1,1]}); if (!done) return; @@ -1078,6 +1078,7 @@ m.AttackPlan.prototype.update = function(gameState, events) // In case yes, we'll determine if we're simply off against an enemy army, a lone unit/building // or if we reached the enemy base. Different plans may react differently. var attackedNB = 0; + var attackedUnitNB = 0; var attackedEvents = events["Attacked"]; for (var evt of attackedEvents) { @@ -1086,14 +1087,26 @@ m.AttackPlan.prototype.update = function(gameState, events) var attacker = gameState.getEntityById(evt.attacker); var ourUnit = gameState.getEntityById(evt.target); - if (attacker && attacker.position() && attacker.hasClass("Unit") && attacker.owner() != 0) + if (attacker && (attacker.owner() != 0 || this.targetPlayer === 0)) + { attackedNB++; - // if we're being attacked by a building, flee. - if (attacker && ourUnit && attacker.hasClass("Structure")) - ourUnit.flee(attacker); + if (attacker.hasClass("Unit")) + attackedUnitNB++; + } } // Are we arrived at destination ? - if ((gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer && attackedNB > 1) || attackedNB > 3) + var maybe = true; + if (attackedUnitNB == 0) + { + var siegeNB = 0; + this.unitCollection.forEach( function (ent) { + if (self.isSiegeUnit(gameState, ent)) + siegeNB++; + }); + if (siegeNB == 0) + maybe = false; + } + if (maybe && ((gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer && attackedNB > 1) || attackedNB > 3)) this.state = "arrived"; } @@ -1131,13 +1144,13 @@ m.AttackPlan.prototype.update = function(gameState, events) // there are walls but we can attack if (nexttoWalls && this.unitCollection.filter(API3.Filters.byCanAttack("StoneWall")).length !== 0) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Attack Plan " + this.type + " " + this.name + " has met walls and is not happy."); this.state = "arrived"; } else if (nexttoWalls) // abort plan { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Attack Plan " + this.type + " " + this.name + " has met walls and gives up."); Engine.ProfileStop(); return 0; @@ -1153,7 +1166,7 @@ m.AttackPlan.prototype.update = function(gameState, events) { if (API3.SquareVectorDistance(this.position, this.targetPos) < 10000) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Attack Plan " + this.type + " " + this.name + " has arrived to destination."); this.state = "arrived"; } @@ -1164,7 +1177,7 @@ m.AttackPlan.prototype.update = function(gameState, events) this.unitCollection.move(this.path[0][0][0], this.path[0][0][1]); else { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Attack Plan " + this.type + " " + this.name + " has arrived to destination."); this.state = "arrived"; } @@ -1237,6 +1250,24 @@ m.AttackPlan.prototype.update = function(gameState, events) var enemyUnits = gameState.getEnemyUnits(this.targetPlayer); var enemyStructures = gameState.getEnemyStructures(this.targetPlayer); + var targetClassesUnit; + var targetClassesSiege; + if (this.type === "Rush") + targetClassesUnit = {"attack": ["Unit", "Structure"], "avoid": ["StoneWall", "Tower", "Fortress"]}; + else + { + if (this.target.hasClass("Fortress")) + targetClassesUnit = {"attack": ["Unit", "Structure"], "avoid": ["StoneWall"]}; + else if (this.target.hasClass("StoneWall")) + targetClassesUnit = {"attack": ["Unit", "Structure"], "avoid": ["Fortress"]}; + else + targetClassesUnit = {"attack": ["Unit", "Structure"], "avoid": ["Fortress", "StoneWall"]}; + } + if (this.target.hasClass("Structure")) + targetClassesSiege = {"attack": ["Structure"]}; + else + targetClassesSiege = {"attack": ["Unit", "Structure"]}; + if (this.unitCollUpdateArray === undefined || this.unitCollUpdateArray.length === 0) this.unitCollUpdateArray = this.unitCollection.toIdArray(); @@ -1300,40 +1331,21 @@ m.AttackPlan.prototype.update = function(gameState, events) else if (ent.hasClass("Cavalry")) range += 30; range = range * range; - // let's filter targets further based on this unit. var entIndex = gameState.ai.accessibility.getAccessValue(ent.position()); - var mStruct = enemyStructures.filter(function (enemy) { - if (!enemy.position() || (enemy.hasClass("StoneWall") && !ent.canAttackClass("StoneWall"))) - return false; - if (API3.SquareVectorDistance(enemy.position(), ent.position()) > range) - return false; - if (siegeUnit && enemy.foundationProgress() === 0) - return false; - if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex) - return false; - return true; - }); - var nearby = (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged")); - var mUnit = enemyUnits.filter(function (enemy) { - if (!enemy.position()) - return false; - if (enemy.hasClass("Animal")) - return false; - if (nearby && enemy.hasClass("Female") && enemy.unitAIState().split(".")[1] == "FLEEING") - return false; - var dist = API3.SquareVectorDistance(enemy.position(), ent.position()); - if (dist > range) - return false; - if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex) - return false; - enemy.setMetadata(PlayerID, "distance", Math.sqrt(dist)); - return true; - }); // Checking for gates if we're a siege unit. - mUnit = mUnit.toEntityArray(); - mStruct = mStruct.toEntityArray(); if (siegeUnit) { + var mStruct = enemyStructures.filter(function (enemy) { + if (!enemy.position() || (enemy.hasClass("StoneWall") && !ent.canAttackClass("StoneWall"))) + return false; + if (API3.SquareVectorDistance(enemy.position(), ent.position()) > range) + return false; + if (enemy.foundationProgress() === 0) + return false; + if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex) + return false; + return true; + }).toEntityArray(); if (mStruct.length !== 0) { mStruct.sort(function (structa,structb) @@ -1363,10 +1375,26 @@ m.AttackPlan.prototype.update = function(gameState, events) } } else - ent.attackMove(self.targetPos[0], self.targetPos[1], {"attack": ["Unit", "Structure"]}); + ent.attackMove(self.targetPos[0], self.targetPos[1], targetClassesSiege); } else { + var nearby = (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged")); + var mUnit = enemyUnits.filter(function (enemy) { + if (!enemy.position()) + return false; + if (enemy.hasClass("Animal")) + return false; + if (nearby && enemy.hasClass("Female") && enemy.unitAIState().split(".")[1] == "FLEEING") + return false; + var dist = API3.SquareVectorDistance(enemy.position(), ent.position()); + if (dist > range) + return false; + if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex) + return false; + enemy.setMetadata(PlayerID, "distance", Math.sqrt(dist)); + return true; + }).toEntityArray(); if (mUnit.length !== 0) { mUnit.sort(function (unitA,unitB) { @@ -1389,28 +1417,63 @@ m.AttackPlan.prototype.update = function(gameState, events) ent.attack(mUnit[rand].id()); } else if (API3.SquareVectorDistance(self.targetPos, ent.position()) > 2500 ) - ent.attackMove(self.targetPos[0], self.targetPos[1], {"attack": ["Unit", "Structure"]}); - else if (mStruct.length !== 0) { - mStruct.sort(function (structa,structb) { - var vala = structa.costSum(); - if (structa.hasClass("Gates") && ent.canAttackClass("StoneWall")) - vala += 10000; - else if (structa.hasClass("ConquestCritical")) - vala += 100; - var valb = structb.costSum(); - if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall")) - valb += 10000; - else if (structb.hasClass("ConquestCritical")) - valb += 100; - return (valb - vala); - }); - if (mStruct[0].hasClass("Gates")) - ent.attack(mStruct[0].id()); - else + ent.attackMove(self.targetPos[0], self.targetPos[1], targetClassesUnit); + ent.attackMove(self.targetPos[0], self.targetPos[1], {"attack": ["Unit", "Structure"]}, true); // in case we are blocked by walls + } + else + { + var mStruct = enemyStructures.filter(function (enemy) { + if (!enemy.position() || (enemy.hasClass("StoneWall") && !ent.canAttackClass("StoneWall"))) + return false; + if (API3.SquareVectorDistance(enemy.position(), ent.position()) > range) + return false; + if (gameState.ai.accessibility.getAccessValue(enemy.position()) !== entIndex) + return false; + return true; + }).toEntityArray(); + if (mStruct.length !== 0) { - var rand = Math.floor(Math.random() * mStruct.length * 0.2); - ent.attack(mStruct[rand].id()); + mStruct.sort(function (structa,structb) { + var vala = structa.costSum(); + if (structa.hasClass("Gates") && ent.canAttackClass("StoneWall")) + vala += 10000; + else if (structa.hasClass("ConquestCritical")) + vala += 100; + var valb = structb.costSum(); + if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall")) + valb += 10000; + else if (structb.hasClass("ConquestCritical")) + valb += 100; + return (valb - vala); + }); + if (mStruct[0].hasClass("Gates")) + ent.attack(mStruct[0].id()); + else + { + var rand = Math.floor(Math.random() * mStruct.length * 0.2); + ent.attack(mStruct[rand].id()); + } + } + else if (needsUpdate) // really nothing let's try to help our nearest unit + { + var distmin = Math.min(); + var attackerId = undefined; + this.unitCollection.forEach( function (unit) { + if (!unit.position()) + return; + if (unit.unitAIState().split(".")[1] !== "COMBAT" || unit.unitAIOrderData().length === 0 + || !unit.unitAIOrderData()[0]["target"]) + return; + var dist = API3.SquareVectorDistance(unit.position(), ent.position()); + if (dist > distmin) + return; + distmin = dist; + attackerId = unit.unitAIOrderData()[0]["target"]; + + }); + if (attackerId) + ent.attack(attackerId); } } } @@ -1421,7 +1484,7 @@ m.AttackPlan.prototype.update = function(gameState, events) // updating targets. if (!this.target || !gameState.getEntityById(this.target.id())) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("Seems like our target has been destroyed. Switching."); this.target = this.getNearestTarget(gameState, this.position, true); if (!this.target) @@ -1447,12 +1510,12 @@ m.AttackPlan.prototype.update = function(gameState, events) if (!this.target) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("No new target found. Remaining units " + this.unitCollection.length); Engine.ProfileStop(); return false; } - else if (this.Config.debug > 0) + else if (this.Config.debug > 1) API3.warn("We will help one of our other attacks"); } this.targetPos = this.target.position(); diff --git a/binaries/data/mods/public/simulation/ai/petra/baseManager.js b/binaries/data/mods/public/simulation/ai/petra/baseManager.js index b44f48768d..b57da14377 100644 --- a/binaries/data/mods/public/simulation/ai/petra/baseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/baseManager.js @@ -134,7 +134,7 @@ m.BaseManager.prototype.checkEvents = function (gameState, events, queues) } if (!basemin) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(" base " + this.ID + " destroyed and no other bases found"); continue; } @@ -183,7 +183,7 @@ m.BaseManager.prototype.assignResourceToDropsite = function (gameState, dropsite { if (this.dropsites[dropsite.id()]) { - if (this.Config.debug) + if (this.Config.debug > 1) warn("assignResourceToDropsite: dropsite already in the list. Should never happen"); return; } @@ -387,7 +387,7 @@ m.BaseManager.prototype.findBestDropsiteLocation = function(gameState, resource) bestIdx = j; } - if (this.Config.debug == 2) + if (this.Config.debug > 2) warn(" for dropsite best is " + bestVal); if (bestVal <= 0) @@ -670,11 +670,13 @@ m.BaseManager.prototype.gatherersByType = function(gameState, type) m.BaseManager.prototype.pickBuilders = function(gameState, workers, number) { var availableWorkers = this.workers.filter(function (ent) { + if (!ent.position()) + return false; if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3) return false; - if (ent.getMetadata(PlayerID, "transport") !== undefined) + if (ent.getMetadata(PlayerID, "transport")) return false; - if (ent.hasClass("Cavalry") || ent.hasClass("Ship") || ent.position() === undefined) + if (ent.hasClass("Cavalry") || ent.hasClass("Ship")) return false; return true; }).toEntityArray(); @@ -800,7 +802,17 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) }); if (assigned + addedToThis < targetNB) { - var nonBuilderWorkers = workers.filter(function(ent) { return (ent.getMetadata(PlayerID, "subrole") !== "builder" && ent.position() !== undefined); }).toEntityArray(); + var nonBuilderWorkers = workers.filter(function(ent) { + if (ent.getMetadata(PlayerID, "subrole") === "builder") + return false; + if (!ent.position()) + return false; + if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3) + return false; + if (ent.getMetadata(PlayerID, "transport")) + return false; + return true; + }).toEntityArray(); var time = target.buildTime(); nonBuilderWorkers.sort(function (workerA,workerB) { @@ -848,8 +860,18 @@ m.BaseManager.prototype.assignToFoundations = function(gameState, noRepair) if (assigned < targetNB/3) { if (builderWorkers.length + addedWorkers < targetNB*2) - { - var nonBuilderWorkers = workers.filter(function(ent) { return (ent.getMetadata(PlayerID, "subrole") !== "builder" && ent.position() !== undefined && ent.getMetadata(PlayerID, "transport") === undefined); }); + { + var nonBuilderWorkers = workers.filter(function(ent) { + if (ent.getMetadata(PlayerID, "subrole") === "builder") + return false; + if (!ent.position()) + return false; + if (ent.getMetadata(PlayerID, "plan") === -2 || ent.getMetadata(PlayerID, "plan") === -3) + return false; + if (ent.getMetadata(PlayerID, "transport")) + return false; + return true; + }); var nearestNonBuilders = nonBuilderWorkers.filterNearest(target.position(), targetNB/3 - assigned); nearestNonBuilders.forEach(function(ent) { diff --git a/binaries/data/mods/public/simulation/ai/petra/config.js b/binaries/data/mods/public/simulation/ai/petra/config.js index a4fceaf25f..67dbbae77a 100644 --- a/binaries/data/mods/public/simulation/ai/petra/config.js +++ b/binaries/data/mods/public/simulation/ai/petra/config.js @@ -4,6 +4,7 @@ var PETRA = function(m) // this defines the medium difficulty m.Config = function() { this.difficulty = 2; // 0 is sandbox, 1 is easy, 2 is medium, 3 is hard, 4 is very hard. + // debug level: 0=none, 1=sanity checks, 2=debug; 3=detailed debug this.debug = 0; this.Military = { diff --git a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js index 976bb4525c..2af2c01c07 100644 --- a/binaries/data/mods/public/simulation/ai/petra/defenseManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/defenseManager.js @@ -96,15 +96,6 @@ m.DefenseManager.prototype.isDangerous = function(gameState, entity) return true; } - var myCCFoundations = gameState.getOwnFoundations().filter(API3.Filters.byClass("CivCentre")); - for (var i in myCCFoundations._entities) - { - if (!myCCFoundations._entities[i].getBuildersNb()) - continue; - if (API3.SquareVectorDistance(myCCFoundations._entities[i].position(), entity.position()) < 6000) - return true; - } - if (this.Config.personality.cooperative > 0.3) { var allyCC = gameState.getExclusiveAllyEntities().filter(API3.Filters.byClass("CivCentre")); @@ -119,8 +110,12 @@ m.DefenseManager.prototype.isDangerous = function(gameState, entity) var myBuildings = gameState.getOwnStructures(); for (var i in myBuildings._entities) + { + if (myBuildings._entities[i].foundationProgress() === 0) + continue; if (API3.SquareVectorDistance(myBuildings._entities[i].position(), entity.position()) < 6000) return true; + } return false; }; @@ -134,11 +129,9 @@ m.DefenseManager.prototype.checkEnemyUnits = function(gameState) return; var self = this; - var filter = API3.Filters.and(API3.Filters.byClass("Unit"), API3.Filters.byOwner(i)); - var enemyUnits = gameState.updatingGlobalCollection("player-" +i + "-units", filter); // loop through enemy units - enemyUnits.forEach( function (ent) { + gameState.getEnemyUnits(i).forEach( function (ent) { // first check: is this unit already part of an army. if (ent.getMetadata(PlayerID, "PartOfArmy") !== undefined) return; @@ -225,7 +218,7 @@ m.DefenseManager.prototype.checkEnemyArmies = function(gameState, events) { if (API3.SquareVectorDistance(bases[i].position(), army.foePosition) < 40000) { - if(this.Config.debug > 0) + if(this.Config.debug > 1) API3.warn("army in neutral territory, but still near one of our CC"); stillDangerous = true; break; @@ -329,7 +322,7 @@ m.DefenseManager.prototype.assignDefenders = function(gameState) }; // If our defense structures are attacked, garrison soldiers inside when possible -// and if a support unit is attacked and has less than 30% health, garrison it inside the nearest cc +// and if a support unit is attacked and has less than 45% health, garrison it inside the nearest cc m.DefenseManager.prototype.checkEvents = function(gameState, events) { var self = this; @@ -342,7 +335,8 @@ m.DefenseManager.prototype.checkEvents = function(gameState, events) if (target.hasClass("Ship")) // TODO integrate ships later need to be sure it is accessible continue; - if (target.hasClass("Support") && target.healthLevel() < 0.4 && !target.getMetadata(PlayerID, "transport")) + if (target.hasClass("Support") && target.healthLevel() < 0.45 && !target.getMetadata(PlayerID, "transport") + && target.getMetadata(PlayerID, "plan") !== -2 && target.getMetadata(PlayerID, "plan") !== -3) { this.garrisonUnitForHealing(gameState, target); continue; diff --git a/binaries/data/mods/public/simulation/ai/petra/entity-extend.js b/binaries/data/mods/public/simulation/ai/petra/entity-extend.js index 428c43f535..de315501ad 100644 --- a/binaries/data/mods/public/simulation/ai/petra/entity-extend.js +++ b/binaries/data/mods/public/simulation/ai/petra/entity-extend.js @@ -65,5 +65,29 @@ m.getMaxStrength = function(ent, againstClass) return strength * hp; }; +m.getHolder = function(ent, gameState) +{ + var found = undefined; + gameState.getEntities().forEach(function (holder) { + if (found || !holder.isGarrisonHolder()) + return; + if (holder._entity.garrisoned.indexOf(ent.id()) !== -1) + found = holder; + }); + return found; +}; + +m.dumpEntity = function(ent) +{ + if (!ent) + return; + API3.warn(" >>> pos " + ent.position() + " state " + ent.unitAIState()); + API3.warn(" >>> role " + ent.getMetadata(PlayerID, "role") + " subrole " + ent.getMetadata(PlayerID, "subrole") + + " garrisoning " + ent.getMetadata(PlayerID, "garrisoning") + " garrisonHolder " + ent.getMetadata(PlayerID, "garrisonHolder") + + " plan " + ent.getMetadata(PlayerID, "plan") + " transport " + ent.getMetadata(PlayerID, "transport") + + " gather-type " + ent.getMetadata(PlayerID, "gather-type") + " target-foundation " + ent.getMetadata(PlayerID, "target-foundation") + + " PartOfArmy " + ent.getMetadata(PlayerID, "PartOfArmy")); +}; + return m; }(PETRA); diff --git a/binaries/data/mods/public/simulation/ai/petra/garrisonManager.js b/binaries/data/mods/public/simulation/ai/petra/garrisonManager.js index 81bff0976a..a45e24a0b1 100644 --- a/binaries/data/mods/public/simulation/ai/petra/garrisonManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/garrisonManager.js @@ -49,6 +49,38 @@ m.GarrisonManager.prototype.update = function(gameState, queues) this.leaveGarrison(ent); list.splice(j--, 1); } + else + { + var ok = false; + var orders = ent.unitAIOrderData(); + for (var order of orders) + { + if (!order.target || order.target != id) + continue; + ok = true; + break; + } + if (ok) + continue; + if (ent.getMetadata(PlayerID, "garrisonHolder") == +id) + { + // The garrison order must have failed + this.leaveGarrison(ent); + list.splice(j--, 1); + } + else + { + if (gameState.ai.HQ.Config.debug > 0) + { + API3.warn("Petra garrison error: unit " + ent.id() + " (" + ent.genericName() + + ") is expected to garrison in " + id + " (" + holder.genericName() + + "), but has no such garrison order " + uneval(orders)); + m.dumpEntity(ent); + } + list.splice(j--, 1); + } + } + } if (!holder.position()) // could happen with siege unit inside a ship @@ -113,7 +145,7 @@ m.GarrisonManager.prototype.garrison = function(gameState, ent, holder, type) this.registerHolder(gameState, holder); this.holders[holder.id()].push(ent.id()); - if (gameState.ai.HQ.Config.debug > 1) + if (gameState.ai.HQ.Config.debug > 2) { warn("garrison unit " + ent.genericName() + " in " + holder.genericName() + " with type " + type); warn(" we try to garrison a unit with plan " + ent.getMetadata(PlayerID, "plan") + " and role " + ent.getMetadata(PlayerID, "role") diff --git a/binaries/data/mods/public/simulation/ai/petra/headquarters.js b/binaries/data/mods/public/simulation/ai/petra/headquarters.js index 8d2e6466ef..637258b415 100644 --- a/binaries/data/mods/public/simulation/ai/petra/headquarters.js +++ b/binaries/data/mods/public/simulation/ai/petra/headquarters.js @@ -93,7 +93,7 @@ m.HQ.prototype.init = function(gameState, queues) this.navalRegions.push(i); } } - if (this.Config.debug > 1) + if (this.Config.debug > 2) { for (var region in this.allowedRegions) API3.warn(" >>> zone " + region + " taille " + gameState.ai.accessibility.regionSize[region]); @@ -203,7 +203,7 @@ m.HQ.prototype.init = function(gameState, queues) break; } } - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("starting size " + startingSize + "(cut at 1500 for fish pushing)"); if (startingSize < 1500) { @@ -227,7 +227,7 @@ m.HQ.prototype.init = function(gameState, queues) } } } - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("startingWood: " + startingWood + "(cut at 8500 for no rush and 6000 for saveResources)"); if (startingWood < 6000) { @@ -242,7 +242,7 @@ m.HQ.prototype.init = function(gameState, queues) var template = gameState.getTemplate(this.bBase[0]); if (!template.available(gameState)) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(" this AI is unable to produce any units"); this.canBuildUnits = false; var allycc = gameState.getExclusiveAllyEntities().filter(API3.Filters.byClass("CivCentre")).toEntityArray(); @@ -250,7 +250,7 @@ m.HQ.prototype.init = function(gameState, queues) { // if we have some allies, keep a fraction of our units to defend them // and devote the rest to atacks - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(" We have allied cc " + allycc.length + " and " + gameState.getOwnUnits().length + " units "); var units = gameState.getOwnUnits(); var num = Math.max(Math.min(Math.round(0.08*(1+this.Config.personality.cooperative)*units.length), 20), 5); @@ -340,7 +340,7 @@ m.HQ.prototype.getSeaIndex = function (gameState, index1, index2) return path[1]; else { - if (this.Config.debug > 0) + if (this.Config.debug > 1) { API3.warn("bad path from " + index1 + " to " + index2 + " ??? " + uneval(path)); API3.warn(" regionLinks start " + uneval(gameState.ai.accessibility.regionLinks[index1])); @@ -855,7 +855,7 @@ m.HQ.prototype.findEconomicCCLocation = function(gameState, template, resource, var cut = 60; if (fromStrategic) // be less restrictive cut = 30; - if (this.Config.debug) + if (this.Config.debug > 1) API3.warn("we have found a base for " + resource + " with best (cut=" + cut + ") = " + bestVal); // not good enough. if (bestVal < cut) @@ -987,7 +987,7 @@ m.HQ.prototype.findStrategicCCLocation = function(gameState, template) bestIdx = j; } - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("We've found a strategic base with bestVal = " + bestVal); Engine.ProfileStop(); @@ -1072,14 +1072,14 @@ m.HQ.prototype.findMarketLocation = function(gameState, template) bestIdx = j; } - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("We found a market position with bestVal = " + bestVal); if (bestVal === undefined) // no constraints. For the time being, place it arbitrarily by the ConstructionPlan return [-1, -1, -1]; var expectedGain = Math.round(bestVal / this.Config.distUnitGain); - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("this would give a trading gain of " + expectedGain); // do not keep it if gain is too small, except if this is our first BarterMarket if (expectedGain < 6 && (!template.hasClass("BarterMarket") || gameState.getOwnStructures().filter(API3.Filters.byClass("BarterMarket")).length > 0)) @@ -1287,7 +1287,7 @@ m.HQ.prototype.buildMoreHouses = function(gameState,queues) var index = this.stopBuilding.indexOf(gameState.applyCiv("structures/{civ}_house")); if (count < 5 && index !== -1) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("no room to place a house ... try to be less restrictive"); this.stopBuilding.splice(index, 1); this.requireHouses = true; @@ -1320,7 +1320,7 @@ m.HQ.prototype.buildMoreHouses = function(gameState,queues) var index = this.stopBuilding.indexOf(gameState.applyCiv("structures/{civ}_house")); if (index !== -1) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("no room to place a house ... try to improve with technology"); this.researchManager.researchPopulationBonus(gameState, queues); } @@ -1341,7 +1341,7 @@ m.HQ.prototype.checkBaseExpansion = function(gameState, queues) // first expand if we have not enough room available for buildings if (this.stopBuilding.length > 1) { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("try to build a new base because not enough room to build " + uneval(this.stopBuilding)); this.buildNewBase(gameState, queues); return; @@ -1353,7 +1353,7 @@ m.HQ.prototype.checkBaseExpansion = function(gameState, queues) popForBase = this.Config.Economy.popForTown + 5; if (Math.floor(numUnits/popForBase) >= gameState.getOwnStructures().filter(API3.Filters.byClass("CivCentre")).length) { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("try to build a new base because of population " + numUnits + " for " + numCCs + " CCs"); this.buildNewBase(gameState, queues); } @@ -1369,7 +1369,7 @@ m.HQ.prototype.buildNewBase = function(gameState, queues, type) return false; // base "-1" means new base. - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("new base planned with type " + type); queues.civilCentre.addItem(new m.ConstructionPlan(gameState, this.bBase[0], { "base": -1, "type": type })); return true; @@ -1842,7 +1842,7 @@ m.HQ.prototype.update = function(gameState, queues, events) this.territoryMap = m.createTerritoryMap(gameState); - if (this.Config.debug > 0) + if (this.Config.debug > 1) { gameState.getOwnUnits().forEach (function (ent) { if (!ent.hasClass("CitizenSoldier") || ent.hasClass("Cavalry")) @@ -1859,15 +1859,7 @@ m.HQ.prototype.update = function(gameState, queues, events) if (gameState.ai.playedTurn - ent.getMetadata(PlayerID, "idleTim") < 50) return; API3.warn(" unit idle since " + (gameState.ai.playedTurn-ent.getMetadata(PlayerID, "idleTim")) + " turns"); - API3.warn(" unitai state " + ent.unitAIState()); - API3.warn(" >>> base " + ent.getMetadata(PlayerID, "base")); - API3.warn(" >>> role " + ent.getMetadata(PlayerID, "role")); - API3.warn(" >>> subrole " + ent.getMetadata(PlayerID, "subrole")); - API3.warn(" >>> gather-type " + ent.getMetadata(PlayerID, "gather-type")); - API3.warn(" >>> target-foundation " + ent.getMetadata(PlayerID, "target-foundation")); - API3.warn(" >>> PartOfArmy " + ent.getMetadata(PlayerID, "PartOfArmy")); - API3.warn(" >>> plan " + ent.getMetadata(PlayerID, "plan")); - API3.warn(" >>> transport " + ent.getMetadata(PlayerID, "transport")); + m.dumpEntity(ent); ent.setMetadata(PlayerID, "idleTim", gameState.ai.playedTurn); }); } @@ -1944,18 +1936,6 @@ m.HQ.prototype.update = function(gameState, queues, events) Engine.ProfileStop(); }; -m.HQ.prototype.getHolder = function(gameState, ent) -{ - var found = undefined; - gameState.getEntities().forEach(function (holder) { - if (found || !holder.isGarrisonHolder()) - return; - if (holder._entity.garrisoned.indexOf(ent.id()) !== -1) - found = holder; - }); - return found; -}; - return m; }(PETRA); diff --git a/binaries/data/mods/public/simulation/ai/petra/navalManager.js b/binaries/data/mods/public/simulation/ai/petra/navalManager.js index 7f6e618fd2..dceca47dc0 100644 --- a/binaries/data/mods/public/simulation/ai/petra/navalManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/navalManager.js @@ -280,7 +280,7 @@ m.NavalManager.prototype.checkEvents = function(gameState, queues, events) continue; var shipId = evt.entityObj.id(); - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("one ship " + shipId + " from plan " + plan.ID + " destroyed during " + plan.state); if (plan.state === "boarding") { @@ -356,7 +356,7 @@ m.NavalManager.prototype.requireTransport = function(gameState, entity, startInd var plan = new m.TransportPlan(gameState, [entity], startIndex, endIndex, endPos); if (plan.failed) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(">>>> transport plan aborted <<<<"); return false; } @@ -367,12 +367,12 @@ m.NavalManager.prototype.requireTransport = function(gameState, entity, startInd // split a transport plan in two, moving all entities not yet affected to a ship in the new plan m.NavalManager.prototype.splitTransport = function(gameState, plan) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(">>>> split of transport plan started <<<<"); var newplan = new m.TransportPlan(gameState, [], plan.startIndex, plan.endIndex, plan.endPos); if (newplan.failed) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(">>>> split of transport plan aborted <<<<"); return false; } @@ -384,7 +384,7 @@ m.NavalManager.prototype.splitTransport = function(gameState, plan) ++nbUnits; newplan.addUnit(ent, ent.getMetadata(PlayerID, "endPos")); }); - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(">>>> previous plan left with units " + plan.units.length); if (nbUnits) this.transportPlans.push(newplan); @@ -625,7 +625,7 @@ m.NavalManager.prototype.update = function(gameState, queues, events) var remaining = this.transportPlans[i].update(gameState); if (remaining === 0) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("no more units on transport plan " + this.transportPlans[i].ID); this.transportPlans[i].releaseAll(); this.transportPlans.splice(i--, 1); diff --git a/binaries/data/mods/public/simulation/ai/petra/queueManager.js b/binaries/data/mods/public/simulation/ai/petra/queueManager.js index a14d99e0e8..c2770d202a 100644 --- a/binaries/data/mods/public/simulation/ai/petra/queueManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/queueManager.js @@ -377,7 +377,7 @@ m.QueueManager.prototype.switchResource = function(gameState, res) this.accounts[j][res] += diff; this.accounts[i][res] -= diff; ++otherQueue.switched; - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn ("switching queue " + res + " from " + i + " to " + j + " in amount " + diff); break; } @@ -429,7 +429,7 @@ m.QueueManager.prototype.update = function(gameState) // Start the next item in the queue if we can afford it. this.startNextItems(gameState); - if (this.Config.debug > 0 && gameState.ai.playedTurn%50 === 0) + if (this.Config.debug > 1 && gameState.ai.playedTurn%50 === 0) this.printQueues(gameState); Engine.ProfileStop(); @@ -511,7 +511,7 @@ m.QueueManager.prototype.getPriority = function(queueName) m.QueueManager.prototype.changePriority = function(queueName, newPriority) { - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn(">>> Priority of queue " + queueName + " changed from " + this.priorities[queueName] + " to " + newPriority); var self = this; if (this.queues[queueName] !== undefined) diff --git a/binaries/data/mods/public/simulation/ai/petra/queueplan-training.js b/binaries/data/mods/public/simulation/ai/petra/queueplan-training.js index 821a598796..2b83a0c71f 100644 --- a/binaries/data/mods/public/simulation/ai/petra/queueplan-training.js +++ b/binaries/data/mods/public/simulation/ai/petra/queueplan-training.js @@ -95,7 +95,7 @@ m.TrainingPlan.prototype.start = function(gameState) this.metadata.base = trainers[0].getMetadata(PlayerID, "base"); trainers[0].train(this.type, this.number, this.metadata, this.promotedTypes(gameState)); } - else if (gameState.ai.Config.debug > 0) + else if (gameState.ai.Config.debug > 1) warn(" no trainers for this queue " + this.type); this.onStart(gameState); }; diff --git a/binaries/data/mods/public/simulation/ai/petra/tradeManager.js b/binaries/data/mods/public/simulation/ai/petra/tradeManager.js index 62cac7838a..30132c344f 100644 --- a/binaries/data/mods/public/simulation/ai/petra/tradeManager.js +++ b/binaries/data/mods/public/simulation/ai/petra/tradeManager.js @@ -109,7 +109,7 @@ m.TradeManager.prototype.buildTradeRoute = function(gameState, queues) } if (distmax > 0) { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn(" a second market will be built in base " + base); // TODO build also docks when better queues.economicBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_market", { "base": base })); @@ -152,11 +152,11 @@ m.TradeManager.prototype.buildTradeRoute = function(gameState, queues) } if (distmax < 0) { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("no trade route possible"); return false; } - if (this.Config.debug > 0) + if (this.Config.debug > 1) API3.warn("one trade route set with gain " + Math.round(distmax / this.Config.distUnitGain)); return true; }; @@ -201,7 +201,7 @@ m.TradeManager.prototype.setTradingGoods = function(gameState) else tradingGoods[mostNeeded[0].type] += nextNeed; Engine.PostCommand(PlayerID, {"type": "set-trading-goods", "tradingGoods": tradingGoods}); - if (this.Config.debug == 2) + if (this.Config.debug > 2) API3.warn(" trading goods set to " + uneval(tradingGoods)); }; @@ -268,7 +268,7 @@ m.TradeManager.prototype.performBarter = function(gameState) if (bestToSell !== undefined) { barterers[0].barter(buy, bestToSell, 100); - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("Necessity bartering: sold " + bestToSell +" for " + buy + " >> need sell " + needs[bestToSell] + " need buy " + needs[buy] + " rate buy " + rates[buy] + " available sell " + available[bestToSell] + " available buy " + available[buy] + " barterRate " + bestRate); @@ -301,7 +301,7 @@ m.TradeManager.prototype.performBarter = function(gameState) if (bestToBuy !== undefined) { barterers[0].barter(bestToBuy, "food", 100); - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("Contingency bartering: sold food for " + bestToBuy + " available sell " + available["food"] + " available buy " + available[bestToBuy] + " barterRate " + getBarterRate(prices, bestToBuy, "food")); return true; @@ -321,7 +321,7 @@ m.TradeManager.prototype.update = function(gameState, queues) var target = this.tradeRoute.target; if (!source || !target || !gameState.getEntityById(source.id()) || !gameState.getEntityById(target.id())) { - if (this.Config.debug > 1) + if (this.Config.debug > 2) API3.warn("We have lost our trade route"); this.tradeRoute = undefined; return; diff --git a/binaries/data/mods/public/simulation/ai/petra/transportPlan.js b/binaries/data/mods/public/simulation/ai/petra/transportPlan.js index 834318cfa0..09842cf3f5 100644 --- a/binaries/data/mods/public/simulation/ai/petra/transportPlan.js +++ b/binaries/data/mods/public/simulation/ai/petra/transportPlan.js @@ -38,7 +38,7 @@ m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos) if (!this.sea) { this.failed = true; - if (this.debug > 0) + if (this.debug > 1) API3.warn("transport plan with bad path: startIndex " + startIndex + " endIndex " + endIndex); return false; } @@ -53,7 +53,7 @@ m.TransportPlan = function(gameState, units, startIndex, endIndex, endPos) this.units.updateEnt(ent); } - if (this.debug > 0) + if (this.debug > 1) API3.warn("Starting a new transport plan with ID " + this.ID + " to index " + endIndex + " with units length " + units.length); @@ -101,7 +101,7 @@ m.TransportPlan.prototype.assignUnitToShip = function(gameState, ent) { ent.setMetadata(PlayerID, "onBoard", ship.id()); done = true; - if (self.debug > 0) + if (self.debug > 1) { if (ent.getMetadata(PlayerID, "role") === "attack") Engine.PostCommand(PlayerID,{"type": "set-shading-color", "entities": [ent.id()], "rgb": [2,0,0]}); @@ -272,7 +272,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState) if (self.nTry[shipId] > 1) // we must have been blocked by something ... try with another boarding point { self.nTry[shipId] = 0; - if (self.debug > 0) + if (self.debug > 1) API3.warn("ship " + shipId + " new attempt for a landing point "); self.boardingPos[shipId] = self.getBoardingPos(gameState, self.startIndex, self.sea, undefined, false); } @@ -293,7 +293,7 @@ m.TransportPlan.prototype.onBoarding = function(gameState) ++self.nTry[ent.id()]; if (self.nTry[ent.id()] > 5) { - if (self.debug > 0) + if (self.debug > 1) API3.warn("unit blocked, but no ways out of the trap ... destroy it"); self.resetUnit(gameState, ent); ent.destroy(); @@ -399,13 +399,13 @@ m.TransportPlan.prototype.onSailing = function(gameState) ship.moveApart(recov.entPos, 15); continue; } - if (gameState.ai.HQ.Config.debug > 0) + if (gameState.ai.HQ.Config.debug > 1) API3.warn(">>> transport " + this.ID + " reloading failed ... <<<"); // destroy the unit if inaccessible otherwise leave it there var index = gameState.ai.accessibility.getAccessValue(ent.position()); if (gameState.ai.HQ.allowedRegions[index]) { - if (gameState.ai.HQ.Config.debug > 0) + if (gameState.ai.HQ.Config.debug > 1) API3.warn(" recovered entity kept " + ent.id()); this.resetUnit(gameState, ent); // TODO we should not destroy it, but now the unit could still be reloaded on the next turn @@ -414,7 +414,7 @@ m.TransportPlan.prototype.onSailing = function(gameState) } else { - if (gameState.ai.HQ.Config.debug > 0) + if (gameState.ai.HQ.Config.debug > 1) API3.warn("recovered entity destroyed " + ent.id()); this.resetUnit(gameState, ent); ent.destroy(); @@ -453,7 +453,7 @@ m.TransportPlan.prototype.onSailing = function(gameState) else if (gameState.ai.accessibility.getAccessValue(ent.position()) !== this.endIndex) { // unit unloaded on a wrong region - try to regarrison it and move a bit the ship - if (gameState.ai.HQ.Config.debug > 0) + if (gameState.ai.HQ.Config.debug > 1) API3.warn(">>> unit unloaded on a wrong region ! try to garrison it again <<<"); var ship = gameState.getEntityById(ent.getMetadata(PlayerID, "onBoard")); if (ship && !this.canceled) @@ -465,7 +465,7 @@ m.TransportPlan.prototype.onSailing = function(gameState) } else { - if (gameState.ai.HQ.Config.debug > 0) + if (gameState.ai.HQ.Config.debug > 1) API3.warn("no way ... we destroy it"); this.resetUnit(gameState, ent); ent.destroy(); @@ -537,7 +537,7 @@ m.TransportPlan.prototype.onSailing = function(gameState) if (self.nTry[shipId] > 2) // we must have been blocked by something ... try with another boarding point { self.nTry[shipId] = 0; - if (self.debug > 0) + if (self.debug > 1) API3.warn(shipId + " new attempt for a landing point "); self.boardingPos[shipId] = self.getBoardingPos(gameState, self.endIndex, self.sea, undefined, true); } diff --git a/binaries/data/mods/public/simulation/ai/petra/worker.js b/binaries/data/mods/public/simulation/ai/petra/worker.js index e6f75d5ee4..550ae89751 100644 --- a/binaries/data/mods/public/simulation/ai/petra/worker.js +++ b/binaries/data/mods/public/simulation/ai/petra/worker.js @@ -13,7 +13,7 @@ m.Worker = function(ent) m.Worker.prototype.update = function(baseManager, gameState) { - if (!this.ent.position()) + if (!this.ent.position() || this.ent.getMetadata(PlayerID, "plan") === -2 || this.ent.getMetadata(PlayerID, "plan") === -3) return; // If we are waiting for a transport or we are sailing, just wait @@ -490,7 +490,7 @@ m.Worker.prototype.startGathering = function(gameState, baseManager) // If we are here, we have nothing left to gather ... certainly no more resources of this type gameState.ai.HQ.lastFailedGather[resource] = gameState.ai.elapsedTime; - if (gameState.ai.HQ.Config.debug > 1) + if (gameState.ai.HQ.Config.debug > 2) warn(" >>>>> worker with gather-type " + resource + " with nothing to gather "); this.ent.setMetadata(PlayerID, "subrole", "idle"); return false;