Changeset View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 576 Lines • ▼ Show 20 Lines | "Order.Repair": function(msg) { | ||||
if (this.CheckTargetRange(msg.data.target, IID_Builder)) | if (this.CheckTargetRange(msg.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"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
}, | }, | ||||
"Order.Garrison": function(msg) { | "Order.Garrison": function(msg) { | ||||
if (!this.AbleToMove()) | |||||
{ | |||||
// Garrisoned turrets (unable to move) go IDLE. | |||||
this.SetNextState("IDLE"); | |||||
return ACCEPT_ORDER; | |||||
} | |||||
if (this.isGarrisoned) | if (this.isGarrisoned) | ||||
{ | { | ||||
this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | this.SetNextState("INDIVIDUAL.GARRISON.GARRISONING"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
} | } | ||||
if (!this.AbleToMove()) | |||||
return this.FinishOrder(); | |||||
// Also pack when we are in range. | // Also pack when we are in range. | ||||
if (this.CanPack()) | if (this.CanPack()) | ||||
{ | { | ||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
} | } | ||||
if (this.CheckGarrisonRange(msg.data.target)) | if (this.CheckGarrisonRange(msg.data.target)) | ||||
this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | this.SetNextState("INDIVIDUAL.GARRISON.GARRISONING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING"); | this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
}, | }, | ||||
"Order.Ungarrison": function() { | "Order.Ungarrison": function() { | ||||
// Note that this order MUST succeed, or we break | // Note that this order MUST succeed, or we break | ||||
// the assumptions done in garrisonable/garrisonHolder, | // the assumptions done in garrisonable/garrisonHolder, | ||||
▲ Show 20 Lines • Show All 1,575 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
this.SetNextState("FINDINGNEWTARGET"); | this.SetNextState("FINDINGNEWTARGET"); | ||||
}, | }, | ||||
// 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 (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, true) != "Capture") | ||||
Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
this.RespondToTargetedEntities([msg.data.attacker]); | this.RespondToTargetedEntities([msg.data.attacker]); | ||||
}, | }, | ||||
}, | }, | ||||
"FINDINGNEWTARGET": { | "FINDINGNEWTARGET": { | ||||
"Order.Cheer": function() { | "Order.Cheer": function() { | ||||
if (!this.cheeringTime) | if (!this.cheeringTime) | ||||
return this.FinishOrder(); | return this.FinishOrder(); | ||||
▲ Show 20 Lines • Show All 1,024 Lines • ▼ Show 20 Lines | "GARRISON": { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
if (!msg.likelyFailure && !msg.likelySuccess) | if (!msg.likelyFailure && !msg.likelySuccess) | ||||
return; | return; | ||||
if (this.CheckGarrisonRange(this.order.data.target)) | if (this.CheckGarrisonRange(this.order.data.target)) | ||||
this.SetNextState("GARRISONED"); | this.SetNextState("GARRISONING"); | ||||
else | else | ||||
{ | { | ||||
// Unable to reach the target, try again (or follow if it is a moving target) | // Unable to reach the target, try again (or follow if it is a moving target) | ||||
// except if the target does not exist anymore or its orders have changed. | // except if the target does not exist anymore or its orders have changed. | ||||
if (this.pickup) | if (this.pickup) | ||||
{ | { | ||||
let cmpUnitAI = Engine.QueryInterface(this.pickup, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(this.pickup, IID_UnitAI); | ||||
if (!cmpUnitAI || (!cmpUnitAI.HasPickupOrder(this.entity) && !cmpUnitAI.IsIdle())) | if (!cmpUnitAI || (!cmpUnitAI.HasPickupOrder(this.entity) && !cmpUnitAI.IsIdle())) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
} | } | ||||
} | } | ||||
}, | }, | ||||
}, | }, | ||||
"GARRISONED": { | "GARRISONING": { | ||||
"enter": function() { | "enter": function() { | ||||
let target = this.order.data.target; | let target = this.order.data.target; | ||||
let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | ||||
if (!cmpGarrisonable || !cmpGarrisonable.Garrison(target)) | if (!cmpGarrisonable || !cmpGarrisonable.Garrison(target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 12 Lines | "GARRISON": { | ||||
let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); | let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); | ||||
if (this.CanReturnResource(target, true, cmpResourceGatherer)) | if (this.CanReturnResource(target, true, cmpResourceGatherer)) | ||||
{ | { | ||||
cmpResourceGatherer.CommitResources(target); | cmpResourceGatherer.CommitResources(target); | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
} | } | ||||
if (this.IsTurret()) | this.FinishOrder(); | ||||
{ | |||||
this.SetNextState("IDLE"); | |||||
return true; | return true; | ||||
} | |||||
return false; | |||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
"CHEERING": { | "CHEERING": { | ||||
▲ Show 20 Lines • Show All 324 Lines • ▼ Show 20 Lines | UnitAI.prototype.OnOwnershipChanged = function(msg) | ||||
if (this.isGuardOf && (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, this.isGuardOf))) | if (this.isGuardOf && (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, this.isGuardOf))) | ||||
this.RemoveGuard(); | this.RemoveGuard(); | ||||
// If the unit isn't being created or dying, reset stance and clear orders | // If the unit isn't being created or dying, reset stance and clear orders | ||||
if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) | if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) | ||||
{ | { | ||||
// Switch to a virgin state to let states execute their leave handlers. | // Switch to a virgin state to let states execute their leave handlers. | ||||
// Except if garrisoned or (un)packing, in which case we only clear the order queue. | // Except if garrisoned or (un)packing, in which case we only clear the order queue. | ||||
if (this.isGarrisoned || this.IsPacking()) | if (this.IsPacking()) | ||||
{ | { | ||||
this.orderQueue.length = Math.min(this.orderQueue.length, 1); | this.orderQueue.length = Math.min(this.orderQueue.length, 1); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
let index = this.GetCurrentState().indexOf("."); | let index = this.GetCurrentState().indexOf("."); | ||||
if (index != -1) | if (index != -1) | ||||
this.UnitFsm.SwitchToNextState(this, this.GetCurrentState().slice(0,index)); | this.UnitFsm.SwitchToNextState(this, this.GetCurrentState().slice(0,index)); | ||||
Lint: ESLintBear (comma-spacing) A space is required after ','. Lint: ESLintBear (comma-spacing): `A space is required after ','.` | |||||
this.Stop(false); | this.Stop(false); | ||||
} | } | ||||
this.workOrders = []; | this.workOrders = []; | ||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
if (cmpTrader) | if (cmpTrader) | ||||
cmpTrader.StopTrading(); | cmpTrader.StopTrading(); | ||||
Show All 37 Lines | |||||
UnitAI.prototype.OnPickupCanceled = function(msg) | UnitAI.prototype.OnPickupCanceled = function(msg) | ||||
{ | { | ||||
for (let i = 0; i < this.orderQueue.length; ++i) | for (let i = 0; i < this.orderQueue.length; ++i) | ||||
{ | { | ||||
if (this.orderQueue[i].type != "PickupUnit" || this.orderQueue[i].data.target != msg.entity) | if (this.orderQueue[i].type != "PickupUnit" || this.orderQueue[i].data.target != msg.entity) | ||||
continue; | continue; | ||||
if (i == 0) | if (i == 0) | ||||
this.UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); | this.UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
else | else | ||||
this.orderQueue.splice(i, 1); | this.orderQueue.splice(i, 1); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
break; | break; | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, | ||||
range.min, range.max, players, IID_Resistance, | range.min, range.max, players, IID_Resistance, | ||||
cmpRangeManager.GetEntityFlagMask("normal"), false); | cmpRangeManager.GetEntityFlagMask("normal"), false); | ||||
if (enable) | if (enable) | ||||
cmpRangeManager.EnableActiveQuery(this.losAttackRangeQuery); | cmpRangeManager.EnableActiveQuery(this.losAttackRangeQuery); | ||||
}; | }; | ||||
//// FSM linkage functions //// | //// FSM linkage functions //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
// Setting the next state to the current state will leave/re-enter the top-most substate. | // Setting the next state to the current state will leave/re-enter the top-most substate. | ||||
// Must be called from inside the FSM. | // Must be called from inside the FSM. | ||||
UnitAI.prototype.SetNextState = function(state) | UnitAI.prototype.SetNextState = function(state) | ||||
{ | { | ||||
this.UnitFsm.SetNextState(this, state); | this.UnitFsm.SetNextState(this, state); | ||||
}; | }; | ||||
Show All 30 Lines | if (!this.orderQueue.length) | ||||
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); | ||||
} | } | ||||
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 || this.IsFormationController() || | if (this.orderQueue.length && (this.IsFormationController() || | ||||
cmpPosition && cmpPosition.IsInWorld())) | 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 } | ||||
); | ); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | UnitAI.prototype.PushOrderAfterForced = function(type, data) | ||||
else | else | ||||
{ | { | ||||
for (let i = 1; i < this.orderQueue.length; ++i) | for (let i = 1; i < this.orderQueue.length; ++i) | ||||
{ | { | ||||
if (this.orderQueue[i].data && this.orderQueue[i].data.force) | if (this.orderQueue[i].data && this.orderQueue[i].data.force) | ||||
continue; | continue; | ||||
if (this.orderQueue[i].type == type) | if (this.orderQueue[i].type == type) | ||||
continue; | continue; | ||||
this.orderQueue.splice(i, 0, {"type": type, "data": data}); | this.orderQueue.splice(i, 0, {"type": type, "data": data}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
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() }); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
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; | |||||
// Do not replace packing/unpacking unless it is cancel order. | // Do not replace packing/unpacking unless it is cancel order. | ||||
// 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.IsPacking() && type != "CancelPack" && type != "CancelUnpack" && type != "Stop") | if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack" && type != "Stop") | ||||
{ | { | ||||
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") | if (type == "Attack") | ||||
{ | { | ||||
Show All 27 Lines | else if (this.IsFormationMember()) | ||||
this.PushOrderFront(type, data); | this.PushOrderFront(type, data); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
this.orderQueue = []; | this.orderQueue = []; | ||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||
} | } | ||||
if (garrisonHolder) | |||||
this.PushOrder("Garrison", { "target": garrisonHolder }); | |||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
UnitAI.prototype.GetOrders = function() | UnitAI.prototype.GetOrders = function() | ||||
{ | { | ||||
return this.orderQueue.slice(); | return this.orderQueue.slice(); | ||||
}; | }; | ||||
Show All 9 Lines | for (let order of this.orderQueue) | ||||
if (order.data) | if (order.data) | ||||
orders.push(clone(order.data)); | orders.push(clone(order.data)); | ||||
return orders; | return orders; | ||||
}; | }; | ||||
UnitAI.prototype.UpdateWorkOrders = function(type) | UnitAI.prototype.UpdateWorkOrders = function(type) | ||||
{ | { | ||||
var isWorkType = type => type == "Gather" || type == "Trade" || type == "Repair" || type == "ReturnResource"; | var isWorkType = type => type == "Gather" || type == "Trade" || type == "Repair" || type == "ReturnResource"; | ||||
Lint: ESLintBear (no-shadow) 'type' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'type' is already declared in the upper scope.` | |||||
if (isWorkType(type)) | if (isWorkType(type)) | ||||
{ | { | ||||
this.workOrders = []; | this.workOrders = []; | ||||
return; | return; | ||||
} | } | ||||
if (this.workOrders.length) | if (this.workOrders.length) | ||||
return; | return; | ||||
Show All 10 Lines | if (cmpUnitAI) | ||||
this.workOrders = cmpUnitAI.orderQueue.slice(i); | this.workOrders = cmpUnitAI.orderQueue.slice(i); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// If nothing found, take the unit orders | // If nothing found, take the unit orders | ||||
for (var i = 0; i < this.orderQueue.length; ++i) | for (var i = 0; i < this.orderQueue.length; ++i) | ||||
Lint: JSHintBear 'i' is already defined. Lint: JSHintBear: `'i' is already defined.` | |||||
{ | { | ||||
if (isWorkType(this.orderQueue[i].type)) | if (isWorkType(this.orderQueue[i].type)) | ||||
{ | { | ||||
this.workOrders = this.orderQueue.slice(i); | this.workOrders = this.orderQueue.slice(i); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
UnitAI.prototype.TimerHandler = function(data, lateness) | UnitAI.prototype.TimerHandler = function(data, lateness) | ||||
{ | { | ||||
// Reset the timer | // Reset the timer | ||||
if (data.timerRepeat === undefined) | if (data.timerRepeat === undefined) | ||||
this.timer = undefined; | this.timer = undefined; | ||||
this.UnitFsm.ProcessMessage(this, {"type": "Timer", "data": data, "lateness": lateness}); | this.UnitFsm.ProcessMessage(this, {"type": "Timer", "data": data, "lateness": lateness}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
}; | }; | ||||
/** | /** | ||||
* Set up the UnitAI timer to run after 'offset' msecs, and then | * Set up the UnitAI timer to run after 'offset' msecs, and then | ||||
* every 'repeat' msecs until StopTimer is called. A "Timer" message | * every 'repeat' msecs until StopTimer is called. A "Timer" message | ||||
* will be sent each time the timer runs. | * will be sent each time the timer runs. | ||||
*/ | */ | ||||
UnitAI.prototype.StartTimer = function(offset, repeat) | UnitAI.prototype.StartTimer = function(offset, repeat) | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | UnitAI.prototype.OnGlobalEntityRenamed = function(msg) | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
UnitAI.prototype.OnAttacked = function(msg) | UnitAI.prototype.OnAttacked = function(msg) | ||||
{ | { | ||||
if (msg.fromStatusEffect) | if (msg.fromStatusEffect) | ||||
return; | return; | ||||
this.UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg}); | this.UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
}; | }; | ||||
UnitAI.prototype.OnGuardedAttacked = function(msg) | UnitAI.prototype.OnGuardedAttacked = function(msg) | ||||
{ | { | ||||
this.UnitFsm.ProcessMessage(this, {"type": "GuardedAttacked", "data": msg.data}); | this.UnitFsm.ProcessMessage(this, {"type": "GuardedAttacked", "data": msg.data}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
}; | }; | ||||
UnitAI.prototype.OnRangeUpdate = function(msg) | UnitAI.prototype.OnRangeUpdate = function(msg) | ||||
{ | { | ||||
if (msg.tag == this.losRangeQuery) | if (msg.tag == this.losRangeQuery) | ||||
this.UnitFsm.ProcessMessage(this, { "type": "LosRangeUpdate", "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": "LosRangeUpdate", "data": msg }); | ||||
else if (msg.tag == this.losHealRangeQuery) | else if (msg.tag == this.losHealRangeQuery) | ||||
this.UnitFsm.ProcessMessage(this, { "type": "LosHealRangeUpdate", "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": "LosHealRangeUpdate", "data": msg }); | ||||
else if (msg.tag == this.losAttackRangeQuery) | else if (msg.tag == this.losAttackRangeQuery) | ||||
this.UnitFsm.ProcessMessage(this, { "type": "LosAttackRangeUpdate", "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": "LosAttackRangeUpdate", "data": msg }); | ||||
}; | }; | ||||
UnitAI.prototype.OnPackFinished = function(msg) | UnitAI.prototype.OnPackFinished = function(msg) | ||||
{ | { | ||||
this.UnitFsm.ProcessMessage(this, {"type": "PackFinished", "packed": msg.packed}); | this.UnitFsm.ProcessMessage(this, {"type": "PackFinished", "packed": msg.packed}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
}; | }; | ||||
/** | /** | ||||
* A general function to process messages sent from components. | * A general function to process messages sent from components. | ||||
* @param {string} type - The type of message to process. | * @param {string} type - The type of message to process. | ||||
* @param {Object} msg - Optionally extra data to use. | * @param {Object} msg - Optionally extra data to use. | ||||
*/ | */ | ||||
UnitAI.prototype.ProcessMessage = function(type, msg) | UnitAI.prototype.ProcessMessage = function(type, msg) | ||||
{ | { | ||||
this.UnitFsm.ProcessMessage(this, { "type": type, "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": type, "data": msg }); | ||||
}; | }; | ||||
//// Helper functions to be called by the FSM //// | //// Helper functions to be called by the FSM //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
UnitAI.prototype.GetWalkSpeed = function() | UnitAI.prototype.GetWalkSpeed = function() | ||||
{ | { | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
if (!cmpUnitMotion) | if (!cmpUnitMotion) | ||||
return 0; | return 0; | ||||
return cmpUnitMotion.GetWalkSpeed(); | return cmpUnitMotion.GetWalkSpeed(); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 706 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* 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)); | ||||
Lint: ESLintBear (no-shadow) 'target' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'target' is already declared in the upper scope.` | |||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | ||||
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 => | ||||
Lint: ESLintBear (no-shadow) 'target' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'target' is already declared in the upper scope.` | |||||
this.CanAttack(target) | this.CanAttack(target) | ||||
&& this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true)) | && this.CheckTargetDistanceFromHeldPosition(target, IID_Attack, this.GetBestAttackAgainst(target, true)) | ||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
&& (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | && (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | ||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
); | ); | ||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | ||||
return true; | return true; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* Try to respond to healable entities. | * Try to respond to healable entities. | ||||
* Returns true if it responded. | * Returns true if it responded. | ||||
*/ | */ | ||||
UnitAI.prototype.RespondToHealableEntities = function(ents) | UnitAI.prototype.RespondToHealableEntities = function(ents) | ||||
{ | { | ||||
let ent = ents.find(ent => this.CanHeal(ent)); | let ent = ents.find(ent => this.CanHeal(ent)); | ||||
Lint: ESLintBear (no-shadow) 'ent' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'ent' is already declared in the upper scope.` | |||||
if (!ent) | if (!ent) | ||||
return false; | return false; | ||||
this.PushOrderFront("Heal", { "target": ent, "force": false }); | this.PushOrderFront("Heal", { "target": ent, "force": false }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
Show All 9 Lines | if (force) | ||||
return false; | return false; | ||||
// If we are guarding/escorting, don't abandon as long as the guarded unit is in target range of the attacker | // If we are guarding/escorting, don't abandon as long as the guarded unit is in target range of the attacker | ||||
if (this.isGuardOf) | if (this.isGuardOf) | ||||
{ | { | ||||
let cmpUnitAI = Engine.QueryInterface(target, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(target, IID_UnitAI); | ||||
let cmpAttack = Engine.QueryInterface(target, IID_Attack); | let cmpAttack = Engine.QueryInterface(target, IID_Attack); | ||||
if (cmpUnitAI && cmpAttack && | if (cmpUnitAI && cmpAttack && | ||||
cmpAttack.GetAttackTypes().some(type => cmpUnitAI.CheckTargetAttackRange(this.isGuardOf, type))) | cmpAttack.GetAttackTypes().some(type => cmpUnitAI.CheckTargetAttackRange(this.isGuardOf, type))) | ||||
Lint: ESLintBear (no-shadow) 'type' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'type' is already declared in the upper scope.` | |||||
return false; | return false; | ||||
Lint: ESLintBear (indent) Expected indentation of 3 tabs but found 4. Lint: ESLintBear (indent): `Expected indentation of 3 tabs but found 4.` | |||||
} | } | ||||
if (this.GetStance().respondHoldGround) | if (this.GetStance().respondHoldGround) | ||||
if (!this.CheckTargetDistanceFromHeldPosition(target, iid, type)) | if (!this.CheckTargetDistanceFromHeldPosition(target, iid, type)) | ||||
return true; | return true; | ||||
// Stop if it's left our vision range, unless we're especially persistent. | // Stop if it's left our vision range, unless we're especially persistent. | ||||
if (!this.GetStance().respondChaseBeyondVision) | if (!this.GetStance().respondChaseBeyondVision) | ||||
Show All 13 Lines | 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) | ||||
{ | { | ||||
let cmpUnitAI = Engine.QueryInterface(target, IID_UnitAI); | let cmpUnitAI = Engine.QueryInterface(target, IID_UnitAI); | ||||
Lint: ESLintBear (no-multi-spaces) Multiple spaces found before 'Engine'. Lint: ESLintBear (no-multi-spaces): `Multiple spaces found before 'Engine'.` | |||||
let cmpAttack = Engine.QueryInterface(target, IID_Attack); | let cmpAttack = Engine.QueryInterface(target, IID_Attack); | ||||
if (cmpUnitAI && cmpAttack && | if (cmpUnitAI && cmpAttack && | ||||
cmpAttack.GetAttackTypes().some(type => cmpUnitAI.CheckTargetAttackRange(this.isGuardOf, type))) | cmpAttack.GetAttackTypes().some(type => cmpUnitAI.CheckTargetAttackRange(this.isGuardOf, type))) | ||||
return true; | return true; | ||||
} | } | ||||
return force; | return force; | ||||
}; | }; | ||||
//// External interface functions //// | //// External interface functions //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
/** | /** | ||||
* Order a unit to leave the formation it is in. | * Order a unit to leave the formation it is in. | ||||
* Used to handle queued no-formation orders for units in formation. | * Used to handle queued no-formation orders for units in formation. | ||||
*/ | */ | ||||
UnitAI.prototype.LeaveFormation = function(queued = true) | UnitAI.prototype.LeaveFormation = function(queued = true) | ||||
{ | { | ||||
// If queued, add the order even if we're not in formation, | // If queued, add the order even if we're not in formation, | ||||
▲ Show 20 Lines • Show All 156 Lines • ▼ Show 20 Lines | UnitAI.prototype.Guard = function(target, queued, pushFront) | ||||
if (target === this.entity) | if (target === this.entity) | ||||
return; | return; | ||||
if (this.isGuardOf) | if (this.isGuardOf) | ||||
{ | { | ||||
if (this.isGuardOf == target && this.order && this.order.type == "Guard") | if (this.isGuardOf == target && this.order && this.order.type == "Guard") | ||||
return; | return; | ||||
else | else | ||||
this.RemoveGuard(); | this.RemoveGuard(); | ||||
Lint: ESLintBear (no-else-return) Unnecessary 'else' after 'return'. Lint: ESLintBear (no-else-return): `Unnecessary 'else' after 'return'.` | |||||
} | } | ||||
this.AddOrder("Guard", { "target": target, "force": false }, queued, pushFront); | this.AddOrder("Guard", { "target": target, "force": false }, queued, pushFront); | ||||
}; | }; | ||||
/** | /** | ||||
* @return {boolean} - Whether it makes sense to guard the given entity. | * @return {boolean} - Whether it makes sense to guard the given entity. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 209 Lines • ▼ Show 20 Lines | |||||
UnitAI.prototype.Ungarrison = function() | UnitAI.prototype.Ungarrison = function() | ||||
{ | { | ||||
if (!this.isGarrisoned) | if (!this.isGarrisoned) | ||||
return; | return; | ||||
this.AddOrder("Ungarrison", null, false); | this.AddOrder("Ungarrison", null, false); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds a garrison order for units that are already garrisoned in the garrison holder. | |||||
*/ | |||||
UnitAI.prototype.Autogarrison = function(target) | |||||
{ | |||||
this.PushOrderFront("Garrison", { "target": target }); | |||||
}; | |||||
/** | |||||
* Adds gather order to the queue, forced by the player | * Adds gather order to the queue, forced by the player | ||||
* until the target is reached | * until the target is reached | ||||
*/ | */ | ||||
UnitAI.prototype.Gather = function(target, queued, pushFront) | UnitAI.prototype.Gather = function(target, queued, pushFront) | ||||
{ | { | ||||
this.PerformGather(target, queued, true, pushFront); | this.PerformGather(target, queued, true, pushFront); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 453 Lines • ▼ Show 20 Lines | for (var ent of cmpFormation.members) | ||||
{ | { | ||||
if (!cmpUnitAI.CanAttack(targ)) | if (!cmpUnitAI.CanAttack(targ)) | ||||
continue; | continue; | ||||
if (this.order.data.targetClasses) | if (this.order.data.targetClasses) | ||||
{ | { | ||||
var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); | var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); | ||||
var targetClasses = this.order.data.targetClasses; | var targetClasses = this.order.data.targetClasses; | ||||
if (targetClasses.attack && cmpIdentity | if (targetClasses.attack && cmpIdentity | ||||
&& !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | ||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
continue; | continue; | ||||
if (targetClasses.avoid && cmpIdentity | if (targetClasses.avoid && cmpIdentity | ||||
&& MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | ||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
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, "allowCapture": this.order.data.allowCapture }); | ||||
return true; | return true; | ||||
} | } | ||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
var targets = this.GetTargetsFromUnit(); | var targets = this.GetTargetsFromUnit(); | ||||
Lint: JSHintBear 'targets' is already defined. Lint: JSHintBear: `'targets' is already defined.` | |||||
for (var targ of targets) | for (var targ of targets) | ||||
Lint: JSHintBear 'targ' is already defined. Lint: JSHintBear: `'targ' is already defined.` | |||||
{ | { | ||||
if (!this.CanAttack(targ)) | if (!this.CanAttack(targ)) | ||||
continue; | continue; | ||||
if (this.order.data.targetClasses) | if (this.order.data.targetClasses) | ||||
{ | { | ||||
var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); | var cmpIdentity = Engine.QueryInterface(targ, IID_Identity); | ||||
Lint: JSHintBear 'cmpIdentity' is already defined. Lint: JSHintBear: `'cmpIdentity' is already defined.` | |||||
var targetClasses = this.order.data.targetClasses; | var targetClasses = this.order.data.targetClasses; | ||||
Lint: JSHintBear 'targetClasses' is already defined. Lint: JSHintBear: `'targetClasses' is already defined.` | |||||
if (cmpIdentity && targetClasses.attack | if (cmpIdentity && targetClasses.attack | ||||
&& !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | ||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
continue; | continue; | ||||
if (cmpIdentity && targetClasses.avoid | if (cmpIdentity && targetClasses.avoid | ||||
&& MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | ||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
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, "allowCapture": this.order.data.allowCapture }); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | 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) | UnitAI.prototype.SetHeldPosition = function(x, z) | ||||
{ | { | ||||
this.heldPosition = {"x": x, "z": z}; | this.heldPosition = {"x": x, "z": z}; | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
}; | }; | ||||
UnitAI.prototype.SetHeldPositionOnEntity = function(entity) | UnitAI.prototype.SetHeldPositionOnEntity = function(entity) | ||||
{ | { | ||||
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(); | var pos = cmpPosition.GetPosition(); | ||||
Show All 10 Lines | UnitAI.prototype.WalkToHeldPosition = function() | ||||
if (this.heldPosition) | if (this.heldPosition) | ||||
{ | { | ||||
this.AddOrder("Walk", { "x": this.heldPosition.x, "z": this.heldPosition.z, "force": false }, false, false); | this.AddOrder("Walk", { "x": this.heldPosition.x, "z": this.heldPosition.z, "force": false }, false, false); | ||||
return true; | return true; | ||||
} | } | ||||
return false; | return false; | ||||
}; | }; | ||||
//// Helper functions //// | //// Helper functions //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
/** | /** | ||||
* 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 | ||||
* { "min": number, "max": number } | * { "min": number, "max": number } | ||||
* Object."elevationBonus": number may be present when iid == IID_Attack. | * Object."elevationBonus": number may be present when iid == IID_Attack. | ||||
* Returns undefined when the entity does not have the requested component. | * Returns undefined when the entity does not have the requested component. | ||||
*/ | */ | ||||
UnitAI.prototype.GetRange = function(iid, type) | UnitAI.prototype.GetRange = function(iid, type) | ||||
{ | { | ||||
let component = Engine.QueryInterface(this.entity, iid); | let component = Engine.QueryInterface(this.entity, iid); | ||||
if (!component) | if (!component) | ||||
return undefined; | return undefined; | ||||
return component.GetRange(type); | return component.GetRange(type); | ||||
} | } | ||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
UnitAI.prototype.CanAttack = function(target) | UnitAI.prototype.CanAttack = function(target) | ||||
{ | { | ||||
// Formation controllers should always respond to commands | // Formation controllers should always respond to commands | ||||
// (then the individual units can make up their own minds) | // (then the individual units can make up their own minds) | ||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
UnitAI.prototype.IsPacking = function() | UnitAI.prototype.IsPacking = function() | ||||
{ | { | ||||
var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
return cmpPack && cmpPack.IsPacking(); | return cmpPack && cmpPack.IsPacking(); | ||||
}; | }; | ||||
//// Formation specific functions //// | //// Formation specific functions //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
UnitAI.prototype.IsAttackingAsFormation = function() | UnitAI.prototype.IsAttackingAsFormation = function() | ||||
{ | { | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
return cmpAttack && cmpAttack.CanAttackAsFormation() | return cmpAttack && cmpAttack.CanAttackAsFormation() | ||||
&& this.GetCurrentState() == "FORMATIONCONTROLLER.COMBAT.ATTACKING"; | && this.GetCurrentState() == "FORMATIONCONTROLLER.COMBAT.ATTACKING"; | ||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
}; | }; | ||||
UnitAI.prototype.MoveRandomly = function(distance) | UnitAI.prototype.MoveRandomly = function(distance) | ||||
{ | { | ||||
// To minimize drift all across the map, describe circles | // To minimize drift all across the map, describe circles | ||||
// approximated by polygons. | // approximated by polygons. | ||||
// And to avoid getting stuck in obstacles or narrow spaces, each side | // And to avoid getting stuck in obstacles or narrow spaces, each side | ||||
// of the polygon is obtained by trying to go away from a point situated | // of the polygon is obtained by trying to go away from a point situated | ||||
Show All 35 Lines | UnitAI.prototype.SetFacePointAfterMove = function(val) | ||||
if (cmpMotion) | if (cmpMotion) | ||||
cmpMotion.SetFacePointAfterMove(val); | cmpMotion.SetFacePointAfterMove(val); | ||||
}; | }; | ||||
UnitAI.prototype.GetFacePointAfterMove = function() | UnitAI.prototype.GetFacePointAfterMove = function() | ||||
{ | { | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
return cmpUnitMotion && cmpUnitMotion.GetFacePointAfterMove(); | return cmpUnitMotion && cmpUnitMotion.GetFacePointAfterMove(); | ||||
} | } | ||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
UnitAI.prototype.AttackEntitiesByPreference = function(ents) | UnitAI.prototype.AttackEntitiesByPreference = function(ents) | ||||
{ | { | ||||
if (!ents.length) | if (!ents.length) | ||||
return false; | return false; | ||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
if (!cmpAttack) | if (!cmpAttack) | ||||
▲ Show 20 Lines • Show All 103 Lines • Show Last 20 Lines |
'&&' should be placed at the end of the line.