Index: binaries/data/mods/public/simulation/components/Formation.js =================================================================== --- binaries/data/mods/public/simulation/components/Formation.js +++ binaries/data/mods/public/simulation/components/Formation.js @@ -890,23 +890,29 @@ }; /** - * Set formation controller's speed based on its current members. + * Get the formation controller's speed based on its current members. */ -Formation.prototype.ComputeMotionParameters = function() +Formation.prototype.GetFormationSpeedMultiplier = function() { - var maxRadius = 0; - var minSpeed = Infinity; + let minSpeed = Infinity; - for (var ent of this.members) + for (let ent of this.members) { - var cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion); + let cmpUnitMotion = Engine.QueryInterface(ent, IID_UnitMotion); if (cmpUnitMotion) minSpeed = Math.min(minSpeed, cmpUnitMotion.GetWalkSpeed()); } - minSpeed *= this.GetSpeedMultiplier(); + let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); + return minSpeed * this.GetSpeedMultiplier() / cmpUnitMotion.GetWalkSpeed(); +} - var cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); - cmpUnitMotion.SetSpeedMultiplier(minSpeed / cmpUnitMotion.GetWalkSpeed()); +/** + * Set formation controller's speed based on its current members. + */ +Formation.prototype.ComputeMotionParameters = function() +{ + let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); + cmpUnitMotion.SetSpeedMultiplier(this.GetFormationSpeedMultiplier()); }; Formation.prototype.ShapeUpdate = function() Index: binaries/data/mods/public/simulation/components/UnitAI.js =================================================================== --- binaries/data/mods/public/simulation/components/UnitAI.js +++ binaries/data/mods/public/simulation/components/UnitAI.js @@ -947,6 +947,8 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); + let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); cmpFormation.SetRearrange(true); cmpFormation.MoveMembersIntoFormation(true, true); @@ -954,6 +956,8 @@ }, "leave": function() { + let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); + this.SetSpeedMultiplier(cmpFormation.GetFormationSpeedMultiplier()); this.StopMoving(); }, @@ -973,6 +977,8 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); + this.StartTimer(0, 1000); let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); cmpFormation.SetRearrange(true); @@ -981,6 +987,8 @@ }, "leave": function() { + let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); + this.SetSpeedMultiplier(cmpFormation.GetFormationSpeedMultiplier()); this.StopMoving(); this.StopTimer(); }, @@ -1020,6 +1028,8 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); + this.StartTimer(0, 1000); let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); @@ -1034,6 +1044,8 @@ }, "leave": function(msg) { + let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); + this.SetSpeedMultiplier(cmpFormation.GetFormationSpeedMultiplier()); this.StopTimer(); this.StopMoving(); delete this.patrolStartPosOrder; @@ -1573,10 +1585,13 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); + return false; }, "leave": function() { + this.ResetSpeedMultiplier(); this.StopMoving(); }, @@ -1596,6 +1611,8 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); + // Show weapons rather than carried resources. this.SetAnimationVariant("combat"); @@ -1608,6 +1625,7 @@ }, "leave": function(msg) { + this.ResetSpeedMultiplier(); this.StopMoving(); this.StopTimer(); this.SetDefaultAnimationVariant(); @@ -1632,6 +1650,7 @@ this.FinishOrder(); return true; } + this.PersistMinWalkTime(this.order.data, false); if (!this.patrolStartPosOrder) { @@ -1646,6 +1665,7 @@ }, "leave": function() { + this.ResetSpeedMultiplier(); this.StopMoving(); this.StopTimer(); delete this.patrolStartPosOrder; @@ -5975,6 +5995,41 @@ }; /** + * Adjust the speed of the unit if the target is closeby. We do this to avoid + * dodging arrows by clickspamming. + * + * @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.PersistMinWalkTime = function(data, mayRun = true) +{ + let cmpUnitMotion = Engine.QueryInterface(this.entity, IID_UnitMotion); + if (!cmpUnitMotion) + return; + + let cmpPosition = Engine.QueryInterface(this.entity, IID_Position); + if (!cmpPosition || !cmpPosition.IsInWorld()) + return; + 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 && data.z) + distance = position.distanceTo(new Vector2D(data.x, data.z)); + + // We ignore running formations for now. + let cmpFormation = Engine.QueryInterface(this.entity, IID_Formation); + cmpUnitMotion.SetSpeedMultiplier(Math.min(cmpFormation ? cmpFormation.GetFormationSpeedMultiplier() : mayRun ? this.GetRunMultiplier() : 1, distance / this.GetWalkSpeed() / 2)); +}; + +/** * Try to match the targets current movement speed. * * @param {number} target - The entity ID of the target to match.