From f80f1fb86bbf7d40b83f1454bfcf74cfd0ee476b Mon Sep 17 00:00:00 2001 From: Jubal Date: Sat, 19 Nov 2011 13:44:56 +0000 Subject: [PATCH] This patch adds territory support for JuBot, which is the main thing to get it up to date for the next alpha. More advanced features are in development but some will probably have to wait until Christmas/Early 2012. This was SVN commit r10560. --- .../public/simulation/ai/jubot/economy.js | 330 +++++++++++++----- .../public/simulation/ai/jubot/military.js | 63 +++- .../simulation/ai/jubot/plan-building.js | 20 +- .../simulation/ai/jubot/plan-buildingecon.js | 74 +++- 4 files changed, 379 insertions(+), 108 deletions(-) diff --git a/binaries/data/mods/public/simulation/ai/jubot/economy.js b/binaries/data/mods/public/simulation/ai/jubot/economy.js index 93b09e778c..386d560b16 100644 --- a/binaries/data/mods/public/simulation/ai/jubot/economy.js +++ b/binaries/data/mods/public/simulation/ai/jubot/economy.js @@ -21,10 +21,9 @@ var EconomyManager = Class({ }; }, - - checkBuildingList: function (gameState) { + villageBuildingList: function (gameState) { if (gameState.displayCiv() == "hele"){ - this.targetBuildings = [ + this.villageBuildings = [ { "template": "structures/{civ}_scout_tower", "priority": 105, @@ -41,10 +40,123 @@ var EconomyManager = Class({ "count": 1, }, { - "template": "structures/{civ}_scout_tower", - "priority": 90, - "count": 3, + "template": "structures/{civ}_field", + "priority": 70, + "count": 2, }, + ]; + } + // Celt building list + else if (gameState.displayCiv() == "celt"){ + this.villageBuildings = [ + { + "template": "structures/{civ}_scout_tower", + "priority": 105, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 103, + "count": 1, + }, + { + "template": "structures/{civ}_barracks", + "priority": 101, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 70, + "count": 2, + }, + ]; + } + // Carthage building list + else if (gameState.displayCiv() == "cart"){ + this.villageBuildings = [ + { + "template": "structures/{civ}_scout_tower", + "priority": 105, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 103, + "count": 1, + }, + { + "template": "structures/{civ}_barracks", + "priority": 101, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 70, + "count": 2, + }, + ]; + } + // Celt building list + else if (gameState.displayCiv() == "iber"){ + this.villageBuildings = [ + { + "template": "structures/{civ}_scout_tower", + "priority": 105, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 103, + "count": 1, + }, + { + "template": "structures/{civ}_barracks", + "priority": 101, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 70, + "count": 2, + }, + ]; + } + + // Fallback option just in case + else { + this.villageBuildings = [ + { + "template": "structures/{civ}_scout_tower", + "priority": 105, + "count": 1, + }, + { + "template": "structures/{civ}_field", + "priority": 100, + "count": 2, + }, + { + "template": "structures/{civ}_barracks", + "priority": 99, + "count": 1, + }, + { + "template": "structures/{civ}_scout_tower", + "priority": 60, + "count": 4, + }, + { + "template": "structures/{civ}_field", + "priority": 40, + "count": 5, + }, + ]; + } + }, + + checkBuildingList: function (gameState) { + if (gameState.displayCiv() == "hele"){ + this.targetBuildings = [ { "template": "structures/hele_gymnasion", "priority": 80, @@ -60,11 +172,6 @@ var EconomyManager = Class({ "priority": 60, "count": 1, }, - { - "template": "structures/{civ}_scout_tower", - "priority": 50, - "count": 5, - }, { "template": "structures/{civ}_field", "priority": 40, @@ -75,11 +182,6 @@ var EconomyManager = Class({ // Celt building list else if (gameState.displayCiv() == "celt"){ this.targetBuildings = [ - { - "template": "structures/{civ}_field", - "priority": 100, - "count": 1, - }, { "template": "structures/{civ}_barracks", "priority": 90, @@ -90,31 +192,11 @@ var EconomyManager = Class({ "priority": 80, "count": 1, }, - { - "template": "structures/{civ}_scout_tower", - "priority": 60, - "count": 3, - }, - { - "template": "structures/{civ}_field", - "priority": 40, - "count": 3, - }, ]; } // Carthage building list else if (gameState.displayCiv() == "cart"){ this.targetBuildings = [ - { - "template": "structures/{civ}_field", - "priority": 100, - "count": 1, - }, - { - "template": "structures/{civ}_barracks", - "priority": 100, - "count": 1, - }, { "template": "structures/cart_fortress", "priority": 80, @@ -125,11 +207,6 @@ var EconomyManager = Class({ "priority": 75, "count": 1, }, - { - "template": "structures/{civ}_scout_tower", - "priority": 70, - "count": 3, - }, { "template": "structures/cart_embassy_celtic", "priority": 50, @@ -145,52 +222,22 @@ var EconomyManager = Class({ "priority": 50, "count": 1, }, - { - "template": "structures/{civ}_field", - "priority": 40, - "count": 3, - }, ]; } // Celt building list else if (gameState.displayCiv() == "iber"){ this.targetBuildings = [ - { - "template": "structures/{civ}_field", - "priority": 100, - "count": 1, - }, - { - "template": "structures/{civ}_barracks", - "priority": 100, - "count": 1, - }, { "template": "structures/iber_fortress", "priority": 80, "count": 1, }, - { - "template": "structures/{civ}_scout_tower", - "priority": 70, - "count": 3, - }, - { - "template": "structures/{civ}_field", - "priority": 40, - "count": 3, - }, ]; } // Fallback option just in case else { this.targetBuildings = [ - { - "template": "structures/{civ}_scout_tower", - "priority": 105, - "count": 1, - }, { "template": "structures/{civ}_field", "priority": 100, @@ -244,17 +291,47 @@ var EconomyManager = Class({ if (gameState.findFoundations().length > 0) return; + // START BY GETTING ALL CCs UP TO SMALL VILLAGE LEVEL + for each (var building in this.villageBuildings) + { + var numBuildings = gameState.countEntitiesAndQueuedWithType(gameState.applyCiv(building.template)); + + var wantedtotal = building.count * numCCs; + // If we have too few, build another + if (numBuildings < wantedtotal && building.template != gameState.applyCiv("structures/{civ}_field")) + { + planGroups.economyConstruction.addPlan(building.priority, + new BuildingConstructionPlan(gameState, building.template, 1) + ); + return; + } + else if (numBuildings < wantedtotal && building.template == gameState.applyCiv("structures/{civ}_field")) + { + planGroups.economyConstruction.addPlan(building.priority, + new BuildingConstructionPlanResources(gameState, building.template, 1) + ); + return; + } + } + // THEN BUILD THE MAIN BASE INTO A TOWN for each (var building in this.targetBuildings) { var numBuildings = gameState.countEntitiesAndQueuedWithType(gameState.applyCiv(building.template)); // If we have too few, build another - if (numBuildings < building.count) + if (numBuildings < building.count && building.template != gameState.applyCiv("structures/{civ}_field")) { planGroups.economyConstruction.addPlan(building.priority, new BuildingConstructionPlan(gameState, building.template, 1) ); return; } + else if (numBuildings < building.count && building.template == gameState.applyCiv("structures/{civ}_field")) + { + planGroups.economyConstruction.addPlan(building.priority, + new BuildingConstructionPlanResources(gameState, building.template, 1) + ); + return; + } } }, @@ -400,8 +477,8 @@ var EconomyManager = Class({ var targets = gameState.entities.filter(function(enten) { var foeposition = enten.position(); if (foeposition){ - var dist = VectorDistance(foeposition, currentPosition); - return (enten.isEnemy() && enten.owner()!= 0 && dist < 50); + var dist = SquareVectorDistance(foeposition, currentPosition); + return (enten.isEnemy() && enten.owner()!= 0 && dist < 2500); } else { return false; @@ -466,7 +543,7 @@ var EconomyManager = Class({ // Make sure there's actually some of that type if (!resourceSupplies[type]) continue; - + // The types are food wood stone metal // Pick the closest one. // TODO: we should care about distance to dropsites, not (just) to the worker, // and gather rates of workers @@ -481,39 +558,66 @@ var EconomyManager = Class({ if (supply.entity.hasClass("SeaCreature")) return; - var distcheck = 1000000; - var supplydistcheck = 1000000; + var distcheck = 10000000000; + var supplydistcheck = 100000000000; gameState.getOwnEntities().forEach(function(centre) { if (centre.hasClass("CivCentre")) { var centrePosition = centre.position(); - var currentsupplydistcheck = VectorDistance(supply.position, centrePosition); + var currentsupplydistcheck = SquareVectorDistance(supply.position, centrePosition); if (currentsupplydistcheck < currentsupplydistcheck){ supplydistcheck = currentsupplydistcheck; } - var currentdistcheck = VectorDistance(supply.position, centrePosition); + var currentdistcheck = SquareVectorDistance(supply.position, centrePosition); if (currentdistcheck < distcheck){ distcheck = currentdistcheck; } // Skip targets that are far too far away (e.g. in the enemy base) } - else if (centre.hasClass("Economic")) + else if (centre.hasClass("DropsiteFood") && type == "food") { var centrePosition = centre.position(); - var currentsupplydistcheck = VectorDistance(supply.position, centrePosition); + var currentsupplydistcheck = SquareVectorDistance(supply.position, centrePosition); + if (currentsupplydistcheck < currentsupplydistcheck){ + supplydistcheck = currentsupplydistcheck; + } + // Skip targets that are far too far away (e.g. in the enemy base) + } + else if (centre.hasClass("DropsiteWood") && type == "wood") + { + var centrePosition = centre.position(); + var currentsupplydistcheck = SquareVectorDistance(supply.position, centrePosition); + if (currentsupplydistcheck < currentsupplydistcheck){ + supplydistcheck = currentsupplydistcheck; + } + // Skip targets that are far too far away (e.g. in the enemy base) + } + else if (centre.hasClass("DropsiteStone") && type == "stone") + { + var centrePosition = centre.position(); + var currentsupplydistcheck = SquareVectorDistance(supply.position, centrePosition); + if (currentsupplydistcheck < currentsupplydistcheck){ + supplydistcheck = currentsupplydistcheck; + } + // Skip targets that are far too far away (e.g. in the enemy base) + } + else if (centre.hasClass("DropsiteMetal") && type == "metal") + { + var centrePosition = centre.position(); + var currentsupplydistcheck = SquareVectorDistance(supply.position, centrePosition); if (currentsupplydistcheck < currentsupplydistcheck){ supplydistcheck = currentsupplydistcheck; } // Skip targets that are far too far away (e.g. in the enemy base) } }); - if (distcheck > 500) + if (distcheck > 250000) return; - var dist = VectorDistance(supply.position, workerPosition); + var dist = SquareVectorDistance(supply.position, workerPosition); // Skip targets that are far too far away (e.g. in the enemy base) - if (dist > 500) + if (dist > 250000) return; supplies.push({ dist: dist, entity: supply.entity }); @@ -526,36 +630,77 @@ var EconomyManager = Class({ return false; }); - + + if (type == "food"){ + var whatshallwebuild = "structures/{civ}_farmstead" + } + else { + var whatshallwebuild = "structures/{civ}_mill" + } + + // Start gathering if (supplies.length) { // THIS SHOULD BE A GLOBAL VARIABLE var currentposformill = supplies[0].entity.position(); - var distcheckoldII = 10000; + var distcheckoldII = 1000000000; // CHECK DISTANCE gameState.getOwnEntities().forEach(function(centre) { - if (centre.hasClass("CivCentre") || centre.hasClass("Economic")) + if (centre.hasClass("CivCentre")) { var centrePosition = centre.position(); - var distcheckII = VectorDistance(currentposformill, centrePosition); + var distcheckII = SquareVectorDistance(currentposformill, centrePosition); + if (distcheckII < distcheckoldII){ + distcheckoldII = distcheckII; + } + } + else if (centre.hasClass("DropsiteFood") && type == "food") + { + var centrePosition = centre.position(); + var distcheckII = SquareVectorDistance(currentposformill, centrePosition); + if (distcheckII < distcheckoldII){ + distcheckoldII = distcheckII; + } + } + else if (centre.hasClass("DropsiteWood") && type == "wood") + { + var centrePosition = centre.position(); + var distcheckII = SquareVectorDistance(currentposformill, centrePosition); + if (distcheckII < distcheckoldII){ + distcheckoldII = distcheckII; + } + } + else if (centre.hasClass("DropsiteMetal") && type == "metal") + { + var centrePosition = centre.position(); + var distcheckII = SquareVectorDistance(currentposformill, centrePosition); + if (distcheckII < distcheckoldII){ + distcheckoldII = distcheckII; + } + } + else if (centre.hasClass("DropsiteStone") && type == "stone") + { + var centrePosition = centre.position(); + var distcheckII = SquareVectorDistance(currentposformill, centrePosition); if (distcheckII < distcheckoldII){ distcheckoldII = distcheckII; } } }); var foundationsyes = false; - if (gameState.findFoundations().length > 2){ + if (gameState.findFoundations().length > 1){ foundationsyes = false; } else{ foundationsyes = true; } + //warn(type + " is the resource and " + distcheckoldII + " is the distance."); - if (distcheckoldII > 60 && foundationsyes == true){ + if (distcheckoldII > 5000 && foundationsyes == true){ //JuBotAI.prototype.chat("Building Mill"); - planGroups.economyConstruction.addPlan(80, - new BuildingConstructionPlanEcon(gameState, "structures/{civ}_mill", 1, currentposformill) + planGroups.economyConstruction.addPlan(150, + new BuildingConstructionPlanEcon(gameState, whatshallwebuild, 1, currentposformill) ); //JuBotAI.prototype.chat("Gathering"); ent.gather(supplies[0].entity); @@ -647,6 +792,7 @@ var EconomyManager = Class({ //this.buildRegroup(gameState, planGroups) this.checkBuildingList(gameState); + this.villageBuildingList(gameState); this.reassignRolelessUnits(gameState); diff --git a/binaries/data/mods/public/simulation/ai/jubot/military.js b/binaries/data/mods/public/simulation/ai/jubot/military.js index 368a21ed3e..51e2a237a8 100644 --- a/binaries/data/mods/public/simulation/ai/jubot/military.js +++ b/binaries/data/mods/public/simulation/ai/jubot/military.js @@ -203,8 +203,8 @@ var MilitaryAttackManager = Class({ var targets = gameState.entities.filter(function(ent) { var foeposition = ent.position(); if (foeposition){ - var dist = VectorDistance(foeposition, currentPosition); - return (ent.isEnemy() && ent.owner()!= 0 && dist < 50); + var dist = SquareVectorDistance(foeposition, currentPosition); + return (ent.isEnemy() && ent.owner()!= 0 && dist < 2500); } else { return false; @@ -223,6 +223,52 @@ var MilitaryAttackManager = Class({ }); }, + CombatAnalyser: function(gameState, planGroups, startunit) + { + var centrepoint = startunit.position(); + var targets = gameState.entities.filter(function(squeak) { + var currentPosition = squeak.position(); + if (currentPosition){ + var dist = SquareVectorDistance(foeposition, currentPosition); + return (dist < 2500); + } + else { + return false; + } + }); + if (targets.length) + { + var forest = 0; + var foeTot = 0; + var foeCav = 0; + var foeInf = 0; + var foeBow = 0; + var foeRangeCav = 0; + targets.forEach(function(item) { + if (item.hasClass("ForestPlant")){ + forest += 1; + } + if (item.isEnemy() && item.owner != 0 && item.hasClass("Infantry") && item.hasClass("Melee")){ + foeTot += 1; + foeInf += 1; + } + if (item.isEnemy() && item.owner != 0 && item.hasClass("Infantry" && item.hasClass("Ranged"))){ + foeTot += 1; + foeBow += 1; + } + if (item.isEnemy() && item.owner != 0 && item.hasClass("Cavalry") && item.hasClass("Melee")){ + foeTot += 1; + foeCav += 1; + } + if (item.isEnemy() && item.owner != 0 && item.hasClass("Cavalry" && item.hasClass("Ranged"))){ + foeTot += 1; + foeRangeCav += 1; + } + }); + } + + }, + combatcheckMilitia: function(gameState, planGroups, assaultgroup) { var regroupneeded = gameState.getOwnEntitiesWithRole(assaultgroup); @@ -232,8 +278,8 @@ var MilitaryAttackManager = Class({ var targets = gameState.entities.filter(function(ent) { var foeposition = ent.position(); if (foeposition){ - var dist = VectorDistance(foeposition, currentPosition); - return (ent.isEnemy() && ent.owner()!= 0 && dist < 50); + var dist = SquareVectorDistance(foeposition, currentPosition); + return (ent.isEnemy() && ent.owner()!= 0 && dist < 2500); } else { return false; @@ -243,8 +289,8 @@ var MilitaryAttackManager = Class({ var ownbuildings = gameState.getOwnEntities().filter(function(ent) { var foeposition = ent.position(); if (foeposition){ - var dist = VectorDistance(foeposition, currentPosition); - return (dist < 50 && ent.hasClass("Village")); + var dist = SquareVectorDistance(foeposition, currentPosition); + return (dist < 2500 && ent.hasClass("Village")); } else { return false; @@ -252,12 +298,17 @@ var MilitaryAttackManager = Class({ }); if (targets.length >= 5 && ownbuildings.length > 0){ regroupneeded.forEach(function(person) { + var position = targets.toEntityArray()[0].position(); + var ourposition = person.position(); + var distance = SquareVectorDistance(position, ourposition); + if (distance <= 22500){ var targetrandomiser = Math.floor(Math.random()*targets.length); var target = targets.toEntityArray()[targetrandomiser]; var targetPos = target.position(); // TODO: this should be an attack-move command person.move(targetPos[0], targetPos[1]); person.setMetadata("role", "militiafighter"); + } }); } }); diff --git a/binaries/data/mods/public/simulation/ai/jubot/plan-building.js b/binaries/data/mods/public/simulation/ai/jubot/plan-building.js index f6351e7db8..42f6f4aff0 100644 --- a/binaries/data/mods/public/simulation/ai/jubot/plan-building.js +++ b/binaries/data/mods/public/simulation/ai/jubot/plan-building.js @@ -200,10 +200,24 @@ var BuildingConstructionPlan = Class({ gameState.getOwnEntities().forEach(function(ent) { if (ent.hasClass("Structure")) { - var infl = 32; + var infl = 15; if (ent.hasClass("CivCentre")) - infl *= 5; - + { + infl = infl*5; + } + else if (ent.hasClass("Village")) + { + infl = 0; + } + else if (ent.hasClass("Economic")) + { + infl = 20; + } + else + { + infl = 0; + } + var pos = ent.position(); var x = Math.round(pos[0] / cellSize); var z = Math.round(pos[1] / cellSize); diff --git a/binaries/data/mods/public/simulation/ai/jubot/plan-buildingecon.js b/binaries/data/mods/public/simulation/ai/jubot/plan-buildingecon.js index a7c1c016ce..019a5e0045 100644 --- a/binaries/data/mods/public/simulation/ai/jubot/plan-buildingecon.js +++ b/binaries/data/mods/public/simulation/ai/jubot/plan-buildingecon.js @@ -3,6 +3,9 @@ var BuildingConstructionPlanEcon = Class({ _init: function(gameState, type, indno, resourcepos) { this.type = gameState.applyCiv(type); + + this.resourceposition = resourcepos; + this.pos = this.findGoodPosition(gameState); var template = gameState.getTemplate(this.type); if (!template) @@ -10,9 +13,8 @@ var BuildingConstructionPlanEcon = Class({ this.invalidTemplate = true; return; } - + this.cost = new Resources(template.cost()); - this.resourceposition = resourcepos; }, canExecute: function(gameState) @@ -37,7 +39,6 @@ var BuildingConstructionPlanEcon = Class({ // do the building themselves - all we care about is that there is // some unit that can start the foundation - var pos = this.findGoodPosition(gameState); //Check distance from Pos to CC - we don't want to get too far from the centre, for now. // THIS SHOULD BE A GLOBAL VARIABLE //var distcheckold = 10000; @@ -56,7 +57,7 @@ var BuildingConstructionPlanEcon = Class({ //}); //Distcheck is thus the distance to the nearest CC - we only build if it's low enough. ///if (distcheckold < 400){ - builders[0].construct(this.type, pos.x, pos.z, pos.angle); + builders[0].construct(this.type, this.pos.x, this.pos.z, this.pos.angle); //} //else { //var pos = this.findGoodPositionOldStyle(gameState); @@ -188,7 +189,6 @@ var BuildingConstructionPlanEcon = Class({ ); obstructionTiles[i] = (invalidTerritory || (passabilityMap.data[i] & obstructionMask)) ? 0 : 65535; } - // Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64); this.expandInfluences(obstructionTiles, passabilityMap.width, passabilityMap.height); @@ -198,7 +198,7 @@ var BuildingConstructionPlanEcon = Class({ // Compute each tile's closeness to friendly structures: var friendlyTiles = new Uint16Array(passabilityMap.data.length); - var infl = 100; + var infl = 25; var pos = this.resourceposition; var x = Math.round(pos[0] / cellSize); var z = Math.round(pos[1] / cellSize); @@ -228,10 +228,69 @@ var BuildingConstructionPlanEcon = Class({ { bestVal = v; bestIdx = i; - //JuBotAI.prototype.chat("BestVal is " + bestVal + ", and bestIdx is " + bestIdx + "."); } } } + //warn("BestVal is " + bestVal + ", and bestIdx is " + bestIdx + "."); + + if (bestVal <= 5) { + //warn("Trying to build Civ Centre"); + this.type = gameState.applyCiv("structures/{civ}_civil_centre"); + + var playerID = gameState.getPlayerID(); + var buildOwn = template.hasBuildTerritory("own"); + var buildAlly = template.hasBuildTerritory("ally"); + var buildNeutral = template.hasBuildTerritory("neutral"); + var buildEnemy = template.hasBuildTerritory("enemy"); + // Since this is for CCs, only refrain from building on actual enemy territory. + var obstructionTilesII = new Uint16Array(passabilityMap.data.length); + for (var i = 0; i < passabilityMap.data.length; ++i) + { + var tilePlayer = (territoryMap.data[i] & TERRITORY_PLAYER_MASK); + var invalidTerritory = ( + (!buildEnemy && gameState.isPlayerEnemy(tilePlayer) && tilePlayer !=0) + ); + obstructionTilesII[i] = (invalidTerritory || (passabilityMap.data[i] & obstructionMask)) ? 0 : 65535; + } +// Engine.DumpImage("tiles0.png", obstructionTiles, passabilityMap.width, passabilityMap.height, 64); + + this.expandInfluences(obstructionTilesII, passabilityMap.width, passabilityMap.height); + + // TODO: handle distance restrictions for e.g. CivCentres + + // Compute each tile's closeness to friendly structures: + + var friendlyTiles = new Uint16Array(passabilityMap.data.length); + var infl = 50; + var pos = this.resourceposition; + var x = Math.round(pos[0] / cellSize); + var z = Math.round(pos[1] / cellSize); + self.addInfluence(friendlyTiles, passabilityMap.width, passabilityMap.height, x, z, infl); + + + var template = gameState.getTemplate(this.type); + var radius = Math.ceil(template.obstructionRadius() / cellSize) + 1; + var bestIdx = 0; + var bestVal = -1; + for (var i = 0; i < passabilityMap.data.length; ++i) + { + if (obstructionTilesII[i] > radius) + { + var v = friendlyTiles[i]; + //var foe = enemyTiles[i]; + //JuBotAI.prototype.chat(v); + //JuBotAI.prototype.chat(i); + //JuBotAI.prototype.chat(foe); + if (v >= bestVal) + { + bestVal = v; + bestIdx = i; + } + } + } + //warn("For CC, BestVal is " + bestVal + ", and bestIdx is " + bestIdx + "."); + } + var x = ((bestIdx % passabilityMap.width) + 0.5) * cellSize; var z = (Math.floor(bestIdx / passabilityMap.width) + 0.5) * cellSize; @@ -242,6 +301,7 @@ var BuildingConstructionPlanEcon = Class({ var angle = 0.75*Math.PI; return { + "canbuild": true, "x": x, "z": z, "angle": angle