Index: binaries/data/mods/public/simulation/components/Attack.js =================================================================== --- binaries/data/mods/public/simulation/components/Attack.js +++ binaries/data/mods/public/simulation/components/Attack.js @@ -488,10 +488,14 @@ // If the repeat time since the last attack hasn't elapsed, // delay the action to avoid attacking too fast. + // Also add a random offset to the repeat time, + // to avoid units attacking in perfect synchronicity. let prepare = timings.prepare; + let randomOffset = timings.repeat * 0.025; + let repeat = timings.repeat + randIntInclusive(-randomOffset, randomOffset); if (this.lastAttacked) { - let repeatLeft = this.lastAttacked + timings.repeat - cmpTimer.GetTime(); + let repeatLeft = this.lastAttacked + repeat - cmpTimer.GetTime(); prepare = Math.max(prepare, repeatLeft); } @@ -499,7 +503,7 @@ if (cmpVisual) { cmpVisual.SelectAnimation("attack_" + type.toLowerCase(), false, 1.0); - cmpVisual.SetAnimationSyncRepeat(timings.repeat); + cmpVisual.SetAnimationSyncRepeat(repeat); cmpVisual.SetAnimationSyncOffset(prepare); } @@ -507,7 +511,7 @@ this.resyncAnimation = prepare != timings.prepare; this.target = target; this.callerIID = callerIID; - this.timer = cmpTimer.SetInterval(this.entity, IID_Attack, "Attack", prepare, timings.repeat, type); + this.timer = cmpTimer.SetInterval(this.entity, IID_Attack, "Attack", prepare, repeat, type); return true; };