Changeset View
Changeset View
Standalone View
Standalone View
binaries/data/mods/public/simulation/components/UnitAI.js
Show First 20 Lines • Show All 941 Lines • ▼ Show 20 Lines | "FORMATIONCONTROLLER": { | ||||
"WALKING": { | "WALKING": { | ||||
"enter": function() { | "enter": function() { | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
cmpFormation.SetRearrange(true); | cmpFormation.SetRearrange(true); | ||||
cmpFormation.MoveMembersIntoFormation(true, true); | cmpFormation.MoveMembersIntoFormation(true, true); | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | |||||
this.SetSpeedMultiplier(cmpFormation.GetCurrentSpeedMultiplier()); | |||||
this.StopMoving(); | this.StopMoving(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
if (msg.likelyFailure || this.CheckRange(this.order.data)) | if (msg.likelyFailure || this.CheckRange(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
this.CallMemberFunction("ResetFinishOrder", []); | this.CallMemberFunction("ResetFinishOrder", []); | ||||
} | } | ||||
}, | }, | ||||
}, | }, | ||||
"WALKINGANDFIGHTING": { | "WALKINGANDFIGHTING": { | ||||
"enter": function(msg) { | "enter": function(msg) { | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
cmpFormation.SetRearrange(true); | cmpFormation.SetRearrange(true); | ||||
cmpFormation.MoveMembersIntoFormation(true, true, "combat"); | cmpFormation.MoveMembersIntoFormation(true, true, "combat"); | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | |||||
this.SetSpeedMultiplier(cmpFormation.GetCurrentSpeedMultiplier()); | |||||
this.StopMoving(); | this.StopMoving(); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
// check if there are no enemies to attack | // check if there are no enemies to attack | ||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
}, | }, | ||||
Show All 23 Lines | "PATROL": { | ||||
this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | ||||
} | } | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | ||||
cmpFormation.SetRearrange(true); | cmpFormation.SetRearrange(true); | ||||
cmpFormation.MoveMembersIntoFormation(true, true, "combat"); | cmpFormation.MoveMembersIntoFormation(true, true, "combat"); | ||||
return false; | return false; | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
// Check if there are no enemies to attack | // Check if there are no enemies to attack | ||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
}, | }, | ||||
"leave": function(msg) { | "leave": function(msg) { | ||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | |||||
this.SetSpeedMultiplier(cmpFormation.GetCurrentSpeedMultiplier()); | |||||
this.StopTimer(); | this.StopTimer(); | ||||
this.StopMoving(); | this.StopMoving(); | ||||
delete this.patrolStartPosOrder; | delete this.patrolStartPosOrder; | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
if (!msg.likelyFailure && !this.CheckRange(this.order.data)) | if (!msg.likelyFailure && !this.CheckRange(this.order.data)) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 523 Lines • ▼ Show 20 Lines | "INDIVIDUAL": { | ||||
"WALKING": { | "WALKING": { | ||||
"enter": function() { | "enter": function() { | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.ResetSpeedMultiplier(); | |||||
this.StopMoving(); | this.StopMoving(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
// If it looks like the path is failing, and we are close enough (3 tiles) | // If it looks like the path is failing, and we are close enough (3 tiles) | ||||
// stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | // stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | ||||
if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | ||||
this.CheckRange(this.order.data)) | this.CheckRange(this.order.data)) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
}, | }, | ||||
"WALKINGANDFIGHTING": { | "WALKINGANDFIGHTING": { | ||||
"enter": function() { | "enter": function() { | ||||
if (!this.MoveTo(this.order.data)) | if (!this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
// Show weapons rather than carried resources. | // Show weapons rather than carried resources. | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
return false; | return false; | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
}, | }, | ||||
"leave": function(msg) { | "leave": function(msg) { | ||||
this.ResetSpeedMultiplier(); | |||||
this.StopMoving(); | this.StopMoving(); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
}, | }, | ||||
"MovementUpdate": function(msg) { | "MovementUpdate": function(msg) { | ||||
// If it looks like the path is failing, and we are close enough (3 tiles) | // If it looks like the path is failing, and we are close enough (3 tiles) | ||||
// stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | // stop anyways. This avoids pathing for an unreachable goal and reduces lag considerably. | ||||
if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | if (msg.likelyFailure || msg.obstructed && this.RelaxedMaxRangeCheck(this.order.data, this.DefaultRelaxedMaxRange) || | ||||
this.CheckRange(this.order.data)) | this.CheckRange(this.order.data)) | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
}, | }, | ||||
}, | }, | ||||
"PATROL": { | "PATROL": { | ||||
"enter": function() { | "enter": function() { | ||||
// Memorize the origin position in case that we want to go back | // Memorize the origin position in case that we want to go back | ||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | ||||
if (!cmpPosition || !cmpPosition.IsInWorld() || | if (!cmpPosition || !cmpPosition.IsInWorld() || | ||||
!this.MoveTo(this.order.data)) | !this.MoveTo(this.order.data)) | ||||
{ | { | ||||
this.FinishOrder(); | this.FinishOrder(); | ||||
return true; | return true; | ||||
} | } | ||||
this.EnsureMinWalkTime(this.order.data, false); | |||||
if (!this.patrolStartPosOrder) | if (!this.patrolStartPosOrder) | ||||
{ | { | ||||
this.patrolStartPosOrder = cmpPosition.GetPosition(); | this.patrolStartPosOrder = cmpPosition.GetPosition(); | ||||
this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | this.patrolStartPosOrder.targetClasses = this.order.data.targetClasses; | ||||
this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | this.patrolStartPosOrder.allowCapture = this.order.data.allowCapture; | ||||
} | } | ||||
this.StartTimer(0, 1000); | this.StartTimer(0, 1000); | ||||
this.SetAnimationVariant("combat"); | this.SetAnimationVariant("combat"); | ||||
return false; | return false; | ||||
}, | }, | ||||
"leave": function() { | "leave": function() { | ||||
this.ResetSpeedMultiplier(); | |||||
this.StopMoving(); | this.StopMoving(); | ||||
this.StopTimer(); | this.StopTimer(); | ||||
delete this.patrolStartPosOrder; | delete this.patrolStartPosOrder; | ||||
this.SetDefaultAnimationVariant(); | this.SetDefaultAnimationVariant(); | ||||
}, | }, | ||||
"Timer": function(msg) { | "Timer": function(msg) { | ||||
this.FindWalkAndFightTargets(); | this.FindWalkAndFightTargets(); | ||||
▲ Show 20 Lines • Show All 4,313 Lines • ▼ Show 20 Lines | |||||
UnitAI.prototype.SetSpeedMultiplier = function(speed) | UnitAI.prototype.SetSpeedMultiplier = function(speed) | ||||
{ | { | ||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | ||||
if (cmpUnitMotion) | if (cmpUnitMotion) | ||||
cmpUnitMotion.SetSpeedMultiplier(speed); | cmpUnitMotion.SetSpeedMultiplier(speed); | ||||
}; | }; | ||||
/** | /** | ||||
* Adjust the speed of the unit if the target is closeby. We do this to avoid | |||||
* dodging arrows by clickspamming. This becomes superfluous if/when accelerations | |||||
* are implemented. | |||||
* | |||||
* @param {Object} data - Containing either a target entity or position, | |||||
* defining the goal of the movement | |||||
* @param {boolean} mayRun - Whether the entity is allowed to run to match the speed. | |||||
*/ | |||||
UnitAI.prototype.EnsureMinWalkTime = function(data, mayRun = true) | |||||
{ | |||||
let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); | |||||
Stan: Maybe query it later if needed? | |||||
Done Inline Actionswhatever happens we need it, so better return early if we can't use it (ok in case there is no position component, then we don't need it, but probably we don't have a unitMotion then anyways) bb: whatever happens we need it, so better return early if we can't use it (ok in case there is no… | |||||
Done Inline ActionsAlright :) Stan: Alright :) | |||||
if (!cmpUnitMotion) | |||||
return; | |||||
let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); | |||||
if (!cmpPosition || !cmpPosition.IsInWorld()) | |||||
return; | |||||
Done Inline ActionsOnly used in the elseif? Stan: Only used in the elseif? | |||||
Done Inline ActionsNo bb: No | |||||
let position = cmpPosition.GetPosition2D(); | |||||
let distance = 0; | |||||
if (data.target) | |||||
{ | |||||
let cmpTargetPosition = Engine.QueryInterface(data.target, IID_Position); | |||||
if (!cmpTargetPosition || !cmpTargetPosition.IsInWorld()) | |||||
return; | |||||
distance = position.distanceTo(cmpTargetPosition.GetPosition2D()); | |||||
} | |||||
else if (data.x !== undefined && data.z !== undefined) | |||||
distance = Math.euclidDistance2D(position.x, position.y, data.x, data.z); | |||||
// We ignore running formations for now. | |||||
let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); | |||||
Not Done Inline ActionsDouble ternary is a bit difficult to read IMHO. Freagarach: Double ternary is a bit difficult to read IMHO. | |||||
Done Inline ActionsNever got them to a nice form bb: Never got them to a nice form | |||||
cmpUnitMotion.SetSpeedMultiplier(Math.min( | |||||
cmpFormation ? cmpFormation.GetCurrentSpeedMultiplier() : | |||||
mayRun ? this.GetRunMultiplier() : 1, | |||||
Done Inline Actions@wraitii did you also test changing this 2 into something smaller (the smaller it is, the more of dancing is allowed, but the less this affects gameplay). bb: @wraitii did you also test changing this `2` into something smaller (the smaller it is, the… | |||||
Not Done Inline ActionsI did not. The value of 2 felt pretty good to me. That being said, I think you might want to clamp this so that it's never below a speed of like 3 or so. wraitii: I did not. The value of 2 felt pretty good to me.
That being said, I think you might want to… | |||||
distance / this.GetWalkSpeed() / 2 | |||||
)); | |||||
}; | |||||
/** | |||||
* Try to match the targets current movement speed. | * Try to match the targets current movement speed. | ||||
* | * | ||||
* @param {number} target - The entity ID of the target to match. | * @param {number} target - The entity ID of the target to match. | ||||
* @param {boolean} mayRun - Whether the entity is allowed to run to match the speed. | * @param {boolean} mayRun - Whether the entity is allowed to run to match the speed. | ||||
*/ | */ | ||||
UnitAI.prototype.TryMatchTargetSpeed = function(target, mayRun = true) | UnitAI.prototype.TryMatchTargetSpeed = function(target, mayRun = true) | ||||
{ | { | ||||
let cmpUnitMotionTarget = Engine.QueryInterface(target, IID_UnitMotion); | let cmpUnitMotionTarget = Engine.QueryInterface(target, IID_UnitMotion); | ||||
▲ Show 20 Lines • Show All 375 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
Maybe query it later if needed?