1
0
forked from 0ad/0ad

some minor tweaks to petra ai

This was SVN commit r14913.
This commit is contained in:
mimo 2014-04-10 20:25:02 +00:00
parent 7840fd3049
commit bb8e14fae1
7 changed files with 98 additions and 102 deletions

View File

@ -30,15 +30,11 @@ m.Army = function(gameState, owner, ownEntities, foeEntities)
// who we assigned against, for quick removal.
this.assignedTo = {};
// For substrengths, format is "name": [classes]
this.foeEntities = [];
this.foeStrength = 0;
this.foeSubStrength = {};
this.ownEntities = [];
this.ownStrength = 0;
this.ownSubStrength = {};
// actually add units
for (var i in foeEntities)

View File

@ -12,8 +12,8 @@ m.AttackManager = function(Config)
this.attackNumber = 0;
this.rushNumber = 0;
this.raidNumber = 0;
this.upcomingAttacks = { "CityAttack": [], "Rush": [], "Raid": [] };
this.startedAttacks = { "CityAttack": [], "Rush": [], "Raid": [] };
this.upcomingAttacks = { "Rush": [], "Raid": [], "Attack": [], "HugeAttack": [] };
this.startedAttacks = { "Rush": [], "Raid": [], "Attack": [], "HugeAttack": [] };
this.debugTime = 0;
};
@ -153,13 +153,6 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
}
}
}
// Number of running attacks
if (this.Config.debug > 0 && gameState.ai.playedTurn%50 === 0)
{
for (var attackType in this.startedAttacks)
warn(" === current number of " + attackType + " = " + this.startedAttacks[attackType].length);
}
// creating plans after updating because an aborted plan might be reused in that case.
@ -181,28 +174,30 @@ m.AttackManager.prototype.update = function(gameState, queues, events)
}
// if we have a barracks, there's no water, we're at age >= 1 and we've decided to attack.
else if (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_barracks"), true) >= 1
&& (this.startedAttacks["Attack"].length + this.startedAttacks["HugeAttack"].length < Math.round(gameState.getPopulationMax()/100))
&& (gameState.currentPhase() > 1 || gameState.isResearching(gameState.townPhase())))
{
if (gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_dock"), true) === 0 && gameState.ai.HQ.waterMap)
{
// wait till we get a dock.
}
else if (this.upcomingAttacks["CityAttack"].length === 0)
else if (this.upcomingAttacks["Attack"].length === 0 && this.upcomingAttacks["HugeAttack"].length === 0)
{
if (this.attackNumber < 2)
var attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber);
if (this.attackNumber < 2 || this.startedAttacks["HugeAttack"].length > 0)
var type = "Attack";
else
var attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber, "superSized");
var type = "HugeAttack";
var attackPlan = new m.AttackPlan(gameState, this.Config, this.totalNumber, type);
if (attackPlan.failed)
this.attackPlansEncounteredWater = true; // hack
else
{
if (this.Config.debug > 0)
warn("Military Manager: Creating the plan " + this.totalNumber);
warn("Military Manager: Creating the plan " + type + " " + this.totalNumber);
this.attackNumber++;
this.totalNumber++;
this.upcomingAttacks["CityAttack"].push(attackPlan);
this.upcomingAttacks[type].push(attackPlan);
}
}
}

View File

@ -14,7 +14,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, enemy, target)
{
this.Config = Config;
this.name = uniqueID;
this.type = type || "normal";
this.type = type || "Attack";
this.state = "unexecuted";
this.targetPlayer = enemy;
@ -72,7 +72,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, enemy, target)
priority = 150;
this.unitStat["Cavalry"] = { "priority": 1, "minSize": 3, "targetSize": 4, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"], "interests": [ ["strength",1], ["cost",1] ] };
}
else if (type === "superSized")
else if (type === "HugeAttack")
{
priority = 90;
// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units.
@ -105,8 +105,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, enemy, target)
return (strength[0] > 15 || strength[1] > 15);
};*/
var filter = API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan", this.name), API3.Filters.byOwner(PlayerID));
this.unitCollection = gameState.getOwnUnits().filter(filter);
this.unitCollection = gameState.getOwnUnits().filter(API3.Filters.byMetadata(PlayerID, "plan", this.name));
this.unitCollection.registerUpdates();
this.unit = {};
@ -121,7 +120,7 @@ m.AttackPlan = function(gameState, Config, uniqueID, type, enemy, target)
var cat = unitCat;
var Unit = this.unitStat[cat];
filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)));
var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]), API3.Filters.byMetadata(PlayerID, "plan",this.name));
this.unit[cat] = gameState.getOwnUnits().filter(filter);
this.unit[cat].registerUpdates();
this.buildOrder.push([0, Unit["classes"], this.unit[cat], Unit, cat]);
@ -252,7 +251,7 @@ m.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, rese
// no minsize as we don't want the plan to fail at the last minute though.
this.unitStat[name] = unitStats;
var Unit = this.unitStat[name];
var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]),API3.Filters.and(API3.Filters.byMetadata(PlayerID, "plan",this.name),API3.Filters.byOwner(PlayerID)));
var filter = API3.Filters.and(API3.Filters.byClassesAnd(Unit["classes"]), API3.Filters.byMetadata(PlayerID, "plan",this.name));
this.unit[name] = gameState.getOwnUnits().filter(filter);
this.unit[name].registerUpdates();
this.buildOrder.push([0, Unit["classes"], this.unit[name], Unit, name]);
@ -329,7 +328,21 @@ m.AttackPlan.prototype.updatePreparation = function(gameState, events)
this.queueSiege.empty();
}
else // Abort the plan so that its units will be reassigned to other plans.
{
if (this.Config.debug > 0)
{
var am = gameState.ai.HQ.attackManager;
warn(" attacks upcoming: raid " + am.upcomingAttacks["Raid"].length
+ " raid " + am.upcomingAttacks["Rush"].length
+ " attack " + am.upcomingAttacks["Attack"].length
+ " huge " + am.upcomingAttacks["HugeAttack"].length);
warn(" attacks started: raid " + am.startedAttacks["Raid"].length
+ " raid " + am.startedAttacks["Rush"].length
+ " attack " + am.startedAttacks["Attack"].length
+ " huge " + am.startedAttacks["HugeAttack"].length);
}
return 0;
}
}
else if (this.mustStart(gameState) && (gameState.countOwnQueuedEntitiesWithMetadata("plan", +this.name) > 0))
{
@ -531,7 +544,7 @@ m.AttackPlan.prototype.getNearestTarget = function(gameState, position)
{
if (this.type === "Raid")
var targets = this.raidTargetFinder(gameState);
else if (this.type === "Rush" || this.type === "normal")
else if (this.type === "Rush" || this.type === "Attack")
var targets = this.rushTargetFinder(gameState);
else
var targets = this.defaultTargetFinder(gameState);
@ -618,7 +631,7 @@ m.AttackPlan.prototype.rushTargetFinder = function(gameState)
if (target)
targets.addEnt(target);
if (targets.length == 0 && this.type === "normal")
if (targets.length == 0 && this.type === "Attack")
targets = this.defaultTargetFinder(gameState);
return targets;
@ -810,7 +823,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
ourUnit.flee(attacker);
}
// Are we arrived at destination ?
if ((gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer && attackedNB > 1) || attackedNB > 4)
if ((gameState.ai.HQ.territoryMap.getOwner(this.position) === this.targetPlayer && attackedNB > 1) || attackedNB > 3)
this.state = "arrived";
}
@ -833,9 +846,9 @@ m.AttackPlan.prototype.update = function(gameState, events)
var farthest = 0;
var farthestEnt = -1;
sieges.forEach (function (ent) {
if (API3.SquareVectorDistance(ent.position(),self.position) > farthest)
if (API3.SquareVectorDistance(ent.position(), self.position) > farthest)
{
farthest = API3.SquareVectorDistance(ent.position(),self.position);
farthest = API3.SquareVectorDistance(ent.position(), self.position);
farthestEnt = ent;
}
});
@ -952,7 +965,10 @@ m.AttackPlan.prototype.update = function(gameState, events)
if (targets.length !== 0)
{
for (var i in targets._entities)
{
this.target = targets._entities[i];
break;
}
this.targetPos = this.target.position();
}
}
@ -961,7 +977,6 @@ m.AttackPlan.prototype.update = function(gameState, events)
// basic state of attacking.
if (this.state === "")
{
// events watch: if siege units are attacked, we'll send some units to deal with enemies.
var attackedEvents = events["Attacked"];
for (var key in attackedEvents)
{
@ -972,11 +987,25 @@ m.AttackPlan.prototype.update = function(gameState, events)
if (!attacker || !attacker.position() || !attacker.hasClass("Unit"))
continue;
var ourUnit = gameState.getEntityById(e.target);
if (!ourUnit.hasClass("Siege"))
continue;
var collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5).toEntityArray();
for (var unit in collec)
unit.attack(attacker.id());
if (this.isSiegeUnit(gameState, ourUnit))
{
// if siege units are attacked, we'll send some units to deal with enemies.
var collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5).toEntityArray();
for each (var ent in collec)
ent.attack(attacker.id());
}
else
{
// if other units are attacked, abandon their target (if it was a structure or a support) and retaliate
var orderData = ourUnit.unitAIOrderData();
if (orderData.length !== 0 && orderData[0]["target"])
{
var target = gameState.getEntityById(orderData[0]["target"]);
if (target && !target.hasClass("Structure") && !target.hasClass("Support"))
continue;
}
ourUnit.attack(attacker.id());
}
}
var enemyUnits = gameState.getEnemyUnits(this.targetPlayer);
@ -1008,11 +1037,9 @@ m.AttackPlan.prototype.update = function(gameState, events)
// update the order if needed
var needsUpdate = false;
var maybeUpdate = false;
var isSiegeUnit = ent.hasClass("Siege") ||
(gameState.civ() === "maur" && ent.hasClass("Elephant") && ent.hasClass("Champion"));
if (ent.isIdle())
needsUpdate = true;
else if (isSiegeUnit && orderData && orderData["target"])
else if (this.isSiegeUnit(gameState, ent) && orderData && orderData["target"])
{
var target = gameState.getEntityById(orderData["target"]);
if (!target)
@ -1064,7 +1091,7 @@ m.AttackPlan.prototype.update = function(gameState, events)
// Checking for gates if we're a siege unit.
mUnit = mUnit.toEntityArray();
mStruct = mStruct.toEntityArray();
if (isSiegeUnit)
if (this.isSiegeUnit(gameState, ent))
{
mStruct.sort(function (structa,structb)
{
@ -1225,6 +1252,12 @@ m.AttackPlan.prototype.hasForceOrder = function(data, value)
return forced;
};
m.AttackPlan.prototype.isSiegeUnit = function(gameState, ent)
{
return (ent.hasClass("Siege") ||
(gameState.civ() === "maur" && ent.hasClass("Elephant") && ent.hasClass("Champion")));
};
m.AttackPlan.prototype.debugAttack = function()
{
warn("---------- attack " + this.name);

View File

@ -4,7 +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.
this.debug = 0;
this.debug = 1;
this.Military = {
"towerLapseTime" : 90, // Time to wait between building 2 towers
@ -46,20 +46,17 @@ m.Config = function() {
},
"advanced" : {
"default" : [],
"hele" : [ "structures/{civ}_gymnasion" ],
"athen" : [ "structures/{civ}_gymnasion" ],
"spart" : [ "structures/{civ}_syssiton" ],
"athen" : [ "structures/{civ}_gymnasion", "structures/{civ}_prytaneion", "structures/{civ}_theatron" ],
"cart" : [ "structures/{civ}_embassy_celtic",
"structures/{civ}_embassy_iberian", "structures/{civ}_embassy_italiote" ],
"celt" : [ "structures/{civ}_kennel" ],
"pers" : [ "structures/{civ}_fortress", "structures/{civ}_stables", "structures/{civ}_apadana" ],
"gaul" : [ "structures/{civ}_tavern" ],
"mace" : [ "structures/{civ}_siege_workshop", "structures/{civ}_library", "structures/{civ}_theatron" ],
"maur" : [ "structures/{civ}_elephant_stables" ],
"pers" : [ "structures/{civ}_stables", "structures/{civ}_apadana" ],
"ptol" : [ "structures/{civ}_library" ],
"rome" : [ "structures/{civ}_army_camp" ],
"mace" : [ "structures/{civ}_siege_workshop"],
"maur" : [ "structures/{civ}_elephant_stables"]
},
"fort" : {
"default" : [ "structures/{civ}_fortress" ],
"celt" : [ "structures/{civ}_fortress_b", "structures/{civ}_fortress_g" ]
"sele" : [ "structures/{civ}_library" ],
"spart" : [ "structures/{civ}_syssiton", "structures/{civ}_theatron" ]
}
};

View File

@ -10,27 +10,6 @@ m.DefenseArmy = function(gameState, defManager, ownEntities, foeEntities)
this.watchTSMultiplicator = this.Config.Defense.armyStrengthWariness;
this.watchDecrement = this.Config.Defense.prudence;
this.foeSubStrength = {
"spear" : ["Infantry", "Spear"], //also pikemen
"sword" : ["Infantry", "Sword"],
"ranged" : ["Infantry", "Ranged"],
"meleeCav" : ["Cavalry", "Melee"],
"rangedCav" : ["Cavalry", "Ranged"],
"Elephant" : ["Elephant"],
"meleeSiege" : ["Siege", "Melee"],
"rangedSiege" : ["Siege", "Ranged"]
};
this.ownSubStrength = {
"spear" : ["Infantry", "Spear"], //also pikemen
"sword" : ["Infantry", "Sword"],
"ranged" : ["Infantry", "Ranged"],
"meleeCav" : ["Cavalry", "Melee"],
"rangedCav" : ["Cavalry", "Ranged"],
"Elephant" : ["Elephant"],
"meleeSiege" : ["Siege", "Melee"],
"rangedSiege" : ["Siege", "Ranged"]
};
this.checkDangerosity(gameState); // might push us to 1.
this.watchLevel = this.foeStrength * this.watchTSMultiplicator;

View File

@ -157,17 +157,10 @@ m.HQ.prototype.init = function(gameState, queues)
else
this.bAdvanced = this.Config.buildings.advanced['default'];
if (civ in this.Config.buildings.fort)
this.bFort = this.Config.buildings.fort[civ];
else
this.bFort = this.Config.buildings.fort['default'];
for (var i in this.bBase)
this.bBase[i] = gameState.applyCiv(this.bBase[i]);
for (var i in this.bAdvanced)
this.bAdvanced[i] = gameState.applyCiv(this.bAdvanced[i]);
for (var i in this.bFort)
this.bFort[i] = gameState.applyCiv(this.bFort[i]);
};
m.HQ.prototype.checkEvents = function (gameState, events, queues)
@ -1335,36 +1328,33 @@ m.HQ.prototype.buildDefenses = function(gameState, queues)
if (gameState.currentPhase() > 2 || gameState.isResearching(gameState.cityPhase()))
{
// try to build fortresses
if (queues.defenseBuilding.length() === 0 && this.canBuild(gameState, this.bFort[0]))
if (queues.defenseBuilding.length() === 0 && this.canBuild(gameState, "structures/{civ}_fortress"))
{
var numFortresses = 0;
for (var i in this.bFort)
numFortresses += gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bFort[i]), true);
var numFortresses = gameState.countEntitiesAndQueuedByType(gameState.applyCiv("structures/{civ}_fortress"), true);
if (gameState.getTimeElapsed() > (1 + 0.10*numFortresses)*this.fortressLapseTime + this.fortressStartTime)
{
this.fortressStartTime = gameState.getTimeElapsed();
// TODO should affect it to the right base
queues.defenseBuilding.addItem(new m.ConstructionPlan(gameState, this.bFort[0]));
queues.defenseBuilding.addItem(new m.ConstructionPlan(gameState, "structures/{civ}_fortress"));
}
}
// let's add a siege building plan to the current attack plan if there is none currently.
var numSiegeBuilder = 0;
if (gameState.civ() === "mace" || gameState.civ() === "maur")
numSiegeBuilder = gameState.countEntitiesByType(gameState.applyCiv(this.bAdvanced[0]), true);
var numSiegeBuilder = gameState.countEntitiesByType(gameState.applyCiv(this.bAdvanced[0]), true);
else
for (var i in this.bFort)
numSiegeBuilder += gameState.countEntitiesByType(gameState.applyCiv(this.bFort[i]), true);
var numSiegeBuilder = gameState.countEntitiesByType(gameState.applyCiv("structures/{civ}_fortress"), true);
if (numSiegeBuilder > 0)
{
if (this.attackManager.upcomingAttacks["CityAttack"].length !== 0)
{
var attack = this.attackManager.upcomingAttacks["CityAttack"][0];
if (!attack.unitStat["Siege"])
attack.addSiegeUnits(gameState);
}
var attack = undefined;
// There can only be one upcoming attack
if (this.attackManager.upcomingAttacks["Attack"].length !== 0)
var attack = this.attackManager.upcomingAttacks["Attack"][0];
else if (this.attackManager.upcomingAttacks["HugeAttack"].length !== 0)
var attack = this.attackManager.upcomingAttacks["HugeAttack"][0];
if (attack && !attack.unitStat["Siege"])
attack.addSiegeUnits(gameState);
}
}
@ -1439,10 +1429,16 @@ m.HQ.prototype.constructTrainingBuildings = function(gameState, queues)
inConst += gameState.countFoundationsByType(gameState.applyCiv(this.bAdvanced[i]));
if (inConst == 0 && this.bAdvanced && this.bAdvanced.length !== 0)
{
var i = Math.floor(Math.random() * this.bAdvanced.length);
if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i]), true) < 1 &&
this.canBuild(gameState, this.bAdvanced[i]))
queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : bestBase }));
for (var i in this.bAdvanced)
{
if (gameState.countEntitiesAndQueuedByType(gameState.applyCiv(this.bAdvanced[i]), true) < 1 &&
this.canBuild(gameState, this.bAdvanced[i]))
{
queues.militaryBuilding.addItem(new m.ConstructionPlan(gameState, this.bAdvanced[i], { "base" : bestBase }));
break;
}
}
}
}
}

View File

@ -311,7 +311,7 @@ m.QueueManager.prototype.printQueues = function(gameState)
var q = this.queues[i];
if (q.queue.length > 0)
{
warn(i + ": ( paused " + q.paused + " with priority " + this.priorities[i] +" and accounts " + uneval(this.accounts[i]) +")");
warn(i + ": ( with priority " + this.priorities[i] +" and accounts " + uneval(this.accounts[i]) +")");
warn(" while maxAccountWanted(0.6) is " + uneval(q.maxAccountWanted(gameState, 0.6)));
}
for (var j in q.queue)