Changeset View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 588 Lines • ▼ Show 20 Lines | UnitAI.prototype.UnitFsmSpec = { | ||||
"Order.Garrison": function(msg) { | "Order.Garrison": function(msg) { | ||||
if (!this.AbleToMove()) | if (!this.AbleToMove()) | ||||
{ | { | ||||
// Garrisoned turrets (unable to move) go IDLE. | // Garrisoned turrets (unable to move) go IDLE. | ||||
this.SetNextState("IDLE"); | this.SetNextState("IDLE"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
} | } | ||||
if (this.IsGarrisoned()) | if (this.isGarrisoned) | ||||
{ | { | ||||
this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
} | } | ||||
// Also pack when we are in range. | // Also pack when we are in range. | ||||
if (this.CanPack()) | if (this.CanPack()) | ||||
{ | { | ||||
this.PushOrderFront("Pack", { "force": true }); | this.PushOrderFront("Pack", { "force": true }); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
} | } | ||||
if (this.CheckGarrisonRange(this.order.data.target)) | if (this.CheckGarrisonRange(this.order.data.target)) | ||||
this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | this.SetNextState("INDIVIDUAL.GARRISON.GARRISONED"); | ||||
else | else | ||||
this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING"); | this.SetNextState("INDIVIDUAL.GARRISON.APPROACHING"); | ||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
}, | }, | ||||
"Order.Ungarrison": function() { | "Order.Ungarrison": function() { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
this.isGarrisoned = false; | |||||
return ACCEPT_ORDER; | return ACCEPT_ORDER; | ||||
}, | }, | ||||
"Order.Cheer": function(msg) { | "Order.Cheer": function(msg) { | ||||
return REJECT_ORDER; | return REJECT_ORDER; | ||||
}, | }, | ||||
"Order.Pack": function(msg) { | "Order.Pack": function(msg) { | ||||
▲ Show 20 Lines • Show All 1,546 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: 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() { | ||||
if (!this.cheeringTime) | if (!this.cheeringTime) | ||||
return REJECT_ORDER; | return REJECT_ORDER; | ||||
▲ Show 20 Lines • Show All 451 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 484 Lines • ▼ Show 20 Lines | "GARRISON": { | ||||
"enter": function() { | "enter": function() { | ||||
let target = this.order.data.target; | let target = this.order.data.target; | ||||
if (!target) | if (!target) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
// Called when autogarrisoning. | // Called when autogarrisoning. | ||||
if (this.isGarrisoned) | if (this.isGarrisoned) | ||||
{ | { | ||||
this.SetImmobile(true); | this.SetImmobile(true); | ||||
if (this.IsTurret()) | if (this.IsTurret()) | ||||
{ | { | ||||
this.SetNextState("IDLE"); | this.SetNextState("IDLE"); | ||||
return true; | return true; | ||||
} | } | ||||
Done Inline ActionsNotice this fixes a bug present in SVN. Freagarach: Notice this fixes a bug present in SVN.
(Look at the selection state of an entity on a wall… | |||||
return false; | return false; | ||||
} | } | ||||
if (this.CanGarrison(target)) | if (this.CanGarrison(target)) | ||||
if (this.CheckGarrisonRange(target)) | if (this.CheckGarrisonRange(target)) | ||||
{ | { | ||||
let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | ||||
if (cmpGarrisonable.Garrison(target)) | if (cmpGarrisonable.Garrison(target)) | ||||
{ | { | ||||
this.isGarrisoned = true; | |||||
this.SetImmobile(true); | |||||
if (this.formationController) | if (this.formationController) | ||||
{ | { | ||||
var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); | var cmpFormation = Engine.QueryInterface(this.formationController, IID_Formation); | ||||
if (cmpFormation) | if (cmpFormation) | ||||
{ | { | ||||
var rearrange = cmpFormation.rearrange; | var rearrange = cmpFormation.rearrange; | ||||
cmpFormation.SetRearrange(false); | cmpFormation.SetRearrange(false); | ||||
cmpFormation.RemoveMembers([this.entity]); | cmpFormation.RemoveMembers([this.entity]); | ||||
▲ Show 20 Lines • Show All 185 Lines • ▼ Show 20 Lines | |||||
}, | }, | ||||
}; | }; | ||||
UnitAI.prototype.Init = function() | UnitAI.prototype.Init = function() | ||||
{ | { | ||||
this.orderQueue = []; // current order is at the front of the list | this.orderQueue = []; // current order is at the front of the list | ||||
this.order = undefined; // always == this.orderQueue[0] | this.order = undefined; // always == this.orderQueue[0] | ||||
this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to | this.formationController = INVALID_ENTITY; // entity with IID_Formation that we belong to | ||||
this.isGarrisoned = false; | |||||
this.isIdle = false; | this.isIdle = false; | ||||
this.isImmobile = false; // True if the unit is currently unable to move (garrisoned,...) | |||||
this.heldPosition = undefined; | this.heldPosition = undefined; | ||||
// Queue of remembered works | // Queue of remembered works | ||||
this.workOrders = []; | this.workOrders = []; | ||||
this.isGuardOf = undefined; | this.isGuardOf = undefined; | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
return this.isIdle; | return this.isIdle; | ||||
}; | }; | ||||
/** | /** | ||||
* Used by formation controllers to toggle the idleness of their members. | * Used by formation controllers to toggle the idleness of their members. | ||||
*/ | */ | ||||
UnitAI.prototype.ResetIdle = function() | UnitAI.prototype.ResetIdle = function() | ||||
{ | { | ||||
Done Inline ActionsI don't really understand what you're trying to say here. (it also seems to me like you should just query Garrisonable from outside now instead?) wraitii: I don't really understand what you're trying to say here.
(it also seems to me like you should… | |||||
let shouldBeIdle = this.GetCurrentState().endsWith(".IDLE"); | let shouldBeIdle = this.GetCurrentState().endsWith(".IDLE"); | ||||
if (this.isIdle == shouldBeIdle) | if (this.isIdle == shouldBeIdle) | ||||
return; | return; | ||||
this.isIdle = shouldBeIdle; | this.isIdle = shouldBeIdle; | ||||
Engine.PostMessage(this.entity, MT_UnitIdleChanged, { "idle": this.isIdle }); | Engine.PostMessage(this.entity, MT_UnitIdleChanged, { "idle": this.isIdle }); | ||||
}; | }; | ||||
UnitAI.prototype.IsGarrisoned = function() | |||||
{ | |||||
return this.isGarrisoned; | |||||
}; | |||||
UnitAI.prototype.SetGarrisoned = function() | UnitAI.prototype.SetGarrisoned = function() | ||||
{ | { | ||||
// UnitAI caches its own garrisoned state for performance. | |||||
this.isGarrisoned = true; | this.isGarrisoned = true; | ||||
this.SetImmobile(); | |||||
}; | }; | ||||
UnitAI.prototype.GetGarrisonHolder = function() | UnitAI.prototype.GetGarrisonHolder = function() | ||||
{ | { | ||||
if (!this.isGarrisoned) | if (!this.isGarrisoned) | ||||
return INVALID_ENTITY; | return INVALID_ENTITY; | ||||
let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | let cmpGarrisonable = Engine.QueryInterface(this.entity, IID_Garrisonable); | ||||
return cmpGarrisonable ? cmpGarrisonable.HolderID() : INVALID_ENTITY; | return cmpGarrisonable ? cmpGarrisonable.HolderID() : INVALID_ENTITY; | ||||
}; | }; | ||||
UnitAI.prototype.ShouldRespondToEndOfAlert = function() | UnitAI.prototype.ShouldRespondToEndOfAlert = function() | ||||
{ | { | ||||
return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; | return !this.orderQueue.length || this.orderQueue[0].type == "Garrison"; | ||||
}; | }; | ||||
UnitAI.prototype.SetImmobile = function(immobile) | UnitAI.prototype.SetImmobile = function() | ||||
{ | |||||
if (this.isImmobile) | |||||
return; | |||||
this.isImmobile = true; | |||||
Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { | |||||
"entity": this.entity, | |||||
"ableToMove": this.AbleToMove() | |||||
}); | |||||
}; | |||||
UnitAI.prototype.SetMobile = function() | |||||
{ | { | ||||
this.isImmobile = immobile; | if (!this.isImmobile) | ||||
return; | |||||
delete this.isImmobile; | |||||
Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { | Engine.PostMessage(this.entity, MT_UnitAbleToMoveChanged, { | ||||
"entity": this.entity, | "entity": this.entity, | ||||
"ableToMove": this.AbleToMove() | "ableToMove": this.AbleToMove() | ||||
}); | }); | ||||
}; | }; | ||||
/** | /** | ||||
* @param cmpUnitMotion - optionally pass unitMotion to avoid querying it here | * @param cmpUnitMotion - optionally pass unitMotion to avoid querying it here | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | UnitAI.prototype.OnOwnershipChanged = function(msg) | ||||
if (this.isGuardOf && (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, this.isGuardOf))) | if (this.isGuardOf && (msg.to == INVALID_PLAYER || !IsOwnedByMutualAllyOfEntity(this.entity, this.isGuardOf))) | ||||
this.RemoveGuard(); | this.RemoveGuard(); | ||||
// If the unit isn't being created or dying, reset stance and clear orders | // If the unit isn't being created or dying, reset stance and clear orders | ||||
if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) | if (msg.to != INVALID_PLAYER && msg.from != INVALID_PLAYER) | ||||
{ | { | ||||
// Switch to a virgin state to let states execute their leave handlers. | // Switch to a virgin state to let states execute their leave handlers. | ||||
// Except if garrisoned or (un)packing, in which case we only clear the order queue. | // Except if garrisoned or (un)packing, in which case we only clear the order queue. | ||||
if (this.isGarrisoned || this.IsPacking()) | if (this.isGarrisoned || this.IsPacking()) | ||||
Done Inline ActionsLess function calls = more performance, and in this case the accessed variable is a property of the this instance, so the getter call doesnt seem necessary as long as the getter can be assumed to do nothing but return the member. 1600 units running one more function call = 1600 more function calls. (now imagine it does two nested iterations around the modified code and you get 160.000 new function calls with a one line difference if youre unlucky or didnt check/consider) elexis: Less function calls = more performance, and in this case the accessed variable is a property of… | |||||
{ | { | ||||
this.orderQueue.length = Math.min(this.orderQueue.length, 1); | this.orderQueue.length = Math.min(this.orderQueue.length, 1); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
let index = this.GetCurrentState().indexOf("."); | let index = this.GetCurrentState().indexOf("."); | ||||
if (index != -1) | if (index != -1) | ||||
this.UnitFsm.SwitchToNextState(this, this.GetCurrentState().slice(0,index)); | this.UnitFsm.SwitchToNextState(this, this.GetCurrentState().slice(0,index)); | ||||
Lint: ESLintBear (comma-spacing) A space is required after ','. Lint: ESLintBear (comma-spacing): `A space is required after ','.` | |||||
this.Stop(false); | this.Stop(false); | ||||
} | } | ||||
this.workOrders = []; | this.workOrders = []; | ||||
let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | let cmpTrader = Engine.QueryInterface(this.entity, IID_Trader); | ||||
if (cmpTrader) | if (cmpTrader) | ||||
cmpTrader.StopTrading(); | cmpTrader.StopTrading(); | ||||
Show All 37 Lines | |||||
UnitAI.prototype.OnPickupCanceled = function(msg) | UnitAI.prototype.OnPickupCanceled = function(msg) | ||||
{ | { | ||||
for (let i = 0; i < this.orderQueue.length; ++i) | for (let i = 0; i < this.orderQueue.length; ++i) | ||||
{ | { | ||||
if (this.orderQueue[i].type != "PickupUnit" || this.orderQueue[i].data.target != msg.entity) | if (this.orderQueue[i].type != "PickupUnit" || this.orderQueue[i].data.target != msg.entity) | ||||
continue; | continue; | ||||
if (i == 0) | if (i == 0) | ||||
this.UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); | this.UnitFsm.ProcessMessage(this, {"type": "PickupCanceled", "data": msg}); | ||||
Lint: ESLintBear (object-curly-spacing) A space is required after '{'. Lint: ESLintBear (object-curly-spacing): `A space is required after '{'.` | |||||
Lint: ESLintBear (object-curly-spacing) A space is required before '}'. Lint: ESLintBear (object-curly-spacing): `A space is required before '}'.` | |||||
else | else | ||||
this.orderQueue.splice(i, 1); | this.orderQueue.splice(i, 1); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
break; | break; | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | this.losAttackRangeQuery = cmpRangeManager.CreateActiveQuery(this.entity, | ||||
range.min, range.max, players, IID_Resistance, | range.min, range.max, players, IID_Resistance, | ||||
cmpRangeManager.GetEntityFlagMask("normal"), false); | cmpRangeManager.GetEntityFlagMask("normal"), false); | ||||
if (enable) | if (enable) | ||||
cmpRangeManager.EnableActiveQuery(this.losAttackRangeQuery); | cmpRangeManager.EnableActiveQuery(this.losAttackRangeQuery); | ||||
}; | }; | ||||
//// FSM linkage functions //// | //// FSM linkage functions //// | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
// Setting the next state to the current state will leave/re-enter the top-most substate. | // Setting the next state to the current state will leave/re-enter the top-most substate. | ||||
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 All 27 Lines | if (!this.orderQueue.length) | ||||
let template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | let template = cmpTemplateManager.GetCurrentTemplateName(this.entity); | ||||
error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | error("FinishOrder called for entity " + this.entity + " (" + template + ") when order queue is empty\n" + stack); | ||||
} | } | ||||
this.orderQueue.shift(); | this.orderQueue.shift(); | ||||
this.order = this.orderQueue[0]; | this.order = this.orderQueue[0]; | ||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (this.orderQueue.length && (this.IsGarrisoned() || this.IsFormationController() || | if (this.orderQueue.length && (this.isGarrisoned || this.IsFormationController() || | ||||
cmpPosition && cmpPosition.IsInWorld())) | cmpPosition && cmpPosition.IsInWorld())) | ||||
{ | { | ||||
let ret = this.UnitFsm.ProcessMessage(this, | let ret = this.UnitFsm.ProcessMessage(this, | ||||
{ "type": "Order."+this.order.type, "data": this.order.data } | { "type": "Order."+this.order.type, "data": this.order.data } | ||||
); | ); | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | else | ||||
{ | { | ||||
this.orderQueue.shift(); | this.orderQueue.shift(); | ||||
this.order = this.orderQueue[0]; | this.order = this.orderQueue[0]; | ||||
} | } | ||||
} | } | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
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 '}'.` | |||||
/** | /** | ||||
* Insert an order after the last forced order onto the queue | * Insert an order after the last forced order onto the queue | ||||
* and after the other orders of the same type | * and after the other orders of the same type | ||||
*/ | */ | ||||
UnitAI.prototype.PushOrderAfterForced = function(type, data) | UnitAI.prototype.PushOrderAfterForced = function(type, data) | ||||
{ | { | ||||
if (!this.order || ((!this.order.data || !this.order.data.force) && this.order.type != type)) | if (!this.order || ((!this.order.data || !this.order.data.force) && this.order.type != type)) | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
if (data && data.force) | if (data && data.force) | ||||
{ | { | ||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||
this.CallMemberFunction("UpdateWorkOrders", [type]); | this.CallMemberFunction("UpdateWorkOrders", [type]); | ||||
else | else | ||||
this.UpdateWorkOrders(type); | this.UpdateWorkOrders(type); | ||||
} | } | ||||
let garrisonHolder = this.IsGarrisoned() && type != "Ungarrison" ? this.GetGarrisonHolder() : null; | let garrisonHolder = this.isGarrisoned && type != "Ungarrison" ? this.GetGarrisonHolder() : null; | ||||
// Do not replace packing/unpacking unless it is cancel order. | // Do not replace packing/unpacking unless it is cancel order. | ||||
// TODO: maybe a better way of doing this would be to use priority levels | // TODO: maybe a better way of doing this would be to use priority levels | ||||
if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack" && type != "Stop") | if (this.IsPacking() && type != "CancelPack" && type != "CancelUnpack" && type != "Stop") | ||||
{ | { | ||||
var order = { "type": type, "data": data }; | var order = { "type": type, "data": data }; | ||||
var packingOrder = this.orderQueue.shift(); | var packingOrder = this.orderQueue.shift(); | ||||
if (type == "Attack") | if (type == "Attack") | ||||
Show All 38 Lines | UnitAI.prototype.ReplaceOrder = function(type, data) | ||||
Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | Engine.PostMessage(this.entity, MT_UnitAIOrderDataChanged, { "to": this.GetOrderData() }); | ||||
}; | }; | ||||
UnitAI.prototype.GetOrders = function() | UnitAI.prototype.GetOrders = function() | ||||
{ | { | ||||
return this.orderQueue.slice(); | return this.orderQueue.slice(); | ||||
}; | }; | ||||
Lint: ESLintBear (no-shadow) 'type' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'type' is already declared in the upper scope.` | |||||
UnitAI.prototype.AddOrders = function(orders) | UnitAI.prototype.AddOrders = function(orders) | ||||
{ | { | ||||
orders.forEach(order => this.PushOrder(order.type, order.data)); | orders.forEach(order => this.PushOrder(order.type, order.data)); | ||||
}; | }; | ||||
UnitAI.prototype.GetOrderData = function() | UnitAI.prototype.GetOrderData = function() | ||||
{ | { | ||||
var orders = []; | var orders = []; | ||||
Show All 10 Lines | UnitAI.prototype.UpdateWorkOrders = function(type) | ||||
if (isWorkType(type)) | if (isWorkType(type)) | ||||
{ | { | ||||
this.workOrders = []; | this.workOrders = []; | ||||
return; | return; | ||||
} | } | ||||
if (this.workOrders.length) | if (this.workOrders.length) | ||||
return; | return; | ||||
Lint: JSHintBear 'i' is already defined. Lint: JSHintBear: `'i' is already defined.` | |||||
if (this.IsFormationMember()) | if (this.IsFormationMember()) | ||||
{ | { | ||||
var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | var cmpUnitAI = Engine.QueryInterface(this.formationController, IID_UnitAI); | ||||
if (cmpUnitAI) | if (cmpUnitAI) | ||||
{ | { | ||||
for (var i = 0; i < cmpUnitAI.orderQueue.length; ++i) | for (var i = 0; i < cmpUnitAI.orderQueue.length; ++i) | ||||
{ | { | ||||
if (isWorkType(cmpUnitAI.orderQueue[i].type)) | if (isWorkType(cmpUnitAI.orderQueue[i].type)) | ||||
Show All 16 Lines | UnitAI.prototype.UpdateWorkOrders = function(type) | ||||
} | } | ||||
}; | }; | ||||
UnitAI.prototype.BackToWork = function() | UnitAI.prototype.BackToWork = function() | ||||
{ | { | ||||
if (this.workOrders.length == 0) | if (this.workOrders.length == 0) | ||||
return false; | return false; | ||||
if (this.IsGarrisoned()) | if (this.isGarrisoned) | ||||
{ | { | ||||
let cmpGarrisonHolder = Engine.QueryInterface(this.GetGarrisonHolder(), IID_GarrisonHolder); | let cmpGarrisonHolder = Engine.QueryInterface(this.GetGarrisonHolder(), IID_GarrisonHolder); | ||||
if (!cmpGarrisonHolder || !cmpGarrisonHolder.PerformEject([this.entity], false)) | if (!cmpGarrisonHolder || !cmpGarrisonHolder.PerformEject([this.entity], false)) | ||||
return false; | return false; | ||||
} | } | ||||
this.orderQueue = []; | this.orderQueue = []; | ||||
Show All 9 Lines | UnitAI.prototype.BackToWork = function() | ||||
this.workOrders = []; | this.workOrders = []; | ||||
return true; | return true; | ||||
}; | }; | ||||
UnitAI.prototype.HasWorkOrders = function() | UnitAI.prototype.HasWorkOrders = function() | ||||
{ | { | ||||
return this.workOrders.length > 0; | return this.workOrders.length > 0; | ||||
}; | }; | ||||
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.GetWorkOrders = function() | UnitAI.prototype.GetWorkOrders = function() | ||||
{ | { | ||||
return this.workOrders; | return this.workOrders; | ||||
}; | }; | ||||
UnitAI.prototype.SetWorkOrders = function(orders) | UnitAI.prototype.SetWorkOrders = function(orders) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | if (order.data && order.data.target && order.data.target == msg.entity) | ||||
if (i == 0) | if (i == 0) | ||||
currentOrderChanged = true; | currentOrderChanged = true; | ||||
order.data.target = msg.newentity; | order.data.target = msg.newentity; | ||||
} | } | ||||
if (order.data && order.data.formationTarget && order.data.formationTarget == msg.entity) | if (order.data && order.data.formationTarget && order.data.formationTarget == msg.entity) | ||||
{ | { | ||||
changed = true; | changed = true; | ||||
if (i == 0) | if (i == 0) | ||||
currentOrderChanged = true; | currentOrderChanged = true; | ||||
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 '}'.` | |||||
order.data.formationTarget = msg.newentity; | order.data.formationTarget = msg.newentity; | ||||
} | } | ||||
} | } | ||||
if (!changed) | if (!changed) | ||||
return; | return; | ||||
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 '}'.` | |||||
if (currentOrderChanged) | if (currentOrderChanged) | ||||
this.UnitFsm.ProcessMessage(this, { "type": "OrderTargetRenamed", "data": msg }); | this.UnitFsm.ProcessMessage(this, { "type": "OrderTargetRenamed", "data": 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 (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
}; | }; | ||||
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 }); | ||||
▲ Show 20 Lines • Show All 684 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | let cmpVision = Engine.QueryInterface(this.entity, IID_Vision); | ||||
if (!cmpVision) | if (!cmpVision) | ||||
return false; | return false; | ||||
let range = cmpVision.GetRange(); | let range = cmpVision.GetRange(); | ||||
let distance = PositionHelper.DistanceBetweenEntities(this.entity, target); | let distance = PositionHelper.DistanceBetweenEntities(this.entity, target); | ||||
return distance < range; | return distance < range; | ||||
Lint: ESLintBear (no-shadow) 'target' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'target' is already declared in the upper scope.` | |||||
}; | }; | ||||
UnitAI.prototype.GetBestAttackAgainst = function(target, allowCapture) | UnitAI.prototype.GetBestAttackAgainst = function(target, allowCapture) | ||||
{ | { | ||||
var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | var cmpAttack = Engine.QueryInterface(this.entity, IID_Attack); | ||||
if (!cmpAttack) | if (!cmpAttack) | ||||
return undefined; | return undefined; | ||||
return cmpAttack.GetBestAttackAgainst(target, allowCapture); | return cmpAttack.GetBestAttackAgainst(target, allowCapture); | ||||
}; | }; | ||||
/** | /** | ||||
* 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. | ||||
*/ | */ | ||||
Lint: ESLintBear (no-shadow) 'target' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'target' is already declared in the upper scope.` | |||||
UnitAI.prototype.AttackVisibleEntity = function(ents) | UnitAI.prototype.AttackVisibleEntity = function(ents) | ||||
{ | { | ||||
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.` | |||||
var target = ents.find(target => this.CanAttack(target)); | var target = ents.find(target => this.CanAttack(target)); | ||||
Lint: JSHintBear Misleading line break before '&&'; readers may interpret this as an expression boundary. Lint: JSHintBear: `Misleading line break before '&&'; readers may interpret this as an expression boundary.` | |||||
Lint: ESLintBear (operator-linebreak) '&&' should be placed at the end of the line. Lint: ESLintBear (operator-linebreak): `'&&' should be placed at the end of the line.` | |||||
if (!target) | if (!target) | ||||
return false; | return false; | ||||
this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | this.PushOrderFront("Attack", { "target": target, "force": false, "allowCapture": true }); | ||||
return true; | return true; | ||||
}; | }; | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* @param {number} ents - An array of the IDs of the spotted entities. | * @param {number} ents - An array of the IDs of the spotted entities. | ||||
* @return {boolean} - Whether we responded. | * @return {boolean} - Whether we responded. | ||||
*/ | */ | ||||
UnitAI.prototype.RespondToSightedEntities = function(ents) | UnitAI.prototype.RespondToSightedEntities = function(ents) | ||||
{ | { | ||||
if (!ents || !ents.length) | if (!ents || !ents.length) | ||||
Lint: ESLintBear (no-shadow) 'ent' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'ent' is already declared in the upper scope.` | |||||
return false; | return false; | ||||
if (this.GetStance().respondFleeOnSight) | if (this.GetStance().respondFleeOnSight) | ||||
{ | { | ||||
this.Flee(ents[0], false); | this.Flee(ents[0], false); | ||||
return true; | return true; | ||||
} | } | ||||
Show All 9 Lines | UnitAI.prototype.RespondToHealableEntities = function(ents) | ||||
let ent = ents.find(ent => this.CanHeal(ent)); | let ent = ents.find(ent => this.CanHeal(ent)); | ||||
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; | ||||
}; | }; | ||||
/** | /** | ||||
Lint: ESLintBear (no-shadow) 'type' is already declared in the upper scope. Lint: ESLintBear (no-shadow): `'type' is already declared in the upper scope.` | |||||
* Returns true if we should stop following the target entity. | * Returns true if we should stop following the target entity. | ||||
Lint: ESLintBear (indent) Expected indentation of 3 tabs but found 4. Lint: ESLintBear (indent): `Expected indentation of 3 tabs but found 4.` | |||||
*/ | */ | ||||
UnitAI.prototype.ShouldAbandonChase = function(target, force, iid, type) | UnitAI.prototype.ShouldAbandonChase = function(target, force, iid, type) | ||||
{ | { | ||||
if (!this.CheckTargetVisible(target)) | if (!this.CheckTargetVisible(target)) | ||||
return true; | return true; | ||||
// Forced orders shouldn't be interrupted. | // Forced orders shouldn't be interrupted. | ||||
if (force) | if (force) | ||||
Show All 13 Lines | 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) | ||||
if (!this.CheckTargetIsInVisionRange(target)) | if (!this.CheckTargetIsInVisionRange(target)) | ||||
return true; | return true; | ||||
return false; | return false; | ||||
Lint: ESLintBear (no-multi-spaces) Multiple spaces found before 'Engine'. Lint: ESLintBear (no-multi-spaces): `Multiple spaces found before 'Engine'.` | |||||
}; | }; | ||||
/* | /* | ||||
* Returns whether we should chase the targeted entity, | * Returns whether we should chase the targeted entity, | ||||
* given our current stance. | * given our current stance. | ||||
*/ | */ | ||||
UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force) | UnitAI.prototype.ShouldChaseTargetedEntity = function(target, force) | ||||
{ | { | ||||
if (!this.AbleToMove()) | if (!this.AbleToMove()) | ||||
return false; | return false; | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
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); | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | if (this.expectedRoute) | ||||
this.expectedRoute = undefined; | this.expectedRoute = undefined; | ||||
if (queued) | if (queued) | ||||
this.PushOrder(type, data); | this.PushOrder(type, data); | ||||
else | else | ||||
{ | { | ||||
// May happen if an order arrives on the same turn the unit is garrisoned | // May happen if an order arrives on the same turn the unit is garrisoned | ||||
// in that case, just forget the order as this will lead to an infinite loop | // in that case, just forget the order as this will lead to an infinite loop | ||||
if (this.IsGarrisoned() && !this.IsTurret() && type != "Ungarrison") | if (this.isGarrisoned && !this.IsTurret() && type != "Ungarrison") | ||||
return; | return; | ||||
this.ReplaceOrder(type, data); | this.ReplaceOrder(type, data); | ||||
} | } | ||||
}; | }; | ||||
/** | /** | ||||
* Adds guard/escort order to the queue, forced by the player. | * Adds guard/escort order to the queue, forced by the player. | ||||
Lint: ESLintBear (no-else-return) Unnecessary 'else' after 'return'. Lint: ESLintBear (no-else-return): `Unnecessary 'else' after 'return'.` | |||||
*/ | */ | ||||
UnitAI.prototype.Guard = function(target, queued) | UnitAI.prototype.Guard = function(target, queued) | ||||
{ | { | ||||
if (!this.CanGuard()) | if (!this.CanGuard()) | ||||
{ | { | ||||
this.WalkToTarget(target, queued); | this.WalkToTarget(target, queued); | ||||
return; | return; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | UnitAI.prototype.Garrison = function(target, queued) | ||||
this.AddOrder("Garrison", { "target": target, "force": true }, queued); | this.AddOrder("Garrison", { "target": target, "force": true }, queued); | ||||
}; | }; | ||||
/** | /** | ||||
* Adds ungarrison order to the queue. | * Adds ungarrison order to the queue. | ||||
*/ | */ | ||||
UnitAI.prototype.Ungarrison = function() | UnitAI.prototype.Ungarrison = function() | ||||
{ | { | ||||
if (this.IsGarrisoned()) | if (!this.isGarrisoned) | ||||
{ | return; | ||||
this.SetImmobile(false); | delete this.isGarrisoned; | ||||
this.SetMobile(); | |||||
this.AddOrder("Ungarrison", null, false); | this.AddOrder("Ungarrison", null, false); | ||||
} | |||||
}; | }; | ||||
/** | /** | ||||
* Adds a garrison order for units that are already garrisoned in the garrison holder. | * Adds a garrison order for units that are already garrisoned in the garrison holder. | ||||
*/ | */ | ||||
UnitAI.prototype.Autogarrison = function(target) | UnitAI.prototype.Autogarrison = function(target) | ||||
{ | { | ||||
this.isGarrisoned = true; | |||||
this.PushOrderFront("Garrison", { "target": target }); | this.PushOrderFront("Garrison", { "target": target }); | ||||
Done Inline ActionsThe other places in which the member is set, the garrison function is performed immediately after. Here it is a PushOrderFront, but it could also be that some code clears the order queue or does another PushOrderFront before this command is processed. In that case the unit would have the garrisoned state but not have been garrisoned, correct? elexis: The other places in which the member is set, the garrison function is performed immediately… | |||||
Done Inline ActionsAutogarrison Is called either from the ProductionQueue.js or from Transform.js. The former means no orders are present. The latter is called when the garrison holder transforms and thus the entities ought to take their orders with them when being put into the GARRISON-state. Freagarach: `Autogarrison` Is called either from the `ProductionQueue.js` or from `Transform.js`. The… | |||||
}; | }; | ||||
/** | /** | ||||
* Adds gather order to the queue, forced by the player | * Adds gather order to the queue, forced by the player | ||||
* until the target is reached | * until the target is reached | ||||
*/ | */ | ||||
UnitAI.prototype.Gather = function(target, queued) | UnitAI.prototype.Gather = function(target, queued) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 412 Lines • ▼ Show 20 Lines | if (!this.GetStance().targetVisibleEnemies) | ||||
return false; | return false; | ||||
let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | let cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); | ||||
return this.AttackEntitiesByPreference(cmpRangeManager.ResetActiveQuery(this.losAttackRangeQuery)); | return this.AttackEntitiesByPreference(cmpRangeManager.ResetActiveQuery(this.losAttackRangeQuery)); | ||||
}; | }; | ||||
UnitAI.prototype.FindWalkAndFightTargets = function() | UnitAI.prototype.FindWalkAndFightTargets = function() | ||||
{ | { | ||||
if (this.IsFormationController()) | if (this.IsFormationController()) | ||||
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.` | |||||
{ | { | ||||
var cmpUnitAI; | var cmpUnitAI; | ||||
var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | var cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
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.` | |||||
for (var ent of cmpFormation.members) | for (var ent of cmpFormation.members) | ||||
{ | { | ||||
if (!(cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI))) | if (!(cmpUnitAI = Engine.QueryInterface(ent, IID_UnitAI))) | ||||
continue; | continue; | ||||
var targets = cmpUnitAI.GetTargetsFromUnit(); | var targets = cmpUnitAI.GetTargetsFromUnit(); | ||||
for (var targ of targets) | for (var targ of targets) | ||||
{ | { | ||||
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; | ||||
Lint: JSHintBear 'targets' is already defined. Lint: JSHintBear: `'targets' is already defined.` | |||||
if (targetClasses.attack && cmpIdentity | if (targetClasses.attack && cmpIdentity | ||||
Lint: JSHintBear 'targ' is already defined. Lint: JSHintBear: `'targ' is already defined.` | |||||
&& !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | && !MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.attack)) | ||||
continue; | continue; | ||||
if (targetClasses.avoid && cmpIdentity | if (targetClasses.avoid && cmpIdentity | ||||
&& MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | && MatchesClassList(cmpIdentity.GetClassesList(), targetClasses.avoid)) | ||||
continue; | continue; | ||||
// Only used by the AIs to prevent some choices of targets | // Only used by the AIs to prevent some choices of targets | ||||
Lint: JSHintBear 'cmpIdentity' is already defined. Lint: JSHintBear: `'cmpIdentity' is already defined.` | |||||
if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | if (targetClasses.vetoEntities && targetClasses.vetoEntities[targ]) | ||||
Lint: JSHintBear 'targetClasses' is already defined. Lint: JSHintBear: `'targetClasses' is already defined.` | |||||
continue; | continue; | ||||
} | } | ||||
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.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; | ||||
} | } | ||||
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.` | |||||
} | } | ||||
return false; | return false; | ||||
} | } | ||||
var targets = this.GetTargetsFromUnit(); | var targets = this.GetTargetsFromUnit(); | ||||
for (var targ of targets) | for (var targ of targets) | ||||
{ | { | ||||
if (!this.CanAttack(targ)) | if (!this.CanAttack(targ)) | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
let cmpUnitMotionTarget = Engine.QueryInterface(target, IID_UnitMotion); | let cmpUnitMotionTarget = Engine.QueryInterface(target, IID_UnitMotion); | ||||
if (cmpUnitMotionTarget) | if (cmpUnitMotionTarget) | ||||
{ | { | ||||
let targetSpeed = cmpUnitMotionTarget.GetCurrentSpeed(); | let targetSpeed = cmpUnitMotionTarget.GetCurrentSpeed(); | ||||
if (targetSpeed) | if (targetSpeed) | ||||
this.SetSpeedMultiplier(Math.min(mayRun ? this.GetRunMultiplier() : 1, targetSpeed / this.GetWalkSpeed())); | this.SetSpeedMultiplier(Math.min(mayRun ? this.GetRunMultiplier() : 1, targetSpeed / this.GetWalkSpeed())); | ||||
} | } | ||||
}; | }; | ||||
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 '}'.` | |||||
/* | /* | ||||
* Remember the position of the target (in lastPos), if any, in case it disappears later | * Remember the position of the target (in lastPos), if any, in case it disappears later | ||||
* and we want to head to its last known position. | * and we want to head to its last known position. | ||||
* @param orderData - The order data to set this on. Defaults to this.order.data | * @param orderData - The order data to set this on. Defaults to this.order.data | ||||
*/ | */ | ||||
UnitAI.prototype.RememberTargetPosition = function(orderData) | UnitAI.prototype.RememberTargetPosition = function(orderData) | ||||
{ | { | ||||
Show All 10 Lines | |||||
}; | }; | ||||
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(); | ||||
this.SetHeldPosition(pos.x, pos.z); | this.SetHeldPosition(pos.x, pos.z); | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
}; | }; | ||||
UnitAI.prototype.GetHeldPosition = function() | UnitAI.prototype.GetHeldPosition = function() | ||||
{ | { | ||||
return this.heldPosition; | return this.heldPosition; | ||||
}; | }; | ||||
UnitAI.prototype.WalkToHeldPosition = function() | 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 (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
/** | /** | ||||
* 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. | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | UnitAI.prototype.CanRepair = function(target) | ||||
var cmpRepairable = Engine.QueryInterface(target, IID_Repairable); | var cmpRepairable = Engine.QueryInterface(target, IID_Repairable); | ||||
if (!cmpFoundation && !cmpRepairable) | if (!cmpFoundation && !cmpRepairable) | ||||
return false; | return false; | ||||
var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | var cmpOwnership = Engine.QueryInterface(this.entity, IID_Ownership); | ||||
return cmpOwnership && IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target); | return cmpOwnership && IsOwnedByAllyOfPlayer(cmpOwnership.GetOwner(), target); | ||||
}; | }; | ||||
UnitAI.prototype.CanPack = function() | UnitAI.prototype.CanPack = function() | ||||
Lint: ESLintBear (spaced-comment) Expected space or tab after '//' in comment. Lint: ESLintBear (spaced-comment): `Expected space or tab after '//' in comment.` | |||||
{ | { | ||||
var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
return cmpPack && !cmpPack.IsPacking() && !cmpPack.IsPacked(); | return cmpPack && !cmpPack.IsPacking() && !cmpPack.IsPacked(); | ||||
}; | }; | ||||
UnitAI.prototype.CanUnpack = function() | UnitAI.prototype.CanUnpack = function() | ||||
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.` | |||||
{ | { | ||||
var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
return cmpPack && !cmpPack.IsPacking() && cmpPack.IsPacked(); | return cmpPack && !cmpPack.IsPacking() && cmpPack.IsPacked(); | ||||
}; | }; | ||||
UnitAI.prototype.IsPacking = function() | UnitAI.prototype.IsPacking = function() | ||||
{ | { | ||||
var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | var cmpPack = Engine.QueryInterface(this.entity, IID_Pack); | ||||
Show All 35 Lines | if (!this.roamAngle) | ||||
this.startAngle = ang; | this.startAngle = ang; | ||||
} | } | ||||
else if (Math.abs((ang - this.startAngle + Math.PI) % (2 * Math.PI) - Math.PI) < Math.abs(this.roamAngle / 2)) | else if (Math.abs((ang - this.startAngle + Math.PI) % (2 * Math.PI) - Math.PI) < Math.abs(this.roamAngle / 2)) | ||||
this.roamAngle *= randBool() ? 1 : -1; | this.roamAngle *= randBool() ? 1 : -1; | ||||
let halfDelta = randFloat(this.roamAngle / 4, this.roamAngle * 3 / 4); | let halfDelta = randFloat(this.roamAngle / 4, this.roamAngle * 3 / 4); | ||||
// First half rotation to decrease the impression of immediate rotation | // First half rotation to decrease the impression of immediate rotation | ||||
ang += halfDelta; | ang += halfDelta; | ||||
cmpUnitMotion.FaceTowardsPoint(pos.x + 0.5 * Math.sin(ang), pos.z + 0.5 * Math.cos(ang)); | cmpUnitMotion.FaceTowardsPoint(pos.x + 0.5 * Math.sin(ang), pos.z + 0.5 * Math.cos(ang)); | ||||
Lint: JSHintBear Missing semicolon. Lint: JSHintBear: `Missing semicolon.` | |||||
Lint: ESLintBear (semi) Missing semicolon. Lint: ESLintBear (semi): `Missing semicolon.` | |||||
// Then second half of the rotation | // Then second half of the rotation | ||||
ang += halfDelta; | ang += halfDelta; | ||||
let dist = randFloat(0.5, 1.5) * distance; | let dist = randFloat(0.5, 1.5) * distance; | ||||
cmpUnitMotion.MoveToPointRange(pos.x - 0.5 * Math.sin(ang), pos.z - 0.5 * Math.cos(ang), dist, -1); | cmpUnitMotion.MoveToPointRange(pos.x - 0.5 * Math.sin(ang), pos.z - 0.5 * Math.cos(ang), dist, -1); | ||||
}; | }; | ||||
UnitAI.prototype.SetFacePointAfterMove = function(val) | UnitAI.prototype.SetFacePointAfterMove = function(val) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 121 Lines • Show Last 20 Lines |
Misleading line break before '&&'; readers may interpret this as an expression boundary.