Changeset View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 313 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.` | ||||||||
} | } | |||||||
this.order.data.relaxed = true; | this.order.data.relaxed = true; | |||||||
if (this.IsAnimal()) | if (this.IsAnimal()) | |||||||
this.SetNextState("ANIMAL.WALKING"); | this.SetNextState("ANIMAL.WALKING"); | |||||||
else | else | |||||||
this.SetNextState("INDIVIDUAL.WALKING"); | this.SetNextState("INDIVIDUAL.WALKING"); | |||||||
▲ Show 20 Lines • Show All 152 Lines • ▼ Show 20 Lines | if (this.GetStance().respondStandGround && !this.order.data.force) | |||||||
this.FinishOrder(); | this.FinishOrder(); | |||||||
return; | return; | |||||||
} | } | |||||||
this.SetNextState("INDIVIDUAL.HEAL.APPROACHING"); | this.SetNextState("INDIVIDUAL.HEAL.APPROACHING"); | |||||||
}, | }, | |||||||
"Order.Gather": function(msg) { | "Order.Gather": function(msg) { | |||||||
if (!this.CanGather(this.order.data.target)) | ||||||||
Done Inline Actions
^ Freagarach: ^ | ||||||||
{ | ||||||||
this.SetNextState("INDIVIDUAL.GATHER.FINDINGNEWTARGET"); | ||||||||
Done Inline ActionsSpace, also add here this.CanGather(target) and you can ditch the one below? Freagarach: Space, also add here `this.CanGather(target)` and you can ditch the one below? | ||||||||
Done Inline ActionsGetGatherRate needs also a specific type, which you don't always have. Freagarach: `GetGatherRate` needs also a specific type, which you don't always have. | ||||||||
Done Inline ActionsI did mean by "target" "this.order.data.target". Freagarach: I did mean by "target" "this.order.data.target". | ||||||||
return; | ||||||||
} | ||||||||
// If the unit is full go to the nearest dropsite instead of trying to gather. | ||||||||
// Unless our target is a treasure which we cannot be full enough with (we can't carry treasures). | ||||||||
let cmpResourceGatherer = Engine.QueryInterface(this.entity, IID_ResourceGatherer); | ||||||||
if (msg.data.type.generic !== "treasure" && cmpResourceGatherer && !cmpResourceGatherer.CanCarryMore(msg.data.type.generic)) | ||||||||
{ | ||||||||
let nearestDropsite = this.FindNearestDropsite(msg.data.type.generic); | ||||||||
// Oh no, couldn't find any dropsites. Give up on gathering. | ||||||||
if (!nearestDropsite) | ||||||||
{ | ||||||||
if (!this.FinishOrder()); | ||||||||
this.WalkToTarget(msg.data.target, false); | ||||||||
Lint: ESLintBear (indent) Expected indentation of 4 tabs but found 5. Lint: ESLintBear (indent): `Expected indentation of 4 tabs but found 5.` | ||||||||
return; | ||||||||
} | ||||||||
Done Inline Actionsdropsites seems to be one word? Freagarach: `dropsites` seems to be one word? | ||||||||
this.PushOrderFront("ReturnResource", { | ||||||||
"target": nearestDropsite, | ||||||||
"force": false, | ||||||||
"type": msg.data.type | ||||||||
}); | ||||||||
return; | ||||||||
} | ||||||||
if (this.MustKillGatherTarget(this.order.data.target)) | if (this.MustKillGatherTarget(this.order.data.target)) | |||||||
{ | { | |||||||
// Make sure we can attack the target, else we'll get very stuck | // Make sure we can attack the target, else we'll get very stuck | |||||||
if (!this.GetBestAttackAgainst(this.order.data.target, false)) | if (!this.GetBestAttackAgainst(this.order.data.target, false)) | |||||||
{ | { | |||||||
// Oops, we can't attack at all - give up | // Oops, we can't attack at all - give up | |||||||
// TODO: should do something so the player knows why this failed | // TODO: should do something so the player knows why this failed | |||||||
this.FinishOrder(); | this.FinishOrder(); | |||||||
▲ Show 20 Lines • Show All 239 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 235 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 969 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: 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": { | |||||||
"Order.Cheer": function() { | "Order.Cheer": function() { | |||||||
this.SetNextState("CHEERING"); | this.SetNextState("CHEERING"); | |||||||
}, | }, | |||||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | "COMBAT": { | |||||||
!msg.obstructed && this.CheckRange(this.order.data)) | !msg.obstructed && this.CheckRange(this.order.data)) | |||||||
this.FinishOrder(); | this.FinishOrder(); | |||||||
}, | }, | |||||||
}, | }, | |||||||
}, | }, | |||||||
}, | }, | |||||||
"GATHER": { | "GATHER": { | |||||||
"leave": function() { | "leave": function() { | |||||||
Done Inline Actions\t -> Freagarach: `\t` -> ` ` | ||||||||
// Show the carried resource, if we've gathered anything. | // Show the carried resource, if we've gathered anything. | |||||||
Done Inline ActionsOh, and this on the previous line. Freagarach: Oh, and this on the previous line. | ||||||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | |||||||
Done Inline ActionsProbably need the order here ^^ Freagarach: Probably need the order here ^^ | ||||||||
}, | }, | |||||||
Done Inline ActionsEarly return? Freagarach: Early return? | ||||||||
"APPROACHING": { | "APPROACHING": { | |||||||
"enter": function() { | "enter": function() { | |||||||
this.gatheringTarget = this.order.data.target; // temporary, deleted in "leave". | this.gatheringTarget = this.order.data.target; // temporary, deleted in "leave". | |||||||
Done Inline Actions(Empty line not needed.) Freagarach: (Empty line not needed.) | ||||||||
Done Inline ActionsComment should go below. Freagarach: Comment should go below. | ||||||||
let cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); | let cmpSupply = Engine.QueryInterface(this.gatheringTarget, IID_ResourceSupply); | |||||||
Done Inline ActionsCheck for cmpResourceGatherer? Freagarach: Check for `cmpResourceGatherer`? | ||||||||
Done Inline ActionsAlso return false when the resourceType == "treasure" since we cannot carry that. (Ugly hardcoding, but I plan to revisit treasures.) Freagarach: Also return false when the resourceType == "treasure" since we cannot carry that. (Ugly… | ||||||||
let cmpMirage = Engine.QueryInterface(this.gatheringTarget, IID_Mirage); | let cmpMirage = Engine.QueryInterface(this.gatheringTarget, IID_Mirage); | |||||||
Done Inline ActionsYou can revert this ;) Freagarach: You can revert this ;) | ||||||||
if ((!cmpMirage || !cmpMirage.Mirages(IID_ResourceSupply)) && | if ((!cmpMirage || !cmpMirage.Mirages(IID_ResourceSupply)) && | |||||||
Done Inline Actionsfalse Freagarach: `false` | ||||||||
(!cmpSupply || !cmpSupply.AddGatherer(this.entity)) || | (!cmpSupply || !cmpSupply.AddGatherer(this.entity)) || | |||||||
!this.MoveTo(this.order.data, IID_ResourceGatherer)) | !this.MoveTo(this.order.data, IID_ResourceGatherer)) | |||||||
{ | { | |||||||
// If the target's last known position is in FOW, try going there | // If the target's last known position is in FOW, try going there | |||||||
// and hope that we might find it then. | // and hope that we might find it then. | |||||||
let lastPos = this.order.data.lastPos; | let lastPos = this.order.data.lastPos; | |||||||
if (this.gatheringTarget != INVALID_ENTITY && | if (this.gatheringTarget != INVALID_ENTITY && | |||||||
Done Inline Actionstrue Freagarach: `true` | ||||||||
lastPos && !this.CheckPositionVisible(lastPos.x, lastPos.z)) | lastPos && !this.CheckPositionVisible(lastPos.x, lastPos.z)) | |||||||
{ | { | |||||||
this.PushOrderFront("Walk", { | this.PushOrderFront("Walk", { | |||||||
"x": lastPos.x, "z": lastPos.z, | "x": lastPos.x, "z": lastPos.z, | |||||||
"force": this.order.data.force | "force": this.order.data.force | |||||||
}); | }); | |||||||
return true; | return true; | |||||||
} | } | |||||||
this.SetNextState("FINDINGNEWTARGET"); | this.SetNextState("FINDINGNEWTARGET"); | |||||||
return true; | return true; | |||||||
Done Inline Actions+\n Freagarach: +`\n` | ||||||||
} | } | |||||||
this.SetAnimationVariant("approach_" + this.order.data.type.specific); | this.SetAnimationVariant("approach_" + this.order.data.type.specific); | |||||||
return false; | return false; | |||||||
}, | }, | |||||||
Done Inline ActionsThis could either be removed to restore the original behavior when there is no dropsite, or changed so the unit walks to the target instead of trying to gather from it. Stan: This could either be removed to restore the original behavior when there is no dropsite, or… | ||||||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | |||||||
// The GATHERING timer will handle finding a valid resource. | // The GATHERING timer will handle finding a valid resource. | |||||||
if (msg.likelyFailure) | if (msg.likelyFailure) | |||||||
this.SetNextState("FINDINGNEWTARGET"); | this.SetNextState("FINDINGNEWTARGET"); | |||||||
else if (this.CheckRange(this.order.data, IID_ResourceGatherer)) | else if (this.CheckRange(this.order.data, IID_ResourceGatherer)) | |||||||
this.SetNextState("GATHERING"); | this.SetNextState("GATHERING"); | |||||||
}, | }, | |||||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | "GATHER": { | |||||||
if (cmpResourceGatherer.IsCarryingAnythingExcept(resourceType.generic)) | if (cmpResourceGatherer.IsCarryingAnythingExcept(resourceType.generic)) | |||||||
cmpResourceGatherer.DropResources(); | cmpResourceGatherer.DropResources(); | |||||||
this.FaceTowardsTarget(this.order.data.target); | this.FaceTowardsTarget(this.order.data.target); | |||||||
// Collect from the target | // Collect from the target | |||||||
let status = cmpResourceGatherer.PerformGather(this.gatheringTarget); | let status = cmpResourceGatherer.PerformGather(this.gatheringTarget); | |||||||
// If we've collected as many resources as possible, | // If we've collected as many resources as possible, | |||||||
// return to the nearest dropsite | // return to the nearest dropsite | |||||||
if (status.filled) | if (status.filled) | |||||||
{ | { | |||||||
let nearestDropsite = this.FindNearestDropsite(resourceType.generic); | let nearestDropsite = this.FindNearestDropsite(resourceType.generic); | |||||||
if (nearestDropsite) | if (nearestDropsite) | |||||||
Done Inline ActionsThis move is not even necessary ^^' Freagarach: This move is not even necessary ^^' | ||||||||
{ | { | |||||||
// (Keep this Gather order on the stack so we'll | // (Keep this Gather order on the stack so we'll | |||||||
// continue gathering after returning) | // continue gathering after returning) | |||||||
// However mark our target as invalid if it's exhausted, so we don't waste time | // However mark our target as invalid if it's exhausted, so we don't waste time | |||||||
// trying to gather from it. | // trying to gather from it. | |||||||
if (status.exhausted) | if (status.exhausted) | |||||||
this.order.data.target = INVALID_ENTITY; | this.order.data.target = INVALID_ENTITY; | |||||||
this.PushOrderFront("ReturnResource", { "target": nearestDropsite, "force": false }); | this.PushOrderFront("ReturnResource", { "target": nearestDropsite, "force": false }); | |||||||
▲ Show 20 Lines • Show All 56 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 791 Lines • ▼ Show 20 Lines | "FEEDING": { | |||||||
}, | }, | |||||||
}, | }, | |||||||
"FLEEING": "INDIVIDUAL.FLEEING", | "FLEEING": "INDIVIDUAL.FLEEING", | |||||||
"COMBAT": "INDIVIDUAL.COMBAT", | "COMBAT": "INDIVIDUAL.COMBAT", | |||||||
"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.` | ||||||||
"CHEERING": { | "CHEERING": { | |||||||
"enter": function() { | "enter": function() { | |||||||
this.SelectAnimation("promotion"); | this.SelectAnimation("promotion"); | |||||||
this.StartTimer(2800); | this.StartTimer(2800); | |||||||
return false; | return false; | |||||||
}, | }, | |||||||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 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 117 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 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 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 '{'.` | ||||||||
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 149 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 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 '{'.` | ||||||||
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 115 Lines • ▼ Show 20 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 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 681 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; | |||||||
}; | }; | |||||||
/** | /** | |||||||
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.` | ||||||||
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 137 Lines • ▼ Show 20 Lines | UnitAI.prototype.Guard = function(target, queued) | |||||||
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); | 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 301 Lines • ▼ Show 20 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() && | |||||||
Done Inline Actions(Please revert this change when committing.) Freagarach: (Please revert this change when committing.) | ||||||||
(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 286 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 135 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); | 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 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: 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 102 Lines • Show Last 20 Lines |
Method 'Order.WalkToTarget' expected no return value.