From aa8d9f5dda92fb701c199c37180804b976f98eb8 Mon Sep 17 00:00:00 2001 From: reaperrr Date: Fri, 31 Mar 2017 15:53:51 +0200 Subject: [PATCH] Fix GrantConditionOnDeploy to support multiple sprite bodies --- .../Conditions/GrantConditionOnDeploy.cs | 30 ++++--- .../Traits/Render/WithMakeAnimation.cs | 79 +++++++++++++++++-- OpenRA.Mods.Common/TraitsInterfaces.cs | 19 ++++- mods/ts/rules/nod-vehicles.yaml | 4 +- mods/ts/rules/shared-vehicles.yaml | 2 +- 5 files changed, 114 insertions(+), 20 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs index a9b6b65d1b..343780f7fd 100644 --- a/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs +++ b/OpenRA.Mods.Common/Traits/Conditions/GrantConditionOnDeploy.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; @@ -42,9 +43,6 @@ namespace OpenRA.Mods.Common.Traits [Desc("Cursor to display when unable to (un)deploy the actor.")] public readonly string DeployBlockedCursor = "deploy-blocked"; - [SequenceReference, Desc("Animation to play for deploying/undeploying.")] - public readonly string DeployAnimation = null; - [Desc("Facing that the actor must face before deploying. Set to -1 to deploy regardless of facing.")] public readonly int Facing = -1; @@ -62,16 +60,16 @@ namespace OpenRA.Mods.Common.Traits public enum DeployState { Undeployed, Deploying, Deployed, Undeploying } - public class GrantConditionOnDeploy : IResolveOrder, IIssueOrder, INotifyCreated + public class GrantConditionOnDeploy : IResolveOrder, IIssueOrder, INotifyCreated, INotifyDeployComplete { readonly Actor self; readonly GrantConditionOnDeployInfo info; readonly bool checkTerrainType; readonly bool canTurn; - readonly Lazy body; DeployState deployState; ConditionManager conditionManager; + INotifyDeployTriggered[] notify; int deployedToken = ConditionManager.InvalidConditionToken; int undeployedToken = ConditionManager.InvalidConditionToken; @@ -81,7 +79,6 @@ namespace OpenRA.Mods.Common.Traits this.info = info; checkTerrainType = info.AllowedTerrainTypes.Count > 0; canTurn = self.Info.HasTraitInfo(); - body = Exts.Lazy(self.TraitOrDefault); if (init.Contains()) deployState = init.Get(); } @@ -89,6 +86,7 @@ namespace OpenRA.Mods.Common.Traits public void Created(Actor self) { conditionManager = self.TraitOrDefault(); + notify = self.TraitsImplementing().ToArray(); switch (deployState) { @@ -192,6 +190,16 @@ namespace OpenRA.Mods.Common.Traits return ramp == 0; } + void INotifyDeployComplete.FinishedDeploy(Actor self) + { + OnDeployCompleted(); + } + + void INotifyDeployComplete.FinishedUndeploy(Actor self) + { + OnUndeployCompleted(); + } + /// Play deploy sound and animation. void Deploy() { Deploy(false); } void Deploy(bool init) @@ -212,10 +220,11 @@ namespace OpenRA.Mods.Common.Traits // If there is no animation to play just grant the condition that is used while deployed. // Alternatively, play the deploy animation and then grant the condition. - if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null) + if (!notify.Any()) OnDeployCompleted(); else - body.Value.PlayCustomAnimation(self, info.DeployAnimation, OnDeployCompleted); + foreach (var n in notify) + n.Deploy(self); } /// Play undeploy sound and animation and after that revoke the condition. @@ -234,10 +243,11 @@ namespace OpenRA.Mods.Common.Traits // If there is no animation to play just grant the condition that is used while undeployed. // Alternatively, play the undeploy animation and then grant the condition. - if (string.IsNullOrEmpty(info.DeployAnimation) || body.Value == null) + if (!notify.Any()) OnUndeployCompleted(); else - body.Value.PlayCustomAnimationBackwards(self, info.DeployAnimation, OnUndeployCompleted); + foreach (var n in notify) + n.Undeploy(self); } void OnDeployStarted() diff --git a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs index dec70c2c5e..47c355b3a6 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithMakeAnimation.cs @@ -10,28 +10,32 @@ #endregion using System; +using System.Linq; using OpenRA.Activities; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits.Render { - [Desc("Replaces the sprite during construction.")] + [Desc("Replaces the sprite during construction/deploy/undeploy.")] public class WithMakeAnimationInfo : ITraitInfo, Requires { - [Desc("Sequence name to use")] + [Desc("Sequence name to use.")] [SequenceReference] public readonly string Sequence = "make"; [GrantedConditionReference] [Desc("The condition to grant to self while the make animation is playing.")] public readonly string Condition = null; + [Desc("Apply to sprite bodies with these names.")] + public readonly string[] BodyNames = { "body" }; + public object Create(ActorInitializer init) { return new WithMakeAnimation(init, this); } } - public class WithMakeAnimation : INotifyCreated + public class WithMakeAnimation : INotifyCreated, INotifyDeployTriggered { readonly WithMakeAnimationInfo info; - readonly WithSpriteBody wsb; + readonly WithSpriteBody[] wsbs; ConditionManager conditionManager; int token = ConditionManager.InvalidConditionToken; @@ -40,7 +44,7 @@ namespace OpenRA.Mods.Common.Traits.Render { this.info = info; var self = init.Self; - wsb = self.Trait(); + wsbs = self.TraitsImplementing().Where(w => info.BodyNames.Contains(w.Info.Name)).ToArray(); } void INotifyCreated.Created(Actor self) @@ -56,6 +60,11 @@ namespace OpenRA.Mods.Common.Traits.Render if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) token = conditionManager.GrantCondition(self, info.Condition); + var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled); + + if (wsb == null) + return; + wsb.PlayCustomAnimation(self, info.Sequence, () => { if (token != ConditionManager.InvalidConditionToken) @@ -71,6 +80,11 @@ namespace OpenRA.Mods.Common.Traits.Render if (conditionManager != null && !string.IsNullOrEmpty(info.Condition) && token == ConditionManager.InvalidConditionToken) token = conditionManager.GrantCondition(self, info.Condition); + var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled); + + if (wsb == null) + return; + wsb.PlayCustomAnimationBackwards(self, info.Sequence, () => { if (token != ConditionManager.InvalidConditionToken) @@ -85,11 +99,14 @@ namespace OpenRA.Mods.Common.Traits.Render { Reverse(self, () => { + var wsb = wsbs.FirstOrDefault(Exts.IsTraitEnabled); + // HACK: The actor remains alive and active for one tick before the followup activity // (sell/transform/etc) runs. This causes visual glitches that we attempt to minimize // by forcing the animation to frame 0 and regranting the make condition. // These workarounds will break the actor if the followup activity doesn't dispose it! - wsb.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); + if (wsb != null) + wsb.DefaultAnimation.PlayFetchIndex(info.Sequence, () => 0); if (conditionManager != null && !string.IsNullOrEmpty(info.Condition)) token = conditionManager.GrantCondition(self, info.Condition); @@ -97,5 +114,55 @@ namespace OpenRA.Mods.Common.Traits.Render self.QueueActivity(queued, activity); }); } + + // TODO: Make this use Forward instead + void INotifyDeployTriggered.Deploy(Actor self) + { + var notified = false; + + foreach (var wsb in wsbs) + { + if (wsb.IsTraitDisabled) + continue; + + var notify = self.TraitsImplementing(); + wsb.PlayCustomAnimation(self, info.Sequence, () => + { + if (notified) + return; + + foreach (var n in notify) + { + n.FinishedDeploy(self); + notified = true; + } + }); + } + } + + // TODO: Make this use Reverse instead + void INotifyDeployTriggered.Undeploy(Actor self) + { + var notified = false; + + foreach (var wsb in wsbs) + { + if (wsb.IsTraitDisabled) + continue; + + var notify = self.TraitsImplementing(); + wsb.PlayCustomAnimationBackwards(self, info.Sequence, () => + { + if (notified) + return; + + foreach (var n in notify) + { + n.FinishedUndeploy(self); + notified = true; + } + }); + } + } } } diff --git a/OpenRA.Mods.Common/TraitsInterfaces.cs b/OpenRA.Mods.Common/TraitsInterfaces.cs index 32c5240df6..77c26d3018 100644 --- a/OpenRA.Mods.Common/TraitsInterfaces.cs +++ b/OpenRA.Mods.Common/TraitsInterfaces.cs @@ -165,7 +165,24 @@ namespace OpenRA.Mods.Common.Traits bool IsOverlayActive(ActorInfo ai); } - public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); } + public interface INotifyTransform + { + void BeforeTransform(Actor self); + void OnTransform(Actor self); + void AfterTransform(Actor toActor); + } + + public interface INotifyDeployComplete + { + void FinishedDeploy(Actor self); + void FinishedUndeploy(Actor self); + } + + public interface INotifyDeployTriggered + { + void Deploy(Actor self); + void Undeploy(Actor self); + } public interface IAcceptResourcesInfo : ITraitInfo { } public interface IAcceptResources diff --git a/mods/ts/rules/nod-vehicles.yaml b/mods/ts/rules/nod-vehicles.yaml index cd06836030..3f1ae5f1b9 100644 --- a/mods/ts/rules/nod-vehicles.yaml +++ b/mods/ts/rules/nod-vehicles.yaml @@ -117,10 +117,10 @@ TTNK: MaxHeightDelta: 3 RenderSprites: Image: ttnk + WithMakeAnimation: GrantConditionOnDeploy: DeployedCondition: deployed UndeployedCondition: undeployed - DeployAnimation: make Facing: 160 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySound: place2.aud @@ -211,10 +211,10 @@ ART2: LightAmbientColor: 0.4, 0.4, 0.4 RenderSprites: Image: art2 + WithMakeAnimation: GrantConditionOnDeploy: DeployedCondition: deployed UndeployedCondition: undeployed - DeployAnimation: make Facing: 96 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySound: place2.aud diff --git a/mods/ts/rules/shared-vehicles.yaml b/mods/ts/rules/shared-vehicles.yaml index 7a4fe0fde3..e64682c026 100644 --- a/mods/ts/rules/shared-vehicles.yaml +++ b/mods/ts/rules/shared-vehicles.yaml @@ -140,6 +140,7 @@ LPST: RequiresCondition: !undeployed Range: 8c0 MaxHeightDelta: 3 + WithMakeAnimation: GrantCondition@PREVIEWWORKAROUND: Condition: real-actor RenderSprites: @@ -150,7 +151,6 @@ LPST: GrantConditionOnDeploy: DeployedCondition: deployed UndeployedCondition: undeployed - DeployAnimation: make Facing: 160 AllowedTerrainTypes: Clear, Road, DirtRoad, Rough DeploySound: place2.aud