Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/ai/petra/attackPlan.js
Show First 20 Lines • Show All 1,328 Lines • ▼ Show 20 Lines | for (let evt of events.Attacked) | ||||
} | } | ||||
if (m.isSiegeUnit(ourUnit)) | if (m.isSiegeUnit(ourUnit)) | ||||
{ // if our siege units are attacked, we'll send some units to deal with enemies. | { // if our siege units are attacked, we'll send some units to deal with enemies. | ||||
let collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5); | let collec = this.unitCollection.filter(API3.Filters.not(API3.Filters.byClass("Siege"))).filterNearest(ourUnit.position(), 5); | ||||
for (let ent of collec.values()) | for (let ent of collec.values()) | ||||
{ | { | ||||
if (m.isSiegeUnit(ent)) // needed as mauryan elephants are not filtered out | if (m.isSiegeUnit(ent)) // needed as mauryan elephants are not filtered out | ||||
continue; | continue; | ||||
ent.attack(attacker.id(), m.allowCapture(gameState, ent, attacker)); | ent.attack(attacker.id(), m.getPrefAttackTypes(gameState, ent, attacker)); | ||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ||||
} | } | ||||
// And if this attacker is a non-ranged siege unit and our unit also, attack it | // And if this attacker is a non-ranged siege unit and our unit also, attack it | ||||
if (m.isSiegeUnit(attacker) && attacker.hasClass("Melee") && ourUnit.hasClass("Melee")) | if (m.isSiegeUnit(attacker) && attacker.hasClass("Melee") && ourUnit.hasClass("Melee")) | ||||
{ | { | ||||
ourUnit.attack(attacker.id(), m.allowCapture(gameState, ourUnit, attacker)); | ourUnit.attack(attacker.id(), m.getPrefAttackTypes(gameState, ourUnit, attacker)); | ||||
ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged")) | if (this.isBlocked && !ourUnit.hasClass("Ranged") && attacker.hasClass("Ranged")) | ||||
{ | { | ||||
// do not react if our melee units are attacked by ranged one and we are blocked by walls | // do not react if our melee units are attacked by ranged one and we are blocked by walls | ||||
// TODO check that the attacker is from behind the wall | // TODO check that the attacker is from behind the wall | ||||
continue; | continue; | ||||
} | } | ||||
else if (m.isSiegeUnit(attacker)) | else if (m.isSiegeUnit(attacker)) | ||||
{ // if our unit is attacked by a siege unit, we'll send some melee units to help it. | { // if our unit is attacked by a siege unit, we'll send some melee units to help it. | ||||
let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5); | let collec = this.unitCollection.filter(API3.Filters.byClass("Melee")).filterNearest(ourUnit.position(), 5); | ||||
for (let ent of collec.values()) | for (let ent of collec.values()) | ||||
{ | { | ||||
ent.attack(attacker.id(), m.allowCapture(gameState, ent, attacker)); | ent.attack(attacker.id(), m.getPrefAttackTypes(gameState, ent, attacker)); | ||||
ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ent.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// Look first for nearby units to help us if possible | // Look first for nearby units to help us if possible | ||||
let collec = this.unitCollection.filterNearest(ourUnit.position(), 2); | let collec = this.unitCollection.filterNearest(ourUnit.position(), 2); | ||||
for (let ent of collec.values()) | for (let ent of collec.values()) | ||||
{ | { | ||||
if (m.isSiegeUnit(ent)) | if (m.isSiegeUnit(ent)) | ||||
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.hasClass("Structure") && !target.hasClass("Support")) | ||||
continue; | continue; | ||||
} | } | ||||
ent.attack(attacker.id(), m.allowCapture(gameState, ent, attacker)); | ent.attack(attacker.id(), m.getPrefAttackTypes(gameState, ent, attacker)); | ||||
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.hasClass("Structure") && !target.hasClass("Support")) | ||||
{ | { | ||||
if (!target.hasClass("Ranged") || !attacker.hasClass("Melee")) | if (!target.hasClass("Ranged") || !attacker.hasClass("Melee")) | ||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
ourUnit.attack(attacker.id(), m.allowCapture(gameState, ourUnit, attacker)); | ourUnit.attack(attacker.id(), m.getPrefAttackTypes(gameState, ourUnit, attacker)); | ||||
ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ourUnit.setMetadata(PlayerID, "lastAttackPlanUpdateTime", time); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
let enemyUnits = gameState.getEnemyUnits(this.targetPlayer); | let enemyUnits = gameState.getEnemyUnits(this.targetPlayer); | ||||
let enemyStructures = gameState.getEnemyStructures(this.targetPlayer); | let enemyStructures = gameState.getEnemyStructures(this.targetPlayer); | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | for (let check = 0; check < lgth; check++) | ||||
valb += 10000; | valb += 10000; | ||||
else if (structb.hasDefensiveFire()) | else if (structb.hasDefensiveFire()) | ||||
valb += 1000; | valb += 1000; | ||||
else if (structb.hasClass("ConquestCritical")) | else if (structb.hasClass("ConquestCritical")) | ||||
valb += 200; | valb += 200; | ||||
return valb - vala; | return valb - vala; | ||||
}); | }); | ||||
if (mStruct[0].hasClass("Gates")) | if (mStruct[0].hasClass("Gates")) | ||||
ent.attack(mStruct[0].id(), m.allowCapture(gameState, ent, mStruct[0])); | ent.attack(mStruct[0].id(), m.getPrefAttackTypes(gameState, ent, mStruct[0])); | ||||
else | else | ||||
{ | { | ||||
let rand = randIntExclusive(0, mStruct.length * 0.2); | let rand = randIntExclusive(0, mStruct.length * 0.2); | ||||
ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand])); | ent.attack(mStruct[rand].id(), m.getPrefAttackTypes(gameState, ent, mStruct[rand])); | ||||
} | } | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if (!ent.hasClass("Ranged")) | if (!ent.hasClass("Ranged")) | ||||
{ | { | ||||
let targetClasses = { "attack": targetClassesSiege.attack, "avoid": targetClassesSiege.avoid.concat("Ship"), "vetoEntities": veto }; | let targetClasses = { "attack": targetClassesSiege.attack, "avoid": targetClassesSiege.avoid.concat("Ship"), "vetoEntities": veto }; | ||||
ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ent.attackMove(this.targetPos[0], this.targetPos[1], targetClasses); | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | for (let check = 0; check < lgth; check++) | ||||
} | } | ||||
if (veto[unitA.id()]) | if (veto[unitA.id()]) | ||||
vala -= 20000; | vala -= 20000; | ||||
if (veto[unitB.id()]) | if (veto[unitB.id()]) | ||||
valb -= 20000; | valb -= 20000; | ||||
return valb - vala; | return valb - vala; | ||||
}); | }); | ||||
let rand = randIntExclusive(0, mUnit.length * 0.1); | let rand = randIntExclusive(0, mUnit.length * 0.1); | ||||
ent.attack(mUnit[rand].id(), m.allowCapture(gameState, ent, mUnit[rand])); | ent.attack(mUnit[rand].id(), m.getPrefAttackTypes(gameState, ent, mUnit[rand])); | ||||
} | } | ||||
else if (this.isBlocked) | else if (this.isBlocked) | ||||
ent.attack(this.target.id(), false); | ent.attack(this.target.id(), ["!Capture"]); | ||||
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.hasClass("Ranged") && !ent.hasClass("Ship")) | ||||
targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto }; | targetClasses = { "attack": ["Unit", "Structure"], "avoid": ["Ship"], "vetoEntities": veto }; | ||||
else | else | ||||
Show All 27 Lines | for (let check = 0; check < lgth; check++) | ||||
let valb = structb.costSum(); | let valb = structb.costSum(); | ||||
if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall")) | if (structb.hasClass("Gates") && ent.canAttackClass("StoneWall")) | ||||
valb += 10000; | valb += 10000; | ||||
else if (structb.hasClass("ConquestCritical")) | else if (structb.hasClass("ConquestCritical")) | ||||
valb += 100; | valb += 100; | ||||
return valb - vala; | return valb - vala; | ||||
}); | }); | ||||
if (mStruct[0].hasClass("Gates")) | if (mStruct[0].hasClass("Gates")) | ||||
ent.attack(mStruct[0].id(), false); | ent.attack(mStruct[0].id(), ["!Capture"]); | ||||
else | else | ||||
{ | { | ||||
let rand = randIntExclusive(0, mStruct.length * 0.2); | let rand = randIntExclusive(0, mStruct.length * 0.2); | ||||
ent.attack(mStruct[rand].id(), m.allowCapture(gameState, ent, mStruct[rand])); | ent.attack(mStruct[rand].id(), m.getPrefAttackTypes(gameState, ent, mStruct[rand])); | ||||
} | } | ||||
} | } | ||||
else if (needsUpdate) // really nothing let's try to help our nearest unit | else if (needsUpdate) // really nothing let's try to help our nearest unit | ||||
{ | { | ||||
let distmin = Math.min(); | let distmin = Math.min(); | ||||
let attacker; | let attacker; | ||||
this.unitCollection.forEach(unit => { | this.unitCollection.forEach(unit => { | ||||
if (!unit.position()) | if (!unit.position()) | ||||
return; | return; | ||||
if (unit.unitAIState().split(".")[1] != "COMBAT" || !unit.unitAIOrderData().length || | if (unit.unitAIState().split(".")[1] != "COMBAT" || !unit.unitAIOrderData().length || | ||||
!unit.unitAIOrderData()[0].target) | !unit.unitAIOrderData()[0].target) | ||||
return; | return; | ||||
if (!gameState.getEntityById(unit.unitAIOrderData()[0].target)) | if (!gameState.getEntityById(unit.unitAIOrderData()[0].target)) | ||||
return; | return; | ||||
let dist = API3.SquareVectorDistance(unit.position(), ent.position()); | let dist = API3.SquareVectorDistance(unit.position(), ent.position()); | ||||
if (dist > distmin) | if (dist > distmin) | ||||
return; | return; | ||||
distmin = dist; | distmin = dist; | ||||
attacker = gameState.getEntityById(unit.unitAIOrderData()[0].target); | attacker = gameState.getEntityById(unit.unitAIOrderData()[0].target); | ||||
}); | }); | ||||
if (attacker) | if (attacker) | ||||
ent.attack(attacker.id(), m.allowCapture(gameState, ent, attacker)); | ent.attack(attacker.id(), m.getPrefAttackTypes(gameState, ent, attacker)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
this.unitCollUpdateArray.splice(0, lgth); | this.unitCollUpdateArray.splice(0, lgth); | ||||
this.startingAttack = false; | this.startingAttack = false; | ||||
// check if this enemy has resigned | // check if this enemy has resigned | ||||
Show All 36 Lines | for (let evt of events.Attacked) | ||||
if (!attacker || !gameState.getEntityById(evt.target)) | if (!attacker || !gameState.getEntityById(evt.target)) | ||||
continue; | continue; | ||||
for (let ent of this.unitCollection.values()) | for (let ent of this.unitCollection.values()) | ||||
{ | { | ||||
if (ent.getMetadata(PlayerID, "transport") !== undefined) | if (ent.getMetadata(PlayerID, "transport") !== undefined) | ||||
continue; | continue; | ||||
if (!ent.isIdle()) | if (!ent.isIdle()) | ||||
continue; | continue; | ||||
ent.attack(attacker.id(), m.allowCapture(gameState, ent, attacker)); | ent.attack(attacker.id(), m.getPrefAttackTypes(gameState, ent, attacker)); | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
}; | }; | ||||
m.AttackPlan.prototype.UpdateWalking = function(gameState, events) | m.AttackPlan.prototype.UpdateWalking = function(gameState, events) | ||||
{ | { | ||||
// we're marching towards the target | // we're marching towards the target | ||||
▲ Show 20 Lines • Show All 395 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator