Use new FastMoving class instead of Cavalry in AI/petra.
This class is an AI hint that such units are to be treated as moving fast, e.g. war dogs, or cavalry. This makes it easier to introduce camels and chariots correctly. Further work is required to make the AI unit choices less hardcoded. Patch by: Nescio Reviewed By: Angen, wraitii Differential Revision: https://code.wildfiregames.com/D2251 This was SVN commit r23916.
This commit is contained in:
parent
17e6d8b24b
commit
164af0742a
@ -119,7 +119,7 @@ PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
||||
priority = 250;
|
||||
this.unitStat.Infantry = { "priority": 1, "minSize": 10, "targetSize": 20, "batchSize": 2, "classes": ["Infantry"],
|
||||
"interests": [["strength", 1], ["costsResource", 0.5, "stone"], ["costsResource", 0.6, "metal"]] };
|
||||
this.unitStat.Cavalry = { "priority": 1, "minSize": 2, "targetSize": 4, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
|
||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"],
|
||||
"interests": [["strength", 1]] };
|
||||
if (data && data.targetSize)
|
||||
this.unitStat.Infantry.targetSize = data.targetSize;
|
||||
@ -128,7 +128,7 @@ PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
||||
else if (type == "Raid")
|
||||
{
|
||||
priority = 150;
|
||||
this.unitStat.Cavalry = { "priority": 1, "minSize": 3, "targetSize": 4, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
|
||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 3, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"],
|
||||
"interests": [ ["strength", 1] ] };
|
||||
this.neededShips = 1;
|
||||
}
|
||||
@ -144,13 +144,13 @@ PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
||||
"interests": [["strength", 3]] };
|
||||
this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"],
|
||||
"interests": [["strength", 3]] };
|
||||
this.unitStat.RangedCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Ranged", "CitizenSoldier"],
|
||||
this.unitStat.RangedFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving", "Ranged", "CitizenSoldier"],
|
||||
"interests": [["strength", 2]] };
|
||||
this.unitStat.MeleeCavalry = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["Cavalry", "Melee", "CitizenSoldier"],
|
||||
this.unitStat.MeleeFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving", "Melee", "CitizenSoldier"],
|
||||
"interests": [["strength", 2]] };
|
||||
this.unitStat.ChampRangedCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Ranged", "Champion"],
|
||||
this.unitStat.ChampRangedFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving", "Ranged", "Champion"],
|
||||
"interests": [["strength", 3]] };
|
||||
this.unitStat.ChampMeleeCavalry = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["Cavalry", "Melee", "Champion"],
|
||||
this.unitStat.ChampMeleeFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving", "Melee", "Champion"],
|
||||
"interests": [["strength", 2]] };
|
||||
this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"],
|
||||
"interests": [["strength", 2]] };
|
||||
@ -163,7 +163,7 @@ PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data)
|
||||
"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
|
||||
this.unitStat.MeleeInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Melee"],
|
||||
"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] };
|
||||
this.unitStat.Cavalry = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["Cavalry", "CitizenSoldier"],
|
||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"],
|
||||
"interests": [["strength", 1]] };
|
||||
this.neededShips = 3;
|
||||
}
|
||||
@ -435,7 +435,7 @@ PETRA.AttackPlan.prototype.updatePreparation = function(gameState)
|
||||
if (this.type != "Raid" || !this.forced) // Forced Raids have special purposes (as relic capture)
|
||||
this.assignUnits(gameState);
|
||||
if (this.type != "Raid" && gameState.ai.HQ.attackManager.getAttackInPreparation("Raid") !== undefined)
|
||||
this.reassignCavUnit(gameState); // reassign some cav (if any) to fasten raid preparations
|
||||
this.reassignFastUnit(gameState); // reassign some fast units (if any) to fasten raid preparations
|
||||
|
||||
// Fasten the end game.
|
||||
if (gameState.ai.playedTurn % 5 == 0 && this.hasSiegeUnits())
|
||||
@ -655,7 +655,7 @@ PETRA.AttackPlan.prototype.assignUnits = function(gameState)
|
||||
{
|
||||
let plan = this.name;
|
||||
let added = false;
|
||||
// If we can not build units, assign all available except those affected to allied defense to the current attack
|
||||
// If we can not build units, assign all available except those affected to allied defense to the current attack.
|
||||
if (!this.canBuildUnits)
|
||||
{
|
||||
for (let ent of gameState.getOwnUnits().values())
|
||||
@ -671,11 +671,11 @@ PETRA.AttackPlan.prototype.assignUnits = function(gameState)
|
||||
|
||||
if (this.type == "Raid")
|
||||
{
|
||||
// Raid are fast cavalry attack: assign all cav except some for hunting
|
||||
// Raids are quick attacks: assign all FastMoving soldiers except some for hunting.
|
||||
let num = 0;
|
||||
for (let ent of gameState.getOwnUnits().values())
|
||||
{
|
||||
if (!ent.hasClass("Cavalry") || !this.isAvailableUnit(gameState, ent))
|
||||
if (!ent.hasClass("FastMoving") || !this.isAvailableUnit(gameState, ent))
|
||||
continue;
|
||||
if (num++ < 2)
|
||||
continue;
|
||||
@ -686,7 +686,7 @@ PETRA.AttackPlan.prototype.assignUnits = function(gameState)
|
||||
return added;
|
||||
}
|
||||
|
||||
// Assign all units without specific role
|
||||
// Assign all units without specific role.
|
||||
for (let ent of gameState.getOwnEntitiesByRole(undefined, true).values())
|
||||
{
|
||||
if (!ent.hasClass("Unit") || !this.isAvailableUnit(gameState, ent))
|
||||
@ -697,7 +697,7 @@ PETRA.AttackPlan.prototype.assignUnits = function(gameState)
|
||||
this.unitCollection.updateEnt(ent);
|
||||
added = true;
|
||||
}
|
||||
// Add units previously in a plan, but which left it because needed for defense or attack finished
|
||||
// Add units previously in a plan, but which left it because needed for defense or attack finished.
|
||||
for (let ent of gameState.ai.HQ.attackManager.outOfPlan.values())
|
||||
{
|
||||
if (!this.isAvailableUnit(gameState, ent))
|
||||
@ -751,14 +751,14 @@ PETRA.AttackPlan.prototype.isAvailableUnit = function(gameState, ent)
|
||||
return true;
|
||||
};
|
||||
|
||||
/** Reassign one (at each turn) Cav unit to fasten raid preparation. */
|
||||
PETRA.AttackPlan.prototype.reassignCavUnit = function(gameState)
|
||||
/** Reassign one (at each turn) FastMoving unit to fasten raid preparation. */
|
||||
PETRA.AttackPlan.prototype.reassignFastUnit = function(gameState)
|
||||
{
|
||||
for (let ent of this.unitCollection.values())
|
||||
{
|
||||
if (!ent.position() || ent.getMetadata(PlayerID, "transport") !== undefined)
|
||||
continue;
|
||||
if (!ent.hasClass("Cavalry") || !ent.hasClass("CitizenSoldier"))
|
||||
if (!ent.hasClass("FastMoving") || !ent.hasClass("CitizenSoldier"))
|
||||
continue;
|
||||
let raid = gameState.ai.HQ.attackManager.getAttackInPreparation("Raid");
|
||||
ent.setMetadata(PlayerID, "plan", raid.name);
|
||||
@ -1510,7 +1510,7 @@ PETRA.AttackPlan.prototype.update = function(gameState, events)
|
||||
maybeUpdate = true;
|
||||
else if (attackedByStructure[ent.id()] && target.hasClass("Field"))
|
||||
maybeUpdate = true;
|
||||
else if (!ent.hasClass("Cavalry") && !ent.hasClass("Ranged") &&
|
||||
else if (!ent.hasClass("FastMoving") && !ent.hasClass("Ranged") &&
|
||||
target.hasClass("FemaleCitizen") && target.unitAIState().split(".")[1] == "FLEEING")
|
||||
maybeUpdate = true;
|
||||
}
|
||||
@ -1539,7 +1539,7 @@ PETRA.AttackPlan.prototype.update = function(gameState, events)
|
||||
}
|
||||
else if (attackTypes && attackTypes.indexOf("Ranged") !== -1)
|
||||
range = 30 + ent.attackRange("Ranged").max;
|
||||
else if (ent.hasClass("Cavalry"))
|
||||
else if (ent.hasClass("FastMoving"))
|
||||
range += 30;
|
||||
range *= range;
|
||||
let entAccess = PETRA.getLandAccess(gameState, ent);
|
||||
@ -1597,7 +1597,7 @@ PETRA.AttackPlan.prototype.update = function(gameState, events)
|
||||
}
|
||||
else
|
||||
{
|
||||
let nearby = !ent.hasClass("Cavalry") && !ent.hasClass("Ranged");
|
||||
let nearby = !ent.hasClass("FastMoving") && !ent.hasClass("Ranged");
|
||||
let mUnit = enemyUnits.filter(enemy => {
|
||||
if (!enemy.position() || !ent.canAttackTarget(enemy, PETRA.allowCapture(gameState, ent, enemy)))
|
||||
return false;
|
||||
|
@ -650,7 +650,7 @@ PETRA.BaseManager.prototype.reassignIdleWorkers = function(gameState, idleWorker
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ent.hasClass("Cavalry"))
|
||||
else if (PETRA.isFastMoving(ent))
|
||||
ent.setMetadata(PlayerID, "subrole", "hunter");
|
||||
else if (ent.hasClass("FishingBoat"))
|
||||
ent.setMetadata(PlayerID, "subrole", "fisher");
|
||||
|
@ -4,6 +4,13 @@ PETRA.isSiegeUnit = function(ent)
|
||||
return ent.hasClass("Siege") || ent.hasClass("Elephant") && ent.hasClass("Melee") && ent.hasClass("Champion");
|
||||
};
|
||||
|
||||
/** returns true if this unit should be considered as "fast". */
|
||||
PETRA.isFastMoving = function(ent)
|
||||
{
|
||||
// TODO: use clever logic based on walkspeed comparisons.
|
||||
return ent.hasClass("FastMoving");
|
||||
};
|
||||
|
||||
/** returns some sort of DPS * health factor. If you specify a class, it'll use the modifiers against that class too. */
|
||||
PETRA.getMaxStrength = function(ent, debugLevel, DamageTypeImportance, againstClass)
|
||||
{
|
||||
|
@ -306,7 +306,7 @@ PETRA.HQ.prototype.buildFirstBase = function(gameState)
|
||||
{
|
||||
if (!ent.hasClass("Worker") && !(ent.hasClass("Support") && ent.hasClass("Elephant")))
|
||||
continue;
|
||||
if (ent.hasClass("Cavalry"))
|
||||
if (PETRA.isFastMoving(ent))
|
||||
continue;
|
||||
let pos = ent.position();
|
||||
if (!pos)
|
||||
|
@ -112,7 +112,7 @@ PETRA.Worker.prototype.update = function(gameState, ent)
|
||||
}
|
||||
else if (!gameState.isPlayerAlly(territoryOwner))
|
||||
{
|
||||
let distanceSquare = ent.hasClass("Cavalry") ? 90000 : 30000;
|
||||
let distanceSquare = ent.isFastMoving() ? 90000 : 30000;
|
||||
let targetAccess = PETRA.getLandAccess(gameState, target);
|
||||
let foodDropsites = gameState.playerData.hasSharedDropsites ?
|
||||
gameState.getAnyDropsites("food") : gameState.getOwnDropsites("food");
|
||||
@ -744,7 +744,7 @@ PETRA.Worker.prototype.startHunting = function(gameState, position)
|
||||
let nearestSupplyDist = Math.min();
|
||||
let nearestSupply;
|
||||
|
||||
let isCavalry = this.ent.hasClass("Cavalry");
|
||||
let isFastMoving = PETRA.isFastMoving(this.ent);
|
||||
let isRanged = this.ent.hasClass("Ranged");
|
||||
let entPosition = position ? position : this.ent.position();
|
||||
let foodDropsites = gameState.playerData.hasSharedDropsites ?
|
||||
@ -784,41 +784,41 @@ PETRA.Worker.prototype.startHunting = function(gameState, position)
|
||||
|
||||
if (PETRA.IsSupplyFull(gameState, supply))
|
||||
continue;
|
||||
// check if available resource is worth one additionnal gatherer (except for farms)
|
||||
// Check if available resource is worth one additionnal gatherer (except for farms).
|
||||
let nbGatherers = supply.resourceSupplyNumGatherers() + gameState.ai.HQ.GetTCGatherer(supply.id());
|
||||
if (nbGatherers > 0 && supply.resourceSupplyAmount()/(1+nbGatherers) < 30)
|
||||
continue;
|
||||
|
||||
let canFlee = !supply.hasClass("Domestic") && supply.templateName().indexOf("resource|") == -1;
|
||||
// Only cavalry and range units should hunt fleeing animals
|
||||
if (canFlee && !isCavalry && !isRanged)
|
||||
// Only FastMoving and Ranged units should hunt fleeing animals.
|
||||
if (canFlee && !isFastMoving && !isRanged)
|
||||
continue;
|
||||
|
||||
let supplyAccess = PETRA.getLandAccess(gameState, supply);
|
||||
if (supplyAccess != this.entAccess)
|
||||
continue;
|
||||
|
||||
// measure the distance to the resource
|
||||
// measure the distance to the resource.
|
||||
let dist = API3.SquareVectorDistance(entPosition, supply.position());
|
||||
if (dist > nearestSupplyDist)
|
||||
continue;
|
||||
|
||||
// Only cavalry should hunt faraway
|
||||
if (!isCavalry && dist > 25000)
|
||||
// Only FastMoving should hunt faraway.
|
||||
if (!isFastMoving && dist > 25000)
|
||||
continue;
|
||||
|
||||
// Avoid ennemy territory
|
||||
// Avoid enemy territory.
|
||||
let territoryOwner = gameState.ai.HQ.territoryMap.getOwner(supply.position());
|
||||
if (territoryOwner != 0 && !gameState.isPlayerAlly(territoryOwner)) // player is its own ally
|
||||
if (territoryOwner != 0 && !gameState.isPlayerAlly(territoryOwner)) // Player is its own ally.
|
||||
continue;
|
||||
// And if in ally territory, don't hunt this ally's cattle
|
||||
// And if in ally territory, don't hunt this ally's cattle.
|
||||
if (territoryOwner != 0 && territoryOwner != PlayerID && supply.owner() == territoryOwner)
|
||||
continue;
|
||||
|
||||
// Only cavalry should hunt far from dropsite (specially for non domestic animals which flee)
|
||||
if (!isCavalry && canFlee && territoryOwner == 0)
|
||||
// Only FastMoving should hunt far from dropsite (specially for non-Domestic animals which flee).
|
||||
if (!isFastMoving && canFlee && territoryOwner == 0)
|
||||
continue;
|
||||
let distanceSquare = isCavalry ? 35000 : (canFlee ? 7000 : 12000);
|
||||
let distanceSquare = isFastMoving ? 35000 : (canFlee ? 7000 : 12000);
|
||||
if (!hasFoodDropsiteWithinDistance(supply.position(), supplyAccess, distanceSquare))
|
||||
continue;
|
||||
|
||||
|
@ -57,7 +57,7 @@ Identity.prototype.Schema =
|
||||
"</element>" +
|
||||
"</optional>" +
|
||||
"<optional>" +
|
||||
"<element name='Classes' a:help='Optional list of space-separated classes applying to this entity. Choices include: AfricanElephant, AmunGuard, Animal, ApedemakGuard, Ashoka, Barter, Celt, CitizenSoldier, CivCentre, ConquestCritical, Domestic, DropsiteFood, DropsiteMetal, DropsiteStone, DropsiteWood, FemaleCitizen, ForestPlant, GarrisonFortress, Human, Iberian, Immortal, IndianElephant, Italian, Juggernaut, KushTrireme, MercenaryCamp, Organic, Player, PtolemyIV, SeaCreature, Spy, Structure, Unit, WallLong, WallMedium, WallShort, WallTower.'>" +
|
||||
"<element name='Classes' a:help='Optional list of space-separated classes applying to this entity. Choices include: AfricanElephant, AmunGuard, Animal, ApedemakGuard, Ashoka, Barter, Celt, CitizenSoldier, CivCentre, ConquestCritical, Domestic, DropsiteFood, DropsiteMetal, DropsiteStone, DropsiteWood, FastMoving, FemaleCitizen, ForestPlant, GarrisonFortress, Human, Iberian, Immortal, IndianElephant, Italian, Juggernaut, KushTrireme, MercenaryCamp, Organic, Player, PtolemyIV, SeaCreature, Spy, Structure, Unit, WallLong, WallMedium, WallShort, WallTower.'>" +
|
||||
"<attribute name='datatype'>" +
|
||||
"<value>tokens</value>" +
|
||||
"</attribute>" +
|
||||
|
@ -35,7 +35,7 @@
|
||||
<Identity>
|
||||
<GenericName>Cavalry</GenericName>
|
||||
<Rank>Basic</Rank>
|
||||
<Classes datatype="tokens">Human CitizenSoldier</Classes>
|
||||
<Classes datatype="tokens">Human FastMoving CitizenSoldier</Classes>
|
||||
<VisibleClasses datatype="tokens">Citizen Soldier Cavalry</VisibleClasses>
|
||||
<Formations datatype="tokens">
|
||||
special/formations/wedge
|
||||
|
@ -22,6 +22,7 @@
|
||||
<Max>240</Max>
|
||||
</Health>
|
||||
<Identity>
|
||||
<Classes datatype="tokens">FastMoving</Classes>
|
||||
<VisibleClasses datatype="tokens">Cavalry</VisibleClasses>
|
||||
<GenericName>Champion Cavalry</GenericName>
|
||||
<Formations datatype="tokens">
|
||||
|
@ -35,7 +35,7 @@
|
||||
<Identity>
|
||||
<GenericName>War Dog</GenericName>
|
||||
<Tooltip>Cannot attack Structures, Ships, or Siege Engines.</Tooltip>
|
||||
<Classes datatype="tokens">Human</Classes>
|
||||
<Classes datatype="tokens">Human FastMoving</Classes>
|
||||
<VisibleClasses datatype="tokens">Dog Melee</VisibleClasses>
|
||||
</Identity>
|
||||
<Loot>
|
||||
|
@ -21,6 +21,7 @@
|
||||
<Max>1500</Max>
|
||||
</Health>
|
||||
<Identity>
|
||||
<Classes datatype="tokens">FastMoving</Classes>
|
||||
<VisibleClasses datatype="tokens">Cavalry</VisibleClasses>
|
||||
<GenericName>Hero Cavalry</GenericName>
|
||||
<Formations datatype="tokens">
|
||||
|
Loading…
Reference in New Issue
Block a user