From 52fd32c311da2fc9d2dc2645d8e93e76192a2733 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 18 May 2019 09:00:12 +0000 Subject: [PATCH] Split IPlaceBuildingPreviewGeneratorInfo from PBOG. --- .../Orders/PlaceBuildingOrderGenerator.cs | 158 ++++++++---------- .../ActorPreviewPlaceBuildingPreview.cs | 109 ++++++++++++ .../FootprintPlaceBuildingPreview.cs | 120 +++++++++++++ .../Buildings/SequencePlaceBuildingPreview.cs | 101 +++++++++++ .../Traits/Player/PlaceBuilding.cs | 8 - .../20190314/RemovePlaceBuildingPalettes.cs | 40 +++++ OpenRA.Mods.Common/UpdateRules/UpdatePath.cs | 1 + mods/cnc/rules/defaults.yaml | 2 + mods/d2k/rules/defaults.yaml | 1 + mods/d2k/rules/structures.yaml | 2 + mods/ra/rules/defaults.yaml | 2 + mods/ts/rules/defaults.yaml | 9 + mods/ts/rules/player.yaml | 2 - 13 files changed, 454 insertions(+), 101 deletions(-) create mode 100644 OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs create mode 100644 OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs create mode 100644 OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs create mode 100644 OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index 8ff57e379e..d68bde42ff 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -20,64 +20,76 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Orders { + [Flags] + public enum PlaceBuildingCellType { None = 0, Valid = 1, Invalid = 2, LineBuild = 4 } + + [RequireExplicitImplementation] + public interface IPlaceBuildingPreviewGeneratorInfo : ITraitInfoInterface + { + IPlaceBuildingPreview CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init); + } + + public interface IPlaceBuildingPreview + { + int2 TopLeftScreenOffset { get; } + void Tick(); + IEnumerable Render(WorldRenderer wr, CPos topLeft, Dictionary footprint); + } + public class PlaceBuildingOrderGenerator : OrderGenerator { - [Flags] - enum CellType { Valid = 0, Invalid = 1, LineBuild = 2 } - readonly ProductionQueue queue; - readonly ActorInfo actorInfo; - readonly BuildingInfo buildingInfo; readonly PlaceBuildingInfo placeBuildingInfo; readonly BuildingInfluence buildingInfluence; - readonly string faction; - readonly Sprite buildOk; - readonly Sprite buildBlocked; readonly Viewport viewport; - readonly WVec centerOffset; - readonly int2 topLeftScreenOffset; - IActorPreview[] preview; - - bool initialized; + readonly ActorInfo actorInfo; + readonly BuildingInfo buildingInfo; + readonly IPlaceBuildingPreview preview; public PlaceBuildingOrderGenerator(ProductionQueue queue, string name, WorldRenderer worldRenderer) { var world = queue.Actor.World; this.queue = queue; - viewport = worldRenderer.Viewport; placeBuildingInfo = queue.Actor.Owner.PlayerActor.Info.TraitInfo(); + buildingInfluence = world.WorldActor.Trait(); + viewport = worldRenderer.Viewport; // Clear selection if using Left-Click Orders if (Game.Settings.Game.UseClassicMouseStyle) world.Selection.Clear(); - var map = world.Map; - var tileset = world.Map.Tileset.ToLowerInvariant(); - - actorInfo = map.Rules.Actors[name]; + actorInfo = world.Map.Rules.Actors[name]; buildingInfo = actorInfo.TraitInfo(); - centerOffset = buildingInfo.CenterOffset(world); - topLeftScreenOffset = -worldRenderer.ScreenPxOffset(centerOffset); - var buildableInfo = actorInfo.TraitInfo(); - var mostLikelyProducer = queue.MostLikelyProducer(); - faction = buildableInfo.ForceFaction - ?? (mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName); + var previewGeneratorInfo = actorInfo.TraitInfoOrDefault(); + if (previewGeneratorInfo != null) + { + var faction = actorInfo.TraitInfo().ForceFaction; + if (faction == null) + { + var mostLikelyProducer = queue.MostLikelyProducer(); + faction = mostLikelyProducer.Trait != null ? mostLikelyProducer.Trait.Faction : queue.Actor.Owner.Faction.InternalName; + } - if (map.Rules.Sequences.HasSequence("overlay", "build-valid-{0}".F(tileset))) - buildOk = map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); - else - buildOk = map.Rules.Sequences.GetSequence("overlay", "build-valid").GetSprite(0); - buildBlocked = map.Rules.Sequences.GetSequence("overlay", "build-invalid").GetSprite(0); + var td = new TypeDictionary() + { + new FactionInit(faction), + new OwnerInit(queue.Actor.Owner), + }; - buildingInfluence = world.WorldActor.Trait(); + foreach (var api in actorInfo.TraitInfos()) + foreach (var o in api.ActorPreviewInits(actorInfo, ActorPreviewType.PlaceBuilding)) + td.Add(o); + + preview = previewGeneratorInfo.CreatePreview(worldRenderer, actorInfo, td); + } } - CellType MakeCellType(bool valid, bool lineBuild = false) + PlaceBuildingCellType MakeCellType(bool valid, bool lineBuild = false) { - var cell = valid ? CellType.Valid : CellType.Invalid; + var cell = valid ? PlaceBuildingCellType.Valid : PlaceBuildingCellType.Invalid; if (lineBuild) - cell |= CellType.LineBuild; + cell |= PlaceBuildingCellType.LineBuild; return cell; } @@ -98,6 +110,18 @@ namespace OpenRA.Mods.Common.Orders return ret; } + CPos TopLeft + { + get + { + var offsetPos = Viewport.LastMousePos; + if (preview != null) + offsetPos += preview.TopLeftScreenOffset; + + return viewport.ViewToWorld(offsetPos); + } + } + IEnumerable InnerOrder(World world, CPos cell, MouseInput mi) { if (world.Paused) @@ -107,7 +131,7 @@ namespace OpenRA.Mods.Common.Orders if (mi.Button == MouseButton.Left) { var orderType = "PlaceBuilding"; - var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset); + var topLeft = TopLeft; var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo != null) @@ -152,11 +176,8 @@ namespace OpenRA.Mods.Common.Orders if (queue.AllQueued().All(i => !i.Done || i.Item != actorInfo.Name)) world.CancelInputMode(); - if (preview == null) - return; - - foreach (var p in preview) - p.Tick(); + if (preview != null) + preview.Tick(); } bool AcceptsPlug(CPos cell, PlugInfo plug) @@ -172,23 +193,15 @@ namespace OpenRA.Mods.Common.Orders protected override IEnumerable Render(WorldRenderer wr, World world) { yield break; } protected override IEnumerable RenderAboveShroud(WorldRenderer wr, World world) { - var topLeft = viewport.ViewToWorld(Viewport.LastMousePos + topLeftScreenOffset); - var centerPosition = world.Map.CenterOfCell(topLeft) + centerOffset; - var rules = world.Map.Rules; - - foreach (var dec in actorInfo.TraitInfos()) - foreach (var r in dec.Render(wr, world, actorInfo, centerPosition)) - yield return r; - - var cells = new Dictionary(); - + var topLeft = TopLeft; + var footprint = new Dictionary(); var plugInfo = actorInfo.TraitInfoOrDefault(); if (plugInfo != null) { if (buildingInfo.Dimensions.X != 1 || buildingInfo.Dimensions.Y != 1) throw new InvalidOperationException("Plug requires a 1x1 sized Building"); - cells.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); + footprint.Add(topLeft, MakeCellType(AcceptsPlug(topLeft, plugInfo))); } else if (actorInfo.HasTraitInfo()) { @@ -198,56 +211,19 @@ namespace OpenRA.Mods.Common.Orders if (!Game.GetModifierKeys().HasModifier(Modifiers.Shift)) foreach (var t in BuildingUtils.GetLineBuildCells(world, topLeft, actorInfo, buildingInfo)) - cells.Add(t.First, MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.First), true)); + footprint.Add(t.First, MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, t.First), true)); - cells[topLeft] = MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft)); + footprint[topLeft] = MakeCellType(buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft)); } else { - if (!initialized) - { - var td = new TypeDictionary() - { - new FactionInit(faction), - new OwnerInit(queue.Actor.Owner), - }; - - foreach (var api in actorInfo.TraitInfos()) - foreach (var o in api.ActorPreviewInits(actorInfo, ActorPreviewType.PlaceBuilding)) - td.Add(o); - - var init = new ActorPreviewInitializer(actorInfo, wr, td); - preview = actorInfo.TraitInfos() - .SelectMany(rpi => rpi.RenderPreview(init)) - .ToArray(); - - initialized = true; - } - - var previewRenderables = preview - .SelectMany(p => p.Render(wr, centerPosition)) - .OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey); - - foreach (var r in previewRenderables) - yield return r; - var res = world.WorldActor.TraitOrDefault(); var isCloseEnough = buildingInfo.IsCloseEnoughToBase(world, world.LocalPlayer, actorInfo, topLeft); foreach (var t in buildingInfo.Tiles(topLeft)) - cells.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, actorInfo, buildingInfo) && (res == null || res.GetResource(t) == null))); + footprint.Add(t, MakeCellType(isCloseEnough && world.IsCellBuildable(t, actorInfo, buildingInfo) && (res == null || res.GetResource(t) == null))); } - var cellPalette = wr.Palette(placeBuildingInfo.Palette); - var linePalette = wr.Palette(placeBuildingInfo.LineBuildSegmentPalette); - var topLeftPos = world.Map.CenterOfCell(topLeft); - foreach (var c in cells) - { - var tile = !c.Value.HasFlag(CellType.Invalid) ? buildOk : buildBlocked; - var pal = c.Value.HasFlag(CellType.LineBuild) ? linePalette : cellPalette; - var pos = world.Map.CenterOfCell(c.Key); - yield return new SpriteRenderable(tile, pos, new WVec(0, 0, topLeftPos.Z - pos.Z), - -511, pal, 1f, true); - } + return preview != null ? preview.Render(wr, topLeft, footprint) : Enumerable.Empty(); } protected override string GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi) { return "default"; } diff --git a/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs b/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs new file mode 100644 index 0000000000..21d4952aed --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Buildings/ActorPreviewPlaceBuildingPreview.cs @@ -0,0 +1,109 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Mods.Common.Orders; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Creates a building placement preview based on the map editor actor preview.")] + public class ActorPreviewPlaceBuildingPreviewInfo : FootprintPlaceBuildingPreviewInfo + { + [Desc("Enable the building's idle animation.")] + public readonly bool Animated = true; + + [PaletteReference("OverridePaletteIsPlayerPalette")] + [Desc("Custom palette name.")] + public readonly string OverridePalette = null; + + [Desc("Custom palette is a player palette BaseName.")] + public readonly bool OverridePaletteIsPlayerPalette = true; + + [Desc("Footprint types to draw underneath the actor preview.")] + public readonly PlaceBuildingCellType FootprintUnderPreview = PlaceBuildingCellType.None; + + [Desc("Footprint types to draw above the actor preview.")] + public readonly PlaceBuildingCellType FootprintOverPreview = PlaceBuildingCellType.Valid | PlaceBuildingCellType.LineBuild | PlaceBuildingCellType.Invalid; + + protected override IPlaceBuildingPreview CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init) + { + return new ActorPreviewPlaceBuildingPreviewPreview(wr, ai, this, init); + } + + public override object Create(ActorInitializer init) + { + return new ActorPreviewPlaceBuildingPreview(); + } + } + + public class ActorPreviewPlaceBuildingPreview { } + + class ActorPreviewPlaceBuildingPreviewPreview : FootprintPlaceBuildingPreviewPreview + { + readonly ActorPreviewPlaceBuildingPreviewInfo info; + readonly PaletteReference palette; + readonly IActorPreview[] preview; + + public ActorPreviewPlaceBuildingPreviewPreview(WorldRenderer wr, ActorInfo ai, ActorPreviewPlaceBuildingPreviewInfo info, TypeDictionary init) + : base(wr, ai, info, init) + { + this.info = info; + var previewInit = new ActorPreviewInitializer(actorInfo, wr, init); + preview = actorInfo.TraitInfos() + .SelectMany(rpi => rpi.RenderPreview(previewInit)) + .ToArray(); + + if (!string.IsNullOrEmpty(info.OverridePalette)) + { + var owner = init.Get().Value(wr.World); + palette = wr.Palette(info.OverridePaletteIsPlayerPalette ? info.OverridePalette + owner.InternalName : info.OverridePalette); + } + } + + protected override void TickInner() + { + if (!info.Animated) + return; + + foreach (var p in preview) + p.Tick(); + } + + protected override IEnumerable RenderInner(WorldRenderer wr, CPos topLeft, Dictionary footprint) + { + var centerPosition = wr.World.Map.CenterOfCell(topLeft) + centerOffset; + var previewRenderables = preview + .SelectMany(p => p.Render(wr, centerPosition)); + + if (palette != null) + previewRenderables = previewRenderables.Select(a => a.IsDecoration ? a : a.WithPalette(palette)); + + foreach (var r in RenderDecorations(wr, topLeft)) + yield return r; + + if (info.FootprintUnderPreview != PlaceBuildingCellType.None) + foreach (var r in RenderFootprint(wr, topLeft, footprint, info.FootprintUnderPreview)) + yield return r; + + foreach (var r in previewRenderables.OrderBy(WorldRenderer.RenderableScreenZPositionComparisonKey)) + yield return r; + + if (info.FootprintOverPreview != PlaceBuildingCellType.None) + foreach (var r in RenderFootprint(wr, topLeft, footprint, info.FootprintOverPreview)) + yield return r; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs b/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs new file mode 100644 index 0000000000..c569b2354e --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Buildings/FootprintPlaceBuildingPreview.cs @@ -0,0 +1,120 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Orders; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Creates a building placement preview showing only the building footprint.")] + public class FootprintPlaceBuildingPreviewInfo : TraitInfo, IPlaceBuildingPreviewGeneratorInfo + { + [PaletteReference] + [Desc("Palette to use for rendering the placement sprite.")] + public readonly string Palette = TileSet.TerrainPaletteInternalName; + + [PaletteReference] + [Desc("Palette to use for rendering the placement sprite for line build segments.")] + public readonly string LineBuildSegmentPalette = TileSet.TerrainPaletteInternalName; + + protected virtual IPlaceBuildingPreview CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init) + { + return new FootprintPlaceBuildingPreviewPreview(wr, ai, this, init); + } + + IPlaceBuildingPreview IPlaceBuildingPreviewGeneratorInfo.CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init) + { + return CreatePreview(wr, ai, init); + } + } + + public class FootprintPlaceBuildingPreview { } + + class FootprintPlaceBuildingPreviewPreview : IPlaceBuildingPreview + { + protected readonly ActorInfo actorInfo; + protected readonly WVec centerOffset; + readonly FootprintPlaceBuildingPreviewInfo info; + readonly IPlaceBuildingDecorationInfo[] decorations; + readonly int2 topLeftScreenOffset; + readonly Sprite buildOk; + readonly Sprite buildBlocked; + + public FootprintPlaceBuildingPreviewPreview(WorldRenderer wr, ActorInfo ai, FootprintPlaceBuildingPreviewInfo info, TypeDictionary init) + { + actorInfo = ai; + this.info = info; + decorations = actorInfo.TraitInfos().ToArray(); + + var world = wr.World; + centerOffset = actorInfo.TraitInfo().CenterOffset(world); + topLeftScreenOffset = -wr.ScreenPxOffset(centerOffset); + + var tileset = world.Map.Tileset.ToLowerInvariant(); + if (world.Map.Rules.Sequences.HasSequence("overlay", "build-valid-{0}".F(tileset))) + buildOk = world.Map.Rules.Sequences.GetSequence("overlay", "build-valid-{0}".F(tileset)).GetSprite(0); + else + buildOk = world.Map.Rules.Sequences.GetSequence("overlay", "build-valid").GetSprite(0); + buildBlocked = world.Map.Rules.Sequences.GetSequence("overlay", "build-invalid").GetSprite(0); + } + + protected virtual void TickInner() { } + + protected IEnumerable RenderFootprint(WorldRenderer wr, CPos topLeft, Dictionary footprint, + PlaceBuildingCellType filter = PlaceBuildingCellType.Invalid | PlaceBuildingCellType.Valid | PlaceBuildingCellType.LineBuild) + { + var cellPalette = wr.Palette(info.Palette); + var linePalette = wr.Palette(info.LineBuildSegmentPalette); + var topLeftPos = wr.World.Map.CenterOfCell(topLeft); + foreach (var c in footprint) + { + if ((c.Value & filter) == 0) + continue; + + var tile = !c.Value.HasFlag(PlaceBuildingCellType.Invalid) ? buildOk : buildBlocked; + var pal = c.Value.HasFlag(PlaceBuildingCellType.LineBuild) ? linePalette : cellPalette; + var pos = wr.World.Map.CenterOfCell(c.Key); + var offset = new WVec(0, 0, topLeftPos.Z - pos.Z); + yield return new SpriteRenderable(tile, pos, offset, -511, pal, 1f, true); + } + } + + protected IEnumerable RenderDecorations(WorldRenderer wr, CPos topLeft) + { + var centerPosition = wr.World.Map.CenterOfCell(topLeft) + centerOffset; + foreach (var d in decorations) + foreach (var r in d.Render(wr, wr.World, actorInfo, centerPosition)) + yield return r; + } + + protected virtual IEnumerable RenderInner(WorldRenderer wr, CPos topLeft, Dictionary footprint) + { + foreach (var r in RenderDecorations(wr, topLeft)) + yield return r; + + foreach (var r in RenderFootprint(wr, topLeft, footprint)) + yield return r; + } + + IEnumerable IPlaceBuildingPreview.Render(WorldRenderer wr, CPos topLeft, Dictionary footprint) + { + return RenderInner(wr, topLeft, footprint); + } + + void IPlaceBuildingPreview.Tick() { TickInner(); } + + int2 IPlaceBuildingPreview.TopLeftScreenOffset { get { return topLeftScreenOffset; } } + } +} diff --git a/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs b/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs new file mode 100644 index 0000000000..83c48b0182 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Buildings/SequencePlaceBuildingPreview.cs @@ -0,0 +1,101 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Orders; +using OpenRA.Mods.Common.Traits.Render; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Creates a building placement preview based on a defined sequence.")] + public class SequencePlaceBuildingPreviewInfo : FootprintPlaceBuildingPreviewInfo, Requires + { + [SequenceReference] + [Desc("Sequence name to use.")] + public readonly string Sequence = "idle"; + + [PaletteReference("SequencePaletteIsPlayerPalette")] + [Desc("Custom palette name.")] + public readonly string SequencePalette = null; + + [Desc("Custom palette is a player palette BaseName.")] + public readonly bool SequencePaletteIsPlayerPalette = true; + + [Desc("Footprint types to draw underneath the actor preview.")] + public readonly PlaceBuildingCellType FootprintUnderPreview = PlaceBuildingCellType.None; + + [Desc("Footprint types to draw above the actor preview.")] + public readonly PlaceBuildingCellType FootprintOverPreview = PlaceBuildingCellType.Valid | PlaceBuildingCellType.LineBuild | PlaceBuildingCellType.Invalid; + + protected override IPlaceBuildingPreview CreatePreview(WorldRenderer wr, ActorInfo ai, TypeDictionary init) + { + return new SequencePlaceBuildingPreviewPreview(wr, ai, this, init); + } + + public override object Create(ActorInitializer init) + { + return new SequencePlaceBuildingPreview(); + } + } + + public class SequencePlaceBuildingPreview { } + + class SequencePlaceBuildingPreviewPreview : FootprintPlaceBuildingPreviewPreview + { + readonly SequencePlaceBuildingPreviewInfo info; + readonly Animation preview; + readonly PaletteReference palette; + + public SequencePlaceBuildingPreviewPreview(WorldRenderer wr, ActorInfo ai, SequencePlaceBuildingPreviewInfo info, TypeDictionary init) + : base(wr, ai, info, init) + { + this.info = info; + var owner = init.Get().Value(wr.World); + var faction = init.Get().Value(wr.World); + + var rsi = ai.TraitInfo(); + + if (!string.IsNullOrEmpty(info.SequencePalette)) + palette = wr.Palette(info.SequencePaletteIsPlayerPalette ? info.SequencePalette + owner.InternalName : info.SequencePalette); + else + palette = wr.Palette(rsi.Palette ?? rsi.PlayerPalette + owner.InternalName); + + preview = new Animation(wr.World, rsi.GetImage(ai, wr.World.Map.Rules.Sequences, faction)); + preview.PlayRepeating(info.Sequence); + } + + protected override void TickInner() + { + preview.Tick(); + } + + protected override IEnumerable RenderInner(WorldRenderer wr, CPos topLeft, Dictionary footprint) + { + foreach (var r in RenderDecorations(wr, topLeft)) + yield return r; + + if (info.FootprintUnderPreview != PlaceBuildingCellType.None) + foreach (var r in RenderFootprint(wr, topLeft, footprint, info.FootprintUnderPreview)) + yield return r; + + var centerPosition = wr.World.Map.CenterOfCell(topLeft) + centerOffset; + foreach (var r in preview.Render(centerPosition, WVec.Zero, 0, palette, 1.0f)) + yield return r; + + if (info.FootprintOverPreview != PlaceBuildingCellType.None) + foreach (var r in RenderFootprint(wr, topLeft, footprint, info.FootprintOverPreview)) + yield return r; + } + } +} diff --git a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs index d011ff2685..f59aeac706 100644 --- a/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs +++ b/OpenRA.Mods.Common/Traits/Player/PlaceBuilding.cs @@ -21,14 +21,6 @@ namespace OpenRA.Mods.Common.Traits [Desc("Allows the player to execute build orders.", " Attach this to the player actor.")] public class PlaceBuildingInfo : ITraitInfo { - [PaletteReference] - [Desc("Palette to use for rendering the placement sprite.")] - public readonly string Palette = TileSet.TerrainPaletteInternalName; - - [PaletteReference] - [Desc("Palette to use for rendering the placement sprite for line build segments.")] - public readonly string LineBuildSegmentPalette = TileSet.TerrainPaletteInternalName; - [Desc("Play NewOptionsNotification this many ticks after building placement.")] public readonly int NewOptionsNotificationDelay = 10; diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs new file mode 100644 index 0000000000..ca2b71c91e --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20190314/RemovePlaceBuildingPalettes.cs @@ -0,0 +1,40 @@ +#region Copyright & License Information +/* + * Copyright 2007-2019 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class RemovePlaceBuildingPalettes : UpdateRule + { + public override string Name { get { return "Remove Palette and LineBuildSegmentPalette from PlaceBuilding"; } } + public override string Description + { + get + { + return "The Palette and LineBuildSegmentPalette fields have been moved from PlaceBuilding,\n" + + "to the *PlaceBuildingPreview traits."; + } + } + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + // Repairable isn't conditional or otherwise supports multiple traits, so LastChildMatching should be fine. + foreach (var placeBuilding in actorNode.ChildrenMatching("PlaceBuilding")) + { + placeBuilding.RemoveNodes("Palette"); + placeBuilding.RemoveNodes("LineBuildSegmentPalette"); + } + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index 64e892dbf0..d503788d0e 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -126,6 +126,7 @@ namespace OpenRA.Mods.Common.UpdateRules new RefactorHarvesterIdle(), new SplitHarvesterSpriteBody(), new RenameAttackMoveConditions(), + new RemovePlaceBuildingPalettes(), }) }; diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 3961262a67..86b5f4d079 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -699,6 +699,7 @@ Building: Dimensions: 1,1 Footprint: x + ActorPreviewPlaceBuildingPreview: SoundOnDamageTransition: DamagedSounds: xplos.aud DestroyedSounds: crumble.aud @@ -870,6 +871,7 @@ Footprint: x BuildSounds: hvydoor1.aud TerrainTypes: Clear,Road + FootprintPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building Adjacent: 4 diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 322f1befda..9225f11567 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -385,6 +385,7 @@ Footprint: x TerrainTypes: Rock, Concrete BuildSounds: BUILD1.WAV + ActorPreviewPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building Adjacent: 3 diff --git a/mods/d2k/rules/structures.yaml b/mods/d2k/rules/structures.yaml index f972be8894..5d44752b66 100644 --- a/mods/d2k/rules/structures.yaml +++ b/mods/d2k/rules/structures.yaml @@ -5,6 +5,7 @@ TerrainTypes: Rock BuildSounds: CHUNG.WAV AllowInvalidPlacement: true + FootprintPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building Adjacent: 4 @@ -732,6 +733,7 @@ wall: Building: BuildSounds: CHUNG.WAV TerrainTypes: Rock, Concrete + FootprintPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building Adjacent: 7 diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index 6265500810..8401f9d85c 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -646,6 +646,7 @@ RequiresBaseProvider: True BuildSounds: placbldg.aud, build5.aud UndeploySounds: cashturn.aud + ActorPreviewPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building SoundOnDamageTransition: @@ -749,6 +750,7 @@ BuildSounds: placbldg.aud TerrainTypes: Clear,Road UndeploySounds: cashturn.aud + FootprintPlaceBuildingPreview: RequiresBuildableArea: AreaTypes: building Adjacent: 7 diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 3950378180..01e5d27afd 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -317,6 +317,9 @@ BuildSounds: place2.aud TerrainTypes: Clear, Rough, Road, DirtRoad, Green, Sand, Pavement UndeploySounds: cashturn.aud + ActorPreviewPlaceBuildingPreview: + Palette: placebuilding + LineBuildSegmentPalette: placelinesegment RequiresBuildableArea: AreaTypes: building Adjacent: 4 @@ -466,6 +469,9 @@ BuildSounds: place2.aud TerrainTypes: Clear, Rough, Road, DirtRoad, Green, Sand, Pavement UndeploySounds: cashturn.aud + FootprintPlaceBuildingPreview: + Palette: placebuilding + LineBuildSegmentPalette: placelinesegment RequiresBuildableArea: AreaTypes: building Adjacent: 7 @@ -513,6 +519,9 @@ Building: BuildSounds: place2.aud UndeploySounds: cashturn.aud + FootprintPlaceBuildingPreview: + Palette: placebuilding + LineBuildSegmentPalette: placelinesegment KillsSelf: RemoveInstead: true RenderSprites: diff --git a/mods/ts/rules/player.yaml b/mods/ts/rules/player.yaml index a4ed9f66d4..3975ca18b4 100644 --- a/mods/ts/rules/player.yaml +++ b/mods/ts/rules/player.yaml @@ -67,8 +67,6 @@ Player: PlaceBuilding: NewOptionsNotification: NewOptions CannotPlaceNotification: BuildingCannotPlaceAudio - Palette: placebuilding - LineBuildSegmentPalette: placelinesegment SupportPowerManager: ScriptTriggers: MissionObjectives: