diff --git a/OpenRA.Mods.RA/Graphics/ActorPreview.cs b/OpenRA.Mods.RA/Graphics/ActorPreview.cs new file mode 100644 index 0000000000..f33977deba --- /dev/null +++ b/OpenRA.Mods.RA/Graphics/ActorPreview.cs @@ -0,0 +1,45 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Primitives; + +namespace OpenRA.Mods.RA.Graphics +{ + public interface IActorPreview + { + void Tick(); + IEnumerable Render(WorldRenderer wr, WPos pos); + } + + public class ActorPreviewInitializer + { + public readonly ActorInfo Actor; + public readonly Player Owner; + public readonly WorldRenderer WorldRenderer; + public World World { get { return WorldRenderer.world; } } + + readonly TypeDictionary dict; + + public ActorPreviewInitializer(ActorInfo actor, Player owner, WorldRenderer worldRenderer, TypeDictionary dict) + { + Actor = actor; + Owner = owner; + WorldRenderer = worldRenderer; + this.dict = dict; + } + + public T Get() where T : IActorInit { return dict.Get(); } + public U Get() where T : IActorInit { return dict.Get().Value(World); } + public bool Contains() where T : IActorInit { return dict.Contains(); } + } +} diff --git a/OpenRA.Mods.RA/Graphics/SpriteActorPreview.cs b/OpenRA.Mods.RA/Graphics/SpriteActorPreview.cs new file mode 100644 index 0000000000..a8066af1d3 --- /dev/null +++ b/OpenRA.Mods.RA/Graphics/SpriteActorPreview.cs @@ -0,0 +1,42 @@ +#region Copyright & License Information +/* + * Copyright 2007-2014 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Primitives; + +namespace OpenRA.Mods.RA.Graphics +{ + public class SpriteActorPreview : IActorPreview + { + readonly Animation animation; + readonly WVec offset; + readonly int zOffset; + readonly PaletteReference pr; + readonly float scale; + + public SpriteActorPreview(Animation animation, WVec offset, int zOffset, PaletteReference pr, float scale) + { + this.animation = animation; + this.offset = offset; + this.zOffset = zOffset; + this.pr = pr; + this.scale = scale; + } + + public void Tick() { animation.Tick(); } + + public IEnumerable Render(WorldRenderer wr, WPos pos) + { + return animation.Render(pos, offset, zOffset, pr, scale); + } + } +} diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index 3a0809d7d3..141d0a0564 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -545,6 +545,8 @@ + + diff --git a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs index 3d23129501..48aeae7a1c 100644 --- a/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.RA/Orders/PlaceBuildingOrderGenerator.cs @@ -13,8 +13,10 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Graphics; using OpenRA.Mods.RA.Render; using OpenRA.Traits; +using OpenRA.Primitives; namespace OpenRA.Mods.RA.Orders { @@ -23,8 +25,8 @@ namespace OpenRA.Mods.RA.Orders readonly Actor Producer; readonly string Building; readonly BuildingInfo BuildingInfo; + IActorPreview[] preview; - IEnumerable preview; Sprite buildOk, buildBlocked; bool initialized = false; @@ -79,7 +81,15 @@ namespace OpenRA.Mods.RA.Orders } } - public void Tick(World world) {} + public void Tick(World world) + { + if (preview == null) + return; + + foreach (var p in preview) + p.Tick(); + } + public IEnumerable Render(WorldRenderer wr, World world) { yield break; } public IEnumerable RenderAfterWorld(WorldRenderer wr, World world) { @@ -108,23 +118,22 @@ namespace OpenRA.Mods.RA.Orders { if (!initialized) { - var rbi = rules.Actors[Building].Traits.GetOrDefault(); - if (rbi == null) - preview = new IRenderable[0]; - else - { - var palette = rbi.Palette ?? (Producer.Owner != null ? - rbi.PlayerPalette + Producer.Owner.InternalName : null); - - preview = rbi.RenderPreview(world, rules.Actors[Building], wr.Palette(palette)); - } + var init = new ActorPreviewInitializer(rules.Actors[Building], Producer.Owner, wr, new TypeDictionary()); + preview = rules.Actors[Building].Traits.WithInterface() + .SelectMany(rpi => rpi.RenderPreview(init)) + .ToArray(); initialized = true; } - var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo) - WPos.Zero; - foreach (var r in preview) - yield return r.OffsetBy(offset); + var comparer = new RenderableComparer(wr); + var offset = world.Map.CenterOfCell(topLeft) + FootprintUtils.CenterOffset(world, BuildingInfo); + var previewRenderables = preview + .SelectMany(p => p.Render(wr, offset)) + .OrderBy(r => r, comparer); + + foreach (var r in previewRenderables) + yield return r; var res = world.WorldActor.Trait(); var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, Building, topLeft); diff --git a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs index 204426465d..5b9265bde4 100755 --- a/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs +++ b/OpenRA.Mods.RA/Render/RenderBuildingWarFactory.cs @@ -12,27 +12,27 @@ using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.RA.Buildings; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA.Render { class RenderBuildingWarFactoryInfo : RenderBuildingInfo { - public override object Create(ActorInitializer init) { return new RenderBuildingWarFactory( init, this ); } + public override object Create(ActorInitializer init) { return new RenderBuildingWarFactory(init, this); } - /* get around unverifiability */ - IEnumerable BaseBuildingPreview(World world, ActorInfo building, PaletteReference pr) + public override IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - return base.RenderPreview(world, building, pr); - } + foreach (var orig in base.RenderPreviewSprites(init, rs, image, facings, p)) + yield return orig; - public override IEnumerable RenderPreview(World world, ActorInfo building, PaletteReference pr) - { - var p = BaseBuildingPreview(world, building, pr); - var anim = new Animation(world, RenderSprites.GetImage(building), () => 0); + // Show additional roof overlay + var anim = new Animation(init.World, image, () => 0); anim.PlayRepeating("idle-top"); - return p.Concat(anim.Render(WPos.Zero, WVec.Zero, 0, pr, Scale)); + var bi = init.Actor.Traits.Get(); + var offset = FootprintUtils.CenterOffset(init.World, bi).Y + 512; + yield return new SpriteActorPreview(anim, WVec.Zero, offset, p, rs.Scale); } } diff --git a/OpenRA.Mods.RA/Render/RenderSimple.cs b/OpenRA.Mods.RA/Render/RenderSimple.cs index 080253dd93..567cedc97e 100644 --- a/OpenRA.Mods.RA/Render/RenderSimple.cs +++ b/OpenRA.Mods.RA/Render/RenderSimple.cs @@ -11,20 +11,23 @@ using System; using System.Collections.Generic; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA.Render { - public class RenderSimpleInfo : RenderSpritesInfo, IQuantizeBodyOrientationInfo, ILegacyEditorRenderInfo, Requires + public class RenderSimpleInfo : RenderSpritesInfo, IRenderActorPreviewSpritesInfo, IQuantizeBodyOrientationInfo, ILegacyEditorRenderInfo, Requires { public override object Create(ActorInitializer init) { return new RenderSimple(init.self); } - public virtual IEnumerable RenderPreview(World world, ActorInfo ai, PaletteReference pr) + public virtual IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p) { - var anim = new Animation(world, RenderSimple.GetImage(ai), () => 0); - anim.PlayRepeating("idle"); + var ifacing = init.Actor.Traits.GetOrDefault(); + var facing = ifacing != null ? init.Contains() ? init.Get() : ifacing.GetInitialFacing() : 0; - return anim.Render(WPos.Zero, WVec.Zero, 0, pr, Scale); + var anim = new Animation(init.World, image, () => facing); + anim.PlayRepeating("idle"); + yield return new SpriteActorPreview(anim, WVec.Zero, 0, p, rs.Scale); } public virtual int QuantizedBodyFacings(SequenceProvider sequenceProvider, ActorInfo ai) diff --git a/OpenRA.Mods.RA/Render/RenderSprites.cs b/OpenRA.Mods.RA/Render/RenderSprites.cs index 6815c66575..6f9eef80b2 100644 --- a/OpenRA.Mods.RA/Render/RenderSprites.cs +++ b/OpenRA.Mods.RA/Render/RenderSprites.cs @@ -12,12 +12,15 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; using OpenRA.Primitives; namespace OpenRA.Mods.RA.Render { - public class RenderSpritesInfo : ITraitInfo + public interface IRenderActorPreviewSpritesInfo { IEnumerable RenderPreviewSprites(ActorPreviewInitializer init, RenderSpritesInfo rs, string image, int facings, PaletteReference p); } + + public class RenderSpritesInfo : IRenderActorPreviewInfo, ITraitInfo { [Desc("Defaults to the actor name.")] public readonly string Image = null; @@ -30,6 +33,23 @@ namespace OpenRA.Mods.RA.Render public readonly float Scale = 1f; public virtual object Create(ActorInitializer init) { return new RenderSprites(init.self); } + + public IEnumerable RenderPreview(ActorPreviewInitializer init) + { + var sequenceProvider = init.World.Map.SequenceProvider; + var image = RenderSprites.GetImage(init.Actor); + var palette = init.WorldRenderer.Palette(Palette ?? (init.Owner != null ? PlayerPalette + init.Owner.InternalName : null)); + + var facings = 0; + var body = init.Actor.Traits.GetOrDefault(); + if (body != null) + facings = body.QuantizedFacings == -1 ? init.Actor.Traits.Get().QuantizedBodyFacings(sequenceProvider, init.Actor) : body.QuantizedFacings; + + foreach (var spi in init.Actor.Traits.WithInterface()) + foreach (var preview in spi.RenderPreviewSprites(init, this, image, facings, palette)) + yield return preview; + } + } public class RenderSprites : IRender, ITick, INotifyOwnerChanged, INotifyEffectiveOwnerChanged diff --git a/OpenRA.Mods.RA/TraitsInterfaces.cs b/OpenRA.Mods.RA/TraitsInterfaces.cs index 3ec75b1301..50deaa7f60 100755 --- a/OpenRA.Mods.RA/TraitsInterfaces.cs +++ b/OpenRA.Mods.RA/TraitsInterfaces.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using OpenRA.Mods.RA.Activities; +using OpenRA.Mods.RA.Graphics; using OpenRA.Traits; namespace OpenRA.Mods.RA @@ -50,4 +51,5 @@ namespace OpenRA.Mods.RA public interface INotifyTransform { void BeforeTransform(Actor self); void OnTransform(Actor self); void AfterTransform(Actor toActor); } public interface INotifyAttack { void Attacking(Actor self, Target target, Armament a, Barrel barrel); } public interface INotifyChat { bool OnChat(string from, string message); } + public interface IRenderActorPreviewInfo { IEnumerable RenderPreview(ActorPreviewInitializer init); } }