Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 387 Lines • ▼ Show 20 Lines | "Order.Attack": function(msg) { | ||||
// Check the target is alive | // Check the target is alive | ||||
if (!this.TargetIsAlive(this.order.data.target)) | if (!this.TargetIsAlive(this.order.data.target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// Work out how to attack the given target | // Work out how to attack the given target | ||||
var type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.allowCapture); | var type = this.GetBestAttackAgainst(this.order.data.target, this.order.data.prefAttackTypes); | ||||
if (!type) | if (!type) | ||||
{ | { | ||||
// Oops, we can't attack at all | // Oops, we can't attack at all | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
this.order.data.attackType = type; | this.order.data.attackType = type; | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | "Order.Heal": function(msg) { | ||||
this.SetNextState("INDIVIDUAL.HEAL.APPROACHING"); | this.SetNextState("INDIVIDUAL.HEAL.APPROACHING"); | ||||
}, | }, | ||||
"Order.Gather": function(msg) { | "Order.Gather": function(msg) { | ||||
// If the target is still alive, we need to kill it first | // If the target is still alive, we need to kill it first | ||||
if (this.MustKillGatherTarget(this.order.data.target)) | if (this.MustKillGatherTarget(this.order.data.target)) | ||||
{ | { | ||||
// Make sure we can attack the target, else we'll get very stuck | // Make sure we can attack the target, else we'll get very stuck | ||||
if (!this.GetBestAttackAgainst(this.order.data.target, false)) | if (!this.GetBestAttackAgainst(this.order.data.target, ["!Capture"])) | ||||
{ | { | ||||
// Oops, we can't attack at all - give up | // Oops, we can't attack at all - give up | ||||
// TODO: should do something so the player knows why this failed | // TODO: should do something so the player knows why this failed | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// The target was visible when this order was issued, | // The target was visible when this order was issued, | ||||
// but could now be invisible again. | // but could now be invisible again. | ||||
if (!this.CheckTargetVisible(this.order.data.target)) | if (!this.CheckTargetVisible(this.order.data.target)) | ||||
{ | { | ||||
if (this.order.data.secondTry === undefined) | if (this.order.data.secondTry === undefined) | ||||
{ | { | ||||
this.order.data.secondTry = true; | this.order.data.secondTry = true; | ||||
this.PushOrderFront("Walk", this.order.data.lastPos); | this.PushOrderFront("Walk", this.order.data.lastPos); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
// We couldn't move there, or the target moved away | // We couldn't move there, or the target moved away | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
this.PushOrderFront("Attack", { "target": this.order.data.target, "force": !!this.order.data.force, "hunting": true, "allowCapture": false }); | this.PushOrderFront("Attack", { "target": this.order.data.target, "force": !!this.order.data.force, "hunting": true, "prefAttackTypes": ["!Capture"] }); | ||||
return; | return; | ||||
} | } | ||||
this.RememberTargetPosition(); | this.RememberTargetPosition(); | ||||
if (!this.order.data.initPos) | if (!this.order.data.initPos) | ||||
this.order.data.initPos = this.order.data.lastPos; | this.order.data.initPos = this.order.data.lastPos; | ||||
if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer)) | if (this.CheckTargetRange(this.order.data.target, IID_ResourceGatherer)) | ||||
▲ Show 20 Lines • Show All 164 Lines • ▼ Show 20 Lines | "Order.Stop": function(msg) { | ||||
if (!this.IsAttackingAsFormation()) | if (!this.IsAttackingAsFormation()) | ||||
this.CallMemberFunction("Stop", [false]); | this.CallMemberFunction("Stop", [false]); | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
"Order.Attack": function(msg) { | "Order.Attack": function(msg) { | ||||
var target = msg.data.target; | var target = msg.data.target; | ||||
var allowCapture = msg.data.allowCapture; | |||||
var cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI); | var cmpTargetUnitAI = Engine.QueryInterface(target, IID_UnitAI); | ||||
if (cmpTargetUnitAI && cmpTargetUnitAI.IsFormationMember()) | if (cmpTargetUnitAI && cmpTargetUnitAI.IsFormationMember()) | ||||
target = cmpTargetUnitAI.GetFormationController(); | target = cmpTargetUnitAI.GetFormationController(); | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
// Check if we are already in range, otherwise walk there | // Check if we are already in range, otherwise walk there | ||||
if (!this.CheckTargetAttackRange(target, target)) | if (!this.CheckTargetAttackRange(target, target)) | ||||
{ | { | ||||
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | ||||
{ | { | ||||
this.SetNextState("COMBAT.APPROACHING"); | this.SetNextState("COMBAT.APPROACHING"); | ||||
return; | return; | ||||
} | } | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
this.CallMemberFunction("Attack", [target, allowCapture, false]); | this.CallMemberFunction("Attack", [target, msg.data.prefAttackTypes, false]); | ||||
if (cmpAttack.CanAttackAsFormation()) | if (cmpAttack.CanAttackAsFormation()) | ||||
this.SetNextState("COMBAT.ATTACKING"); | this.SetNextState("COMBAT.ATTACKING"); | ||||
else | else | ||||
this.SetNextState("MEMBER"); | this.SetNextState("MEMBER"); | ||||
}, | }, | ||||
"Order.Garrison": function(msg) { | "Order.Garrison": function(msg) { | ||||
if (!Engine.QueryInterface(msg.data.target, IID_GarrisonHolder)) | if (!Engine.QueryInterface(msg.data.target, IID_GarrisonHolder)) | ||||
Show All 34 Lines | "Order.Gather": function(msg) { | ||||
else | else | ||||
{ | { | ||||
// We couldn't move there, or the target moved away | // We couldn't move there, or the target moved away | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
this.PushOrderFront("Attack", { "target": msg.data.target, "force": !!msg.data.force, "hunting": true, "allowCapture": false, "min": 0, "max": 10 }); | this.PushOrderFront("Attack", { "target": msg.data.target, "force": !!msg.data.force, "hunting": true, "allowCapture": ["!Capture"], "min": 0, "max": 10 }); | ||||
return; | return; | ||||
} | } | ||||
// TODO: on what should we base this range? | // TODO: on what should we base this range? | ||||
// Check if we are already in range, otherwise walk there | // Check if we are already in range, otherwise walk there | ||||
if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) | if (!this.CheckTargetRangeExplicit(msg.data.target, 0, 10)) | ||||
{ | { | ||||
if (!this.CanGather(msg.data.target) || !this.CheckTargetVisible(msg.data.target)) | if (!this.CanGather(msg.data.target) || !this.CheckTargetVisible(msg.data.target)) | ||||
▲ Show 20 Lines • Show All 162 Lines • ▼ Show 20 Lines | "PATROL": { | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
if (!this.patrolStartPosOrder) | if (!this.patrolStartPosOrder) | ||||
{ | { | ||||
this.patrolStartPosOrder = cmpPosition.GetPosition(); | this.patrolStartPosOrder = cmpPosition.GetPosition(); | ||||
this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | ||||
this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | this.patrolStartPosOrder.prefAttackTypes = this.order.data.prefAttackTypes; | ||||
} | } | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
this.CallMemberFunction("Attack", [this.order.data.target, this.order.data.allowCapture, false]); | this.CallMemberFunction("Attack", [this.order.data.target, this.order.data.prefAttackTypes, false]); | ||||
if (cmpAttack.CanAttackAsFormation()) | if (cmpAttack.CanAttackAsFormation()) | ||||
this.SetNextState("COMBAT.ATTACKING"); | this.SetNextState("COMBAT.ATTACKING"); | ||||
else | else | ||||
this.SetNextState("MEMBER"); | this.SetNextState("MEMBER"); | ||||
}, | }, | ||||
}, | }, | ||||
"ATTACKING": { | "ATTACKING": { | ||||
// Wait for individual members to finish | // Wait for individual members to finish | ||||
"enter": function(msg) { | "enter": function(msg) { | ||||
var target = this.order.data.target; | var target = this.order.data.target; | ||||
var allowCapture = this.order.data.allowCapture; | |||||
// Check if we are already in range, otherwise walk there | // Check if we are already in range, otherwise walk there | ||||
if (!this.CheckTargetAttackRange(target, target)) | if (!this.CheckTargetAttackRange(target, target)) | ||||
{ | { | ||||
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": allowCapture }); | this.PushOrderFront("Attack", { "target": target, "force": false, "prefAttackTypes": this.order.data.prefAttackTypes }); | ||||
return true; | return true; | ||||
} | } | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
// TODO fix the rearranging while attacking as formation | // TODO fix the rearranging while attacking as formation | ||||
cmpFormation.SetRearrange(!this.IsAttackingAsFormation()); | cmpFormation.SetRearrange(!this.IsAttackingAsFormation()); | ||||
cmpFormation.MoveMembersIntoFormation(false, false); | cmpFormation.MoveMembersIntoFormation(false, false); | ||||
this.StartTimer(200, 200); | this.StartTimer(200, 200); | ||||
return false; | return false; | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
var target = this.order.data.target; | var target = this.order.data.target; | ||||
var allowCapture = this.order.data.allowCapture; | |||||
// Check if we are already in range, otherwise walk there | // Check if we are already in range, otherwise walk there | ||||
if (!this.CheckTargetAttackRange(target, target)) | if (!this.CheckTargetAttackRange(target, target)) | ||||
{ | { | ||||
if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | if (this.TargetIsAlive(target) && this.CheckTargetVisible(target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": allowCapture }); | this.PushOrderFront("Attack", { "target": target, "force": false, "prefAttackTypes": this.order.data.prefAttackTypes }); | ||||
return; | return; | ||||
} | } | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
}, | }, | ||||
"leave": function(msg) { | "leave": function(msg) { | ||||
▲ Show 20 Lines • Show All 215 Lines • ▼ Show 20 Lines | "GuardedAttacked": function(msg) { | ||||
if (cmpBuildingAI && this.CanRepair(this.isGuardOf)) | if (cmpBuildingAI && this.CanRepair(this.isGuardOf)) | ||||
{ | { | ||||
this.PushOrderFront("Repair", { "target": this.isGuardOf, "autocontinue": false, "force": false }); | this.PushOrderFront("Repair", { "target": this.isGuardOf, "autocontinue": false, "force": false }); | ||||
return; | return; | ||||
} | } | ||||
// target the unit | // target the unit | ||||
if (this.CheckTargetVisible(msg.data.attacker)) | if (this.CheckTargetVisible(msg.data.attacker)) | ||||
this.PushOrderFront("Attack", { "target": msg.data.attacker, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": msg.data.attacker, "force": false, "prefAttackTypes": ["Capture"] }); | ||||
else | else | ||||
{ | { | ||||
var cmpPosition = Engine.QueryInterface(msg.data.attacker, IID_Position); | var cmpPosition = Engine.QueryInterface(msg.data.attacker, IID_Position); | ||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | if (!cmpPosition || !cmpPosition.IsInWorld()) | ||||
return; | return; | ||||
var pos = cmpPosition.GetPosition(); | var pos = cmpPosition.GetPosition(); | ||||
this.PushOrderFront("WalkAndFight", { "x": pos.x, "z": pos.z, "target": msg.data.attacker, "force": false }); | this.PushOrderFront("WalkAndFight", { "x": pos.x, "z": pos.z, "target": msg.data.attacker, "force": false }); | ||||
// if we already had a WalkAndFight, keep only the most recent one in case the target has moved | // if we already had a WalkAndFight, keep only the most recent one in case the target has moved | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | "PATROL": { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
if (!this.patrolStartPosOrder) | if (!this.patrolStartPosOrder) | ||||
{ | { | ||||
this.patrolStartPosOrder = cmpPosition.GetPosition(); | this.patrolStartPosOrder = cmpPosition.GetPosition(); | ||||
this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | ||||
this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | this.patrolStartPosOrder.prefAttackTypes = this.order.data.prefAttackTypes; | ||||
} | } | ||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
▲ Show 20 Lines • Show All 386 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
} | } | ||||
}, | }, | ||||
// TODO: respond to target deaths immediately, rather than waiting | // TODO: respond to target deaths immediately, rather than waiting | ||||
// until the next Timer event | // until the next Timer event | ||||
"Attacked": function(msg) { | "Attacked": function(msg) { | ||||
// If we are capturing and are attacked by something that we would not capture, attack that entity instead | // If we are capturing and are attacked by something that we would not capture, attack that entity instead | ||||
// TODO find out why we want this | |||||
if (this.order.data.attackType == "Capture" && (this.GetStance().targetAttackersAlways || !this.order.data.force) | if (this.order.data.attackType == "Capture" && (this.GetStance().targetAttackersAlways || !this.order.data.force) | ||||
&& this.order.data.target != msg.data.attacker && this.GetBestAttackAgainst(msg.data.attacker, true) != "Capture") | && this.order.data.target != msg.data.attacker && this.GetBestAttackAgainst(msg.data.attacker, ["Capture"]) != "Capture") | ||||
this.RespondToTargetedEntities([msg.data.attacker]); | this.RespondToTargetedEntities([msg.data.attacker]); | ||||
}, | }, | ||||
}, | }, | ||||
"FINDINGNEWTARGET": { | "FINDINGNEWTARGET": { | ||||
"enter": function() { | "enter": function() { | ||||
// If we're targetting a formation, find a new member of that formation. | // If we're targetting a formation, find a new member of that formation. | ||||
let cmpTargetFormation = Engine.QueryInterface(this.order.data.formationTarget || INVALID_ENTITY, IID_Formation); | let cmpTargetFormation = Engine.QueryInterface(this.order.data.formationTarget || INVALID_ENTITY, IID_Formation); | ||||
▲ Show 20 Lines • Show All 2,488 Lines • ▼ Show 20 Lines | if (!cmpVision) | ||||
return false; | return false; | ||||
var range = cmpVision.GetRange(); | var range = cmpVision.GetRange(); | ||||
var distance = DistanceBetweenEntities(this.entity, target); | var distance = DistanceBetweenEntities(this.entity, target); | ||||
return distance < range; | return distance < range; | ||||
}; | }; | ||||
UnitAI.prototype.GetBestAttackAgainst = function(target, allowCapture) | UnitAI.prototype.GetBestAttackAgainst = function(target, prefAttackTypes) | ||||
{ | { | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
if (!cmpAttack) | if (!cmpAttack) | ||||
return undefined; | return undefined; | ||||
return cmpAttack.GetBestAttackAgainst(target, allowCapture); | return cmpAttack.GetBestAttackAgainst(target, prefAttackTypes); | ||||
}; | }; | ||||
/** | /** | ||||
* Try to find one of the given entities which can be attacked, | * Try to find one of the given entities which can be attacked, | ||||
* and start attacking it. | * and start attacking it. | ||||
* Returns true if it found something to attack. | * Returns true if it found something to attack. | ||||
*/ | */ | ||||
UnitAI.prototype.AttackVisibleEntity = function(ents) | UnitAI.prototype.AttackVisibleEntity = function(ents) | ||||
{ | { | ||||
var target = ents.find(target => this.CanAttack(target)); | var target = ents.find(target => this.CanAttack(target)); | ||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": target, "force": false, "prefAttackTypes": ["Capture"] }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
* Try to find one of the given entities which can be attacked | * Try to find one of the given entities which can be attacked | ||||
* and which is close to the hold position, and start attacking it. | * and which is close to the hold position, and start attacking it. | ||||
* Returns true if it found something to attack. | * Returns true if it found something to attack. | ||||
*/ | */ | ||||
UnitAI.prototype.AttackEntityInZone = function(ents) | UnitAI.prototype.AttackEntityInZone = function(ents) | ||||
{ | { | ||||
var target = ents.find(target => | var target = ents.find(target => | ||||
this.CanAttack(target) | this.CanAttack(target) | ||||
&& this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true)) | && this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, ["Capture"])) | ||||
&& (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | && (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | ||||
); | ); | ||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": target, "force": false, "prefAttackTypes": ["Capture"] }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
* Try to respond appropriately given our current stance, | * Try to respond appropriately given our current stance, | ||||
* given a list of entities that match our stance's target criteria. | * given a list of entities that match our stance's target criteria. | ||||
* Returns true if it responded. | * Returns true if it responded. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 377 Lines • ▼ Show 20 Lines | UnitAI.prototype.WalkToTarget = function(target, queued) | ||||
this.AddOrder("WalkToTarget", { "target": target, "force": true }, queued); | this.AddOrder("WalkToTarget", { "target": target, "force": true }, queued); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds walk-and-fight order to queue, this only occurs in response | * Adds walk-and-fight order to queue, this only occurs in response | ||||
* to a player order, and so is forced. | * to a player order, and so is forced. | ||||
* If targetClasses is given, only entities matching the targetClasses can be attacked. | * If targetClasses is given, only entities matching the targetClasses can be attacked. | ||||
*/ | */ | ||||
UnitAI.prototype.WalkAndFight = function(x, z, targetClasses, allowCapture = true, queued = false) | UnitAI.prototype.WalkAndFight = function(x, z, targetClasses, prefAttackTypes = ["Capture"], queued = false) | ||||
{ | { | ||||
this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "allowCapture": allowCapture, "force": true }, queued); | this.AddOrder("WalkAndFight", { "x": x, "z": z, "targetClasses": targetClasses, "prefAttackTypes": prefAttackTypes, "force": true }, queued); | ||||
}; | }; | ||||
UnitAI.prototype.Patrol = function(x, z, targetClasses, allowCapture = true, queued = false) | UnitAI.prototype.Patrol = function(x, z, targetClasses, prefAttackTypes = ["Capture"], queued = false) | ||||
{ | { | ||||
if (!this.CanPatrol()) | if (!this.CanPatrol()) | ||||
{ | { | ||||
this.Walk(x, z, queued); | this.Walk(x, z, queued); | ||||
return; | return; | ||||
} | } | ||||
this.AddOrder("Patrol", { "x": x, "z": z, "targetClasses": targetClasses, "allowCapture": allowCapture, "force": true }, queued); | this.AddOrder("Patrol", { "x": x, "z": z, "targetClasses": targetClasses, "prefAttackTypes": prefAttackTypes, "force": true }, queued); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds leave foundation order to queue, treated as forced. | * Adds leave foundation order to queue, treated as forced. | ||||
*/ | */ | ||||
UnitAI.prototype.LeaveFoundation = function(target) | UnitAI.prototype.LeaveFoundation = function(target) | ||||
{ | { | ||||
// If we're already being told to leave a foundation, then | // If we're already being told to leave a foundation, then | ||||
// ignore this new request so we don't end up being too indecisive | // ignore this new request so we don't end up being too indecisive | ||||
// to ever actually move anywhere | // to ever actually move anywhere | ||||
// Ignore also the request if we are packing | // Ignore also the request if we are packing | ||||
if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target) || this.IsPacking())) | if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target) || this.IsPacking())) | ||||
return; | return; | ||||
this.PushOrderFront("LeaveFoundation", { "target": target, "force": true }); | this.PushOrderFront("LeaveFoundation", { "target": target, "force": true }); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds attack order to the queue, forced by the player. | * Adds attack order to the queue, forced by the player. | ||||
*/ | */ | ||||
UnitAI.prototype.Attack = function(target, allowCapture = true, queued = false) | UnitAI.prototype.Attack = function(target, prefAttackTypes = ["Capture"], queued = false) | ||||
{ | { | ||||
if (!this.CanAttack(target)) | if (!this.CanAttack(target)) | ||||
{ | { | ||||
// We don't want to let healers walk to the target unit so they can be easily killed. | // We don't want to let healers walk to the target unit so they can be easily killed. | ||||
// Instead we just let them get into healing range. | // Instead we just let them get into healing range. | ||||
if (this.IsHealer()) | if (this.IsHealer()) | ||||
this.MoveToTargetRange(target, IID_Heal); | this.MoveToTargetRange(target, IID_Heal); | ||||
else | else | ||||
this.WalkToTarget(target, queued); | this.WalkToTarget(target, queued); | ||||
return; | return; | ||||
} | } | ||||
let order = { | let order = { | ||||
"target": target, | "target": target, | ||||
"force": true, | "force": true, | ||||
"allowCapture": allowCapture, | "prefAttackTypes": prefAttackTypes, | ||||
}; | }; | ||||
this.RememberTargetPosition(order); | this.RememberTargetPosition(order); | ||||
this.AddOrder("Attack", order, queued); | this.AddOrder("Attack", order, queued); | ||||
}; | }; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 431 Lines • ▼ Show 20 Lines | for (var ent of cmpFormation.members) | ||||
continue; | continue; | ||||
if (targetClasses.avoid && cmpIdentity | if (targetClasses.avoid && cmpIdentity | ||||
&& MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | ||||
continue; | continue; | ||||
// Only used by the AIs to prevent some choices of targets | // Only used by the AIs to prevent some choices of targets | ||||
if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | ||||
continue; | continue; | ||||
} | } | ||||
this.PushOrderFront("Attack", { "target": targ, "force": false, "allowCapture": this.order.data.allowCapture }); | this.PushOrderFront("Attack", { "target": targ, "force": false, "prefAttackTypes": this.order.data.prefAttackTypes }); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
var targets = this.GetTargetsFromUnit(); | var targets = this.GetTargetsFromUnit(); | ||||
for (var targ of targets) | for (var targ of targets) | ||||
Show All 9 Lines | if (this.order.data.targetClasses) | ||||
continue; | continue; | ||||
if (cmpIdentity && targetClasses.avoid | if (cmpIdentity && targetClasses.avoid | ||||
&& MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | ||||
continue; | continue; | ||||
// Only used by the AIs to prevent some choices of targets | // Only used by the AIs to prevent some choices of targets | ||||
if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | ||||
continue; | continue; | ||||
} | } | ||||
this.PushOrderFront("Attack", { "target": targ, "force": false, "allowCapture": this.order.data.allowCapture }); | this.PushOrderFront("Attack", { "target": targ, "force": false, "prefAttackTypes": this.order.data.prefAttackTypes }); | ||||
return true; | return true; | ||||
} | } | ||||
// healers on a walk-and-fight order should heal injured units | // healers on a walk-and-fight order should heal injured units | ||||
if (this.IsHealer()) | if (this.IsHealer()) | ||||
return this.FindNewHealTargets(); | return this.FindNewHealTargets(); | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 509 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator