diff --git a/OpenRA.Mods.Common/ActorInitializer.cs b/OpenRA.Mods.Common/ActorInitializer.cs index 457eee6673..fc2eb8cf0f 100644 --- a/OpenRA.Mods.Common/ActorInitializer.cs +++ b/OpenRA.Mods.Common/ActorInitializer.cs @@ -11,6 +11,13 @@ namespace OpenRA.Mods.Common public int Value(World world) { return value; } } + public class DynamicFacingInit : IActorInit> + { + readonly Func func; + public DynamicFacingInit(Func func) { this.func = func; } + public Func Value(World world) { return func; } + } + public class SubCellInit : IActorInit { [FieldFromYamlKey] readonly int value = (int)SubCell.FullCell; diff --git a/OpenRA.Mods.Common/Graphics/ActorPreview.cs b/OpenRA.Mods.Common/Graphics/ActorPreview.cs index eb44e24fcf..dee6f6110b 100644 --- a/OpenRA.Mods.Common/Graphics/ActorPreview.cs +++ b/OpenRA.Mods.Common/Graphics/ActorPreview.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; @@ -42,6 +43,45 @@ namespace OpenRA.Mods.Common.Graphics public U Get() where T : IActorInit { return dict.Get().Value(World); } public bool Contains() where T : IActorInit { return dict.Contains(); } + public Func GetOrientation() + { + var facingInfo = Actor.TraitInfoOrDefault(); + if (facingInfo == null) + return () => WRot.Zero; + + // Dynamic facing takes priority + var dynamicInit = dict.GetOrDefault(); + if (dynamicInit != null) + { + // TODO: Account for terrain slope + var getFacing = dynamicInit.Value(null); + return () => WRot.FromFacing(getFacing()); + } + + // Fall back to initial actor facing if an Init isn't available + var facingInit = dict.GetOrDefault(); + var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing(); + var orientation = WRot.FromFacing(facing); + return () => orientation; + } + + public Func GetFacing() + { + var facingInfo = Actor.TraitInfoOrDefault(); + if (facingInfo == null) + return () => 0; + + // Dynamic facing takes priority + var dynamicInit = dict.GetOrDefault(); + if (dynamicInit != null) + return dynamicInit.Value(null); + + // Fall back to initial actor facing if an Init isn't available + var facingInit = dict.GetOrDefault(); + var facing = facingInit != null ? facingInit.Value(null) : facingInfo.GetInitialFacing(); + return () => facing; + } + public DamageState GetDamageState() { var health = dict.GetOrDefault(); diff --git a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs index 99d316fd6b..4f6182ac94 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderVoxels.cs @@ -59,11 +59,8 @@ namespace OpenRA.Mods.Common.Traits.Render body.QuantizedFacings; var palette = init.WorldRenderer.Palette(Palette ?? PlayerPalette + ownerName); - var ifacing = init.Actor.TraitInfoOrDefault(); - var facing = ifacing != null ? init.Contains() ? init.Get() : ifacing.GetInitialFacing() : 0; - var orientation = WRot.FromFacing(facing); var components = init.Actor.TraitInfos() - .SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, () => orientation, facings, palette)) + .SelectMany(rvpi => rvpi.RenderPreviewVoxels(init, this, image, init.GetOrientation(), facings, palette)) .ToArray(); yield return new VoxelPreview(components, WVec.Zero, 0, Scale, LightPitch, diff --git a/OpenRA.Mods.Common/Traits/Render/WithFacingSpriteBody.cs b/OpenRA.Mods.Common/Traits/Render/WithFacingSpriteBody.cs index 4e1153704f..5546039f64 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithFacingSpriteBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithFacingSpriteBody.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; @@ -22,10 +23,7 @@ namespace OpenRA.Mods.Common.Traits.Render public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - var ifacing = init.Actor.TraitInfoOrDefault(); - var facing = ifacing != null ? init.Contains() ? init.Get() : ifacing.GetInitialFacing() : 0; - - var anim = new Animation(init.World, image, () => facing); + var anim = new Animation(init.World, image, init.GetFacing()); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); diff --git a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs index d891528424..f0abb02bde 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithIdleOverlay.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; @@ -46,15 +47,28 @@ namespace OpenRA.Mods.Common.Traits.Render if (Palette != null) p = init.WorldRenderer.Palette(Palette); - var body = init.Actor.TraitInfo(); - var facing = init.Contains() ? init.Get() : 0; - var anim = new Animation(init.World, image, () => facing); + Func facing; + if (init.Contains()) + facing = init.Get>(); + else + { + var f = init.Contains() ? init.Get() : 0; + facing = () => f; + } + + var anim = new Animation(init.World, image, facing); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); - var orientation = body.QuantizeOrientation(WRot.FromFacing(facing), facings); - var offset = body.LocalToWorld(Offset.Rotate(orientation)); - var zOffset = offset.Y + offset.Z + 1; - yield return new SpriteActorPreview(anim, () => offset, () => zOffset, p, rs.Scale); + var body = init.Actor.TraitInfo(); + Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + Func offset = () => body.LocalToWorld(Offset.Rotate(orientation())); + Func zOffset = () => + { + var tmpOffset = offset(); + return tmpOffset.Y + tmpOffset.Z + 1; + }; + + yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale); } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs index aefaceff6b..dfe0f5125e 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithInfantryBody.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; @@ -31,12 +32,7 @@ namespace OpenRA.Mods.Common.Traits.Render public IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - var facing = 0; - var ifacing = init.Actor.TraitInfoOrDefault(); - if (ifacing != null) - facing = init.Contains() ? init.Get() : ifacing.GetInitialFacing(); - - var anim = new Animation(init.World, image, () => facing); + var anim = new Animation(init.World, image, init.GetFacing()); anim.PlayRepeating(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), StandSequences.First())); yield return new SpriteActorPreview(anim, () => WVec.Zero, () => 0, p, rs.Scale); } diff --git a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs index fdc8a3547c..2c5ae38056 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithParachute.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithParachute.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; @@ -68,15 +69,28 @@ namespace OpenRA.Mods.Common.Traits.Render if (Palette != null) p = init.WorldRenderer.Palette(Palette); + Func facing; + if (init.Contains()) + facing = init.Get>(); + else + { + var f = init.Contains() ? init.Get() : 0; + facing = () => f; + } + var anim = new Animation(init.World, image); anim.PlayThen(OpeningSequence, () => anim.PlayRepeating(Sequence)); var body = init.Actor.TraitInfo(); - var facing = init.Contains() ? init.Get() : 0; - var orientation = body.QuantizeOrientation(WRot.FromFacing(facing), facings); - var offset = body.LocalToWorld(Offset.Rotate(orientation)); - var zOffset = offset.Y + offset.Z + 1; - yield return new SpriteActorPreview(anim, () => offset, () => zOffset, p, rs.Scale); + Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + Func offset = () => body.LocalToWorld(Offset.Rotate(orientation())); + Func zOffset = () => + { + var tmpOffset = offset(); + return tmpOffset.Y + tmpOffset.Z + 1; + }; + + yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale); } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs b/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs index 5158f0cb4f..ca02eba0ba 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithSpriteTurret.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; @@ -44,17 +45,20 @@ namespace OpenRA.Mods.Common.Traits.Render var t = init.Actor.TraitInfos() .First(tt => tt.Turret == Turret); - var ifacing = init.Actor.TraitInfoOrDefault(); - var bodyFacing = ifacing != null ? init.Contains() ? init.Get() : ifacing.GetInitialFacing() : 0; var turretFacing = Turreted.GetInitialTurretFacing(init, t.InitialFacing, Turret); - var anim = new Animation(init.World, image, () => turretFacing); anim.Play(RenderSprites.NormalizeSequence(anim, init.GetDamageState(), Sequence)); - var orientation = body.QuantizeOrientation(WRot.FromFacing(bodyFacing), facings); - var offset = body.LocalToWorld(t.Offset.Rotate(orientation)); - var zOffset = -(offset.Y + offset.Z) + 1; - yield return new SpriteActorPreview(anim, () => offset, () => zOffset, p, rs.Scale); + Func facing = init.GetFacing(); + Func orientation = () => body.QuantizeOrientation(WRot.FromFacing(facing()), facings); + Func offset = () => body.LocalToWorld(t.Offset.Rotate(orientation())); + Func zOffset = () => + { + var tmpOffset = offset(); + return -(tmpOffset.Y + tmpOffset.Z) + 1; + }; + + yield return new SpriteActorPreview(anim, offset, zOffset, p, rs.Scale); } } diff --git a/OpenRA.Mods.Common/Traits/ThrowsParticle.cs b/OpenRA.Mods.Common/Traits/ThrowsParticle.cs index af94f420f3..dcd768894b 100644 --- a/OpenRA.Mods.Common/Traits/ThrowsParticle.cs +++ b/OpenRA.Mods.Common/Traits/ThrowsParticle.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits.Render; using OpenRA.Traits; @@ -64,7 +65,8 @@ namespace OpenRA.Mods.Common.Traits var body = self.Trait(); // TODO: Carry orientation over from the parent instead of just facing - var bodyFacing = init.Contains() ? init.Get() : 0; + var bodyFacing = init.Contains() ? init.Get>()() + : init.Contains() ? init.Get() : 0; facing = WAngle.FromFacing(Turreted.GetInitialTurretFacing(init, 0)); // Calculate final position diff --git a/OpenRA.Mods.Common/Traits/Turreted.cs b/OpenRA.Mods.Common/Traits/Turreted.cs index 749282e8ab..66c90ca3ad 100644 --- a/OpenRA.Mods.Common/Traits/Turreted.cs +++ b/OpenRA.Mods.Common/Traits/Turreted.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Primitives; using OpenRA.Traits; @@ -61,6 +62,9 @@ namespace OpenRA.Mods.Common.Traits if (init.Contains()) return init.Get(); + if (init.Contains()) + return init.Get>()(); + if (init.Contains()) return init.Get();