Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/ai/petra/attackPlan.js
Show First 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | PETRA.AttackPlan = function(gameState, Config, uniqueID, type, data) | ||||
this.unitStat = {}; | this.unitStat = {}; | ||||
// neededShips is the minimal number of ships which should be available for transport | // neededShips is the minimal number of ships which should be available for transport | ||||
if (type == "Rush") | if (type == "Rush") | ||||
{ | { | ||||
priority = 250; | priority = 250; | ||||
this.unitStat.Infantry = { "priority": 1, "minSize": 10, "targetSize": 20, "batchSize": 2, "classes": ["Infantry"], | this.unitStat.Infantry = { "priority": 1, "minSize": 10, "targetSize": 20, "batchSize": 2, "classes": ["Infantry"], | ||||
"interests": [["strength", 1], ["costsResource", 0.5, "stone"], ["costsResource", 0.6, "metal"]] }; | "interests": [["strength", 1], ["costsResource", 0.5, "stone"], ["costsResource", 0.6, "metal"]] }; | ||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"], | this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving+CitizenSoldier"], | ||||
"interests": [["strength", 1]] }; | "interests": [["strength", 1]] }; | ||||
if (data && data.targetSize) | if (data && data.targetSize) | ||||
this.unitStat.Infantry.targetSize = data.targetSize; | this.unitStat.Infantry.targetSize = data.targetSize; | ||||
this.neededShips = 1; | this.neededShips = 1; | ||||
} | } | ||||
else if (type == "Raid") | else if (type == "Raid") | ||||
{ | { | ||||
priority = 150; | priority = 150; | ||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 3, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"], | this.unitStat.FastMoving = { "priority": 1, "minSize": 3, "targetSize": 4, "batchSize": 2, "classes": ["FastMoving+CitizenSoldier"], | ||||
"interests": [ ["strength", 1] ] }; | "interests": [ ["strength", 1] ] }; | ||||
this.neededShips = 1; | this.neededShips = 1; | ||||
} | } | ||||
else if (type == "HugeAttack") | else if (type == "HugeAttack") | ||||
{ | { | ||||
priority = 90; | priority = 90; | ||||
// basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units. | // basically we want a mix of citizen soldiers so our barracks have a purpose, and champion units. | ||||
this.unitStat.RangedInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Ranged", "CitizenSoldier"], | this.unitStat.RangedInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry+Ranged+CitizenSoldier"], | ||||
"interests": [["strength", 3]] }; | "interests": [["strength", 3]] }; | ||||
this.unitStat.MeleeInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry", "Melee", "CitizenSoldier"], | this.unitStat.MeleeInfantry = { "priority": 0.7, "minSize": 5, "targetSize": 20, "batchSize": 5, "classes": ["Infantry+Melee+CitizenSoldier"], | ||||
"interests": [["strength", 3]] }; | "interests": [["strength", 3]] }; | ||||
this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Ranged", "Champion"], | this.unitStat.ChampRangedInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry+Ranged+Champion"], | ||||
"interests": [["strength", 3]] }; | "interests": [["strength", 3]] }; | ||||
this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry", "Melee", "Champion"], | this.unitStat.ChampMeleeInfantry = { "priority": 1, "minSize": 3, "targetSize": 18, "batchSize": 3, "classes": ["Infantry+Melee+Champion"], | ||||
"interests": [["strength", 3]] }; | "interests": [["strength", 3]] }; | ||||
this.unitStat.RangedFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving", "Ranged", "CitizenSoldier"], | this.unitStat.RangedFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving+Ranged+CitizenSoldier"], | ||||
"interests": [["strength", 2]] }; | "interests": [["strength", 2]] }; | ||||
this.unitStat.MeleeFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving", "Melee", "CitizenSoldier"], | this.unitStat.MeleeFastMoving = { "priority": 0.7, "minSize": 4, "targetSize": 20, "batchSize": 4, "classes": ["FastMoving+Melee+CitizenSoldier"], | ||||
"interests": [["strength", 2]] }; | "interests": [["strength", 2]] }; | ||||
this.unitStat.ChampRangedFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving", "Ranged", "Champion"], | this.unitStat.ChampRangedFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving+Ranged+Champion"], | ||||
"interests": [["strength", 3]] }; | "interests": [["strength", 3]] }; | ||||
this.unitStat.ChampMeleeFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving", "Melee", "Champion"], | this.unitStat.ChampMeleeFastMoving = { "priority": 1, "minSize": 3, "targetSize": 15, "batchSize": 3, "classes": ["FastMoving+Melee+Champion"], | ||||
"interests": [["strength", 2]] }; | "interests": [["strength", 2]] }; | ||||
this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"], | this.unitStat.Hero = { "priority": 1, "minSize": 0, "targetSize": 1, "batchSize": 1, "classes": ["Hero"], | ||||
"interests": [["strength", 2]] }; | "interests": [["strength", 2]] }; | ||||
this.neededShips = 5; | this.neededShips = 5; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
priority = 70; | priority = 70; | ||||
this.unitStat.RangedInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry", "Ranged"], | this.unitStat.RangedInfantry = { "priority": 1, "minSize": 6, "targetSize": 16, "batchSize": 3, "classes": ["Infantry+Ranged"], | ||||
"interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] }; | "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"], | 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"]] }; | "interests": [["canGather", 1], ["strength", 1.6], ["costsResource", 0.3, "stone"], ["costsResource", 0.3, "metal"]] }; | ||||
this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["FastMoving", "CitizenSoldier"], | this.unitStat.FastMoving = { "priority": 1, "minSize": 2, "targetSize": 6, "batchSize": 2, "classes": ["FastMoving+CitizenSoldier"], | ||||
"interests": [["strength", 1]] }; | "interests": [["strength", 1]] }; | ||||
this.neededShips = 3; | this.neededShips = 3; | ||||
} | } | ||||
// Put some randomness on the attack size | // Put some randomness on the attack size | ||||
let variation = randFloat(0.8, 1.2); | let variation = randFloat(0.8, 1.2); | ||||
// and lower priority and smaller sizes for easier difficulty levels | // and lower priority and smaller sizes for easier difficulty levels | ||||
if (this.Config.difficulty < 2) | if (this.Config.difficulty < 2) | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | PETRA.AttackPlan.prototype.init = function(gameState) | ||||
this.unit = {}; | this.unit = {}; | ||||
// defining the entity collections. Will look for units I own, that are part of this plan. | // defining the entity collections. Will look for units I own, that are part of this plan. | ||||
// Also defining the buildOrders. | // Also defining the buildOrders. | ||||
for (let cat in this.unitStat) | for (let cat in this.unitStat) | ||||
{ | { | ||||
let Unit = this.unitStat[cat]; | let Unit = this.unitStat[cat]; | ||||
this.unit[cat] = this.unitCollection.filter(API3.Filters.byClassesAnd(Unit.classes)); | this.unit[cat] = this.unitCollection.filter(API3.Filters.byClasses(Unit.classes)); | ||||
this.unit[cat].registerUpdates(); | this.unit[cat].registerUpdates(); | ||||
if (this.canBuildUnits) | if (this.canBuildUnits) | ||||
this.buildOrders.push([0, Unit.classes, this.unit[cat], Unit, cat]); | this.buildOrders.push([0, Unit.classes, this.unit[cat], Unit, cat]); | ||||
} | } | ||||
}; | }; | ||||
PETRA.AttackPlan.prototype.getName = function() | PETRA.AttackPlan.prototype.getName = function() | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | |||||
/** Adds a build order. If resetQueue is true, this will reset the queue. */ | /** Adds a build order. If resetQueue is true, this will reset the queue. */ | ||||
PETRA.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) | PETRA.AttackPlan.prototype.addBuildOrder = function(gameState, name, unitStats, resetQueue) | ||||
{ | { | ||||
if (!this.isStarted()) | if (!this.isStarted()) | ||||
{ | { | ||||
// no minsize as we don't want the plan to fail at the last minute though. | // no minsize as we don't want the plan to fail at the last minute though. | ||||
this.unitStat[name] = unitStats; | this.unitStat[name] = unitStats; | ||||
let Unit = this.unitStat[name]; | let Unit = this.unitStat[name]; | ||||
this.unit[name] = this.unitCollection.filter(API3.Filters.byClassesAnd(Unit.classes)); | this.unit[name] = this.unitCollection.filter(API3.Filters.byClasses(Unit.classes)); | ||||
this.unit[name].registerUpdates(); | this.unit[name].registerUpdates(); | ||||
this.buildOrders.push([0, Unit.classes, this.unit[name], Unit, name]); | this.buildOrders.push([0, Unit.classes, this.unit[name], Unit, name]); | ||||
if (resetQueue) | if (resetQueue) | ||||
this.emptyQueues(); | this.emptyQueues(); | ||||
} | } | ||||
}; | }; | ||||
PETRA.AttackPlan.prototype.addSiegeUnits = function(gameState) | PETRA.AttackPlan.prototype.addSiegeUnits = function(gameState) | ||||
Show All 12 Lines | for (let ent of gameState.getOwnTrainingFacilities().values()) | ||||
for (let trainable of trainables) | for (let trainable of trainables) | ||||
{ | { | ||||
if (gameState.isTemplateDisabled(trainable)) | if (gameState.isTemplateDisabled(trainable)) | ||||
continue; | continue; | ||||
let template = gameState.getTemplate(trainable); | let template = gameState.getTemplate(trainable); | ||||
if (!template || !template.available(gameState)) | if (!template || !template.available(gameState)) | ||||
continue; | continue; | ||||
for (let i = 0; i < classes.length; ++i) | for (let i = 0; i < classes.length; ++i) | ||||
if (classes[i].every(c => template.hasClass(c))) | if (template.hasClasses(classes[i])) | ||||
hasTrainer[i] = true; | hasTrainer[i] = true; | ||||
} | } | ||||
} | } | ||||
if (hasTrainer.every(e => !e)) | if (hasTrainer.every(e => !e)) | ||||
return false; | return false; | ||||
let i = this.name % classes.length; | let i = this.name % classes.length; | ||||
for (let k = 0; k < classes.length; ++k) | for (let k = 0; k < classes.length; ++k) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 225 Lines • ▼ Show 20 Lines | if (this.Config.debug > 1 && gameState.ai.playedTurn%50 === 0) | ||||
API3.warn("===================================="); | API3.warn("===================================="); | ||||
} | } | ||||
let firstOrder = this.buildOrders[0]; | let firstOrder = this.buildOrders[0]; | ||||
if (firstOrder[0] < firstOrder[3].targetSize) | if (firstOrder[0] < firstOrder[3].targetSize) | ||||
{ | { | ||||
// find the actual queue we want | // find the actual queue we want | ||||
let queue = this.queue; | let queue = this.queue; | ||||
if (firstOrder[3].classes.indexOf("Siege") != -1 || firstOrder[3].classes.indexOf("Elephant") != -1 && | if (MatchesClassList(firstOrder[3].classes, ["Siege", "Elephant+Melee+Champion"])) | ||||
firstOrder[3].classes.indexOf("Melee") != -1 && firstOrder[3].classes.indexOf("Champion") != -1) | |||||
queue = this.queueSiege; | queue = this.queueSiege; | ||||
else if (firstOrder[3].classes.indexOf("Hero") != -1) | else if (firstOrder[3].classes.indexOf("Hero") != -1) | ||||
queue = this.queueSiege; | queue = this.queueSiege; | ||||
else if (firstOrder[3].classes.indexOf("Champion") != -1) | else if (firstOrder[3].classes.indexOf("Champion") != -1) | ||||
queue = this.queueChamp; | queue = this.queueChamp; | ||||
if (queue.length() <= 5) | if (queue.length() <= 5) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | for (let ent of gameState.getOwnUnits().values()) | ||||
added = true; | added = true; | ||||
} | } | ||||
return added; | return added; | ||||
} | } | ||||
// Assign all units without specific role. | // Assign all units without specific role. | ||||
for (let ent of gameState.getOwnEntitiesByRole(undefined, true).values()) | for (let ent of gameState.getOwnEntitiesByRole(undefined, true).values()) | ||||
{ | { | ||||
if (!ent.hasClass("Unit") || !this.isAvailableUnit(gameState, ent)) | if (ent.hasClasses(["!Unit", "Ship", "Support"]) || | ||||
continue; | !this.isAvailableUnit(gameState, ent) || | ||||
if (ent.hasClass("Ship") || ent.hasClass("Support") || ent.attackTypes() === undefined) | ent.attackTypes() === undefined) | ||||
continue; | continue; | ||||
ent.setMetadata(PlayerID, "plan", plan); | ent.setMetadata(PlayerID, "plan", plan); | ||||
this.unitCollection.updateEnt(ent); | this.unitCollection.updateEnt(ent); | ||||
added = true; | 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()) | for (let ent of gameState.ai.HQ.attackManager.outOfPlan.values()) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | |||||
/** Reassign one (at each turn) FastMoving unit to fasten raid preparation. */ | /** Reassign one (at each turn) FastMoving unit to fasten raid preparation. */ | ||||
PETRA.AttackPlan.prototype.reassignFastUnit = function(gameState) | PETRA.AttackPlan.prototype.reassignFastUnit = function(gameState) | ||||
{ | { | ||||
for (let ent of this.unitCollection.values()) | for (let ent of this.unitCollection.values()) | ||||
{ | { | ||||
if (!ent.position() || ent.getMetadata(PlayerID, "transport") !== undefined) | if (!ent.position() || ent.getMetadata(PlayerID, "transport") !== undefined) | ||||
continue; | continue; | ||||
if (!ent.hasClass("FastMoving") || !ent.hasClass("CitizenSoldier")) | if (!ent.hasClasses(["FastMoving", "CitizenSoldier"])) | ||||
continue; | continue; | ||||
let raid = gameState.ai.HQ.attackManager.getAttackInPreparation("Raid"); | let raid = gameState.ai.HQ.attackManager.getAttackInPreparation("Raid"); | ||||
ent.setMetadata(PlayerID, "plan", raid.name); | ent.setMetadata(PlayerID, "plan", raid.name); | ||||
this.unitCollection.updateEnt(ent); | this.unitCollection.updateEnt(ent); | ||||
raid.unitCollection.updateEnt(ent); | raid.unitCollection.updateEnt(ent); | ||||
return; | return; | ||||
} | } | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 596 Lines • ▼ Show 20 Lines | for (let evt of events.Attacked) | ||||
if (PETRA.isSiegeUnit(ent) || !ent.canAttackTarget(attacker, allowCapture)) | if (PETRA.isSiegeUnit(ent) || !ent.canAttackTarget(attacker, allowCapture)) | ||||
continue; | continue; | ||||
let orderData = ent.unitAIOrderData(); | let orderData = ent.unitAIOrderData(); | ||||
if (orderData && orderData.length && orderData[0].target) | if (orderData && orderData.length && orderData[0].target) | ||||
{ | { | ||||
if (orderData[0].target === attacker.id()) | if (orderData[0].target === attacker.id()) | ||||
continue; | continue; | ||||
let target = gameState.getEntityById(orderData[0].target); | let target = gameState.getEntityById(orderData[0].target); | ||||
if (target && !target.hasClass("Structure") && !target.hasClass("Support")) | if (target && !target.hasClasses(["Structure", "Support"])) | ||||
continue; | continue; | ||||
} | } | ||||
ent.attack(attacker.id(), allowCapture); | ent.attack(attacker.id(), allowCapture); | ||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ||||
} | } | ||||
// Then the unit under attack: abandon its target (if it was a structure or a support) and retaliate | // Then the unit under attack: abandon its target (if it was a structure or a support) and retaliate | ||||
// also if our unit is attacking a range unit and the attacker is a melee unit, retaliate | // also if our unit is attacking a range unit and the attacker is a melee unit, retaliate | ||||
let orderData = ourUnit.unitAIOrderData(); | let orderData = ourUnit.unitAIOrderData(); | ||||
if (orderData && orderData.length && orderData[0].target) | if (orderData && orderData.length && orderData[0].target) | ||||
{ | { | ||||
if (orderData[0].target === attacker.id()) | if (orderData[0].target === attacker.id()) | ||||
continue; | continue; | ||||
let target = gameState.getEntityById(orderData[0].target); | let target = gameState.getEntityById(orderData[0].target); | ||||
if (target && !target.hasClass("Structure") && !target.hasClass("Support")) | if (target && !target.hasClasses(["Structure", "Support"])) | ||||
{ | { | ||||
if (!target.hasClass("Ranged") || !attacker.hasClass("Melee")) | if (!target.hasClass("Ranged") || !attacker.hasClass("Melee")) | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
let allowCapture = PETRA.allowCapture(gameState, ourUnit, attacker); | let allowCapture = PETRA.allowCapture(gameState, ourUnit, attacker); | ||||
if (ourUnit.canAttackTarget(attacker, allowCapture)) | if (ourUnit.canAttackTarget(attacker, allowCapture)) | ||||
{ | { | ||||
Show All 19 Lines | for (let ent of this.unitCollection.values()) | ||||
let targetId = orderData[0].target; | let targetId = orderData[0].target; | ||||
let target = gameState.getEntityById(targetId); | let target = gameState.getEntityById(targetId); | ||||
if (!target || target.hasClass("Structure")) | if (!target || target.hasClass("Structure")) | ||||
continue; | continue; | ||||
if (!(targetId in unitTargets)) | if (!(targetId in unitTargets)) | ||||
{ | { | ||||
if (PETRA.isSiegeUnit(target) || target.hasClass("Hero")) | if (PETRA.isSiegeUnit(target) || target.hasClass("Hero")) | ||||
unitTargets[targetId] = -8; | unitTargets[targetId] = -8; | ||||
else if (target.hasClass("Champion") || target.hasClass("Ship")) | else if (target.hasClasses(["Champion", "Ship"])) | ||||
unitTargets[targetId] = -5; | unitTargets[targetId] = -5; | ||||
else | else | ||||
unitTargets[targetId] = -3; | unitTargets[targetId] = -3; | ||||
} | } | ||||
++unitTargets[targetId]; | ++unitTargets[targetId]; | ||||
} | } | ||||
let veto = {}; | let veto = {}; | ||||
for (let target in unitTargets) | for (let target in unitTargets) | ||||
if (unitTargets[target] > 0) | if (unitTargets[target] > 0) | ||||
veto[target] = true; | veto[target] = true; | ||||
let targetClassesUnit; | let targetClassesUnit; | ||||
let targetClassesSiege; | let targetClassesSiege; | ||||
if (this.type == "Rush") | if (this.type == "Rush") | ||||
targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall", "Tower", "Fortress"], "vetoEntities": veto }; | targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall", "Tower", "Fortress"], "vetoEntities": veto }; | ||||
else | else | ||||
{ | { | ||||
if (this.target.hasClass("Fortress")) | if (this.target.hasClass("Fortress")) | ||||
targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall"], "vetoEntities": veto }; | targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall"], "vetoEntities": veto }; | ||||
else if (this.target.hasClass("Palisade") || this.target.hasClass("Wall")) | else if (this.target.hasClasses(["Palisade", "Wall"])) | ||||
targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Fortress"], "vetoEntities": veto }; | targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Fortress"], "vetoEntities": veto }; | ||||
else | else | ||||
targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall", "Fortress"], "vetoEntities": veto }; | targetClassesUnit = { "attack": ["Unit", "Structure"], "avoid": ["Palisade", "Wall", "Fortress"], "vetoEntities": veto }; | ||||
} | } | ||||
if (this.target.hasClass("Structure")) | if (this.target.hasClass("Structure")) | ||||
targetClassesSiege = { "attack": ["Structure"], "avoid": [], "vetoEntities": veto }; | targetClassesSiege = { "attack": ["Structure"], "avoid": [], "vetoEntities": veto }; | ||||
else | else | ||||
targetClassesSiege = { "attack": ["Unit", "Structure"], "avoid": [], "vetoEntities": veto }; | targetClassesSiege = { "attack": ["Unit", "Structure"], "avoid": [], "vetoEntities": veto }; | ||||
▲ Show 20 Lines • Show All 139 Lines • ▼ Show 20 Lines | for (let check = 0; check < lgth; check++) | ||||
ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ||||
} | } | ||||
else | else | ||||
ent.attackMove(this.targetPos[0], this.targetPos[1], targetClassesSiege); | ent.attackMove(this.targetPos[0], this.targetPos[1], targetClassesSiege); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
let nearby = !ent.hasClass("FastMoving") && !ent.hasClass("Ranged"); | const nearby = !ent.hasClasses(["FastMoving", "Ranged"]); | ||||
let mUnit = enemyUnits.filter(enemy => { | let mUnit = enemyUnits.filter(enemy => { | ||||
if (!enemy.position() || !ent.canAttackTarget(enemy, PETRA.allowCapture(gameState, ent, enemy))) | if (!enemy.position() || !ent.canAttackTarget(enemy, PETRA.allowCapture(gameState, ent, enemy))) | ||||
return false; | return false; | ||||
if (enemy.hasClass("Animal")) | if (enemy.hasClass("Animal")) | ||||
return false; | return false; | ||||
if (nearby && enemy.hasClass("FemaleCitizen") && enemy.unitAIState().split(".")[1] == "FLEEING") | if (nearby && enemy.hasClass("FemaleCitizen") && enemy.unitAIState().split(".")[1] == "FLEEING") | ||||
return false; | return false; | ||||
let dist = API3.SquareVectorDistance(enemy.position(), ent.position()); | let dist = API3.SquareVectorDistance(enemy.position(), ent.position()); | ||||
if (dist > range) | if (dist > range) | ||||
return false; | return false; | ||||
if (PETRA.getLandAccess(gameState, enemy) != entAccess) | if (PETRA.getLandAccess(gameState, enemy) != entAccess) | ||||
return false; | return false; | ||||
// if already too much units targeting this enemy, let's continue towards our main target | // if already too much units targeting this enemy, let's continue towards our main target | ||||
if (veto[enemy.id()] && API3.SquareVectorDistance(this.targetPos, ent.position()) > 2500) | if (veto[enemy.id()] && API3.SquareVectorDistance(this.targetPos, ent.position()) > 2500) | ||||
return false; | return false; | ||||
enemy.setMetadata(PlayerID, "distance", Math.sqrt(dist)); | enemy.setMetadata(PlayerID, "distance", Math.sqrt(dist)); | ||||
return true; | return true; | ||||
}, this).toEntityArray(); | }, this).toEntityArray(); | ||||
if (mUnit.length) | if (mUnit.length) | ||||
{ | { | ||||
mUnit.sort((unitA, unitB) => { | mUnit.sort((unitA, unitB) => { | ||||
let vala = unitA.hasClass("Support") ? 50 : 0; | let vala = unitA.hasClass("Support") ? 50 : 0; | ||||
if (ent.countersClasses(unitA.classes())) | if (ent.counters(unitA)) | ||||
vala += 100; | vala += 100; | ||||
let valb = unitB.hasClass("Support") ? 50 : 0; | let valb = unitB.hasClass("Support") ? 50 : 0; | ||||
if (ent.countersClasses(unitB.classes())) | if (ent.counters(unitB)) | ||||
valb += 100; | valb += 100; | ||||
let distA = unitA.getMetadata(PlayerID, "distance"); | let distA = unitA.getMetadata(PlayerID, "distance"); | ||||
let distB = unitB.getMetadata(PlayerID, "distance"); | let distB = unitB.getMetadata(PlayerID, "distance"); | ||||
if (distA && distB) | if (distA && distB) | ||||
{ | { | ||||
vala -= distA; | vala -= distA; | ||||
valb -= distB; | valb -= distB; | ||||
} | } | ||||
Show All 10 Lines | for (let check = 0; check < lgth; check++) | ||||
// cannot attack. See similar behaviour at #5741. | // cannot attack. See similar behaviour at #5741. | ||||
else if (this.isBlocked && ent.canAttackTarget(this.target, false)) | else if (this.isBlocked && ent.canAttackTarget(this.target, false)) | ||||
ent.attack(this.target.id(), false); | ent.attack(this.target.id(), false); | ||||
else if (API3.SquareVectorDistance(this.targetPos, ent.position()) > 2500) | else if (API3.SquareVectorDistance(this.targetPos, ent.position()) > 2500) | ||||
{ | { | ||||
let targetClasses = targetClassesUnit; | let targetClasses = targetClassesUnit; | ||||
if (maybeUpdate && ent.unitAIState() === "INDIVIDUAL.COMBAT.APPROACHING") // we may be blocked by walls, attack everything | if (maybeUpdate && ent.unitAIState() === "INDIVIDUAL.COMBAT.APPROACHING") // we may be blocked by walls, attack everything | ||||
{ | { | ||||
if (!ent.hasClass("Ranged") && !ent.hasClass("Ship")) | if (!ent.hasClasses(["Ranged", "Ship"])) | ||||
targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto }; | targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto }; | ||||
else | else | ||||
targetClasses = { "attack": ["Unit", "Structure"], "vetoEntities": veto }; | targetClasses = { "attack": ["Unit", "Structure"], "vetoEntities": veto }; | ||||
} | } | ||||
else if (!ent.hasClass("Ranged") && !ent.hasClass("Ship")) | else if (!ent.hasClasses(["Ranged", "Ship"])) | ||||
targetClasses = { "attack": targetClassesUnit.attack, "avoid": targetClassesUnit.avoid.concat("Ship"), "vetoEntities": veto }; | targetClasses = { "attack": targetClassesUnit.attack, "avoid": targetClassesUnit.avoid.concat("Ship"), "vetoEntities": veto }; | ||||
ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
let mStruct = enemyStructures.filter(enemy => { | let mStruct = enemyStructures.filter(enemy => { | ||||
if (this.isBlocked && enemy.id() != this.target.id()) | if (this.isBlocked && enemy.id() != this.target.id()) | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 507 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator