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