diff --git a/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs index ae11f808e6..fec5116581 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs @@ -28,6 +28,12 @@ namespace OpenRA.Mods.Common.Traits.Render [Desc("Shown while reloading.")] [SequenceReference(null, true)] public readonly string ReloadPrefix = null; + [Desc("Delay in ticks before animation starts, either relative to attack preparation or attack.")] + public readonly int Delay = 0; + + [Desc("Should the animation be delayed relative to preparation or actual attack?")] + public readonly AttackDelayType DelayRelativeTo = AttackDelayType.Preparation; + public object Create(ActorInitializer init) { return new WithAttackAnimation(init, this); } } @@ -38,6 +44,8 @@ namespace OpenRA.Mods.Common.Traits.Render readonly Armament armament; readonly WithSpriteBody wsb; + int tick; + public WithAttackAnimation(ActorInitializer init, WithAttackAnimationInfo info) { this.info = info; @@ -47,16 +55,39 @@ namespace OpenRA.Mods.Common.Traits.Render wsb = init.Self.Trait(); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { } - - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void PlayAttackAnimation(Actor self) { if (!string.IsNullOrEmpty(info.AttackSequence)) wsb.PlayCustomAnimation(self, info.AttackSequence, () => wsb.CancelCustomAnimation(self)); } + void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + { + if (info.DelayRelativeTo == AttackDelayType.Attack) + { + if (info.Delay > 0) + tick = info.Delay; + else + PlayAttackAnimation(self); + } + } + + void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + { + if (info.DelayRelativeTo == AttackDelayType.Preparation) + { + if (info.Delay > 0) + tick = info.Delay; + else + PlayAttackAnimation(self); + } + } + void ITick.Tick(Actor self) { + if (info.Delay > 0 && --tick == 0) + PlayAttackAnimation(self); + if (string.IsNullOrEmpty(info.AimSequence) && string.IsNullOrEmpty(info.ReloadPrefix)) return; diff --git a/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs index 223cff7974..80a868ee20 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithAttackOverlay.cs @@ -27,16 +27,23 @@ namespace OpenRA.Mods.Common.Traits.Render [Desc("Custom palette is a player palette BaseName")] public readonly bool IsPlayerPalette = false; + [Desc("Delay in ticks before overlay starts, either relative to attack preparation or attack.")] + public readonly int Delay = 0; + + [Desc("Should the overlay be delayed relative to preparation or actual attack?")] + public readonly AttackDelayType DelayRelativeTo = AttackDelayType.Preparation; + public object Create(ActorInitializer init) { return new WithAttackOverlay(init, this); } } - public class WithAttackOverlay : INotifyAttack + public class WithAttackOverlay : INotifyAttack, ITick { readonly Animation overlay; readonly RenderSprites renderSprites; readonly WithAttackOverlayInfo info; bool attacking; + int tick; public WithAttackOverlay(ActorInitializer init, WithAttackOverlayInfo info) { @@ -50,12 +57,38 @@ namespace OpenRA.Mods.Common.Traits.Render info.Palette, info.IsPlayerPalette); } - void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { } - - void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + void PlayOverlay(Actor self) { attacking = true; overlay.PlayThen(info.Sequence, () => attacking = false); } + + void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) + { + if (info.DelayRelativeTo == AttackDelayType.Attack) + { + if (info.Delay > 0) + tick = info.Delay; + else + PlayOverlay(self); + } + } + + void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) + { + if (info.DelayRelativeTo == AttackDelayType.Preparation) + { + if (info.Delay > 0) + tick = info.Delay; + else + PlayOverlay(self); + } + } + + void ITick.Tick(Actor self) + { + if (info.Delay > 0 && --tick == 0) + PlayOverlay(self); + } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index ca652ebc09..3a963ff077 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -19,6 +19,8 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { + public enum AttackDelayType { Preparation, Attack } + public interface IQuantizeBodyOrientationInfo : ITraitInfo { int QuantizedBodyFacings(ActorInfo ai, SequenceProvider sequenceProvider, string race);