diff --git a/OpenRA.Mods.Common/Traits/World/BuildableTerrainOverlay.cs b/OpenRA.Mods.Common/Traits/World/BuildableTerrainOverlay.cs new file mode 100644 index 0000000000..6fcc10ea43 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/BuildableTerrainOverlay.cs @@ -0,0 +1,106 @@ +#region Copyright & License Information +/* + * Copyright 2007-2021 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.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [TraitLocation(SystemActors.EditorWorld)] + class BuildableTerrainOverlayInfo : TraitInfo + { + [FieldLoader.Require] + public readonly HashSet AllowedTerrainTypes = null; + + [PaletteReference] + [Desc("Palette to use for rendering the sprite.")] + public readonly string Palette = TileSet.TerrainPaletteInternalName; + + [Desc("Sprite definition.")] + public readonly string Image = "overlay"; + + [SequenceReference("Image")] + [Desc("Sequence to use for unbuildable area.")] + public readonly string Sequence = "build-invalid"; + + [Desc("Custom opacity to apply to the overlay sprite.")] + public readonly float Alpha = 1f; + + public override object Create(ActorInitializer init) + { + return new BuildableTerrainOverlay(init.Self, this); + } + } + + class BuildableTerrainOverlay : IRenderAboveWorld, IWorldLoaded, INotifyActorDisposing + { + readonly BuildableTerrainOverlayInfo info; + readonly World world; + readonly Sprite disabledSprite; + + public bool Enabled = false; + TerrainSpriteLayer render; + PaletteReference palette; + + bool disposed; + + public BuildableTerrainOverlay(Actor self, BuildableTerrainOverlayInfo info) + { + this.info = info; + world = self.World; + + var rules = self.World.Map.Rules; + disabledSprite = rules.Sequences.GetSequence(info.Image, info.Sequence).GetSprite(0); + } + + void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr) + { + render = new TerrainSpriteLayer(w, wr, disabledSprite, BlendMode.Alpha, wr.World.Type != WorldType.Editor); + + world.Map.Tiles.CellEntryChanged += UpdateTerrainCell; + world.Map.CustomTerrain.CellEntryChanged += UpdateTerrainCell; + + var cells = w.Map.AllCells.Where(c => w.Map.Contains(c) && + !info.AllowedTerrainTypes.Contains(w.Map.GetTerrainInfo(c).Type)).ToHashSet(); + + palette = wr.Palette(info.Palette); + + foreach (var cell in cells) + UpdateTerrainCell(cell); + } + + void UpdateTerrainCell(CPos cell) + { + if (!world.Map.Contains(cell)) + return; + + if (!info.AllowedTerrainTypes.Contains(world.Map.GetTerrainInfo(cell).Type)) + render.Update(cell, disabledSprite, palette, 1f, info.Alpha); + } + + void IRenderAboveWorld.RenderAboveWorld(Actor self, WorldRenderer wr) + { + if (Enabled) + render.Draw(wr.Viewport); + } + + void INotifyActorDisposing.Disposing(Actor self) + { + if (disposed) + return; + + render.Dispose(); + disposed = true; + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs index b8ce525ca5..8848df32a1 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapEditorLogic.cs @@ -35,6 +35,19 @@ namespace OpenRA.Mods.Common.Widgets.Logic gridButton.IsHighlighted = () => terrainGeometryTrait.Enabled; } + var lockButton = widget.GetOrNull("BUILDABLE_BUTTON"); + if (lockButton != null) + { + var buildableTerrainTrait = world.WorldActor.TraitOrDefault(); + if (buildableTerrainTrait != null) + { + lockButton.OnClick = () => buildableTerrainTrait.Enabled ^= true; + lockButton.IsHighlighted = () => buildableTerrainTrait.Enabled; + } + else + lockButton.Disabled = true; + } + var copypasteButton = widget.GetOrNull("COPYPASTE_BUTTON"); if (copypasteButton != null) { diff --git a/mods/cnc/chrome/editor.yaml b/mods/cnc/chrome/editor.yaml index a04b3bd126..b12fb30134 100644 --- a/mods/cnc/chrome/editor.yaml +++ b/mods/cnc/chrome/editor.yaml @@ -584,6 +584,17 @@ Container@EDITOR_WORLD_ROOT: Height: 25 Text: History Font: Bold + Button@BUILDABLE_BUTTON: + X: WINDOW_RIGHT - 1020 + Y: 5 + Width: 100 + Height: 25 + Text: Buildable + Font: Bold + Key: f2 + TooltipTemplate: BUTTON_TOOLTIP + TooltipText: Toggle unbuildable cells + TooltipContainer: TOOLTIP_CONTAINER Button@UNDO_BUTTON: X: WINDOW_RIGHT - 910 Y: 5 diff --git a/mods/cnc/rules/world.yaml b/mods/cnc/rules/world.yaml index 40b975b733..b9672b43c5 100644 --- a/mods/cnc/rules/world.yaml +++ b/mods/cnc/rules/world.yaml @@ -278,3 +278,5 @@ EditorWorld: EditorSelectionLayer: LoadWidgetAtGameStart: EditorActionManager: + BuildableTerrainOverlay: + AllowedTerrainTypes: Clear, Road diff --git a/mods/common/chrome/editor.yaml b/mods/common/chrome/editor.yaml index 2f90423a79..516094b452 100644 --- a/mods/common/chrome/editor.yaml +++ b/mods/common/chrome/editor.yaml @@ -610,6 +610,16 @@ Container@EDITOR_WORLD_ROOT: TooltipTemplate: BUTTON_TOOLTIP TooltipText: Redo last step TooltipContainer: TOOLTIP_CONTAINER + Button@BUILDABLE_BUTTON: + X: 700 + Width: 90 + Height: 25 + Text: Buildable + Font: Bold + Key: f2 + TooltipTemplate: BUTTON_TOOLTIP + TooltipText: Toggle unbuildable cells + TooltipContainer: TOOLTIP_CONTAINER Label@COORDINATE_LABEL: X: 835 Width: 50 diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index 150d1142d7..e7a942786b 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -255,3 +255,5 @@ EditorWorld: EditorSelectionLayer: LoadWidgetAtGameStart: EditorActionManager: + BuildableTerrainOverlay: + AllowedTerrainTypes: Rock, Concrete diff --git a/mods/ra/rules/world.yaml b/mods/ra/rules/world.yaml index 4adef5c032..ec2d152013 100644 --- a/mods/ra/rules/world.yaml +++ b/mods/ra/rules/world.yaml @@ -305,3 +305,5 @@ EditorWorld: EditorSelectionLayer: LoadWidgetAtGameStart: EditorActionManager: + BuildableTerrainOverlay: + AllowedTerrainTypes: Clear, Road diff --git a/mods/ts/rules/world.yaml b/mods/ts/rules/world.yaml index e2abbca63a..92ee41a26e 100644 --- a/mods/ts/rules/world.yaml +++ b/mods/ts/rules/world.yaml @@ -412,3 +412,7 @@ EditorWorld: FootprintAlpha: 0.7 LoadWidgetAtGameStart: EditorActionManager: + BuildableTerrainOverlay: + AllowedTerrainTypes: Clear, Rough, Road, DirtRoad, Green, Sand, Pavement + Palette: ra + Alpha: 0.35