Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | UnitAI.prototype.UnitFsmSpec = { | ||||
"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) { | ||||
// Let players move captured domestic animals around | // Let players move captured domestic animals around | ||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) | if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// For packable units: | // For packable units: | ||||
// 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. | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | else if (this.IsFormationMember()) | ||||
this.SetNextState("FORMATIONMEMBER.IDLE"); | this.SetNextState("FORMATIONMEMBER.IDLE"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.IDLE"); | this.SetNextState("INDIVIDUAL.IDLE"); | ||||
}, | }, | ||||
"Order.Walk": function(msg) { | "Order.Walk": function(msg) { | ||||
// Let players move captured domestic animals around | // Let players move captured domestic animals around | ||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) | if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// For packable units: | // For packable units: | ||||
// 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. | ||||
Show All 9 Lines | "Order.Walk": function(msg) { | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.WALKING"); | this.SetNextState("ANIMAL.WALKING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.WALKING"); | this.SetNextState("INDIVIDUAL.WALKING"); | ||||
}, | }, | ||||
"Order.WalkAndFight": function(msg) { | "Order.WalkAndFight": function(msg) { | ||||
// Let players move captured domestic animals around | // Let players move captured domestic animals around | ||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) | if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// For packable units: | // For packable units: | ||||
// 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. | ||||
Show All 10 Lines | 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"); | ||||
}, | }, | ||||
"Order.WalkToTarget": function(msg) { | "Order.WalkToTarget": function(msg) { | ||||
// Let players move captured domestic animals around | // Let players move captured domestic animals around | ||||
if (this.IsAnimal() && !this.IsDomestic() || this.IsTurret()) | if (this.IsAnimal() && !this.IsDomestic() || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// For packable units: | // For packable units: | ||||
// 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. | ||||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Lines | if (this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType)) | ||||
this.SetNextState("ANIMAL.COMBAT.ATTACKING"); | this.SetNextState("ANIMAL.COMBAT.ATTACKING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); | this.SetNextState("INDIVIDUAL.COMBAT.ATTACKING"); | ||||
return; | return; | ||||
} | } | ||||
// If we can't reach the target, but are standing ground, then abandon this attack order. | // If we can't reach the target, but are standing ground, then abandon this attack order. | ||||
// Unless we're hunting, that's a special case where we should continue attacking our target. | // Unless we're hunting, that's a special case where we should continue attacking our target. | ||||
if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting || this.IsTurret()) | if (this.GetStance().respondStandGround && !this.order.data.force && !this.order.data.hunting || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
// For packable units out of attack range: | // For packable units out of attack range: | ||||
// 1. If packed, we need to move to attack range and then unpack. | // 1. If packed, we need to move to attack range and then unpack. | ||||
// 2. If unpacked, we first need to pack, then follow case 1. | // 2. If unpacked, we first need to pack, then follow case 1. | ||||
Show All 9 Lines | "Order.Attack": function(msg) { | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.COMBAT.APPROACHING"); | this.SetNextState("ANIMAL.COMBAT.APPROACHING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.COMBAT.APPROACHING"); | this.SetNextState("INDIVIDUAL.COMBAT.APPROACHING"); | ||||
}, | }, | ||||
"Order.Patrol": function(msg) { | "Order.Patrol": function(msg) { | ||||
if (this.IsAnimal() || this.IsTurret()) | if (this.IsAnimal() || !this.AbleToMove()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
if (this.CanPack()) | if (this.CanPack()) | ||||
{ | { | ||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | "Order.Repair": function(msg) { | ||||
// Try to move within range | // Try to move within range | ||||
if (this.CheckTargetRange(this.order.data.target, IID_Builder)) | if (this.CheckTargetRange(this.order.data.target, IID_Builder)) | ||||
this.SetNextState("INDIVIDUAL.REPAIR.REPAIRING"); | this.SetNextState("INDIVIDUAL.REPAIR.REPAIRING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.REPAIR.APPROACHING"); | this.SetNextState("INDIVIDUAL.REPAIR.APPROACHING"); | ||||
}, | }, | ||||
"Order.Garrison": function(msg) { | "Order.Garrison": function(msg) { | ||||
if (this.IsTurret()) | if (!this.AbleToMove()) | ||||
{ | { | ||||
this.SetNextState("IDLE"); | this.SetNextState("IDLE"); | ||||
return; | return; | ||||
} | } | ||||
else if (this.IsGarrisoned()) | else if (this.IsGarrisoned()) | ||||
{ | { | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.GARRISON.GARRISONED"); | this.SetNextState("ANIMAL.GARRISON.GARRISONED"); | ||||
▲ Show 20 Lines • Show All 2,408 Lines • ▼ Show 20 Lines | "GARRISON": { | ||||
// Check that we're in range of the garrison target | // Check that we're in range of the garrison target | ||||
if (this.CheckGarrisonRange(target)) | if (this.CheckGarrisonRange(target)) | ||||
{ | { | ||||
var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | ||||
// Check that garrisoning succeeds | // Check that garrisoning succeeds | ||||
if (cmpGarrisonHolder.Garrison(this.entity)) | if (cmpGarrisonHolder.Garrison(this.entity)) | ||||
{ | { | ||||
this.isGarrisoned = true; | this.isGarrisoned = true; | ||||
this.SetImmobile(true); | |||||
if (this.formationController) | if (this.formationController) | ||||
{ | { | ||||
var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); | var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); | ||||
if (cmpFormation) | if (cmpFormation) | ||||
{ | { | ||||
// disable rearrange for this removal, | // disable rearrange for this removal, | ||||
// but enable it again for the next | // but enable it again for the next | ||||
▲ Show 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | |||||
UnitAI.prototype.Init = function() | UnitAI.prototype.Init = function() | ||||
{ | { | ||||
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.finishedOrder = false; // used to find if all formation members finished the order | this.finishedOrder = false; // used to find if all formation members finished the order | ||||
this.heldPosition = undefined; | this.heldPosition = undefined; | ||||
// Queue of remembered works | // Queue of remembered works | ||||
this.workOrders = []; | this.workOrders = []; | ||||
this.isGuardOf = undefined; | this.isGuardOf = undefined; | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | UnitAI.prototype.GetGarrisonHolder = function() | ||||
return INVALID_ENTITY; | return INVALID_ENTITY; | ||||
}; | }; | ||||
UnitAI.prototype.ShouldRespondToEndOfAlert = function() | UnitAI.prototype.ShouldRespondToEndOfAlert = function() | ||||
{ | { | ||||
return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; | return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; | ||||
}; | }; | ||||
UnitAI.prototype.SetImmobile = function(immobile) | |||||
{ | |||||
this.isImmobile = immobile; | |||||
Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { | |||||
"entity": this.entity, | |||||
"ableToMove": this.AbleToMove() | |||||
}); | |||||
}; | |||||
/** | |||||
* @param cmpUnitMotion - optionally pass unitMotion to avoid querying it here | |||||
* @returns true if the entity can move, i.e. has UnitMotion and isn't immobile. | |||||
*/ | |||||
UnitAI.prototype.AbleToMove = function(cmpUnitMotion) | |||||
{ | |||||
if (this.isImmobile || this.IsTurret()) | |||||
return false; | |||||
if (!cmpUnitMotion) | |||||
cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | |||||
return !!cmpUnitMotion; | |||||
}; | |||||
UnitAI.prototype.IsFleeing = function() | UnitAI.prototype.IsFleeing = function() | ||||
{ | { | ||||
var state = this.GetCurrentState().split(".").pop(); | var state = this.GetCurrentState().split(".").pop(); | ||||
return (state == "FLEEING"); | return (state == "FLEEING"); | ||||
}; | }; | ||||
UnitAI.prototype.IsWalking = function() | UnitAI.prototype.IsWalking = function() | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 420 Lines • ▼ Show 20 Lines | UnitAI.prototype.EnsureCorrectPackStateForAttack = function(requirePacked) | ||||
return false; | return false; | ||||
}; | }; | ||||
UnitAI.prototype.WillMoveFromFoundation = function(target, checkPacking = true) | UnitAI.prototype.WillMoveFromFoundation = function(target, checkPacking = true) | ||||
{ | { | ||||
// If foundation is not ally of entity, or if entity is unpacked siege, | // If foundation is not ally of entity, or if entity is unpacked siege, | ||||
// ignore the order. | // ignore the order. | ||||
if (!IsOwnedByAllyOfEntity(this.entity, target) && | if (!IsOwnedByAllyOfEntity(this.entity, target) && | ||||
!Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() || | !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() || | ||||
checkPacking && this.IsPacking() || | checkPacking && this.IsPacking() || this.CanPack() || !this.AbleToMove()) | ||||
this.CanPack() || this.IsTurret()) | |||||
return false; | return false; | ||||
// Move a tile outside the building. | // Move a tile outside the building. | ||||
return !this.CheckTargetRangeExplicit(target, g_LeaveFoundationRange, -1); | return !this.CheckTargetRangeExplicit(target, g_LeaveFoundationRange, -1); | ||||
}; | }; | ||||
UnitAI.prototype.ReplaceOrder = function(type, data) | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 573 Lines • ▼ Show 20 Lines | else if (data.min || data.max) | ||||
return this.MoveToPointRange(data.x, data.z, data.min || -1, data.max || -1); | return this.MoveToPointRange(data.x, data.z, data.min || -1, data.max || -1); | ||||
return this.MoveToPoint(data.x, data.z); | return this.MoveToPoint(data.x, data.z); | ||||
}; | }; | ||||
UnitAI.prototype.MoveToPoint = function(x, z) | UnitAI.prototype.MoveToPoint = function(x, z) | ||||
{ | { | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToPointRange(x, z, 0, 0); // For point goals, allow a max range of 0. | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToPointRange(x, z, 0, 0); // For point goals, allow a max range of 0. | ||||
}; | }; | ||||
UnitAI.prototype.MoveToPointRange = function(x, z, rangeMin, rangeMax) | UnitAI.prototype.MoveToPointRange = function(x, z, rangeMin, rangeMax) | ||||
{ | { | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToPointRange(x, z, rangeMin, rangeMax); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToPointRange(x, z, rangeMin, rangeMax); | ||||
}; | }; | ||||
UnitAI.prototype.MoveToTarget = function(target) | UnitAI.prototype.MoveToTarget = function(target) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, 0, 1); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, 0, 1); | ||||
}; | }; | ||||
UnitAI.prototype.MoveToTargetRange = function(target, iid, type) | UnitAI.prototype.MoveToTargetRange = function(target, iid, type) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target) || this.IsTurret()) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
let range = this.GetRange(iid, type); | let range = this.GetRange(iid, type); | ||||
if (!range) | if (!range) | ||||
return false; | return false; | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | ||||
}; | }; | ||||
/** | /** | ||||
* Move unit so we hope the target is in the attack range | * Move unit so we hope the target is in the attack range | ||||
* for melee attacks, this goes straight to the default range checks | * for melee attacks, this goes straight to the default range checks | ||||
* for ranged attacks, the parabolic range is used | * for ranged attacks, the parabolic range is used | ||||
*/ | */ | ||||
UnitAI.prototype.MoveToTargetAttackRange = function(target, type) | UnitAI.prototype.MoveToTargetAttackRange = function(target, type) | ||||
{ | { | ||||
// for formation members, the formation will take care of the range check | // for formation members, the formation will take care of the range check | ||||
if (this.IsFormationMember()) | if (this.IsFormationMember()) | ||||
{ | { | ||||
let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | let cmpFormationUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | ||||
if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation()) | if (cmpFormationUnitAI && cmpFormationUnitAI.IsAttackingAsFormation()) | ||||
return false; | return false; | ||||
} | } | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | |||||
if (!this.AbleToMove(cmpUnitMotion)) | |||||
return false; | |||||
let cmpFormation = Engine.QueryInterface(target, IID_Formation); | let cmpFormation = Engine.QueryInterface(target, IID_Formation); | ||||
if (cmpFormation) | if (cmpFormation) | ||||
target = cmpFormation.GetClosestMember(this.entity); | target = cmpFormation.GetClosestMember(this.entity); | ||||
if (type != "Ranged") | if (type != "Ranged") | ||||
return this.MoveToTargetRange(target, IID_Attack, type); | return this.MoveToTargetRange(target, IID_Attack, type); | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
Show All 20 Lines | UnitAI.prototype.MoveToTargetAttackRange = function(target, type) | ||||
// No negative roots please | // No negative roots please | ||||
if (h <= -range.max / 2) | if (h <= -range.max / 2) | ||||
// return false? Or hope you come close enough? | // return false? Or hope you come close enough? | ||||
parabolicMaxRange = 0; | parabolicMaxRange = 0; | ||||
// The parabole changes while walking so be cautious: | // The parabole changes while walking so be cautious: | ||||
let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange; | let guessedMaxRange = parabolicMaxRange > range.max ? (range.max + parabolicMaxRange) / 2 : parabolicMaxRange; | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | |||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange); | return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, guessedMaxRange); | ||||
}; | }; | ||||
UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max) | UnitAI.prototype.MoveToTargetRangeExplicit = function(target, min, max) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, min, max); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, min, max); | ||||
}; | }; | ||||
/** | /** | ||||
* Move unit so we hope the target is in the attack range of the formation. | * Move unit so we hope the target is in the attack range of the formation. | ||||
* | * | ||||
* @param {number} target - The target entity ID to attack. | * @param {number} target - The target entity ID to attack. | ||||
* @return {boolean} - Whether the order to move has succeeded. | * @return {boolean} - Whether the order to move has succeeded. | ||||
*/ | */ | ||||
UnitAI.prototype.MoveFormationToTargetAttackRange = function(target) | UnitAI.prototype.MoveFormationToTargetAttackRange = function(target) | ||||
{ | { | ||||
let cmpTargetFormation = Engine.QueryInterface(target, IID_Formation); | let cmpTargetFormation = Engine.QueryInterface(target, IID_Formation); | ||||
if (cmpTargetFormation) | if (cmpTargetFormation) | ||||
target = cmpTargetFormation.GetClosestMember(this.entity); | target = cmpTargetFormation.GetClosestMember(this.entity); | ||||
if (!this.CheckTargetVisible(target) || this.IsTurret()) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
let cmpFormationAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpFormationAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
if (!cmpFormationAttack) | if (!cmpFormationAttack) | ||||
return false; | return false; | ||||
let range = cmpFormationAttack.GetRange(target); | let range = cmpFormationAttack.GetRange(target); | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | ||||
}; | }; | ||||
UnitAI.prototype.MoveToGarrisonRange = function(target) | UnitAI.prototype.MoveToGarrisonRange = function(target) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return false; | return false; | ||||
var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | var cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | ||||
if (!cmpGarrisonHolder) | if (!cmpGarrisonHolder) | ||||
return false; | return false; | ||||
var range = cmpGarrisonHolder.GetLoadingRange(); | var range = cmpGarrisonHolder.GetLoadingRange(); | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | return this.AbleToMove(cmpUnitMotion) && cmpUnitMotion.MoveToTargetRange(target, range.min, range.max); | ||||
}; | }; | ||||
/** | /** | ||||
* Generic dispatcher for other Check...Range functions. | * Generic dispatcher for other Check...Range functions. | ||||
* @param iid - Interface ID (optional) implementing GetRange | * @param iid - Interface ID (optional) implementing GetRange | ||||
* @param type - Range type for the interface call | * @param type - Range type for the interface call | ||||
*/ | */ | ||||
UnitAI.prototype.CheckRange = function(data, iid, type) | UnitAI.prototype.CheckRange = function(data, iid, type) | ||||
▲ Show 20 Lines • Show All 368 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/* | /* | ||||
* Returns whether we should chase the targeted entity, | * Returns whether we should chase the targeted entity, | ||||
* given our current stance. | * given our current stance. | ||||
*/ | */ | ||||
UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force) | UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force) | ||||
{ | { | ||||
if (this.IsTurret()) | if (!this.AbleToMove()) | ||||
return false; | return false; | ||||
if (this.GetStance().respondChase) | if (this.GetStance().respondChase) | ||||
return true; | return true; | ||||
// If we are guarding/escorting, chase at least as long as the guarded unit is in target range of the attacker | // If we are guarding/escorting, chase at least as long as the guarded unit is in target range of the attacker | ||||
if (this.isGuardOf) | if (this.isGuardOf) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 309 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* 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 | |||||
if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target))) | if (this.order && (this.order.type == "LeaveFoundation" || (this.order.type == "Flee" && this.order.data.target == target))) | ||||
return; | return; | ||||
// Ignore also the request if we are packing. | |||||
if (this.orderQueue.length && this.orderQueue[0].type == "Unpack" && this.WillMoveFromFoundation(target, false)) | if (this.orderQueue.length && this.orderQueue[0].type == "Unpack" && this.WillMoveFromFoundation(target, false)) | ||||
{ | { | ||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
if (cmpPack) | if (cmpPack) | ||||
cmpPack.CancelPack(); | cmpPack.CancelPack(); | ||||
} | } | ||||
if (this.IsPacking()) | if (this.IsPacking()) | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* Adds ungarrison order to the queue. | * Adds ungarrison order to the queue. | ||||
*/ | */ | ||||
UnitAI.prototype.Ungarrison = function() | UnitAI.prototype.Ungarrison = function() | ||||
{ | { | ||||
if (this.IsGarrisoned()) | if (this.IsGarrisoned()) | ||||
{ | |||||
this.SetImmobile(false); | |||||
this.AddOrder("Ungarrison", null, false); | this.AddOrder("Ungarrison", null, false); | ||||
} | |||||
}; | }; | ||||
/** | /** | ||||
* Adds a garrison order for units that are already garrisoned in the garrison holder. | * Adds a garrison order for units that are already garrisoned in the garrison holder. | ||||
*/ | */ | ||||
UnitAI.prototype.Autogarrison = function(target) | UnitAI.prototype.Autogarrison = function(target) | ||||
{ | { | ||||
this.isGarrisoned = true; | this.isGarrisoned = true; | ||||
▲ Show 20 Lines • Show All 950 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator