diff --git a/OpenRA.Mods.Common/ActorInitializer.cs b/OpenRA.Mods.Common/ActorInitializer.cs index 66614467b2..b8ba2a5c67 100644 --- a/OpenRA.Mods.Common/ActorInitializer.cs +++ b/OpenRA.Mods.Common/ActorInitializer.cs @@ -23,6 +23,12 @@ namespace OpenRA.Mods.Common : base(value) { } } + public class TerrainOrientationInit : ValueActorInit, ISingleInstanceInit + { + public TerrainOrientationInit(WRot value) + : base(value) { } + } + public class CreationActivityDelayInit : ValueActorInit, ISingleInstanceInit { public CreationActivityDelayInit(int value) diff --git a/OpenRA.Mods.Common/Graphics/ActorPreview.cs b/OpenRA.Mods.Common/Graphics/ActorPreview.cs index 6732ffecf4..afca3a4fe9 100644 --- a/OpenRA.Mods.Common/Graphics/ActorPreview.cs +++ b/OpenRA.Mods.Common/Graphics/ActorPreview.cs @@ -67,20 +67,32 @@ namespace OpenRA.Mods.Common.Graphics if (facingInfo == null) return () => WRot.None; + WAngle facing; + // Dynamic facing takes priority var dynamicInit = reference.GetOrDefault(); if (dynamicInit != null) { - // TODO: Account for terrain slope var getFacing = dynamicInit.Value; - return () => WRot.FromYaw(getFacing()); + facing = getFacing(); + } + else + { + // Fall back to initial actor facing if an Init isn't available + var facingInit = reference.GetOrDefault(); + facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); } - // Fall back to initial actor facing if an Init isn't available - var facingInit = reference.GetOrDefault(); - var facing = facingInit != null ? facingInit.Value : facingInfo.GetInitialFacing(); - var orientation = WRot.FromYaw(facing); - return () => orientation; + var mobileInfo = Actor.TraitInfoOrDefault(); + var location = reference.GetOrDefault(); + if (location == null || mobileInfo == null || mobileInfo.TerrainOrientationAdjustmentMargin.Length < 0) + return () => WRot.FromYaw(facing); + + var orientationInit = reference.GetOrDefault(); + var terrainOrientation = orientationInit != null ? orientationInit.Value : World.Map.TerrainOrientation(location.Value); + var terrainAdjustedFacing = new WRot(new WVec(0, 0, 1024).Rotate(terrainOrientation), facing); + + return () => terrainOrientation + terrainAdjustedFacing; } public Func GetFacing() diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs index 5bd1393485..6f198e6bfb 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs @@ -47,6 +47,7 @@ namespace OpenRA.Mods.Common.Traits readonly TooltipInfoBase tooltip; IActorPreview[] previews; readonly ActorReference reference; + readonly Action onCellEntryChanged; readonly Dictionary editorData = new(); public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference reference, PlayerReference owner) @@ -98,6 +99,9 @@ namespace OpenRA.Mods.Common.Traits SelectionBox = new SelectionBoxAnnotationRenderable(new WPos(CenterPosition.X, CenterPosition.Y, 8192), new Rectangle(Bounds.X, Bounds.Y, Bounds.Width, Bounds.Height), Color.White); + + // TODO: updating all actors on the map is not very efficient. + onCellEntryChanged = _ => GeneratePreviews(); } public void Tick() @@ -134,12 +138,17 @@ namespace OpenRA.Mods.Common.Traits { foreach (var notify in Info.TraitInfos()) editorData[notify] = notify.AddedToEditor(this, worldRenderer.World); + + // TODO: this should subscribe to ramp cell map as well. + worldRenderer.World.Map.Height.CellEntryChanged += onCellEntryChanged; } public void RemovedFromEditor() { foreach (var kv in editorData) kv.Key.RemovedFromEditor(this, worldRenderer.World, kv.Value); + + worldRenderer.World.Map.Height.CellEntryChanged -= onCellEntryChanged; } public void AddInit(T init) where T : ActorInit