Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | UnitAI.prototype.UnitFsmSpec = { | ||||
"OrderTargetRenamed": function() { | "OrderTargetRenamed": function() { | ||||
// By default, trigger an exit-reenter | // By default, trigger an exit-reenter | ||||
// so that state preconditions are checked against the new entity | // so that state preconditions are checked against the new entity | ||||
// (there is no reason to assume the target is still valid). | // (there is no reason to assume the target is still valid). | ||||
this.SetNextState(this.GetCurrentState()); | this.SetNextState(this.GetCurrentState()); | ||||
}, | }, | ||||
"ResetHeldPosition": function() { | |||||
delete this.heldPosition; | |||||
}, | |||||
// Formation handlers: | // Formation handlers: | ||||
"FormationLeave": function(msg) { | "FormationLeave": function(msg) { | ||||
// ignore when we're not in FORMATIONMEMBER | // ignore when we're not in FORMATIONMEMBER | ||||
}, | }, | ||||
// Called when being told to walk as part of a formation | // Called when being told to walk as part of a formation | ||||
"Order.FormationWalk": function(msg) { | "Order.FormationWalk": function(msg) { | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | "Order.Walk": function(msg) { | ||||
// 1. If packed, we can move. | // 1. If packed, we can move. | ||||
// 2. If unpacked, we first need to pack, then follow case 1. | // 2. If unpacked, we first need to pack, then follow case 1. | ||||
if (this.CanPack()) | if (this.CanPack()) | ||||
{ | { | ||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||
return; | return; | ||||
} | } | ||||
this.SetHeldPosition(this.order.data.x, this.order.data.z); | |||||
// It's not too bad if we don't arrive at exactly the right position. | // It's not too bad if we don't arrive at exactly the right position. | ||||
this.order.data.relaxed = true; | this.order.data.relaxed = true; | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.WALKING"); | this.SetNextState("ANIMAL.WALKING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.WALKING"); | this.SetNextState("INDIVIDUAL.WALKING"); | ||||
}, | }, | ||||
Show All 9 Lines | "Order.WalkAndFight": function(msg) { | ||||
// 1. If packed, we can move. | // 1. If packed, we can move. | ||||
// 2. If unpacked, we first need to pack, then follow case 1. | // 2. If unpacked, we first need to pack, then follow case 1. | ||||
if (this.CanPack()) | if (this.CanPack()) | ||||
{ | { | ||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||
return; | return; | ||||
} | } | ||||
this.SetHeldPosition(this.order.data.x, this.order.data.z); | |||||
// It's not too bad if we don't arrive at exactly the right position. | // It's not too bad if we don't arrive at exactly the right position. | ||||
this.order.data.relaxed = true; | this.order.data.relaxed = true; | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.WALKING"); // WalkAndFight not applicable for animals | this.SetNextState("ANIMAL.WALKING"); // WalkAndFight not applicable for animals | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.WALKINGANDFIGHTING"); | this.SetNextState("INDIVIDUAL.WALKINGANDFIGHTING"); | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 368 Lines • ▼ Show 20 Lines | if (cmpPack && cmpPack.IsPacking() && cmpPack.IsPacked()) | ||||
cmpPack.CancelPack(); | cmpPack.CancelPack(); | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
// States for the special entity representing a group of units moving in formation: | // States for the special entity representing a group of units moving in formation: | ||||
"FORMATIONCONTROLLER": { | "FORMATIONCONTROLLER": { | ||||
"Order.Walk": function(msg) { | "Order.Walk": function(msg) { | ||||
this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]); | |||||
this.SetNextState("WALKING"); | this.SetNextState("WALKING"); | ||||
}, | }, | ||||
"Order.WalkAndFight": function(msg) { | "Order.WalkAndFight": function(msg) { | ||||
this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]); | |||||
this.SetNextState("WALKINGANDFIGHTING"); | this.SetNextState("WALKINGANDFIGHTING"); | ||||
}, | }, | ||||
"Order.MoveIntoFormation": function(msg) { | "Order.MoveIntoFormation": function(msg) { | ||||
this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]); | |||||
this.SetNextState("FORMING"); | this.SetNextState("FORMING"); | ||||
}, | }, | ||||
// Only used by other orders to walk there in formation | // Only used by other orders to walk there in formation | ||||
"Order.WalkToTargetRange": function(msg) { | "Order.WalkToTargetRange": function(msg) { | ||||
if (!this.CheckRange(this.order.data)) | if (!this.CheckRange(this.order.data)) | ||||
this.SetNextState("WALKING"); | this.SetNextState("WALKING"); | ||||
else | else | ||||
Show All 10 Lines | "FORMATIONCONTROLLER": { | ||||
"Order.WalkToPointRange": function(msg) { | "Order.WalkToPointRange": function(msg) { | ||||
if (!this.CheckRange(this.order.data)) | if (!this.CheckRange(this.order.data)) | ||||
this.SetNextState("WALKING"); | this.SetNextState("WALKING"); | ||||
else | else | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
"Order.Patrol": function(msg) { | "Order.Patrol": function(msg) { | ||||
this.CallMemberFunction("SetHeldPosition", [msg.data.x, msg.data.z]); | |||||
this.SetNextState("PATROL"); | this.SetNextState("PATROL"); | ||||
}, | }, | ||||
"Order.Guard": function(msg) { | "Order.Guard": function(msg) { | ||||
this.CallMemberFunction("Guard", [msg.data.target, false]); | this.CallMemberFunction("Guard", [msg.data.target, false]); | ||||
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
cmpFormation.Disband(); | cmpFormation.Disband(); | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 869 Lines • ▼ Show 20 Lines | "PATROL": { | ||||
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.allowCapture = this.order.data.allowCapture; | ||||
} | } | ||||
this.order.onPop = "ResetHeldPosition"; | |||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
delete this.patrolStartPosOrder; | delete this.patrolStartPosOrder; | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||
if (cmpPosition && cmpPosition.IsInWorld()) | |||||
{ | |||||
let pos = cmpPosition.GetPosition2D(); | |||||
this.heldPosition = { "x": pos.x, "z": pos.y }; | |||||
} | |||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
if (!msg.likelyFailure && !msg.likelySuccess && !this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange)) | if (!msg.likelyFailure && !msg.likelySuccess && !this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange)) | ||||
return; | return; | ||||
if (this.orderQueue.length == 1) | if (this.orderQueue.length == 1) | ||||
Show All 17 Lines | "GUARD": { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
// Show weapons rather than carried resources. | // Show weapons rather than carried resources. | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
this.SetHeldPositionOnEntity(this.isGuardOf); | let cmpGuardedPosition = Engine.QueryInterface(this.isGuardOf, IID_Position); | ||||
if (cmpGuardedPosition && cmpGuardedPosition.IsInWorld()) | |||||
{ | |||||
let pos = cmpGuardedPosition.GetPosition2D(); | |||||
this.heldPosition = { "x": pos.x, "z": pos.y }; | |||||
} | |||||
return false; | return false; | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
// Check the target is alive | // Check the target is alive | ||||
if (!this.TargetIsAlive(this.isGuardOf)) | if (!this.TargetIsAlive(this.isGuardOf)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// Adapt the speed to the one of the target if needed | // Adapt the speed to the one of the target if needed | ||||
let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | let cmpObstructionManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_ObstructionManager); | ||||
if (cmpObstructionManager.IsInTargetRange(this.entity, this.isGuardOf, 0, 3 * this.guardRange, false)) | if (cmpObstructionManager.IsInTargetRange(this.entity, this.isGuardOf, 0, 3 * this.guardRange, false)) | ||||
this.TryMatchTargetSpeed(this.isGuardOf, false); | this.TryMatchTargetSpeed(this.isGuardOf, false); | ||||
this.SetHeldPositionOnEntity(this.isGuardOf); | let cmpGuardedPosition = Engine.QueryInterface(this.isGuardOf, IID_Position); | ||||
if (cmpGuardedPosition && cmpGuardedPosition.IsInWorld()) | |||||
{ | |||||
let pos = cmpGuardedPosition.GetPosition2D(); | |||||
this.heldPosition = { "x": pos.x, "z": pos.y }; | |||||
} | |||||
}, | }, | ||||
"leave": function(msg) { | "leave": function(msg) { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.ResetSpeedMultiplier(); | this.ResetSpeedMultiplier(); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
if (msg.likelyFailure || this.CheckTargetRangeExplicit(this.isGuardOf, 0, this.guardRange)) | if (msg.likelyFailure || this.CheckTargetRangeExplicit(this.isGuardOf, 0, this.guardRange)) | ||||
this.SetNextState("GUARDING"); | this.SetNextState("GUARDING"); | ||||
}, | }, | ||||
}, | }, | ||||
"GUARDING": { | "GUARDING": { | ||||
"enter": function() { | "enter": function() { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.StartTimer(1000, 1000); | this.StartTimer(1000, 1000); | ||||
this.SetHeldPositionOnEntity(this.entity); | |||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
this.FaceTowardsTarget(this.order.data.target); | this.FaceTowardsTarget(this.order.data.target); | ||||
let cmpGuardedPosition = Engine.QueryInterface(this.isGuardOf, IID_Position); | |||||
if (cmpGuardedPosition && cmpGuardedPosition.IsInWorld()) | |||||
{ | |||||
let pos = cmpGuardedPosition.GetPosition2D(); | |||||
this.heldPosition = { "x": pos.x, "z": pos.y }; | |||||
} | |||||
return false; | return false; | ||||
}, | }, | ||||
"LosRangeUpdate": function(msg) { | "LosRangeUpdate": function(msg) { | ||||
// Start attacking one of the newly-seen enemy (if any) | // Start attacking one of the newly-seen enemy (if any) | ||||
if (this.GetStance().targetVisibleEnemies) | if (this.GetStance().targetVisibleEnemies) | ||||
this.AttackEntitiesByPreference(msg.data.added); | this.AttackEntitiesByPreference(msg.data.added); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
// Check the target is alive | // Check the target is alive | ||||
if (!this.TargetIsAlive(this.isGuardOf)) | if (!this.TargetIsAlive(this.isGuardOf)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// Then check is the target has moved and try following it. | // Then check is the target has moved and try following it. | ||||
// TODO: find out what to do if we cannot move. | // TODO: find out what to do if we cannot move. | ||||
if (!this.CheckTargetRangeExplicit(this.isGuardOf, 0, this.guardRange) && | if (!this.CheckTargetRangeExplicit(this.isGuardOf, 0, this.guardRange) && | ||||
this.MoveToTargetRangeExplicit(this.isGuardOf, 0, this.guardRange)) | this.MoveToTargetRangeExplicit(this.isGuardOf, 0, this.guardRange)) | ||||
this.SetNextState("ESCORTING"); | this.SetNextState("ESCORTING"); | ||||
else | else | ||||
{ | { | ||||
let cmpGuardedPosition = Engine.QueryInterface(this.isGuardOf, IID_Position); | |||||
if (cmpGuardedPosition && cmpGuardedPosition.IsInWorld()) | |||||
{ | |||||
let pos = cmpGuardedPosition.GetPosition2D(); | |||||
this.heldPosition = { "x": pos.x, "z": pos.y }; | |||||
} | |||||
this.FaceTowardsTarget(this.order.data.target); | this.FaceTowardsTarget(this.order.data.target); | ||||
// if nothing better to do, check if the guarded needs to be healed or repaired | // if nothing better to do, check if the guarded needs to be healed or repaired | ||||
var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health); | var cmpHealth = Engine.QueryInterface(this.isGuardOf, IID_Health); | ||||
if (cmpHealth && cmpHealth.IsInjured()) | if (cmpHealth && cmpHealth.IsInjured()) | ||||
{ | { | ||||
if (this.CanHeal(this.isGuardOf)) | if (this.CanHeal(this.isGuardOf)) | ||||
this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false }); | this.PushOrderFront("Heal", { "target": this.isGuardOf, "force": false }); | ||||
else if (this.CanRepair(this.isGuardOf)) | else if (this.CanRepair(this.isGuardOf)) | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
this.StopTimer(); | this.StopTimer(); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force, IID_Attack, this.order.data.attackType)) | if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force, IID_Attack, this.order.data.attackType)) | ||||
{ | { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
// Return to our original position | |||||
if (this.GetStance().respondHoldGround) | |||||
this.WalkToHeldPosition(); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.RememberTargetPosition(); | this.RememberTargetPosition(); | ||||
if (this.order.data.hunting && this.orderQueue.length > 1 && | if (this.order.data.hunting && this.orderQueue.length > 1 && | ||||
this.orderQueue[1].type === "Gather") | this.orderQueue[1].type === "Gather") | ||||
this.RememberTargetPosition(this.orderQueue[1].data); | this.RememberTargetPosition(this.orderQueue[1].data); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 208 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
return true; | return true; | ||||
} | } | ||||
// See if we can switch to a new nearby enemy | // See if we can switch to a new nearby enemy | ||||
if (this.FindNewTargets()) | if (this.FindNewTargets()) | ||||
return true; | return true; | ||||
// Return to our original position | |||||
if (this.GetStance().respondHoldGround) | |||||
this.WalkToHeldPosition(); | |||||
return true; | return true; | ||||
}, | }, | ||||
}, | }, | ||||
"CHASING": { | "CHASING": { | ||||
"Order.MoveToChasingPoint": function(msg) { | "Order.MoveToChasingPoint": function(msg) { | ||||
if (this.CheckPointRangeExplicit(msg.data.x, msg.data.z, 0, msg.data.max)) | if (this.CheckPointRangeExplicit(msg.data.x, msg.data.z, 0, msg.data.max)) | ||||
{ | { | ||||
Show All 30 Lines | "COMBAT": { | ||||
this.StopTimer(); | this.StopTimer(); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force, IID_Attack, this.order.data.attackType)) | if (this.ShouldAbandonChase(this.order.data.target, this.order.data.force, IID_Attack, this.order.data.attackType)) | ||||
{ | { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
// Return to our original position | |||||
if (this.GetStance().respondHoldGround) | |||||
this.WalkToHeldPosition(); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.RememberTargetPosition(); | this.RememberTargetPosition(); | ||||
if (this.order.data.hunting && this.orderQueue.length > 1 && | if (this.order.data.hunting && this.orderQueue.length > 1 && | ||||
this.orderQueue[1].type === "Gather") | this.orderQueue[1].type === "Gather") | ||||
this.RememberTargetPosition(this.orderQueue[1].data); | this.RememberTargetPosition(this.orderQueue[1].data); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 525 Lines • ▼ Show 20 Lines | "HEAL": { | ||||
// If we have another order, do that instead. | // If we have another order, do that instead. | ||||
if (this.FinishOrder()) | if (this.FinishOrder()) | ||||
return true; | return true; | ||||
// Heal another one | // Heal another one | ||||
if (this.FindNewHealTargets()) | if (this.FindNewHealTargets()) | ||||
return true; | return true; | ||||
// Return to our original position | |||||
if (this.GetStance().respondHoldGround) | |||||
this.WalkToHeldPosition(); | |||||
// We quit this state right away. | // We quit this state right away. | ||||
return true; | return true; | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
// Returning to dropsite | // Returning to dropsite | ||||
"RETURNRESOURCE": { | "RETURNRESOURCE": { | ||||
▲ Show 20 Lines • Show All 674 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
this.orderQueue = []; // current order is at the front of the list | this.orderQueue = []; // current order is at the front of the list | ||||
this.order = undefined; // always == this.orderQueue[0] | this.order = undefined; // always == this.orderQueue[0] | ||||
this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to | this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to | ||||
this.isGarrisoned = false; | this.isGarrisoned = false; | ||||
this.isIdle = false; | this.isIdle = false; | ||||
this.isImmobile = false; // True if the unit is currently unable to move (garrisoned,...) | this.isImmobile = false; // True if the unit is currently unable to move (garrisoned,...) | ||||
this.heldPosition = undefined; | |||||
// Queue of remembered works | // Queue of remembered works | ||||
this.workOrders = []; | this.workOrders = []; | ||||
this.isGuardOf = undefined; | this.isGuardOf = undefined; | ||||
// For preventing increased action rate due to Stop orders or target death. | // For preventing increased action rate due to Stop orders or target death. | ||||
this.lastAttacked = undefined; | this.lastAttacked = undefined; | ||||
this.lastHealed = undefined; | this.lastHealed = undefined; | ||||
▲ Show 20 Lines • Show All 341 Lines • ▼ Show 20 Lines | UnitAI.prototype.FinishOrder = function() | ||||
if (!this.orderQueue.length) | if (!this.orderQueue.length) | ||||
{ | { | ||||
let stack = new Error().stack.trimRight().replace(/^/mg, ' '); // indent each line | let stack = new Error().stack.trimRight().replace(/^/mg, ' '); // indent each line | ||||
let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | let cmpTemplateManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_TemplateManager); | ||||
let template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | let template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | ||||
error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | ||||
} | } | ||||
if (this.orderQueue[0].onPop) | |||||
this.UnitFsm.ProcessMessage(this, { "type": this.orderQueue[0].onPop }); | |||||
this.orderQueue.shift(); | this.orderQueue.shift(); | ||||
this.order = this.orderQueue[0]; | this.order = this.orderQueue[0]; | ||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (this.orderQueue.length && (this.IsGarrisoned() || cmpPosition && cmpPosition.IsInWorld())) | if (this.orderQueue.length && (this.IsGarrisoned() || cmpPosition && cmpPosition.IsInWorld())) | ||||
{ | { | ||||
let ret = this.UnitFsm.ProcessMessage(this, | let ret = this.UnitFsm.ProcessMessage(this, | ||||
{ "type": "Order."+this.order.type, "data": this.order.data } | { "type": "Order."+this.order.type, "data": this.order.data } | ||||
▲ Show 20 Lines • Show All 202 Lines • ▼ Show 20 Lines | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
// Special cases of orders that shouldn't be replaced: | // Special cases of orders that shouldn't be replaced: | ||||
// 1. Cheering - we're invulnerable, add order after we finish | // 1. Cheering - we're invulnerable, add order after we finish | ||||
// 2. Packing/unpacking - we're immobile, add order after we finish (unless it's cancel) | // 2. Packing/unpacking - we're immobile, add order after we finish (unless it's cancel) | ||||
// TODO: maybe a better way of doing this would be to use priority levels | // TODO: maybe a better way of doing this would be to use priority levels | ||||
if (this.order && this.order.type == "Cheering") | if (this.order && this.order.type == "Cheering") | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
var cheeringOrder = this.orderQueue.shift(); | var cheeringOrder = this.orderQueue.shift(); | ||||
for (let order of this.orderQueue) | |||||
if (order.onPop) | |||||
this.UnitFsm.ProcessMessage(this, { "type": order.onPop }); | |||||
this.orderQueue = [cheeringOrder, order]; | this.orderQueue = [cheeringOrder, order]; | ||||
} | } | ||||
else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") | else if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack") | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||
for (let order of this.orderQueue) | |||||
if (order.onPop) | |||||
this.UnitFsm.ProcessMessage(this, { "type": order.onPop }); | |||||
if (type == "Attack") | if (type == "Attack") | ||||
{ | { | ||||
// The Attack order is able to handle a packing unit, while other orders can't. | // The Attack order is able to handle a packing unit, while other orders can't. | ||||
this.orderQueue = [packingOrder]; | this.orderQueue = [packingOrder]; | ||||
this.PushOrderFront(type, data, true); | this.PushOrderFront(type, data, true); | ||||
} | } | ||||
else if (packingOrder.type == "Unpack" && g_OrdersCancelUnpacking.has(type)) | else if (packingOrder.type == "Unpack" && g_OrdersCancelUnpacking.has(type)) | ||||
{ | { | ||||
// Immediately cancel unpacking before processing an order that demands a packed unit. | // Immediately cancel unpacking before processing an order that demands a packed unit. | ||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
cmpPack.CancelPack(); | cmpPack.CancelPack(); | ||||
if (packingOrder.onPop) | |||||
this.UnitFsm.ProcessMessage(this, { "type": packingOrder.onPop }); | |||||
this.orderQueue = []; | this.orderQueue = []; | ||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||
} | } | ||||
else | else | ||||
this.orderQueue = [packingOrder, order]; | this.orderQueue = [packingOrder, order]; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
for (let order of this.orderQueue) | |||||
if (order.onPop) | |||||
this.UnitFsm.ProcessMessage(this, { "type": order.onPop }); | |||||
this.orderQueue = []; | this.orderQueue = []; | ||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||
} | } | ||||
if (garrisonHolder) | if (garrisonHolder) | ||||
this.PushOrder("Garrison", { "target": garrisonHolder }); | this.PushOrder("Garrison", { "target": garrisonHolder }); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
▲ Show 20 Lines • Show All 904 Lines • ▼ Show 20 Lines | if (!cmpPosition || !cmpPosition.IsInWorld()) | ||||
return false; | return false; | ||||
let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | ||||
if (!cmpVision) | if (!cmpVision) | ||||
return false; | return false; | ||||
let halfvision = cmpVision.GetRange() / 2; | let halfvision = cmpVision.GetRange() / 2; | ||||
let pos = cmpPosition.GetPosition(); | let pos = cmpPosition.GetPosition(); | ||||
let heldPosition = this.heldPosition; | warn("heldpos " + uneval(this.heldPosition)); | ||||
if (heldPosition === undefined) | let heldPosition = this.heldPosition ? this.heldPosition : { "x": pos.x, "z": pos.z }; | ||||
heldPosition = { "x": pos.x, "z": pos.z }; | |||||
return Math.euclidDistance2D(pos.x, pos.z, heldPosition.x, heldPosition.z) < halfvision + range.max; | return Math.euclidDistance2D(pos.x, pos.z, heldPosition.x, heldPosition.z) < halfvision + range.max; | ||||
}; | }; | ||||
UnitAI.prototype.CheckTargetIsInVisionRange = function(target) | UnitAI.prototype.CheckTargetIsInVisionRange = function(target) | ||||
{ | { | ||||
let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | ||||
if (!cmpVision) | if (!cmpVision) | ||||
▲ Show 20 Lines • Show All 874 Lines • ▼ Show 20 Lines | else | ||||
error("UnitAI: Setting to invalid stance '"+stance+"'"); | error("UnitAI: Setting to invalid stance '"+stance+"'"); | ||||
}; | }; | ||||
UnitAI.prototype.SwitchToStance = function(stance) | UnitAI.prototype.SwitchToStance = function(stance) | ||||
{ | { | ||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | if (!cmpPosition || !cmpPosition.IsInWorld()) | ||||
return; | return; | ||||
var pos = cmpPosition.GetPosition(); | |||||
this.SetHeldPosition(pos.x, pos.z); | |||||
this.SetStance(stance); | this.SetStance(stance); | ||||
// Stop moving if switching to stand ground | // Stop moving if switching to stand ground | ||||
// TODO: Also stop existing orders in a sensible way | // TODO: Also stop existing orders in a sensible way | ||||
if (stance == "standground") | if (stance == "standground") | ||||
this.StopMoving(); | this.StopMoving(); | ||||
// Reset the range queries, since the range depends on stance. | // Reset the range queries, since the range depends on stance. | ||||
▲ Show 20 Lines • Show All 240 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if (!orderData) | if (!orderData) | ||||
orderData = this.order.data; | orderData = this.order.data; | ||||
let cmpPosition = Engine.QueryInterface(orderData.target, IID_Position); | let cmpPosition = Engine.QueryInterface(orderData.target, IID_Position); | ||||
if (cmpPosition && cmpPosition.IsInWorld()) | if (cmpPosition && cmpPosition.IsInWorld()) | ||||
orderData.lastPos = cmpPosition.GetPosition(); | orderData.lastPos = cmpPosition.GetPosition(); | ||||
}; | }; | ||||
UnitAI.prototype.SetHeldPosition = function(x, z) | |||||
{ | |||||
this.heldPosition = {"x": x, "z": z}; | |||||
}; | |||||
UnitAI.prototype.SetHeldPositionOnEntity = function(entity) | |||||
{ | |||||
var cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | |||||
return; | |||||
var pos = cmpPosition.GetPosition(); | |||||
this.SetHeldPosition(pos.x, pos.z); | |||||
}; | |||||
UnitAI.prototype.GetHeldPosition = function() | |||||
{ | |||||
return this.heldPosition; | |||||
}; | |||||
UnitAI.prototype.WalkToHeldPosition = function() | |||||
{ | |||||
if (this.heldPosition) | |||||
{ | |||||
this.AddOrder("Walk", { "x": this.heldPosition.x, "z": this.heldPosition.z, "force": false }, false); | |||||
return true; | |||||
} | |||||
return false; | |||||
}; | |||||
//// Helper functions //// | //// Helper functions //// | ||||
/** | /** | ||||
* General getter for ranges. | * General getter for ranges. | ||||
* | * | ||||
* @param {number} iid | * @param {number} iid | ||||
* @param {string} type - [Optional] | * @param {string} type - [Optional] | ||||
* @return {Object | undefined} - The range in the form | * @return {Object | undefined} - The range in the form | ||||
▲ Show 20 Lines • Show All 332 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator