From ce91c5a76f6c9ab9c5d586b4614260f1cb472661 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 1 Mar 2020 12:36:21 +0000 Subject: [PATCH] Fix WithDisguisingInfantryBody idle animation crash. --- .../Render/WithDisguisingInfantryBody.cs | 23 ++++++++++++++--- .../Traits/Render/WithInfantryBody.cs | 25 ++++++++++++------- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs b/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs index 83cd523b72..07bea9573f 100644 --- a/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs +++ b/OpenRA.Mods.Cnc/Traits/Render/WithDisguisingInfantryBody.cs @@ -9,6 +9,7 @@ */ #endregion +using System.Linq; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; @@ -21,39 +22,53 @@ namespace OpenRA.Mods.Cnc.Traits.Render class WithDisguisingInfantryBody : WithInfantryBody { - readonly WithDisguisingInfantryBodyInfo info; readonly Disguise disguise; readonly RenderSprites rs; ActorInfo disguiseActor; Player disguisePlayer; + WithInfantryBodyInfo disguiseInfantryBody; string disguiseImage; public WithDisguisingInfantryBody(ActorInitializer init, WithDisguisingInfantryBodyInfo info) : base(init, info) { - this.info = info; rs = init.Self.Trait(); disguise = init.Self.Trait(); } + protected override WithInfantryBodyInfo GetDisplayInfo() + { + return disguiseInfantryBody ?? Info; + } + protected override void Tick(Actor self) { if (disguise.AsActor != disguiseActor || disguise.AsPlayer != disguisePlayer) { + // Force actor back to the stand state to avoid mismatched sequences + PlayStandAnimation(self); + disguiseActor = disguise.AsActor; disguisePlayer = disguise.AsPlayer; disguiseImage = null; + disguiseInfantryBody = null; if (disguisePlayer != null) { var renderSprites = disguiseActor.TraitInfoOrDefault(); - if (renderSprites != null) + var infantryBody = disguiseActor.TraitInfos() + .FirstOrDefault(t => t.EnabledByDefault); + if (renderSprites != null && infantryBody != null) + { disguiseImage = renderSprites.GetImage(disguiseActor, self.World.Map.Rules.Sequences, disguisePlayer.InternalName); + disguiseInfantryBody = infantryBody; + } } - var sequence = DefaultAnimation.GetRandomExistingSequence(info.StandSequences, Game.CosmeticRandom); + var sequence = DefaultAnimation.GetRandomExistingSequence(GetDisplayInfo().StandSequences, Game.CosmeticRandom); if (sequence != null) DefaultAnimation.ChangeImage(disguiseImage ?? rs.GetImage(self), sequence); + rs.UpdatePalette(); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs index 839761dd6b..2b5f9166c0 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs @@ -55,7 +55,6 @@ namespace OpenRA.Mods.Common.Traits.Render { readonly IMove move; protected readonly Animation DefaultAnimation; - readonly bool hasIdleSequence; bool dirty; string idleSequence; @@ -66,6 +65,12 @@ namespace OpenRA.Mods.Common.Traits.Render bool IsModifyingSequence { get { return rsm != null && rsm.IsModifyingSequence; } } bool wasModifying; + // Allow subclasses to override the info that we use for rendering + protected virtual WithInfantryBodyInfo GetDisplayInfo() + { + return Info; + } + public WithInfantryBody(ActorInitializer init, WithInfantryBodyInfo info) : base(info) { @@ -75,7 +80,6 @@ namespace OpenRA.Mods.Common.Traits.Render DefaultAnimation = new Animation(init.World, rs.GetImage(self), RenderSprites.MakeFacingFunc(self)); rs.Add(new AnimationWithOffset(DefaultAnimation, null, () => IsTraitDisabled)); PlayStandAnimation(self); - hasIdleSequence = Info.IdleSequences.Length > 0; move = init.Self.Trait(); } @@ -83,7 +87,8 @@ namespace OpenRA.Mods.Common.Traits.Render protected override void Created(Actor self) { rsm = self.TraitOrDefault(); - idleDelay = self.World.SharedRandom.Next(Info.MinIdleDelay, Info.MaxIdleDelay); + var info = GetDisplayInfo(); + idleDelay = self.World.SharedRandom.Next(info.MinIdleDelay, info.MaxIdleDelay); base.Created(self); } @@ -100,7 +105,7 @@ namespace OpenRA.Mods.Common.Traits.Render protected virtual bool AllowIdleAnimation(Actor self) { - return hasIdleSequence && !IsModifyingSequence; + return GetDisplayInfo().IdleSequences.Length > 0 && !IsModifyingSequence; } public void PlayStandAnimation(Actor self) @@ -118,8 +123,9 @@ namespace OpenRA.Mods.Common.Traits.Render public void Attacking(Actor self, Target target, Armament a) { string sequence; - if (!Info.AttackSequences.TryGetValue(a.Info.Name, out sequence)) - sequence = Info.DefaultAttackSequence; + var info = GetDisplayInfo(); + if (!info.AttackSequences.TryGetValue(a.Info.Name, out sequence)) + sequence = info.DefaultAttackSequence; if (!string.IsNullOrEmpty(sequence) && DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, sequence))) { @@ -153,7 +159,7 @@ namespace OpenRA.Mods.Common.Traits.Render if ((state != AnimationState.Moving || dirty) && move.CurrentMovementTypes.HasFlag(MovementType.Horizontal)) { state = AnimationState.Moving; - DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, Info.MoveSequence)); + DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, GetDisplayInfo().MoveSequence)); } else if (((state == AnimationState.Moving || dirty) && !move.CurrentMovementTypes.HasFlag(MovementType.Horizontal)) || ((state == AnimationState.Idle || state == AnimationState.IdleAnimating) && !self.IsIdle)) @@ -170,8 +176,9 @@ namespace OpenRA.Mods.Common.Traits.Render if (state == AnimationState.Waiting) { state = AnimationState.Idle; - idleSequence = Info.IdleSequences.Random(self.World.SharedRandom); - idleDelay = self.World.SharedRandom.Next(Info.MinIdleDelay, Info.MaxIdleDelay); + var info = GetDisplayInfo(); + idleSequence = info.IdleSequences.Random(self.World.SharedRandom); + idleDelay = self.World.SharedRandom.Next(info.MinIdleDelay, info.MaxIdleDelay); } else if (state == AnimationState.Idle && idleDelay > 0 && --idleDelay == 0) {