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);
}
}
}