Changeset View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 126 Lines • ▼ Show 20 Lines | "none": { | ||||||
"respondChase": false, | "respondChase": false, | ||||||
"respondChaseBeyondVision": false, | "respondChaseBeyondVision": false, | ||||||
"respondStandGround": false, | "respondStandGround": false, | ||||||
"respondHoldGround": false, | "respondHoldGround": false, | ||||||
"selectable": false | "selectable": false | ||||||
} | } | ||||||
}; | }; | ||||||
// These orders always require a packed unit, so if a unit that is unpacking is given one of these orders, | |||||||
// it can immediately cancel unpacking. | |||||||
Freagarach: it `can` or it `will`? | |||||||
var g_OrdersCancelUnpacking = new Set([ | |||||||
Not Done Inline ActionsThis file having 6k lines and only one global seems to indicate that it'd be better to avoid globals. elexis: This file having 6k lines and only one global seems to indicate that it'd be better to avoid… | |||||||
Not Done Inline ActionsJust because there is only one global is not a reason not to add more. The alternative is having g_OrdersCancelUnpacking be a local variable in PushOrderFront, which is less efficient. causative: Just because there is only one global is not a reason not to add more.
The alternative is… | |||||||
Not Done Inline Actionsmeant to say a local variable in ReplaceOrder causative: meant to say a local variable in ReplaceOrder | |||||||
Not Done Inline ActionsWouldn't it be feasible to call the cancel-unpacking order or code in the affected orders? It would keep the data structure more self-contained. (Assembler is more efficient than JavaScript too, yet we optimize for readability and maintainability unless performance is non-neglibile (in which case things are moved to C++ if it can't be fixed in JS)) elexis: Wouldn't it be feasible to call the cancel-unpacking order or code in the affected orders? It… | |||||||
Not Done Inline ActionsNot without restructuring how UnitAI deals with packing entirely - see the reply to aeonios causative: Not without restructuring how UnitAI deals with packing entirely - see the reply to aeonios | |||||||
Done Inline Actionscould you split it to new lines? ([ "FormationWalk", "Walk" ]) Silier: could you split it to new lines?
```
([
"FormationWalk",
"Walk"
])
``` | |||||||
"FormationWalk", | |||||||
"Walk", | |||||||
"WalkAndFight", | |||||||
"WalkToTarget", | |||||||
"Patrol", | |||||||
"Garrison" | |||||||
]); | |||||||
// When leaving a foundation, we want to be clear of it by this distance. | |||||||
FreagarachUnsubmitted Done Inline ActionsIs this in m or in tiles? (Or something else?) Freagarach: Is this in `m` or in tiles? (Or something else?) | |||||||
var g_LeaveFoundationRange = 4; | |||||||
Not Done Inline ActionsWhat is the benefit of globals when they could be defined in the prototype along the other component properties? elexis: What is the benefit of globals when they could be defined in the prototype along the other… | |||||||
// See ../helpers/FSM.js for some documentation of this FSM specification syntax | // See ../helpers/FSM.js for some documentation of this FSM specification syntax | ||||||
UnitAI.prototype.UnitFsmSpec = { | UnitAI.prototype.UnitFsmSpec = { | ||||||
// Default event handlers: | // Default event handlers: | ||||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||||
// ignore spurious movement messages | // ignore spurious movement messages | ||||||
// (these can happen when stopping moving at the same time | // (these can happen when stopping moving at the same time | ||||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | UnitAI.prototype.UnitFsmSpec = { | ||||||
}, | }, | ||||||
// Special orders: | // Special orders: | ||||||
// (these will be overridden by various states) | // (these will be overridden by various states) | ||||||
"Order.LeaveFoundation": function(msg) { | "Order.LeaveFoundation": function(msg) { | ||||||
// 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, msg.data.target) && !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() || | if (!this.WillMoveFromFoundation(msg.data.target)) | ||||||
this.IsPacking() || this.CanPack() || this.IsTurret()) | |||||||
{ | { | ||||||
this.FinishOrder(); | this.FinishOrder(); | ||||||
return; | return; | ||||||
} | } | ||||||
this.order.data.min = g_LeaveFoundationRange; | |||||||
// Move a tile outside the building if necessary. | |||||||
let range = 4; | |||||||
if (this.CheckTargetRangeExplicit(msg.data.target, range, -1)) | |||||||
this.FinishOrder(); | |||||||
else | |||||||
{ | |||||||
this.order.data.min = range; | |||||||
this.SetNextState("INDIVIDUAL.WALKING"); | this.SetNextState("INDIVIDUAL.WALKING"); | ||||||
} | |||||||
}, | }, | ||||||
// Individual orders: | // Individual orders: | ||||||
// (these will switch the unit out of formation mode) | // (these will switch the unit out of formation mode) | ||||||
"Order.Stop": function(msg) { | "Order.Stop": function(msg) { | ||||||
// We have no control over non-domestic animals. | // We have no control over non-domestic animals. | ||||||
if (this.IsAnimal() && !this.IsDomestic()) | if (this.IsAnimal() && !this.IsDomestic()) | ||||||
▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Lines | if (this.CheckTargetAttackRange(this.order.data.target, this.order.data.attackType)) | ||||||
// 1. If unpacked, we can attack the target. | // 1. If unpacked, we can attack the target. | ||||||
// 2. If packed, we first need to unpack, then follow case 1. | // 2. If packed, we first need to unpack, then follow case 1. | ||||||
if (this.CanUnpack()) | if (this.CanUnpack()) | ||||||
{ | { | ||||||
this.PushOrderFront("Unpack", { "force": true }); | this.PushOrderFront("Unpack", { "force": true }); | ||||||
return; | return; | ||||||
} | } | ||||||
// Cancel any current packing order | |||||||
FreagarachUnsubmitted Done Inline Actions+. Freagarach: +`.` | |||||||
if (!this.EnsureCorrectPackStateForAttack(true)) | |||||||
return; | |||||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||||
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.IsTurret()) | ||||||
{ | { | ||||||
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. | ||||||
if (this.CanPack()) | if (this.CanPack()) | ||||||
{ | { | ||||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||||
return; | return; | ||||||
} | } | ||||||
// If we're currently packing/unpacking, make sure we are packed, so we can move. | |||||||
if (!this.EnsureCorrectPackStateForAttack(false)) | |||||||
return; | |||||||
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.IsTurret()) | ||||||
▲ Show 20 Lines • Show All 796 Lines • ▼ Show 20 Lines | "FORMATIONMEMBER": { | ||||||
}, | }, | ||||||
// Override the LeaveFoundation order since we're not doing | // Override the LeaveFoundation order since we're not doing | ||||||
// anything more important (and we might be stuck in the WALKING | // anything more important (and we might be stuck in the WALKING | ||||||
// state forever and need to get out of foundations in that case) | // state forever and need to get out of foundations in that case) | ||||||
"Order.LeaveFoundation": function(msg) { | "Order.LeaveFoundation": function(msg) { | ||||||
// 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, msg.data.target) && !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive() || | if (!this.WillMoveFromFoundation(msg.data.target)) | ||||||
this.IsPacking() || this.CanPack() || this.IsTurret()) | |||||||
{ | { | ||||||
this.FinishOrder(); | this.FinishOrder(); | ||||||
return; | return; | ||||||
} | } | ||||||
// Move a tile outside the building | this.order.data.min = g_LeaveFoundationRange; | ||||||
let range = 4; | |||||||
if (this.CheckTargetRangeExplicit(msg.data.target, range, -1)) | |||||||
{ | |||||||
// We are already at the target, or can't move at all | |||||||
this.FinishOrder(); | |||||||
} | |||||||
else | |||||||
{ | |||||||
this.order.data.min = range; | |||||||
this.SetNextState("WALKINGTOPOINT"); | this.SetNextState("WALKINGTOPOINT"); | ||||||
} | |||||||
}, | }, | ||||||
"enter": function() { | "enter": function() { | ||||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||||
{ | { | ||||||
// Animals can't go in formation. | // Animals can't go in formation. | ||||||
warn("Entity " + this.entity + " was put in FORMATIONMEMBER state but is an animal"); | warn("Entity " + this.entity + " was put in FORMATIONMEMBER state but is an animal"); | ||||||
this.FinishOrder(); | this.FinishOrder(); | ||||||
▲ Show 20 Lines • Show All 1,821 Lines • ▼ Show 20 Lines | "Attacked": function(msg) { | ||||||
{ | { | ||||||
// Never flee, stop what we were doing | // Never flee, stop what we were doing | ||||||
this.SetNextState("IDLE"); | this.SetNextState("IDLE"); | ||||||
} | } | ||||||
}, | }, | ||||||
"Order.LeaveFoundation": function(msg) { | "Order.LeaveFoundation": function(msg) { | ||||||
// Move a tile outside the building | // Move a tile outside the building | ||||||
let range = 4; | if (this.CheckTargetRangeExplicit(msg.data.target, g_LeaveFoundationRange, -1)) | ||||||
if (this.CheckTargetRangeExplicit(msg.data.target, range, -1)) | |||||||
{ | { | ||||||
this.FinishOrder(); | this.FinishOrder(); | ||||||
return; | return; | ||||||
} | } | ||||||
this.order.data.min = range; | this.order.data.min = g_LeaveFoundationRange; | ||||||
this.SetNextState("WALKING"); | this.SetNextState("WALKING"); | ||||||
}, | }, | ||||||
"IDLE": { | "IDLE": { | ||||||
// (We need an IDLE state so that FinishOrder works) | // (We need an IDLE state so that FinishOrder works) | ||||||
"enter": function() { | "enter": function() { | ||||||
// Start feeding immediately | // Start feeding immediately | ||||||
▲ Show 20 Lines • Show All 511 Lines • ▼ Show 20 Lines | UnitAI.prototype.PushOrder = function(type, data) | ||||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||||
}; | }; | ||||||
/** | /** | ||||||
* Add an order onto the front of the queue, | * Add an order onto the front of the queue, | ||||||
* and execute it immediately. | * and execute it immediately. | ||||||
*/ | */ | ||||||
UnitAI.prototype.PushOrderFront = function(type, data) | UnitAI.prototype.PushOrderFront = function(type, data, ignorePacking = false) | ||||||
{ | { | ||||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||||
// If current order is cheering then add new order after it | // If current order is cheering then add new order after it | ||||||
// same thing if current order if packing/unpacking | // same thing if current order if packing/unpacking | ||||||
if (this.order && this.order.type == "Cheering") | if (this.order && this.order.type == "Cheering") | ||||||
{ | { | ||||||
var cheeringOrder = this.orderQueue.shift(); | var cheeringOrder = this.orderQueue.shift(); | ||||||
this.orderQueue.unshift(cheeringOrder, order); | this.orderQueue.unshift(cheeringOrder, order); | ||||||
} | } | ||||||
else if (this.order && this.IsPacking()) | else if (!ignorePacking && this.order && this.IsPacking()) | ||||||
{ | { | ||||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||||
this.orderQueue.unshift(packingOrder, order); | this.orderQueue.unshift(packingOrder, order); | ||||||
} | } | ||||||
else | else | ||||||
{ | { | ||||||
this.orderQueue.unshift(order); | this.orderQueue.unshift(order); | ||||||
this.order = order; | this.order = order; | ||||||
Show All 37 Lines | for (let i = 1; i < this.orderQueue.length; ++i) | ||||||
return; | return; | ||||||
} | } | ||||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||||
} | } | ||||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||||
}; | }; | ||||||
/** | |||||||
* For a unit that is packing and trying to attack something, | |||||||
* either cancel packing or continue with packing, as appropriate. | |||||||
* Precondition: if the unit is packing/unpacking, then orderQueue | |||||||
* should have the Attack order at index 0, | |||||||
Done Inline Actionsdo not assume that in precondition, check for that inside Silier: do not assume that in precondition, check for that inside | |||||||
* and the Pack/Unpack order at index 1. | |||||||
* This precondition holds because if we are packing while processing "Order.Attack", | |||||||
* then we must have come from ReplaceOrder, which guarantees it. | |||||||
Done Inline Actionsthis is not the case anymore Silier: this is not the case anymore | |||||||
* | |||||||
* @param preferUnpacked - true if the unit needs to be unpacked to continue attacking, | |||||||
FreagarachUnsubmitted Done Inline Actions@param {boolean} preferUnpacked - <text> Freagarach: `@param {boolean} preferUnpacked - <text>`
Alike for below. | |||||||
* false if it needs to be packed. | |||||||
Not Done Inline ActionsPreference usually[for example https://en.wiktionary.org/wiki/prefer#English] means that one would chose one over the other if one has the choice but doesn't rule out that one would reject the other choice, whereas this function requires the packed state to be one way. elexis: Preference usually[for example https://en.wiktionary.org/wiki/prefer#English] means that one… | |||||||
* @return true if the unit can attack now, false if it must continue packing (or unpacking) first. | |||||||
Done Inline ActionsFunction name starts with capital letter Silier: Function name starts with capital letter
I would avoid to pass component, get it inside
Also… | |||||||
*/ | |||||||
UnitAI.prototype.EnsureCorrectPackStateForAttack = function(preferUnpacked) | |||||||
Done Inline Actionsplease use early returns if possible if (something) return /** code **/ instead if (!something) { /**code**/ } Silier: please use early returns if possible
```
if (something)
return
/** code **/
```
instead… | |||||||
{ | |||||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | |||||||
if (!cmpPack || !cmpPack.IsPacking()) | |||||||
return true; | |||||||
Not Done Inline Actionsrequiring exactly 2 orders in queue is not correct, what if attack order was pushed in front of another order already and then pack order was pushed next? Silier: requiring exactly 2 orders in queue is not correct, what if attack order was pushed in front of… | |||||||
Done Inline ActionsRecap of our IRC conversation: in order for the unit to be packing while in Order.Attack, we must have come from ReplaceOrder, which guarantees the two orders are as given in the precondition. Because, before this patch, a unit in Order.Attack would never be packing. causative: Recap of our IRC conversation: in order for the unit to be packing while in Order.Attack, we… | |||||||
Done Inline Actionscould you split condition to multiple lines? Silier: could you split condition to multiple lines? | |||||||
if (this.orderQueue.length != 2 || | |||||||
this.orderQueue[0].type != "Attack" || | |||||||
Done Inline ActionsYou are changing orders. You need to inform about that. see last line in ReplaceOrder. Silier: You are changing orders. You need to inform about that. see last line in ReplaceOrder. | |||||||
Done Inline Actionsplease move || to end of line not to beginning Silier: please move || to end of line not to beginning | |||||||
(this.orderQueue[1].type != "Pack" && this.orderQueue[1].type != "Unpack")) | |||||||
Not Done Inline Actionsunneeded parentheses elexis: unneeded parentheses | |||||||
return true; // violated precondition; should never happen. | |||||||
SilierAuthorUnsubmitted Not Done Inline ActionsI would remove this comment Silier: I would remove this comment | |||||||
Not Done Inline Actions
(One may consider an error() when formalizing such a code path over the comment) elexis: > // should never happen.
(One may consider an `error()` when formalizing such a code path over… | |||||||
Not Done Inline ActionsConsecutive return statements with the same return value can be merged (in particular since it would be arbitrary where to make a new if statement over using an || condition, if they were always merged it would be fully self consistent, though one can see it as consistency too to not care, but it may leave some readers wondering whethere there is a reason to split in one case but not in another, whatever) elexis: Consecutive return statements with the same return value can be merged (in particular since it… | |||||||
if(cmpPack.IsPacked() ^ preferUnpacked) | |||||||
FreagarachUnsubmitted Done Inline Actions+ Freagarach: +` ` | |||||||
Not Done Inline ActionsIs interpreting the true / false keyword as a 32bit series and using bitwise xor on that value cleaner than an inequality test? elexis: Is interpreting the true / false keyword as a 32bit series and using bitwise xor on that value… | |||||||
{ | |||||||
// The unit is already in the packed/unpacked state we want. | |||||||
// Delete the packing order. | |||||||
this.orderQueue.splice(1,1); | |||||||
Not Done Inline Actions(space after comma) elexis: (space after comma) | |||||||
cmpPack.CancelPack(); | |||||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | |||||||
// Continue with the attack order. | |||||||
Not Done Inline Actionsthis is not good solution. Silier: this is not good solution.
If we are here in code, it will queue attack orders behind… | |||||||
Not Done Inline ActionsActually here is another issue than described by me, but that should be solved by not assuming precondition holds true Silier: Actually here is another issue than described by me, but that should be solved by not assuming… | |||||||
Done Inline ActionsIt's intended to queue the attack order behind packing/unpacking order. We don't want to attack if it's in the wrong packing state. We put the packing order first, then return false, which makes "Order.Attack" abort, and the unit continues packing/unpacking. causative: It's intended to queue the attack order behind packing/unpacking order. We don't want to… | |||||||
return true; | |||||||
} | |||||||
// Move the attack order behind the unpacking order, to continue unpacking. | |||||||
let tmp = this.orderQueue[0]; | |||||||
this.orderQueue[0] = this.orderQueue[1]; | |||||||
this.orderQueue[1] = tmp; | |||||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | |||||||
return false; | |||||||
}; | |||||||
Done Inline Actionsonly two states can occur, or first if condition is true, or we move to else branch, making this return dead code, also else branch can be omitted as if branch has return Silier: only two states can occur, or first if condition is true, or we move to else branch, making… | |||||||
UnitAI.prototype.WillMoveFromFoundation = function(target, checkPacking = true) | |||||||
SilierAuthorUnsubmitted Not Done Inline Actionsmaybe checkPacking -> dontMoveWhenPacking would be better Silier: maybe checkPacking -> dontMoveWhenPacking would be better | |||||||
causativeUnsubmitted Done Inline ActionsDon't agree. We still don't want to move when packing, it's just that the caller is going to check that. causative: Don't agree. We still don't want to move when packing, it's just that the caller is going to… | |||||||
{ | |||||||
// If foundation is not ally of entity, or if entity is unpacked siege, | |||||||
// ignore the order. | |||||||
if (!IsOwnedByAllyOfEntity(this.entity, target) && !Engine.QueryInterface(SYSTEM_ENTITY, IID_CeasefireManager).IsCeasefireActive()) | |||||||
return false; | |||||||
if (checkPacking && this.IsPacking()) | |||||||
return false; | |||||||
if (this.CanPack()) | |||||||
return false; | |||||||
Not Done Inline Actions
elexis: || and \n to merge the same return cases | |||||||
if (this.IsTurret()) | |||||||
SilierAuthorUnsubmitted Done Inline Actionsdefinitely you should merge this one and CanPack into one condition Silier: definitely you should merge this one and CanPack into one condition | |||||||
return false; | |||||||
// Move a tile outside the building. | |||||||
if (this.CheckTargetRangeExplicit(target, g_LeaveFoundationRange, -1)) | |||||||
SilierAuthorUnsubmitted Done Inline Actionsreturn !this.CheckTargetRangeExplicit... Silier: return !this.CheckTargetRangeExplicit... | |||||||
StanUnsubmitted Done Inline ActionsYeah should definitely be one statement. Stan: Yeah should definitely be one statement. | |||||||
return false; | |||||||
return true; | |||||||
}; | |||||||
UnitAI.prototype.ReplaceOrder = function(type, data) | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||||
{ | { | ||||||
// Remember the previous work orders to be able to go back to them later if required | // Remember the previous work orders to be able to go back to them later if required | ||||||
if (data && data.force) | if (data && data.force) | ||||||
{ | { | ||||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||||
this.CallMemberFunction("UpdateWorkOrders", [type]); | this.CallMemberFunction("UpdateWorkOrders", [type]); | ||||||
else | else | ||||||
this.UpdateWorkOrders(type); | this.UpdateWorkOrders(type); | ||||||
} | } | ||||||
let garrisonHolder = this.IsGarrisoned() && type != "Ungarrison" ? this.GetGarrisonHolder() : null; | let garrisonHolder = this.IsGarrisoned() && type != "Ungarrison" ? this.GetGarrisonHolder() : null; | ||||||
Done Inline Actionsplease move this inside else if branch this.IsPacking() && type != "CancelPack" && ... so interface is called just when we need one Silier: please move this inside else if branch this.IsPacking() && type != "CancelPack" && ... so… | |||||||
// 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(); | ||||||
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(); | ||||||
if (type == "Attack") | |||||||
{ | |||||||
// The Attack order is able to handle a packing unit, while other orders can't. | |||||||
this.orderQueue = [packingOrder]; | |||||||
this.PushOrderFront(type, data, true); | |||||||
} | |||||||
else if (packingOrder.type == "Unpack" && g_OrdersCancelUnpacking.has(type)) | |||||||
{ | |||||||
// Immediately cancel unpacking before processing an order that demands a packed unit. | |||||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | |||||||
StanUnsubmitted Not Done Inline ActionsI guess we assume it has a pack component? Stan: I guess we assume it has a pack component? | |||||||
causativeUnsubmitted Done Inline ActionsIsPacking() was true so it must. causative: IsPacking() was true so it must. | |||||||
cmpPack.CancelPack(); | |||||||
this.orderQueue = []; | |||||||
this.PushOrder(type, data); | |||||||
} | |||||||
else | |||||||
this.orderQueue = [packingOrder, order]; | this.orderQueue = [packingOrder, order]; | ||||||
Done Inline Actionsif IsPacking returns true, cmpPack has to exists Silier: if IsPacking returns true, cmpPack has to exists
also since type is not in… | |||||||
Done Inline Actionsi meant type "Attack" is not in g_Order.. Silier: i meant type "Attack" is not in g_Order.. | |||||||
} | } | ||||||
else | else | ||||||
{ | { | ||||||
this.orderQueue = []; | this.orderQueue = []; | ||||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||||
} | } | ||||||
if (garrisonHolder) | if (garrisonHolder) | ||||||
▲ Show 20 Lines • Show All 1,307 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 | // Ignore also the request if we are packing | ||||||
Done Inline Actionsmove { to new line If owner of foundation is not ally, unit is not supposed to move, but it cancels unpacking what is bad. Silier: move { to new line
aside from that this does not work as should.
If owner of foundation is not… | |||||||
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))) | ||||||
return; | |||||||
if (this.IsPacking() && this.WillMoveFromFoundation(target, false)) | |||||||
SilierAuthorUnsubmitted Done Inline Actionsthis.orderQueue.length && this.orderQueue[0].type == "Unpack" is much faster check then what is here Silier: this.orderQueue.length && this.orderQueue[0].type == "Unpack" is much faster check then what is… | |||||||
{ | |||||||
let packingOrder = this.orderQueue[0]; | |||||||
StanUnsubmitted Done Inline ActionsWithout that temp variable you can inline the if ? Stan: Without that temp variable you can inline the if ?
| |||||||
if (packingOrder.type == "Unpack") | |||||||
{ | |||||||
// Immediately cancel unpacking before processing an order that demands a packed unit. | |||||||
SilierAuthorUnsubmitted Done Inline Actionsremove this, it is clear from CancelPack call Silier: remove this, it is clear from CancelPack call | |||||||
let cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | |||||||
cmpPack.CancelPack(); | |||||||
// Note that the unpacking order remains on the queue, so we will resume unpacking | |||||||
SilierAuthorUnsubmitted Done Inline Actionsremove this, it is clear from PushOrderFront call at L5166 Silier: remove this, it is clear from PushOrderFront call at L5166 | |||||||
// after the LeaveFoundation order. | |||||||
} | |||||||
} | |||||||
if (this.IsPacking()) | |||||||
StanUnsubmitted Not Done Inline ActionsYou check twice for it? Can there be a case where cancel pack doesn't cancel? Stan: You check twice for it? Can there be a case where cancel pack doesn't cancel? | |||||||
causativeUnsubmitted Done Inline ActionsIt could be packing as opposed to unpacking, which wouldn't be canceled. causative: It could be packing as opposed to unpacking, which wouldn't be canceled. | |||||||
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. | ||||||
*/ | */ | ||||||
▲ Show 20 Lines • Show All 1,008 Lines • Show Last 20 Lines |
it can or it will?