diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index c6546c6698..172a2d3ffc 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -452,6 +452,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Render/WithAimAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithAimAnimation.cs new file mode 100644 index 0000000000..7cc35086d6 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Render/WithAimAnimation.cs @@ -0,0 +1,64 @@ +#region Copyright & License Information +/* + * Copyright 2007-2018 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + public class WithAimAnimationInfo : ConditionalTraitInfo, Requires, Requires + { + [Desc("Armament name")] + public readonly string Armament = "primary"; + + [Desc("Displayed while targeting.")] + [FieldLoader.Require] + [SequenceReference] public readonly string Sequence = null; + + [Desc("Which sprite body to modify.")] + public readonly string Body = "body"; + + public override object Create(ActorInitializer init) { return new WithAimAnimation(init, this); } + + public override void RulesetLoaded(Ruleset rules, ActorInfo ai) + { + var match = ai.TraitInfos().SingleOrDefault(w => w.Name == Body); + if (match == null) + throw new YamlException("WithAimAnimation needs exactly one sprite body with matching name."); + + base.RulesetLoaded(rules, ai); + } + } + + public class WithAimAnimation : ConditionalTrait, INotifyAiming + { + readonly AttackBase attack; + readonly WithSpriteBody wsb; + + public WithAimAnimation(ActorInitializer init, WithAimAnimationInfo info) + : base(info) + { + attack = init.Self.Trait(); + wsb = init.Self.TraitsImplementing().First(w => w.Info.Name == Info.Body); + } + + protected void UpdateSequence() + { + var seq = !IsTraitDisabled && attack.IsAiming ? Info.Sequence : wsb.Info.Sequence; + wsb.DefaultAnimation.ReplaceAnim(seq); + } + + void INotifyAiming.StartedAiming(Actor self, AttackBase ab) { UpdateSequence(); } + void INotifyAiming.StoppedAiming(Actor self, AttackBase ab) { UpdateSequence(); } + protected override void TraitEnabled(Actor self) { UpdateSequence(); } + protected override void TraitDisabled(Actor self) { UpdateSequence(); } + } +} diff --git a/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs index e3057bd79b..3438e47314 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithAttackAnimation.cs @@ -20,13 +20,7 @@ namespace OpenRA.Mods.Common.Traits.Render public readonly string Armament = "primary"; [Desc("Displayed while attacking.")] - [SequenceReference] public readonly string AttackSequence = null; - - [Desc("Displayed while targeting.")] - [SequenceReference] public readonly string AimSequence = null; - - [Desc("Shown while reloading.")] - [SequenceReference(null, true)] public readonly string ReloadPrefix = null; + [SequenceReference] public readonly string Sequence = null; [Desc("Delay in ticks before animation starts, either relative to attack preparation or attack.")] public readonly int Delay = 0; @@ -51,37 +45,28 @@ namespace OpenRA.Mods.Common.Traits.Render public class WithAttackAnimation : ConditionalTrait, ITick, INotifyAttack { - readonly AttackBase attack; readonly Armament armament; readonly WithSpriteBody wsb; - readonly bool noAimOrReloadAnim; int tick; - bool attackAnimPlaying; public WithAttackAnimation(ActorInitializer init, WithAttackAnimationInfo info) : base(info) { - attack = init.Self.Trait(); armament = init.Self.TraitsImplementing() .Single(a => a.Info.Name == Info.Armament); wsb = init.Self.TraitsImplementing().First(w => w.Info.Name == Info.Body); - - noAimOrReloadAnim = string.IsNullOrEmpty(Info.AimSequence) && string.IsNullOrEmpty(Info.ReloadPrefix); } void PlayAttackAnimation(Actor self) { - if (!IsTraitDisabled && !wsb.IsTraitDisabled && !string.IsNullOrEmpty(Info.AttackSequence)) - { - attackAnimPlaying = true; - wsb.PlayCustomAnimation(self, Info.AttackSequence, () => attackAnimPlaying = false); - } + if (!IsTraitDisabled && !wsb.IsTraitDisabled && !string.IsNullOrEmpty(Info.Sequence)) + wsb.PlayCustomAnimation(self, Info.Sequence); } void INotifyAttack.Attacking(Actor self, Target target, Armament a, Barrel barrel) { - if (Info.DelayRelativeTo == AttackDelayType.Attack) + if (a == armament && Info.DelayRelativeTo == AttackDelayType.Attack) { if (Info.Delay > 0) tick = Info.Delay; @@ -92,7 +77,7 @@ namespace OpenRA.Mods.Common.Traits.Render void INotifyAttack.PreparingAttack(Actor self, Target target, Armament a, Barrel barrel) { - if (Info.DelayRelativeTo == AttackDelayType.Preparation) + if (a == armament && Info.DelayRelativeTo == AttackDelayType.Preparation) { if (Info.Delay > 0) tick = Info.Delay; @@ -105,20 +90,6 @@ namespace OpenRA.Mods.Common.Traits.Render { if (Info.Delay > 0 && --tick == 0) PlayAttackAnimation(self); - - if (IsTraitDisabled || noAimOrReloadAnim || attackAnimPlaying || wsb.IsTraitDisabled) - return; - - var sequence = wsb.Info.Sequence; - if (!string.IsNullOrEmpty(Info.AimSequence) && attack.IsAiming) - sequence = Info.AimSequence; - - var prefix = (armament.IsReloading && !string.IsNullOrEmpty(Info.ReloadPrefix)) ? Info.ReloadPrefix : ""; - - if (!string.IsNullOrEmpty(prefix) && sequence != (prefix + sequence)) - sequence = prefix + sequence; - - wsb.DefaultAnimation.ReplaceAnim(sequence); } } }