Added Undo Redo to editor
This commit is contained in:
@@ -24,6 +24,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly WorldRenderer worldRenderer;
|
||||
readonly World world;
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly ActorPreviewWidget preview;
|
||||
readonly WVec centerOffset;
|
||||
@@ -38,6 +39,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
worldRenderer = wr;
|
||||
world = wr.World;
|
||||
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
|
||||
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
|
||||
|
||||
Actor = actor;
|
||||
this.owner = owner;
|
||||
@@ -101,33 +103,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
return true;
|
||||
|
||||
// Enforce first entry of ValidOwnerNames as owner if the actor has RequiresSpecificOwners
|
||||
var ownerName = owner.Name;
|
||||
var specificOwnerInfo = Actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
|
||||
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
|
||||
ownerName = specificOwnerInfo.ValidOwnerNames.First();
|
||||
|
||||
var newActorReference = new ActorReference(Actor.Name);
|
||||
newActorReference.Add(new OwnerInit(ownerName));
|
||||
|
||||
newActorReference.Add(new LocationInit(cell));
|
||||
|
||||
var ios = Actor.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
if (ios != null && ios.SharesCell)
|
||||
{
|
||||
var subcell = editorLayer.FreeSubCellAt(cell);
|
||||
if (subcell != SubCell.Invalid)
|
||||
newActorReference.Add(new SubCellInit(subcell));
|
||||
}
|
||||
|
||||
var initDict = newActorReference.InitDict;
|
||||
|
||||
if (Actor.HasTraitInfo<IFacingInfo>())
|
||||
initDict.Add(new FacingInit(facing));
|
||||
|
||||
if (Actor.HasTraitInfo<TurretedInfo>())
|
||||
initDict.Add(new TurretFacingInit(facing));
|
||||
|
||||
editorLayer.Add(newActorReference);
|
||||
var action = new AddActorAction(editorLayer, Actor, cell, owner, facing);
|
||||
editorActionManager.Add(action);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -151,4 +128,69 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
class AddActorAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly ActorInfo actor;
|
||||
readonly CPos cell;
|
||||
readonly PlayerReference owner;
|
||||
readonly int facing;
|
||||
|
||||
EditorActorPreview editorActorPreview;
|
||||
|
||||
public AddActorAction(EditorActorLayer editorLayer, ActorInfo actor, CPos cell, PlayerReference owner, int facing)
|
||||
{
|
||||
this.editorLayer = editorLayer;
|
||||
this.actor = actor;
|
||||
this.cell = cell;
|
||||
this.owner = owner;
|
||||
this.facing = facing;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Do();
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
var ownerName = owner.Name;
|
||||
var specificOwnerInfo = actor.TraitInfoOrDefault<RequiresSpecificOwnersInfo>();
|
||||
if (specificOwnerInfo != null && !specificOwnerInfo.ValidOwnerNames.Contains(ownerName))
|
||||
ownerName = specificOwnerInfo.ValidOwnerNames.First();
|
||||
|
||||
var newActorReference = new ActorReference(actor.Name);
|
||||
newActorReference.Add(new OwnerInit(ownerName));
|
||||
|
||||
newActorReference.Add(new LocationInit(cell));
|
||||
|
||||
var ios = actor.TraitInfoOrDefault<IOccupySpaceInfo>();
|
||||
if (ios != null && ios.SharesCell)
|
||||
{
|
||||
var subcell = editorLayer.FreeSubCellAt(cell);
|
||||
if (subcell != SubCell.Invalid)
|
||||
newActorReference.Add(new SubCellInit(subcell));
|
||||
}
|
||||
|
||||
var initDict = newActorReference.InitDict;
|
||||
|
||||
if (actor.HasTraitInfo<IFacingInfo>())
|
||||
initDict.Add(new FacingInit(facing));
|
||||
|
||||
if (actor.HasTraitInfo<TurretedInfo>())
|
||||
initDict.Add(new TurretFacingInit(facing));
|
||||
|
||||
editorActorPreview = editorLayer.Add(newActorReference);
|
||||
|
||||
Text = "Added {0} ({1})".F(editorActorPreview.Info.Name, editorActorPreview.ID);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
editorLayer.Remove(editorActorPreview);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly EditorSelectionLayer selectionLayer;
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly Func<MapCopyFilters> getCopyFilters;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
|
||||
State state;
|
||||
CPos start;
|
||||
@@ -46,6 +47,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
this.editorWidget = editorWidget;
|
||||
worldRenderer = wr;
|
||||
|
||||
editorActionManager = wr.World.WorldActor.Trait<EditorActionManager>();
|
||||
|
||||
selectionLayer = wr.World.WorldActor.Trait<EditorSelectionLayer>();
|
||||
editorLayer = wr.World.WorldActor.Trait<EditorActorLayer>();
|
||||
this.getCopyFilters = getCopyFilters;
|
||||
@@ -143,26 +146,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
|
||||
mapTiles[kv.Key] = kv.Value.Item1;
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Resources))
|
||||
mapResources[kv.Key] = kv.Value.Item2;
|
||||
|
||||
mapHeight[kv.Key] = kv.Value.Item3;
|
||||
}
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
||||
{
|
||||
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
|
||||
foreach (var preview in removeActors)
|
||||
editorLayer.Remove(preview);
|
||||
}
|
||||
|
||||
foreach (var kv in previews)
|
||||
editorLayer.Add(kv.Value);
|
||||
var action = new CopyPasteEditorAction(copyFilters, worldRenderer.World.Map, tiles, previews, editorLayer, dest);
|
||||
editorActionManager.Add(action);
|
||||
}
|
||||
|
||||
public void Tick()
|
||||
@@ -187,4 +172,114 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
selectionLayer.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
class CopyPasteEditorAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly MapCopyFilters copyFilters;
|
||||
readonly Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles;
|
||||
readonly Dictionary<string, ActorReference> previews;
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly CellRegion dest;
|
||||
readonly CellLayer<TerrainTile> mapTiles;
|
||||
readonly CellLayer<byte> mapHeight;
|
||||
readonly CellLayer<ResourceTile> mapResources;
|
||||
|
||||
readonly Queue<UndoCopyPaste> undoCopyPastes = new Queue<UndoCopyPaste>();
|
||||
readonly Queue<EditorActorPreview> removedActors = new Queue<EditorActorPreview>();
|
||||
readonly Queue<EditorActorPreview> addedActorPreviews = new Queue<EditorActorPreview>();
|
||||
|
||||
public CopyPasteEditorAction(MapCopyFilters copyFilters, Map map,
|
||||
Dictionary<CPos, Tuple<TerrainTile, ResourceTile, byte>> tiles, Dictionary<string, ActorReference> previews,
|
||||
EditorActorLayer editorLayer, CellRegion dest)
|
||||
{
|
||||
this.copyFilters = copyFilters;
|
||||
this.tiles = tiles;
|
||||
this.previews = previews;
|
||||
this.editorLayer = editorLayer;
|
||||
this.dest = dest;
|
||||
|
||||
mapTiles = map.Tiles;
|
||||
mapHeight = map.Height;
|
||||
mapResources = map.Resources;
|
||||
|
||||
Text = "Copied {0} tiles".F(tiles.Count);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Do();
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
foreach (var kv in tiles)
|
||||
{
|
||||
undoCopyPastes.Enqueue(new UndoCopyPaste(kv.Key, mapTiles[kv.Key], mapResources[kv.Key], mapHeight[kv.Key]));
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
|
||||
mapTiles[kv.Key] = kv.Value.Item1;
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Resources))
|
||||
mapResources[kv.Key] = kv.Value.Item2;
|
||||
|
||||
mapHeight[kv.Key] = kv.Value.Item3;
|
||||
}
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
||||
{
|
||||
var removeActors = dest.SelectMany(editorLayer.PreviewsAt).Distinct().ToList();
|
||||
foreach (var preview in removeActors)
|
||||
{
|
||||
removedActors.Enqueue(preview);
|
||||
editorLayer.Remove(preview);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var kv in previews)
|
||||
addedActorPreviews.Enqueue(editorLayer.Add(kv.Value));
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
while (undoCopyPastes.Count > 0)
|
||||
{
|
||||
var undoCopyPaste = undoCopyPastes.Dequeue();
|
||||
|
||||
var cell = undoCopyPaste.Cell;
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Terrain))
|
||||
mapTiles[cell] = undoCopyPaste.MapTile;
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Resources))
|
||||
mapResources[cell] = undoCopyPaste.ResourceTile;
|
||||
|
||||
mapHeight[cell] = undoCopyPaste.Height;
|
||||
}
|
||||
|
||||
while (addedActorPreviews.Count > 0)
|
||||
editorLayer.Remove(addedActorPreviews.Dequeue());
|
||||
|
||||
if (copyFilters.HasFlag(MapCopyFilters.Actors))
|
||||
while (removedActors.Count > 0)
|
||||
editorLayer.Add(removedActors.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
internal class UndoCopyPaste
|
||||
{
|
||||
public CPos Cell { get; private set; }
|
||||
public TerrainTile MapTile { get; private set; }
|
||||
public ResourceTile ResourceTile { get; private set; }
|
||||
public byte Height { get; private set; }
|
||||
|
||||
public UndoCopyPaste(CPos cell, TerrainTile mapTile, ResourceTile resourceTile, byte height)
|
||||
{
|
||||
Cell = cell;
|
||||
MapTile = mapTile;
|
||||
ResourceTile = resourceTile;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly EditorActorLayer editorLayer;
|
||||
readonly Dictionary<int, ResourceType> resources;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
|
||||
public EditorActorPreview SelectedActor;
|
||||
int2 worldPixel;
|
||||
|
||||
@@ -45,6 +47,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
editorLayer = world.WorldActor.Trait<EditorActorLayer>();
|
||||
resources = world.WorldActor.TraitsImplementing<ResourceType>()
|
||||
.ToDictionary(r => r.Info.ResourceType, r => r);
|
||||
|
||||
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
|
||||
}
|
||||
|
||||
long CalculateActorSelectionPriority(EditorActorPreview actor)
|
||||
@@ -74,7 +78,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var underCursor = editorLayer.PreviewsAt(worldPixel).MinByOrDefault(CalculateActorSelectionPriority);
|
||||
|
||||
var mapResources = world.Map.Resources;
|
||||
ResourceType type;
|
||||
ResourceType type = null;
|
||||
if (underCursor != null)
|
||||
editorWidget.SetTooltip(underCursor.Tooltip);
|
||||
else if (mapResources.Contains(cell) && resources.TryGetValue(mapResources[cell].Type, out type))
|
||||
@@ -97,10 +101,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
editorWidget.SetTooltip(null);
|
||||
|
||||
if (underCursor != null && underCursor != SelectedActor)
|
||||
editorLayer.Remove(underCursor);
|
||||
editorActionManager.Add(new RemoveActorAction(editorLayer, underCursor));
|
||||
|
||||
if (mapResources.Contains(cell) && mapResources[cell].Type != 0)
|
||||
mapResources[cell] = default(ResourceTile);
|
||||
editorActionManager.Add(new RemoveResourceAction(mapResources, cell, type));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -109,4 +113,69 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
public void Tick() { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
class RemoveActorAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly EditorActorLayer editorActorLayer;
|
||||
readonly EditorActorPreview actor;
|
||||
|
||||
public RemoveActorAction(EditorActorLayer editorActorLayer, EditorActorPreview actor)
|
||||
{
|
||||
this.editorActorLayer = editorActorLayer;
|
||||
this.actor = actor;
|
||||
|
||||
Text = "Removed {0} ({1})".F(actor.Info.Name, actor.ID);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Do();
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
editorActorLayer.Remove(actor);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
editorActorLayer.Add(actor);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveResourceAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly CellLayer<ResourceTile> mapResources;
|
||||
readonly CPos cell;
|
||||
|
||||
ResourceTile resourceTile;
|
||||
|
||||
public RemoveResourceAction(CellLayer<ResourceTile> mapResources, CPos cell, ResourceType type)
|
||||
{
|
||||
this.mapResources = mapResources;
|
||||
this.cell = cell;
|
||||
|
||||
Text = "Removed {0}".F(type.Info.TerrainType);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Do();
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
resourceTile = mapResources[cell];
|
||||
mapResources[cell] = default(ResourceTile);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
mapResources[cell] = resourceTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
@@ -23,6 +24,10 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly World world;
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly SpriteWidget preview;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
|
||||
AddResourcesEditorAction action;
|
||||
bool resourceAdded;
|
||||
|
||||
public EditorResourceBrush(EditorViewportControllerWidget editorWidget, ResourceTypeInfo resource, WorldRenderer wr)
|
||||
{
|
||||
@@ -30,6 +35,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
ResourceType = resource;
|
||||
worldRenderer = wr;
|
||||
world = wr.World;
|
||||
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
|
||||
action = new AddResourcesEditorAction(world.Map, ResourceType);
|
||||
|
||||
preview = editorWidget.Get<SpriteWidget>("DRAG_LAYER_PREVIEW");
|
||||
preview.Palette = resource.Palette;
|
||||
@@ -65,11 +72,18 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
|
||||
if (mi.Button == MouseButton.Left && AllowResourceAt(cell))
|
||||
if (mi.Button == MouseButton.Left && mi.Event != MouseInputEvent.Up && AllowResourceAt(cell))
|
||||
{
|
||||
var type = (byte)ResourceType.ResourceType;
|
||||
var index = (byte)ResourceType.MaxDensity;
|
||||
world.Map.Resources[cell] = new ResourceTile(type, index);
|
||||
action.Add(new CellResource(cell, world.Map.Resources[cell], new ResourceTile(type, index)));
|
||||
resourceAdded = true;
|
||||
}
|
||||
else if (resourceAdded && mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Up)
|
||||
{
|
||||
editorActionManager.Add(action);
|
||||
action = new AddResourcesEditorAction(world.Map, ResourceType);
|
||||
resourceAdded = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -112,4 +126,63 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
struct CellResource
|
||||
{
|
||||
public readonly CPos Cell;
|
||||
public readonly ResourceTile ResourceTile;
|
||||
public readonly ResourceTile NewResourceTile;
|
||||
|
||||
public CellResource(CPos cell, ResourceTile resourceTile, ResourceTile newResourceTile)
|
||||
{
|
||||
Cell = cell;
|
||||
ResourceTile = resourceTile;
|
||||
NewResourceTile = newResourceTile;
|
||||
}
|
||||
}
|
||||
|
||||
class AddResourcesEditorAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly Map map;
|
||||
readonly ResourceTypeInfo resourceType;
|
||||
readonly List<CellResource> cellResources = new List<CellResource>();
|
||||
|
||||
public AddResourcesEditorAction(Map map, ResourceTypeInfo resourceType)
|
||||
{
|
||||
this.map = map;
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
foreach (var resourceCell in cellResources)
|
||||
SetTile(resourceCell.Cell, resourceCell.NewResourceTile);
|
||||
}
|
||||
|
||||
void SetTile(CPos cell, ResourceTile tile)
|
||||
{
|
||||
map.Resources[cell] = tile;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
foreach (var resourceCell in cellResources)
|
||||
SetTile(resourceCell.Cell, resourceCell.ResourceTile);
|
||||
}
|
||||
|
||||
public void Add(CellResource cellResource)
|
||||
{
|
||||
SetTile(cellResource.Cell, cellResource.NewResourceTile);
|
||||
cellResources.Add(cellResource);
|
||||
|
||||
var cellText = cellResources.Count != 1 ? "cells" : "cell";
|
||||
Text = "Added {0} {1} of {2}".F(cellResources.Count, cellText, resourceType.TerrainType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Mods.Common.Traits;
|
||||
using OpenRA.Primitives;
|
||||
|
||||
namespace OpenRA.Mods.Common.Widgets
|
||||
@@ -26,6 +27,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly EditorViewportControllerWidget editorWidget;
|
||||
readonly TerrainTemplatePreviewWidget preview;
|
||||
readonly Rectangle bounds;
|
||||
readonly EditorActionManager editorActionManager;
|
||||
|
||||
bool painting;
|
||||
|
||||
@@ -36,6 +38,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
worldRenderer = wr;
|
||||
world = wr.World;
|
||||
|
||||
editorActionManager = world.WorldActor.Trait<EditorActionManager>();
|
||||
|
||||
preview = editorWidget.Get<TerrainTemplatePreviewWidget>("DRAG_TILE_PREVIEW");
|
||||
preview.GetScale = () => worldRenderer.Viewport.Zoom;
|
||||
preview.IsVisible = () => editorWidget.CurrentBrush == this;
|
||||
@@ -97,33 +101,13 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
void PaintCell(CPos cell, bool isMoving)
|
||||
{
|
||||
var map = world.Map;
|
||||
var mapTiles = map.Tiles;
|
||||
var mapHeight = map.Height;
|
||||
|
||||
var tileset = map.Rules.TileSet;
|
||||
var template = tileset.Templates[Template];
|
||||
var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0;
|
||||
|
||||
if (isMoving && PlacementOverlapsSameTemplate(template, cell))
|
||||
return;
|
||||
|
||||
var i = 0;
|
||||
for (var y = 0; y < template.Size.Y; y++)
|
||||
{
|
||||
for (var x = 0; x < template.Size.X; x++, i++)
|
||||
{
|
||||
if (template.Contains(i) && template[i] != null)
|
||||
{
|
||||
var index = template.PickAny ? (byte)Game.CosmeticRandom.Next(0, template.TilesCount) : (byte)i;
|
||||
var c = cell + new CVec(x, y);
|
||||
if (!mapTiles.Contains(c))
|
||||
continue;
|
||||
|
||||
mapTiles[c] = new TerrainTile(Template, index);
|
||||
mapHeight[c] = (byte)(baseHeight + template[index].Height).Clamp(0, map.Grid.MaximumTerrainHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
editorActionManager.Add(new PaintTileEditorAction(Template, map, cell));
|
||||
}
|
||||
|
||||
void FloodFillWithBrush(CPos cell, bool isMoving)
|
||||
@@ -239,4 +223,87 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public void Dispose() { }
|
||||
}
|
||||
|
||||
class PaintTileEditorAction : IEditorAction
|
||||
{
|
||||
public string Text { get; private set; }
|
||||
|
||||
readonly ushort template;
|
||||
readonly Map map;
|
||||
readonly CPos cell;
|
||||
|
||||
readonly Queue<UndoTile> undoTiles = new Queue<UndoTile>();
|
||||
readonly TerrainTemplateInfo terrainTemplate;
|
||||
|
||||
public PaintTileEditorAction(ushort template, Map map, CPos cell)
|
||||
{
|
||||
this.template = template;
|
||||
this.map = map;
|
||||
this.cell = cell;
|
||||
|
||||
var tileset = map.Rules.TileSet;
|
||||
terrainTemplate = tileset.Templates[template];
|
||||
Text = "Added tile {0}".F(terrainTemplate.Id);
|
||||
}
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Do();
|
||||
}
|
||||
|
||||
public void Do()
|
||||
{
|
||||
var mapTiles = map.Tiles;
|
||||
var mapHeight = map.Height;
|
||||
var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0;
|
||||
|
||||
var i = 0;
|
||||
for (var y = 0; y < terrainTemplate.Size.Y; y++)
|
||||
{
|
||||
for (var x = 0; x < terrainTemplate.Size.X; x++, i++)
|
||||
{
|
||||
if (terrainTemplate.Contains(i) && terrainTemplate[i] != null)
|
||||
{
|
||||
var index = terrainTemplate.PickAny ? (byte)Game.CosmeticRandom.Next(0, terrainTemplate.TilesCount) : (byte)i;
|
||||
var c = cell + new CVec(x, y);
|
||||
if (!mapTiles.Contains(c))
|
||||
continue;
|
||||
|
||||
undoTiles.Enqueue(new UndoTile(c, mapTiles[c], mapHeight[c]));
|
||||
|
||||
mapTiles[c] = new TerrainTile(template, index);
|
||||
mapHeight[c] = (byte)(baseHeight + terrainTemplate[index].Height).Clamp(0, map.Grid.MaximumTerrainHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
var mapTiles = map.Tiles;
|
||||
var mapHeight = map.Height;
|
||||
|
||||
while (undoTiles.Count > 0)
|
||||
{
|
||||
var undoTile = undoTiles.Dequeue();
|
||||
|
||||
mapTiles[undoTile.Cell] = undoTile.MapTile;
|
||||
mapHeight[undoTile.Cell] = undoTile.Height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class UndoTile
|
||||
{
|
||||
public CPos Cell { get; private set; }
|
||||
public TerrainTile MapTile { get; private set; }
|
||||
public byte Height { get; private set; }
|
||||
|
||||
public UndoTile(CPos cell, TerrainTile mapTile, byte height)
|
||||
{
|
||||
Cell = cell;
|
||||
MapTile = mapTile;
|
||||
Height = height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user