Changeset View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 340 Lines • ▼ Show 20 Lines | if (this.CanPack()) | ||||
return; | return; | ||||
} | } | ||||
if (this.CheckRange(this.order.data)) | if (this.CheckRange(this.order.data)) | ||||
{ | { | ||||
// We are already at the target, or can't move at all | // We are already at the target, or can't move at all | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
Lint: ESLintBear (consistent-return): `Method 'Order.WalkToTarget' expected no return value.` | |||||
} | } | ||||
// It's not too bad if we don't arrive at exactly the right position. | // It's not too bad if we don't arrive at exactly the right position. | ||||
this.order.data.relaxed = true; | this.order.data.relaxed = true; | ||||
if (this.IsAnimal()) | if (this.IsAnimal()) | ||||
this.SetNextState("ANIMAL.WALKING"); | this.SetNextState("ANIMAL.WALKING"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.WALKING"); | this.SetNextState("INDIVIDUAL.WALKING"); | ||||
}, | }, | ||||
"Order.Follow": function(msg) { | |||||
if (!this.AbleToMove()) | |||||
{ | |||||
this.FinishOrder(); | |||||
return; | |||||
} | |||||
// For packable units: | |||||
// 1. If packed, we can move. | |||||
// 2. If unpacked, we first need to pack, then follow case 1. | |||||
if (this.CanPack()) | |||||
{ | |||||
this.PushOrderFront("Pack", { "force": true }); | |||||
return; | |||||
} | |||||
// It's not too bad if we don't arrive at exactly the right position. | |||||
this.order.data.relaxed = true; | |||||
this.order.data.range = this.GetRange(this.order.data.iid); | |||||
// We need a bit of leeway when following. | |||||
this.order.data.range.max *= 0.9; | |||||
if (this.IsAnimal()) | |||||
this.SetNextState("ANIMAL.WALKING"); | |||||
else | |||||
this.SetNextState("INDIVIDUAL.FOLLOWING"); | |||||
}, | |||||
"Order.PickupUnit": function(msg) { | "Order.PickupUnit": function(msg) { | ||||
let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(this.entity, IID_GarrisonHolder); | ||||
if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) | if (!cmpGarrisonHolder || cmpGarrisonHolder.IsFull()) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 423 Lines • ▼ Show 20 Lines | "Order.Garrison": function(msg) { | ||||
if (!this.CheckGarrisonRange(msg.data.target)) | if (!this.CheckGarrisonRange(msg.data.target)) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(msg.data.target)) | if (!this.CheckTargetVisible(msg.data.target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return; | return; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
Lint: ESLintBear (no-else-return) Unnecessary 'else' after 'return'. Lint: ESLintBear (no-else-return): `Unnecessary 'else' after 'return'.` | |||||
this.SetNextState("GARRISON.APPROACHING"); | this.SetNextState("GARRISON.APPROACHING"); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
this.SetNextState("GARRISON.GARRISONING"); | this.SetNextState("GARRISON.GARRISONING"); | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 246 Lines • ▼ Show 20 Lines | "PATROL": { | ||||
if (this.orderQueue.length == 1) | if (this.orderQueue.length == 1) | ||||
this.PushOrder("Patrol", this.patrolStartPosOrder); | this.PushOrder("Patrol", this.patrolStartPosOrder); | ||||
this.PushOrder(this.order.type, this.order.data); | this.PushOrder(this.order.type, this.order.data); | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
}, | }, | ||||
"GARRISON":{ | "GARRISON":{ | ||||
Lint: ESLintBear (key-spacing) Missing space before value for key 'GARRISON'. Lint: ESLintBear (key-spacing): `Missing space before value for key 'GARRISON'.` | |||||
"APPROACHING": { | "APPROACHING": { | ||||
"enter": function() { | "enter": function() { | ||||
if (!this.MoveToGarrisonRange(this.order.data.target)) | if (!this.MoveToGarrisonRange(this.order.data.target)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
▲ Show 20 Lines • Show All 531 Lines • ▼ Show 20 Lines | "WALKING": { | ||||
// If it looks like the path is failing, and we are close enough (3 tiles) | // If it looks like the path is failing, and we are close enough (3 tiles) | ||||
// stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | // stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | ||||
if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | ||||
this.CheckRange(this.order.data)) | this.CheckRange(this.order.data)) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
}, | }, | ||||
"FOLLOWING": { | |||||
"enter": function() { | |||||
if (!this.MoveToTargetRangeExplicit(this.order.data.target, this.order.data.range.min, this.order.data.range.max)) | |||||
Done Inline Actionsthis.order.data.iid || undefined necessary ? Stan: this.order.data.iid || undefined necessary ? | |||||
{ | |||||
this.FinishOrder(); | |||||
return true; | |||||
} | |||||
this.StartTimer(0, 500); | |||||
Done Inline Actions+ return false ? Stan: + return false ? | |||||
return false; | |||||
}, | |||||
"leave": function() { | |||||
this.StopMoving(); | |||||
this.ResetSpeedMultiplier(); | |||||
this.StopTimer(); | |||||
}, | |||||
"Timer": function() { | |||||
Lint: ESLintBear (consistent-return) Expected to return a value at the end of method 'Timer'. Lint: ESLintBear (consistent-return): `Expected to return a value at the end of method 'Timer'.` | |||||
if (this.CheckTargetRangeExplicit(this.order.data.target, this.order.data.range.min, this.order.data.range.max)) | |||||
{ | |||||
this.StopMoving(); | |||||
this.DelegateOrder(this.order.data); | |||||
} | |||||
else if (!this.MoveToTargetRangeExplicit(this.order.data.target, this.order.data.range.min, this.order.data.range.max)) | |||||
{ | |||||
this.FinishOrder(); | |||||
return true; | |||||
} | |||||
}, | |||||
"MovementUpdate": function(msg) { | |||||
// If it looks like the path is failing, and we are close enough (3 tiles) stop anyways. | |||||
Done Inline Actions+ return false ? Stan: + return false ? | |||||
Done Inline ActionsNot needed. Freagarach: Not needed. | |||||
// This avoids pathing for an unreachable goal and reduces lag considerably. | |||||
if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | |||||
this.CheckTargetRangeExplicit(this.order.data.target, this.order.data.range.min, this.order.data.range.max)) | |||||
{ | |||||
this.TryMatchTargetSpeed(this.order.data.target, true); | |||||
this.DelegateOrder(this.order.data); | |||||
} | |||||
}, | |||||
}, | |||||
"WALKINGANDFIGHTING": { | "WALKINGANDFIGHTING": { | ||||
"enter": function() { | "enter": function() { | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
// Show weapons rather than carried resources. | // Show weapons rather than carried resources. | ||||
▲ Show 20 Lines • Show All 444 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
}, | }, | ||||
// TODO: respond to target deaths immediately, rather than waiting | // TODO: respond to target deaths immediately, rather than waiting | ||||
// until the next Timer event | // until the next Timer event | ||||
"Attacked": function(msg) { | "Attacked": function(msg) { | ||||
// If we are capturing and are attacked by something that we would not capture, attack that entity instead | // If we are capturing and are attacked by something that we would not capture, attack that entity instead | ||||
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: 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.RespondToTargetedEntities([msg.data.attacker]); | this.RespondToTargetedEntities([msg.data.attacker]); | ||||
}, | }, | ||||
}, | }, | ||||
"FINDINGNEWTARGET": { | "FINDINGNEWTARGET": { | ||||
"enter": function() { | "enter": function() { | ||||
// Try to find the formation the target was a part of. | // Try to find the formation the target was a part of. | ||||
let cmpFormation = Engine.QueryInterface(this.order.data.target, IID_Formation); | let cmpFormation = Engine.QueryInterface(this.order.data.target, IID_Formation); | ||||
▲ Show 20 Lines • Show All 141 Lines • ▼ Show 20 Lines | "COMBAT": { | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.StopMoving(); | this.StopMoving(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
// If it looks like the path is failing, and we are close enough (3 tiles) from wanted range | // If it looks like the path is failing, and we are close enough (3 tiles) from wanted range | ||||
// stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | // stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | ||||
if (msg.likelyFailure || | if (msg.likelyFailure || | ||||
Lint: ESLintBear (no-trailing-spaces) Trailing spaces not allowed. Lint: ESLintBear (no-trailing-spaces): `Trailing spaces not allowed.` | |||||
msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.order.data.max + this.DefaultRelaxedMaxRange) || | msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.order.data.max + this.DefaultRelaxedMaxRange) || | ||||
!msg.obstructed && this.CheckRange(this.order.data)) | !msg.obstructed && this.CheckRange(this.order.data)) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
}, | }, | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | "GATHER": { | ||||
if (previousTarget == ent) | if (previousTarget == ent) | ||||
return false; | return false; | ||||
if (type.generic == "treasure" && resourceType.generic == "treasure") | if (type.generic == "treasure" && resourceType.generic == "treasure") | ||||
return true; | return true; | ||||
return type.specific == resourceType.specific && | return type.specific == resourceType.specific && | ||||
(type.specific != "meat" || resourceTemplate == template); | (type.specific != "meat" || resourceTemplate == template); | ||||
}); | }); | ||||
Lint: ESLintBear (indent) Expected indentation of 6 tabs but found 5. Lint: ESLintBear (indent): `Expected indentation of 6 tabs but found 5.` | |||||
if (nearbyResource) | if (nearbyResource) | ||||
{ | { | ||||
this.PerformGather(nearbyResource, false, false); | this.PerformGather(nearbyResource, false, false); | ||||
return true; | return true; | ||||
} | } | ||||
// Failing that, try to move there and se if we are more lucky: maybe there are resources in FOW. | // Failing that, try to move there and se if we are more lucky: maybe there are resources in FOW. | ||||
▲ Show 20 Lines • Show All 600 Lines • ▼ Show 20 Lines | "CHEERING": { | ||||
this.StartTimer(2800, 2800); | this.StartTimer(2800, 2800); | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.StopTimer(); | this.StopTimer(); | ||||
this.ResetAnimation(); | this.ResetAnimation(); | ||||
if (this.formationAnimationVariant) | if (this.formationAnimationVariant) | ||||
this.SetAnimationVariant(this.formationAnimationVariant) | this.SetAnimationVariant(this.formationAnimationVariant) | ||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
else | else | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
var cmpResistance = Engine.QueryInterface(this.entity, IID_Resistance); | var cmpResistance = Engine.QueryInterface(this.entity, IID_Resistance); | ||||
cmpResistance.SetInvulnerability(false); | cmpResistance.SetInvulnerability(false); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | "FEEDING": { | ||||
}, | }, | ||||
}, | }, | ||||
"FLEEING": "INDIVIDUAL.FLEEING", // reuse the same fleeing behaviour for animals | "FLEEING": "INDIVIDUAL.FLEEING", // reuse the same fleeing behaviour for animals | ||||
"COMBAT": "INDIVIDUAL.COMBAT", // reuse the same combat behaviour for animals | "COMBAT": "INDIVIDUAL.COMBAT", // reuse the same combat behaviour for animals | ||||
"WALKING": "INDIVIDUAL.WALKING", // reuse the same walking behaviour for animals | "WALKING": "INDIVIDUAL.WALKING", // reuse the same walking behaviour for animals | ||||
// only used for domestic animals | // only used for domestic animals | ||||
Lint: ESLintBear (indent) Expected indentation of 2 tabs but found 7. Lint: ESLintBear (indent): `Expected indentation of 2 tabs but found 7.` | |||||
// Reuse the same garrison behaviour for animals. | // Reuse the same garrison behaviour for animals. | ||||
"GARRISON": "INDIVIDUAL.GARRISON", | "GARRISON": "INDIVIDUAL.GARRISON", | ||||
}, | }, | ||||
}; | }; | ||||
UnitAI.prototype.Init = function() | UnitAI.prototype.Init = function() | ||||
{ | { | ||||
Show All 33 Lines | |||||
UnitAI.prototype.IsFormationMember = function() | UnitAI.prototype.IsFormationMember = function() | ||||
{ | { | ||||
return (this.formationController != INVALID_ENTITY); | return (this.formationController != INVALID_ENTITY); | ||||
}; | }; | ||||
UnitAI.prototype.IsAnimal = function() | UnitAI.prototype.IsAnimal = function() | ||||
{ | { | ||||
return (this.template.NaturalBehaviour ? true : false); | return (this.template.NaturalBehaviour ? true : false); | ||||
Lint: ESLintBear (no-unneeded-ternary) Unnecessary use of boolean literals in conditional expression. Lint: ESLintBear (no-unneeded-ternary): `Unnecessary use of boolean literals in conditional expression.` | |||||
}; | }; | ||||
UnitAI.prototype.IsDangerousAnimal = function() | UnitAI.prototype.IsDangerousAnimal = function() | ||||
{ | { | ||||
return (this.IsAnimal() && (this.template.NaturalBehaviour == "violent" || | return (this.IsAnimal() && (this.template.NaturalBehaviour == "violent" || | ||||
this.template.NaturalBehaviour == "aggressive")); | this.template.NaturalBehaviour == "aggressive")); | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) | ||||
{ | { | ||||
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 40 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 112 Lines • ▼ Show 20 Lines | UnitAI.prototype.SetupAttackRangeQuery = function(enable = true) | ||||
let range = this.GetQueryRange(IID_Attack); | let range = this.GetQueryRange(IID_Attack); | ||||
this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal")); | this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, range.min, range.max, players, IID_Resistance, cmpRangeManager.GetEntityFlagMask("normal")); | ||||
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. | ||||
UnitAI.prototype.SetNextState = function(state) | UnitAI.prototype.SetNextState = function(state) | ||||
{ | { | ||||
this.UnitFsm.SetNextState(this, state); | this.UnitFsm.SetNextState(this, state); | ||||
}; | }; | ||||
UnitAI.prototype.DeferMessage = function(msg) | UnitAI.prototype.DeferMessage = function(msg) | ||||
▲ Show 20 Lines • Show All 156 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 73 Lines • ▼ Show 20 Lines | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
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 }; | ||||
Lint: JSHintBear 'order' is already defined. Lint: JSHintBear: `'order' is already defined.` | |||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||
if (type == "Attack") | if (type == "Attack") | ||||
{ | { | ||||
// The Attack order is able to handle a packing unit, while other orders can't. | // The Attack order is able to handle a packing unit, while other orders can't. | ||||
this.orderQueue = [packingOrder]; | this.orderQueue = [packingOrder]; | ||||
this.PushOrderFront(type, data, true); | this.PushOrderFront(type, data, true); | ||||
} | } | ||||
else if (packingOrder.type == "Unpack" && g_OrdersCancelUnpacking.has(type)) | else if (packingOrder.type == "Unpack" && g_OrdersCancelUnpacking.has(type)) | ||||
Show All 36 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 we are being re-affected to a work order, forget the previous ones | // If we are being re-affected to a work order, forget the previous ones | ||||
if (isWorkType(type)) | if (isWorkType(type)) | ||||
{ | { | ||||
this.workOrders = []; | this.workOrders = []; | ||||
return; | return; | ||||
} | } | ||||
Show All 14 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 50 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 69 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.OnHealthChanged = function(msg) | UnitAI.prototype.OnHealthChanged = function(msg) | ||||
{ | { | ||||
this.UnitFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to}); | this.UnitFsm.ProcessMessage(this, {"type": "HealthChanged", "from": msg.from, "to": msg.to}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
}; | }; | ||||
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 '}'.` | |||||
}; | }; | ||||
//// 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 692 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: 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.` | |||||
&& (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | && (this.GetStance().respondChaseBeyondVision || this.CheckTargetIsInVisionRange(target)) | ||||
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.` | |||||
); | ); | ||||
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; | ||||
}; | }; | ||||
/** | /** | ||||
* Returns true if we should stop following the target entity. | * Returns true if we should stop following the target entity. | ||||
*/ | */ | ||||
UnitAI.prototype.ShouldAbandonChase = function(target, force, iid, type) | UnitAI.prototype.ShouldAbandonChase = function(target, force, iid, type) | ||||
{ | { | ||||
// Forced orders shouldn't be interrupted. | // Forced orders shouldn't be interrupted. | ||||
if (force) | 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) | ||||
{ | { | ||||
var cmpUnitAI = Engine.QueryInterface(target, IID_UnitAI); | var 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'.` | |||||
var cmpAttack = Engine.QueryInterface(target, IID_Attack); | var 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.` | |||||
} | } | ||||
// Stop if we're in hold-ground mode and it's too far from the holding point | // Stop if we're in hold-ground mode and it's too far from the holding point | ||||
if (this.GetStance().respondHoldGround) | if (this.GetStance().respondHoldGround) | ||||
{ | { | ||||
if (!this.CheckTargetDistanceFromHeldPosition(target, iid, type)) | if (!this.CheckTargetDistanceFromHeldPosition(target, iid, type)) | ||||
return true; | return true; | ||||
} | } | ||||
Show All 21 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; | ||||
} | } | ||||
if (force) | if (force) | ||||
return true; | return true; | ||||
return false; | return false; | ||||
}; | }; | ||||
//// 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.` | |||||
UnitAI.prototype.SetFormationController = function(ent) | UnitAI.prototype.SetFormationController = function(ent) | ||||
{ | { | ||||
this.formationController = ent; | this.formationController = ent; | ||||
// Set obstruction group, so we can walk through members | // Set obstruction group, so we can walk through members | ||||
// of our own formation (or ourself if not in formation) | // of our own formation (or ourself if not in formation) | ||||
var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | UnitAI.prototype.Guard = function(target, queued) | ||||
// if we already had an old guard order, do nothing if the target is the same | // if we already had an old guard order, do nothing if the target is the same | ||||
// and the order is running, otherwise remove the previous order | // and the order is running, otherwise remove the previous order | ||||
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); | this.AddOrder("Guard", { "target": target, "force": false }, queued); | ||||
}; | }; | ||||
UnitAI.prototype.AddGuard = function(target) | UnitAI.prototype.AddGuard = function(target) | ||||
{ | { | ||||
if (!this.CanGuard()) | if (!this.CanGuard()) | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | UnitAI.prototype.Attack = function(target, allowCapture = true, queued = false) | ||||
} | } | ||||
let order = { | let order = { | ||||
"target": target, | "target": target, | ||||
"force": true, | "force": true, | ||||
"allowCapture": allowCapture, | "allowCapture": allowCapture, | ||||
}; | }; | ||||
// This is the case when an entity that has visibly garrisoned entities that can | |||||
// attack, but the entity itself can't attack. | |||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack) | |||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
if (!cmpAttack) | |||||
{ | |||||
order.type = "Attack"; | |||||
order.iid = IID_Attack; | |||||
this.AddOrder("Follow", order, queued); | |||||
return; | |||||
} | |||||
this.RememberTargetPosition(order); | this.RememberTargetPosition(order); | ||||
this.AddOrder("Attack", order, queued); | this.AddOrder("Attack", order, queued); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds garrison order to the queue, forced by the player. | * Adds garrison order to the queue, forced by the player. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 104 Lines • ▼ Show 20 Lines | |||||
UnitAI.prototype.Heal = function(target, queued) | UnitAI.prototype.Heal = function(target, queued) | ||||
{ | { | ||||
if (!this.CanHeal(target)) | if (!this.CanHeal(target)) | ||||
{ | { | ||||
this.WalkToTarget(target, queued); | this.WalkToTarget(target, queued); | ||||
return; | return; | ||||
} | } | ||||
this.AddOrder("Heal", { "target": target, "force": true }, queued); | let order = { | ||||
"target": target, | |||||
"force": true | |||||
}; | |||||
// This is the case when an entity that has visibly garrisoned entities that can | |||||
// heal, but the entity itself can't heal. | |||||
let cmpHeal = Engine.QueryInterface(this.entity, IID_Heal) | |||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
if (!cmpHeal) | |||||
{ | |||||
order.type = "Heal"; | |||||
order.iid = IID_Heal; | |||||
this.AddOrder("Follow", order, queued); | |||||
return; | |||||
} | |||||
this.AddOrder("Heal", order, queued); | |||||
}; | }; | ||||
/** | /** | ||||
* Adds return resource order to the queue, forced by the player. | * Adds return resource order to the queue, forced by the player. | ||||
*/ | */ | ||||
UnitAI.prototype.ReturnResource = function(target, queued) | UnitAI.prototype.ReturnResource = function(target, queued) | ||||
{ | { | ||||
if (!this.CanReturnResource(target, true)) | if (!this.CanReturnResource(target, true)) | ||||
Show All 9 Lines | |||||
{ | { | ||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
if (!cmpTrader) | if (!cmpTrader) | ||||
return; | return; | ||||
cmpTrader.RemoveTargetMarket(target); | cmpTrader.RemoveTargetMarket(target); | ||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||
this.CallMemberFunction("CancelSetupTradeRoute", [target]); | this.CallMemberFunction("CancelSetupTradeRoute", [target]); | ||||
} | } | ||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
/** | /** | ||||
* Adds trade order to the queue. Either walk to the first market, or | * Adds trade order to the queue. Either walk to the first market, or | ||||
* start a new route. Not forced, so it can be interrupted by attacks. | * start a new route. Not forced, so it can be interrupted by attacks. | ||||
* The possible route may be given directly as a SetupTradeRoute argument | * The possible route may be given directly as a SetupTradeRoute argument | ||||
* if coming from a RallyPoint, or through this.expectedRoute if a user command. | * if coming from a RallyPoint, or through this.expectedRoute if a user command. | ||||
*/ | */ | ||||
UnitAI.prototype.SetupTradeRoute = function(target, source, route, queued) | UnitAI.prototype.SetupTradeRoute = function(target, source, route, queued) | ||||
{ | { | ||||
if (!this.CanTrade(target)) | if (!this.CanTrade(target)) | ||||
{ | { | ||||
this.WalkToTarget(target, queued); | this.WalkToTarget(target, queued); | ||||
return; | return; | ||||
} | } | ||||
// AI has currently no access to BackToWork | // AI has currently no access to BackToWork | ||||
let cmpPlayer = QueryOwnerInterface(this.entity); | let cmpPlayer = QueryOwnerInterface(this.entity); | ||||
if (cmpPlayer && cmpPlayer.IsAI() && !this.IsFormationController() && | if (cmpPlayer && cmpPlayer.IsAI() && !this.IsFormationController() && | ||||
this.workOrders.length && this.workOrders[0].type == "Trade") | this.workOrders.length && this.workOrders[0].type == "Trade") | ||||
{ | { | ||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
if (cmpTrader.HasBothMarkets() && | if (cmpTrader.HasBothMarkets() && | ||||
Lint: ESLintBear (no-trailing-spaces) Trailing spaces not allowed. Lint: ESLintBear (no-trailing-spaces): `Trailing spaces not allowed.` | |||||
(cmpTrader.GetFirstMarket() == target && cmpTrader.GetSecondMarket() == source || | (cmpTrader.GetFirstMarket() == target && cmpTrader.GetSecondMarket() == source || | ||||
cmpTrader.GetFirstMarket() == source && cmpTrader.GetSecondMarket() == target)) | cmpTrader.GetFirstMarket() == source && cmpTrader.GetSecondMarket() == target)) | ||||
{ | { | ||||
this.BackToWork(); | this.BackToWork(); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 291 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: 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; | ||||
} | } | ||||
} | } | ||||
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 44 Lines • ▼ Show 20 Lines | UnitAI.prototype.GetQueryRange = function(iid) | ||||
if (iid === IID_Vision) | if (iid === IID_Vision) | ||||
{ | { | ||||
ret.max = visionRange; | ret.max = visionRange; | ||||
return ret; | return ret; | ||||
} | } | ||||
if (this.GetStance().respondStandGround) | if (this.GetStance().respondStandGround) | ||||
{ | { | ||||
let range = this.GetRange(iid); | let range = this.GetRange(iid); | ||||
if (!range) | if (!range) | ||||
return ret; | return ret; | ||||
Done Inline ActionsThese can be called using this.GetRange(iid). Freagarach: These can be called using `this.GetRange(iid)`. | |||||
ret.min = range.min; | ret.min = range.min; | ||||
ret.max = Math.min(range.max, visionRange); | ret.max = Math.min(range.max, visionRange); | ||||
} | } | ||||
else if (this.GetStance().respondChase) | else if (this.GetStance().respondChase) | ||||
ret.max = visionRange; | ret.max = visionRange; | ||||
else if (this.GetStance().respondHoldGround) | else if (this.GetStance().respondHoldGround) | ||||
{ | { | ||||
let range = this.GetRange(iid); | let range = this.GetRange(iid); | ||||
▲ Show 20 Lines • Show All 71 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 before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
}; | }; | ||||
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); | this.AddOrder("Walk", { "x": this.heldPosition.x, "z": this.heldPosition.z, "force": 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 component.GetRange(type); | |||||
let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder); | |||||
if (cmpTurretHolder) | |||||
return cmpTurretHolder.GetSubunitsRange(iid, type); | |||||
Done Inline ActionsYou want this to be GetTurrets, not GetTurretPoints. wraitii: You want this to be GetTurrets, not GetTurretPoints. | |||||
return undefined; | return undefined; | ||||
}; | |||||
return component.GetRange(type); | /** | ||||
} | * Checks whether one of this entities turrets can perform the given action on the given target. | ||||
* | |||||
* @param {string} action - The desired action to check. | |||||
* @param {number} target - The entity ID of the target to perform the action upon. | |||||
* @param {string[]} types - An optional array of the desired types to use (e.g. "Capture" for attack). | |||||
* | |||||
* @return {boolean} Whether at least one subunit can perform the given action. | |||||
*/ | |||||
UnitAI.prototype.CanAnySubUnitPerform = function(action, target, types) | |||||
{ | |||||
let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder); | |||||
return cmpTurretHolder && | |||||
cmpTurretHolder.CanAnySubunitPerform(action, target, types); | |||||
}; | |||||
UnitAI.prototype.CanAttack = function(target) | UnitAI.prototype.CanAttack = function(target, types) | ||||
{ | { | ||||
// 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; | ||||
let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | let cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
return cmpAttack && cmpAttack.CanAttack(target); | return cmpAttack ? cmpAttack.CanAttack(target, types) : | ||||
this.CanAnySubUnitPerform("Attack", target, types); | |||||
}; | }; | ||||
UnitAI.prototype.CanGarrison = function(target) | UnitAI.prototype.CanGarrison = function(target) | ||||
{ | { | ||||
Done Inline Actionsif(!cgh) return false ? Stan: if(!cgh) return false ? | |||||
// 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) | ||||
Done Inline Actionsearly return if no vgp ? just an idea Stan: early return if no vgp ? just an idea | |||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||
return true; | return true; | ||||
Done Inline ActionsMaybe CanSubUnitPerform(action, target, types) Stan: Maybe `CanSubUnitPerform(action, target, types)` | |||||
let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(target, IID_GarrisonHolder); | ||||
Done Inline Actionsreturn visibleGarrisonPoints.some() ? Stan: return visibleGarrisonPoints.some() ? | |||||
if (!cmpGarrisonHolder) | if (!cmpGarrisonHolder) | ||||
return false; | return false; | ||||
// Verify that the target is owned by this entity's player or a mutual ally of this player | // Verify that the target is owned by this entity's player or a mutual ally of this player | ||||
let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | let cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | ||||
if (!cmpOwnership || !(IsOwnedByPlayer(cmpOwnership.GetOwner(), target) || IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target))) | if (!cmpOwnership || !(IsOwnedByPlayer(cmpOwnership.GetOwner(), target) || IsOwnedByMutualAllyOfPlayer(cmpOwnership.GetOwner(), target))) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
}; | }; | ||||
UnitAI.prototype.CanGather = function(target) | UnitAI.prototype.CanGather = function(target) | ||||
{ | { | ||||
Done Inline ActionsI guess the default param is useless ? Stan: I guess the default param is useless ? | |||||
if (this.IsTurret()) | if (this.IsTurret()) | ||||
return false; | return false; | ||||
// The target must be a valid resource supply, or the mirage of one. | // The target must be a valid resource supply, or the mirage of one. | ||||
var cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); | var cmpResourceSupply = QueryMiragedInterface(target, IID_ResourceSupply); | ||||
if (!cmpResourceSupply) | if (!cmpResourceSupply) | ||||
return false; | return false; | ||||
// Formation controllers should always respond to commands | // Formation controllers should always respond to commands | ||||
Show All 9 Lines | UnitAI.prototype.CanGather = function(target) | ||||
// Verify that we can gather from this target | // Verify that we can gather from this target | ||||
if (!cmpResourceGatherer.GetTargetGatherRate(target)) | if (!cmpResourceGatherer.GetTargetGatherRate(target)) | ||||
return false; | return false; | ||||
// No need to verify ownership as we should be able to gather from | // No need to verify ownership as we should be able to gather from | ||||
// a target regardless of ownership. | // a target regardless of ownership. | ||||
// No need to call "cmpResourceSupply.IsAvailable()" either because that | // No need to call "cmpResourceSupply.IsAvailable()" either because that | ||||
// would cause units to walk to full entities instead of choosing another one | // would cause units to walk to full entities instead of choosing another one | ||||
// nearby to gather from, which is undesirable. | // nearby to gather from, which is undesirable. | ||||
Done Inline ActionsEarly continue ? Stan: Early continue ? | |||||
return true; | return true; | ||||
}; | }; | ||||
Done Inline ActionsCan it have a negative range ? Stan: Can it have a negative range ? | |||||
UnitAI.prototype.CanHeal = function(target) | UnitAI.prototype.CanHeal = function(target) | ||||
{ | { | ||||
Done Inline ActionsDunno if reduce would be faster https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max Stan: Dunno if reduce would be faster https://developer.mozilla.org/en… | |||||
Done Inline ActionsThen you'd need to make an array first? Freagarach: Then you'd need to make an array first? | |||||
// 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; | ||||
Done Inline ActionsI guess you coud inline that ? Still dislike multiple return types (One could maybe add a boolean to the result object) Stan: I guess you coud inline that ? Still dislike multiple return types (One could maybe add a… | |||||
let cmpHeal = Engine.QueryInterface(this.entity, IID_Heal); | let cmpHeal = Engine.QueryInterface(this.entity, IID_Heal); | ||||
return cmpHeal && cmpHeal.CanHeal(target); | return cmpHeal ? cmpHeal.CanHeal(target) : | ||||
this.CanAnySubUnitPerform("Heal", target); | |||||
}; | }; | ||||
/** | /** | ||||
* Check if the entity can return carried resources at @param target | * Check if the entity can return carried resources at @param target | ||||
* @param checkCarriedResource check we are carrying resources | * @param checkCarriedResource check we are carrying resources | ||||
* @param cmpResourceGatherer if present, use this directly instead of re-querying. | * @param cmpResourceGatherer if present, use this directly instead of re-querying. | ||||
*/ | */ | ||||
UnitAI.prototype.CanReturnResource = function(target, checkCarriedResource, cmpResourceGatherer = undefined) | UnitAI.prototype.CanReturnResource = function(target, checkCarriedResource, cmpResourceGatherer = undefined) | ||||
▲ Show 20 Lines • Show All 88 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: 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.` | |||||
}; | }; | ||||
//// Animal specific functions //// | //// Animal 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.MoveRandomly = function(distance) | UnitAI.prototype.MoveRandomly = function(distance) | ||||
{ | { | ||||
// To minimize drift all across the map, animals describe circles | // To minimize drift all across the map, animals 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 | ||||
// half a meter backwards of the current position, after rotation. | // half a meter backwards of the current position, after rotation. | ||||
Show All 34 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: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
UnitAI.prototype.AttackEntitiesByPreference = function(ents) | UnitAI.prototype.AttackEntitiesByPreference = function(ents) | ||||
{ | { | ||||
if (!ents.length) | if (!ents.length) | ||||
return false; | return false; | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
if (!cmpAttack) | if (!cmpAttack) | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (!cmpFormation) | ||||
return false; | return false; | ||||
return cmpFormation.GetMembers().every(ent => { | return cmpFormation.GetMembers().every(ent => { | ||||
var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | var cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI); | ||||
return cmpUnitAI[funcname].apply(cmpUnitAI, args); | return cmpUnitAI[funcname].apply(cmpUnitAI, args); | ||||
}); | }); | ||||
}; | }; | ||||
/** | |||||
* Add order to UnitAI components of all turrets. | |||||
Done Inline Actions@param ? Stan: @param ? | |||||
* @param {Object} order - The order to delegate. | |||||
*/ | |||||
UnitAI.prototype.DelegateOrder = function(order) | |||||
{ | |||||
if (!order || !order.type) | |||||
return; | |||||
let cmpTurretHolder = Engine.QueryInterface(this.entity, IID_TurretHolder); | |||||
if (!cmpTurretHolder) | |||||
return; | |||||
Done Inline ActionsForEach slower than for (var x of y) Pros: You can pass the index in the callback We tend to avoid imperative style loops when we can use .some(), .find() etc. If it was a map instead of an array, that would be logical, Cons Seems to be slower/ have more overhead https://coderwall.com/p/kvzbpa/don-t-use-array-foreach-use-for-instead / http://jsperf.com/fast-array-foreach / https://jsperf.com/sdngjkn Less straightforward to read. Some other links https://medium.com/front-end-weekly/stop-array-foreach-and-start-using-filter-map-some-reduce-functions-298b4dabfa09 https://stackoverflow.com/questions/43821759/why-array-foreach-is-slower-than-for-loop-in-javascript Stan: ForEach slower than for (var x of y)
Pros:
You can pass the index in the callback… | |||||
for (let point of cmpTurretHolder.GetTurretPoints()) | |||||
{ | |||||
Done Inline ActionsEarly return ? Stan: Early return ?
| |||||
let cmpUnitAI = Engine.QueryInterface(point.entity, IID_UnitAI); | |||||
Done Inline ActionsShouldn't that be true (as in forced, because it's delegated by the player) ? Stan: Shouldn't that be true (as in forced, because it's delegated by the player) ? | |||||
Done Inline ActionsThis false is whether it is queued or not. The forced is within the order. Freagarach: This `false` is whether it is queued or not. The forced is within the `order`. | |||||
if (!cmpUnitAI) | |||||
continue; | |||||
Done Inline ActionsCan it be undefined? Stan: Can it be undefined? | |||||
Done Inline ActionsIt can't be empty as long as the entity is garrisoned ^^ Freagarach: It can't be empty as long as the entity is garrisoned ^^ | |||||
let orders = cmpUnitAI.GetOrders(); | |||||
if (!orders.length || | |||||
!orders[0].data || !orders[0].data.target || | |||||
orders[0].data.target != order.target || orders[0].type != order.type) | |||||
cmpUnitAI.AddOrder(order.type, order, false); | |||||
} | |||||
}; | |||||
UnitAI.prototype.UnitFsm = new FSM(UnitAI.prototype.UnitFsmSpec); | UnitAI.prototype.UnitFsm = new FSM(UnitAI.prototype.UnitFsmSpec); | ||||
Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); | Engine.RegisterComponentType(IID_UnitAI, "UnitAI", UnitAI); | ||||
Done Inline ActionsYou no longer need these I believe. wraitii: You no longer need these I believe. |
Method 'Order.WalkToTarget' expected no return value.