From 305d82f887df3deb500495e7c2966c98669f1735 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Thu, 13 Dec 2018 23:32:47 +0100 Subject: [PATCH] Replace WithChargeAnimation with -SpriteBody PlayFetchIndex on a With*Animation trait conflicts with the animation concept, as it's bound to conflict with pretty much all 'normal' animation traits and blocks progress on the animation priority system. We also already have multiple precedent SpriteBody traits of similar kind, like WithGateSpriteBody and WithWallSpriteBody. --- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 3 +- .../Traits/Render/WithChargeAnimation.cs | 49 ------------- .../Traits/Render/WithChargeSpriteBody.cs | 65 +++++++++++++++++ .../Traits/Render/WithSpriteBody.cs | 8 +- .../20180923/ReplacedWithChargeAnimation.cs | 73 +++++++++++++++++++ OpenRA.Mods.Common/UpdateRules/UpdatePath.cs | 1 + OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs | 31 +++++++- mods/cnc/rules/structures.yaml | 5 +- 8 files changed, 177 insertions(+), 58 deletions(-) delete mode 100644 OpenRA.Mods.Common/Traits/Render/WithChargeAnimation.cs create mode 100644 OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs create mode 100644 OpenRA.Mods.Common/UpdateRules/Rules/20180923/ReplacedWithChargeAnimation.cs diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 012fdd7bd8..946bf86782 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -856,7 +856,7 @@ - + @@ -948,6 +948,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Render/WithChargeAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithChargeAnimation.cs deleted file mode 100644 index b5253aefe2..0000000000 --- a/OpenRA.Mods.Common/Traits/Render/WithChargeAnimation.cs +++ /dev/null @@ -1,49 +0,0 @@ -#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 -{ - [Desc("Render trait that varies the animation frame based on the AttackCharges trait's charge level.")] - class WithChargeAnimationInfo : ConditionalTraitInfo, Requires, Requires - { - [SequenceReference] - [Desc("Sequence to use for the charge levels.")] - public readonly string Sequence = "active"; - - [Desc("Which sprite body to play the animation on.")] - public readonly string Body = "body"; - - public override object Create(ActorInitializer init) { return new WithChargeAnimation(init.Self, this); } - } - - class WithChargeAnimation : ConditionalTrait - { - readonly WithSpriteBody wsb; - readonly AttackCharges attackCharges; - - public WithChargeAnimation(Actor self, WithChargeAnimationInfo info) - : base(info) - { - wsb = self.TraitsImplementing().Single(w => w.Info.Name == info.Body); - attackCharges = self.Trait(); - } - - protected override void TraitEnabled(Actor self) - { - var attackChargesInfo = (AttackChargesInfo)attackCharges.Info; - wsb.DefaultAnimation.PlayFetchIndex(wsb.NormalizeSequence(self, Info.Sequence), - () => int2.Lerp(0, wsb.DefaultAnimation.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1)); - } - } -} diff --git a/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs b/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs new file mode 100644 index 0000000000..151f3b64da --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Render/WithChargeSpriteBody.cs @@ -0,0 +1,65 @@ +#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.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits.Render +{ + [Desc("Render trait that varies the sprite body frame based on the AttackCharges trait's charge level.")] + public class WithChargeSpriteBodyInfo : WithSpriteBodyInfo, Requires + { + public override object Create(ActorInitializer init) { return new WithChargeSpriteBody(init, this); } + + public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) + { + if (!EnabledByDefault) + yield break; + + var anim = new Animation(init.World, image); + anim.PlayFetchIndex(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence), () => 0); + + yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); + } + } + + public class WithChargeSpriteBody : WithSpriteBody + { + readonly AttackCharges attackCharges; + + public WithChargeSpriteBody(ActorInitializer init, WithChargeSpriteBodyInfo info) + : base(init, info, () => 0) + { + attackCharges = init.Self.Trait(); + ConfigureAnimation(init.Self); + } + + void ConfigureAnimation(Actor self) + { + var attackChargesInfo = (AttackChargesInfo)attackCharges.Info; + DefaultAnimation.PlayFetchIndex(NormalizeSequence(self, Info.Sequence), + () => int2.Lerp(0, DefaultAnimation.CurrentSequence.Length, attackCharges.ChargeLevel, attackChargesInfo.ChargeLevel + 1)); + } + + protected override void TraitEnabled(Actor self) + { + // Do nothing - we just want to disable the default WithSpriteBody implementation + } + + public override void CancelCustomAnimation(Actor self) + { + ConfigureAnimation(self); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs index 27168d6462..a0867d1fdf 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteBody.cs @@ -92,7 +92,7 @@ namespace OpenRA.Mods.Common.Traits.Render DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); } - public void PlayCustomAnimation(Actor self, string name, Action after = null) + public virtual void PlayCustomAnimation(Actor self, string name, Action after = null) { DefaultAnimation.PlayThen(NormalizeSequence(self, name), () => { @@ -102,12 +102,12 @@ namespace OpenRA.Mods.Common.Traits.Render }); } - public void PlayCustomAnimationRepeating(Actor self, string name) + public virtual void PlayCustomAnimationRepeating(Actor self, string name) { DefaultAnimation.PlayRepeating(NormalizeSequence(self, name)); } - public void PlayCustomAnimationBackwards(Actor self, string name, Action after = null) + public virtual void PlayCustomAnimationBackwards(Actor self, string name, Action after = null) { DefaultAnimation.PlayBackwardsThen(NormalizeSequence(self, name), () => { @@ -117,7 +117,7 @@ namespace OpenRA.Mods.Common.Traits.Render }); } - public void CancelCustomAnimation(Actor self) + public virtual void CancelCustomAnimation(Actor self) { DefaultAnimation.PlayRepeating(NormalizeSequence(self, Info.Sequence)); } diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20180923/ReplacedWithChargeAnimation.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/ReplacedWithChargeAnimation.cs new file mode 100644 index 0000000000..1539ae5867 --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20180923/ReplacedWithChargeAnimation.cs @@ -0,0 +1,73 @@ +#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.Collections.Generic; +using System.Linq; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class ReplacedWithChargeAnimation : UpdateRule + { + public override string Name { get { return "Replaced WithChargeAnimation with WithChargeSpriteBody"; } } + public override string Description + { + get + { + return "Replaced WithChargeAnimation with WithChargeSpriteBody."; + } + } + + readonly List locations = new List(); + + public override IEnumerable AfterUpdate(ModData modData) + { + if (locations.Any()) + yield return "WithChargeAnimation has been replaced by WithChargeSpriteBody.\n" + + "You may need to disable/remove any previous (including inherited) *SpriteBody traits\n" + + "on the following actors:\n" + + UpdateUtils.FormatMessageList(locations); + + locations.Clear(); + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + var chargeAnims = actorNode.ChildrenMatching("WithChargeAnimation"); + + foreach (var ca in chargeAnims) + { + // If it's a trait removal, we only rename it. + if (ca.IsRemoval()) + { + ca.RenameKey("WithChargeSpriteBody"); + continue; + } + + var sequence = ca.LastChildMatching("Sequence"); + var body = ca.LastChildMatching("Body"); + + if (sequence == null) + { + var newSequenceNode = new MiniYamlNode("Sequence", "active"); + ca.AddNode(newSequenceNode); + } + + if (body != null) + ca.RemoveNode(body); + + ca.RenameKey("WithChargeSpriteBody"); + locations.Add("{0} ({1})".F(actorNode.Key, ca.Location.Filename)); + } + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index e5b647f04b..cf74f08295 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -111,6 +111,7 @@ namespace OpenRA.Mods.Common.UpdateRules new DefineLevelUpImageDefault(), new RemovedAutoCarryallCircleTurnSpeed(), new RemoveAttackIgnoresVisibility(), + new ReplacedWithChargeAnimation(), }) }; diff --git a/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs b/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs index 28ac004b8d..1fbb1747ba 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs @@ -237,10 +237,16 @@ namespace OpenRA.Mods.Common.UpdateRules file.Item1.Update(file.Item2, Encoding.UTF8.GetBytes(file.Item3.WriteToString())); } + /// Checks if node is a removal (has '-' prefix) + public static bool IsRemoval(this MiniYamlNode node) + { + return node.Key[0].ToString() == "-"; + } + /// Renames a yaml key preserving any @suffix public static void RenameKey(this MiniYamlNode node, string newKey, bool preserveSuffix = true, bool includeRemovals = true) { - var prefix = includeRemovals && node.Key[0].ToString() == "-" ? "-" : ""; + var prefix = includeRemovals && node.IsRemoval() ? "-" : ""; var split = node.Key.IndexOf("@", StringComparison.Ordinal); if (preserveSuffix && split > -1) node.Key = prefix + newKey + node.Key.Substring(split); @@ -298,7 +304,7 @@ namespace OpenRA.Mods.Common.UpdateRules if (node.Key == null) return false; - var prefix = includeRemovals && node.Key[0].ToString() == "-" ? "-" : ""; + var prefix = includeRemovals && node.IsRemoval() ? "-" : ""; if (node.Key == prefix + match) return true; @@ -310,12 +316,33 @@ namespace OpenRA.Mods.Common.UpdateRules return atPosition > 0 && node.Key.Substring(0, atPosition) == prefix + match; } + /// Returns true if the node is of the form <*match*>, <*match*>@arbitrary or @*match* + public static bool KeyContains(this MiniYamlNode node, string match, bool ignoreSuffix = true, bool includeRemovals = true) + { + if (node.Key == null) + return false; + + var atPosition = node.Key.IndexOf('@'); + var relevantPart = ignoreSuffix && atPosition > 0 ? node.Key.Substring(0, atPosition) : node.Key; + + if (relevantPart.Contains(match) && (includeRemovals || !node.IsRemoval())) + return true; + + return false; + } + /// Returns children with keys equal to [match] or [match]@[arbitrary suffix] public static IEnumerable ChildrenMatching(this MiniYamlNode node, string match, bool ignoreSuffix = true, bool includeRemovals = true) { return node.Value.Nodes.Where(n => n.KeyMatches(match, ignoreSuffix, includeRemovals)); } + /// Returns children whose keys contain 'match' (optionally in the suffix) + public static IEnumerable ChildrenContaining(this MiniYamlNode node, string match, bool ignoreSuffix = true, bool includeRemovals = true) + { + return node.Value.Nodes.Where(n => n.KeyContains(match, ignoreSuffix, includeRemovals)); + } + public static MiniYamlNode LastChildMatching(this MiniYamlNode node, string match, bool includeRemovals = true) { return node.ChildrenMatching(match, includeRemovals: includeRemovals).LastOrDefault(); diff --git a/mods/cnc/rules/structures.yaml b/mods/cnc/rules/structures.yaml index 3240b456b6..141be47808 100644 --- a/mods/cnc/rules/structures.yaml +++ b/mods/cnc/rules/structures.yaml @@ -923,8 +923,9 @@ OBLI: Range: 8c0 WithBuildingBib: HasMinibib: Yes - WithChargeAnimation: - RequiresCondition: !build-incomplete + -WithSpriteBody: + WithChargeSpriteBody: + Sequence: active Armament: Weapon: Laser LocalOffset: 0,-85,1280