Merge pull request #8430 from pchote/editor-cordon
Display and support editing the area outside the map bounds
This commit is contained in:
@@ -95,9 +95,8 @@ namespace OpenRA.Graphics
|
||||
var cells = viewport.VisibleCells;
|
||||
|
||||
// Only draw the rows that are visible.
|
||||
// VisibleCells is clamped to the map, so additional checks are unnecessary
|
||||
var firstRow = cells.TopLeft.ToMPos(map).V;
|
||||
var lastRow = cells.BottomRight.ToMPos(map).V + 1;
|
||||
var firstRow = cells.MapCoords.TopLeft.V;
|
||||
var lastRow = Math.Min(cells.MapCoords.BottomRight.V + 1, map.MapSize.Y);
|
||||
|
||||
Game.Renderer.Flush();
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace OpenRA.Graphics
|
||||
readonly Rectangle mapBounds;
|
||||
|
||||
readonly int maxGroundHeight;
|
||||
readonly Size tileSize;
|
||||
|
||||
// Viewport geometry (world-px)
|
||||
public int2 CenterLocation { get; private set; }
|
||||
@@ -90,17 +91,18 @@ namespace OpenRA.Graphics
|
||||
{
|
||||
worldRenderer = wr;
|
||||
|
||||
// Calculate map bounds in world-px
|
||||
var b = map.Bounds;
|
||||
var cells = wr.World.Type == WorldType.Editor ?
|
||||
map.AllCells : map.CellsInsideBounds;
|
||||
|
||||
// Expand to corners of cells
|
||||
var tl = wr.ScreenPxPosition(map.CenterOfCell(new MPos(b.Left, b.Top).ToCPos(map)) - new WVec(512, 512, 0));
|
||||
var br = wr.ScreenPxPosition(map.CenterOfCell(new MPos(b.Right, b.Bottom).ToCPos(map)) + new WVec(511, 511, 0));
|
||||
// Calculate map bounds in world-px
|
||||
var tl = wr.ScreenPxPosition(map.CenterOfCell(cells.TopLeft) - new WVec(512, 512, 0));
|
||||
var br = wr.ScreenPxPosition(map.CenterOfCell(cells.BottomRight) + new WVec(511, 511, 0));
|
||||
mapBounds = Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
|
||||
maxGroundHeight = wr.World.TileSet.MaxGroundHeight;
|
||||
CenterLocation = (tl + br) / 2;
|
||||
Zoom = Game.Settings.Graphics.PixelDouble ? 2 : 1;
|
||||
tileSize = Game.ModData.Manifest.TileSize;
|
||||
}
|
||||
|
||||
public CPos ViewToWorld(int2 view)
|
||||
@@ -211,7 +213,10 @@ namespace OpenRA.Graphics
|
||||
// Convert to screen coordinates
|
||||
var tl = WorldToViewPx(worldRenderer.ScreenPxPosition(ctl - new WVec(0, 0, ctl.Z))).Clamp(ScreenClip);
|
||||
var br = WorldToViewPx(worldRenderer.ScreenPxPosition(cbr - new WVec(0, 0, cbr.Z))).Clamp(ScreenClip);
|
||||
return Rectangle.FromLTRB(tl.X, tl.Y, br.X, br.Y);
|
||||
|
||||
// Add an extra one cell fudge in each direction for safety
|
||||
return Rectangle.FromLTRB(tl.X - tileSize.Width, tl.Y - tileSize.Height,
|
||||
br.X + tileSize.Width, br.Y + tileSize.Height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,6 +230,11 @@ namespace OpenRA.Graphics
|
||||
var wtl = worldRenderer.Position(TopLeft);
|
||||
var wbr = worldRenderer.Position(BottomRight);
|
||||
|
||||
// Map editor shows the full map (including the area outside the regular bounds)
|
||||
Func<MPos, MPos> clamp = map.Clamp;
|
||||
if (worldRenderer.World.Type == WorldType.Editor)
|
||||
clamp = map.MapTiles.Value.Clamp;
|
||||
|
||||
// Due to diamond tile staggering, we need to adjust the top-left bounds outwards by half a cell.
|
||||
if (map.TileShape == TileShape.Diamond)
|
||||
wtl -= new WVec(512, 512, 0);
|
||||
@@ -234,11 +244,11 @@ namespace OpenRA.Graphics
|
||||
var ctl = new MPos(wtl.X / 1024, wtl.Y / dy);
|
||||
var cbr = new MPos(wbr.X / 1024, wbr.Y / dy);
|
||||
|
||||
var tl = map.Clamp(ctl.ToCPos(map));
|
||||
var tl = clamp(ctl).ToCPos(map.TileShape);
|
||||
|
||||
// Also need to account for height of cells in rows below the bottom.
|
||||
var heightPadding = map.TileShape == TileShape.Diamond ? 2 : 0;
|
||||
var br = map.Clamp(new MPos(cbr.U, cbr.V + heightPadding + maxGroundHeight / 2).ToCPos(map));
|
||||
var heightPadding = map.TileShape == TileShape.Diamond ? 3 : 0;
|
||||
var br = clamp(new MPos(cbr.U, cbr.V + heightPadding + maxGroundHeight / 2 + 1)).ToCPos(map.TileShape);
|
||||
|
||||
cells = new CellRegion(map.TileShape, tl, br);
|
||||
cellsDirty = false;
|
||||
|
||||
@@ -125,10 +125,31 @@ namespace OpenRA
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public bool Contains(CPos cell)
|
||||
{
|
||||
// .ToMPos() returns the same result if the X and Y coordinates
|
||||
// are switched. X < Y is invalid in the Diamond coordinate system,
|
||||
// so we pre-filter these to avoid returning the wrong result
|
||||
if (Shape == TileShape.Diamond && cell.X < cell.Y)
|
||||
return false;
|
||||
|
||||
return Contains(cell.ToMPos(Shape));
|
||||
}
|
||||
|
||||
public bool Contains(MPos uv)
|
||||
{
|
||||
return bounds.Contains(uv.U, uv.V);
|
||||
}
|
||||
|
||||
public CPos Clamp(CPos uv)
|
||||
{
|
||||
return Clamp(uv.ToMPos(Shape)).ToCPos(Shape);
|
||||
}
|
||||
|
||||
public MPos Clamp(MPos uv)
|
||||
{
|
||||
return uv.Clamp(new Rectangle(0, 0, Size.Width - 1, Size.Height - 1));
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
@@ -217,6 +217,9 @@ namespace OpenRA
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
public MPos TopLeft { get { return r.mapTopLeft; } }
|
||||
public MPos BottomRight { get { return r.mapBottomRight; } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -630,6 +630,12 @@ namespace OpenRA
|
||||
|
||||
public bool Contains(CPos cell)
|
||||
{
|
||||
// .ToMPos() returns the same result if the X and Y coordinates
|
||||
// are switched. X < Y is invalid in the Diamond coordinate system,
|
||||
// so we pre-filter these to avoid returning the wrong result
|
||||
if (TileShape == TileShape.Diamond && cell.X < cell.Y)
|
||||
return false;
|
||||
|
||||
return Contains(cell.ToMPos(this));
|
||||
}
|
||||
|
||||
@@ -772,6 +778,12 @@ namespace OpenRA
|
||||
return cell.ToMPos(this).Clamp(bounds).ToCPos(this);
|
||||
}
|
||||
|
||||
public MPos Clamp(MPos uv)
|
||||
{
|
||||
var bounds = new Rectangle(Bounds.X, Bounds.Y, Bounds.Width - 1, Bounds.Height - 1);
|
||||
return uv.Clamp(bounds);
|
||||
}
|
||||
|
||||
public CPos ChooseRandomCell(MersenneTwister rand)
|
||||
{
|
||||
var x = rand.Next(Bounds.Left, Bounds.Right);
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
readonly CVec locationOffset;
|
||||
readonly WVec previewOffset;
|
||||
readonly PlayerReference owner;
|
||||
readonly CVec[] footprint;
|
||||
|
||||
int facing = 92;
|
||||
|
||||
@@ -67,6 +68,14 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
td.Add(new RaceInit(owner.Race));
|
||||
preview.SetPreview(actor, td);
|
||||
|
||||
var ios = actor.Traits.GetOrDefault<IOccupySpaceInfo>();
|
||||
if (ios != null)
|
||||
footprint = ios.OccupiedCells(actor, CPos.Zero)
|
||||
.Select(c => c.Key - CPos.Zero)
|
||||
.ToArray();
|
||||
else
|
||||
footprint = new CVec[0];
|
||||
|
||||
// The preview widget may be rendered by the higher-level code before it is ticked.
|
||||
// Force a manual tick to ensure the bounds are set correctly for this first draw.
|
||||
Tick();
|
||||
@@ -85,8 +94,12 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
}
|
||||
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down && world.Map.Contains(cell))
|
||||
if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
||||
{
|
||||
// Check the actor is inside the map
|
||||
if (!footprint.All(c => world.Map.MapTiles.Value.Contains(cell + locationOffset + c)))
|
||||
return true;
|
||||
|
||||
var newActorReference = new ActorReference(Actor.Name);
|
||||
newActorReference.Add(new OwnerInit(owner.Name));
|
||||
|
||||
|
||||
@@ -65,10 +65,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var underCursor = editorLayer.PreviewsAt(worldRenderer.Viewport.ViewToWorldPx(mi.Location))
|
||||
.FirstOrDefault();
|
||||
|
||||
var mapResources = world.Map.MapResources.Value;
|
||||
ResourceType type;
|
||||
if (underCursor != null)
|
||||
editorWidget.SetTooltip(underCursor.Tooltip);
|
||||
else if (world.Map.Contains(cell) && resources.TryGetValue(world.Map.MapResources.Value[cell].Type, out type))
|
||||
else if (mapResources.Contains(cell) && resources.TryGetValue(mapResources[cell].Type, out type))
|
||||
editorWidget.SetTooltip(type.Info.Name);
|
||||
else
|
||||
editorWidget.SetTooltip(null);
|
||||
@@ -84,8 +85,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
if (underCursor != null)
|
||||
editorLayer.Remove(underCursor);
|
||||
|
||||
if (world.Map.MapResources.Value[cell].Type != 0)
|
||||
world.Map.MapResources.Value[cell] = new ResourceTile();
|
||||
if (mapResources.Contains(cell) && mapResources[cell].Type != 0)
|
||||
mapResources[cell] = new ResourceTile();
|
||||
}
|
||||
else if (mi.Button == MouseButton.Left && mi.Event == MouseInputEvent.Down)
|
||||
{
|
||||
|
||||
@@ -82,7 +82,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
public bool AllowResourceAt(CPos cell)
|
||||
{
|
||||
if (!world.Map.Contains(cell))
|
||||
var mapResources = world.Map.MapResources.Value;
|
||||
if (!mapResources.Contains(cell))
|
||||
return false;
|
||||
|
||||
var tile = world.Map.MapTiles.Value[cell];
|
||||
@@ -92,7 +93,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
|
||||
var terrainType = world.TileSet.TerrainInfo[tileInfo.TerrainType];
|
||||
|
||||
if (world.Map.MapResources.Value[cell].Type == ResourceType.ResourceType)
|
||||
if (mapResources[cell].Type == ResourceType.ResourceType)
|
||||
return false;
|
||||
|
||||
if (!ResourceType.AllowedTerrainTypes.Contains(terrainType.Type))
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
return true;
|
||||
|
||||
var map = world.Map;
|
||||
var mapTiles = map.MapTiles.Value;
|
||||
var mapHeight = map.MapHeight.Value;
|
||||
var cell = worldRenderer.Viewport.ViewToWorld(mi.Location);
|
||||
|
||||
if (mi.Event != MouseInputEvent.Down && mi.Event != MouseInputEvent.Move)
|
||||
@@ -87,7 +89,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
var rules = map.Rules;
|
||||
var tileset = rules.TileSets[map.Tileset];
|
||||
var template = tileset.Templates[Template];
|
||||
var baseHeight = map.Contains(cell) ? map.MapHeight.Value[cell] : (byte)0;
|
||||
var baseHeight = mapHeight.Contains(cell) ? mapHeight[cell] : (byte)0;
|
||||
if (mi.Event == MouseInputEvent.Move && PlacementOverlapsSameTemplate(template, cell))
|
||||
return true;
|
||||
|
||||
@@ -100,11 +102,11 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
{
|
||||
var index = template.PickAny ? (byte)Game.CosmeticRandom.Next(0, template.TilesCount) : (byte)i;
|
||||
var c = cell + new CVec(x, y);
|
||||
if (!map.Contains(c))
|
||||
if (!mapTiles.Contains(c))
|
||||
continue;
|
||||
|
||||
map.MapTiles.Value[c] = new TerrainTile(Template, index);
|
||||
map.MapHeight.Value[c] = (byte)(baseHeight + template[index].Height).Clamp(0, world.TileSet.MaxGroundHeight);
|
||||
mapTiles[c] = new TerrainTile(Template, index);
|
||||
mapHeight[c] = (byte)(baseHeight + template[index].Height).Clamp(0, world.TileSet.MaxGroundHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +117,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
bool PlacementOverlapsSameTemplate(TerrainTemplateInfo template, CPos cell)
|
||||
{
|
||||
var map = world.Map;
|
||||
var mapTiles = map.MapTiles.Value;
|
||||
var i = 0;
|
||||
for (var y = 0; y < template.Size.Y; y++)
|
||||
{
|
||||
@@ -123,7 +126,7 @@ namespace OpenRA.Mods.Common.Widgets
|
||||
if (template.Contains(i) && template[i] != null)
|
||||
{
|
||||
var c = cell + new CVec(x, y);
|
||||
if (map.Contains(c) && map.MapTiles.Value[c].Type == template.Id)
|
||||
if (mapTiles.Contains(c) && mapTiles[c].Type == template.Id)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,7 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// so we must also touch all the neighbouring tiles
|
||||
Dirty.Add(cell);
|
||||
foreach (var d in CVec.Directions)
|
||||
{
|
||||
var c = cell + d;
|
||||
if (Map.Contains(c))
|
||||
Dirty.Add(c);
|
||||
}
|
||||
Dirty.Add(cell + d);
|
||||
}
|
||||
|
||||
protected virtual string ChooseRandomVariant(ResourceType t)
|
||||
@@ -103,10 +99,16 @@ namespace OpenRA.Mods.Common.Traits
|
||||
// Set density based on the number of neighboring resources
|
||||
var adjacent = 0;
|
||||
var type = Tiles[c].Type;
|
||||
var resources = Map.MapResources.Value;
|
||||
for (var u = -1; u < 2; u++)
|
||||
{
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (Map.MapResources.Value[c + new CVec(u, v)].Type == type.Info.ResourceType)
|
||||
{
|
||||
var cell = c + new CVec(u, v);
|
||||
if (resources.Contains(cell) && resources[cell].Type == type.Info.ResourceType)
|
||||
adjacent++;
|
||||
}
|
||||
}
|
||||
|
||||
return Math.Max(int2.Lerp(0, type.Info.MaxDensity, adjacent, 9), 1);
|
||||
}
|
||||
@@ -139,7 +141,8 @@ namespace OpenRA.Mods.Common.Traits
|
||||
return;
|
||||
|
||||
foreach (var c in Dirty)
|
||||
Tiles[c] = UpdateDirtyTile(c);
|
||||
if (Tiles.Contains(c))
|
||||
Tiles[c] = UpdateDirtyTile(c);
|
||||
|
||||
Dirty.Clear();
|
||||
|
||||
|
||||
@@ -50,9 +50,14 @@ namespace OpenRA.Mods.Common.Traits
|
||||
{
|
||||
var sum = 0;
|
||||
for (var u = -1; u < 2; u++)
|
||||
{
|
||||
for (var v = -1; v < 2; v++)
|
||||
if (content[cell + new CVec(u, v)].Type == t)
|
||||
{
|
||||
var c = cell + new CVec(u, v);
|
||||
if (content.Contains(c) && content[c].Type == t)
|
||||
++sum;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,13 @@ namespace OpenRA.Mods.Common.Traits
|
||||
}
|
||||
|
||||
DirtyCells(map.AllCells);
|
||||
visibleUnderShroud = map.Contains;
|
||||
|
||||
// All tiles are visible in the editor
|
||||
if (w.Type == WorldType.Editor)
|
||||
visibleUnderShroud = _ => true;
|
||||
else
|
||||
visibleUnderShroud = map.Contains;
|
||||
|
||||
visibleUnderFog = map.Contains;
|
||||
|
||||
var shroudSheet = shroudSprites[0].Sheet;
|
||||
|
||||
@@ -65,31 +65,36 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
return D2kResourceLayer.Variants.Keys.Random(Game.CosmeticRandom);
|
||||
}
|
||||
|
||||
bool CellContains(CPos c, ResourceType t)
|
||||
{
|
||||
return Tiles.Contains(c) && Tiles[c].Type == t;
|
||||
}
|
||||
|
||||
ClearSides FindClearSides(ResourceType t, CPos p)
|
||||
{
|
||||
var ret = ClearSides.None;
|
||||
if (Tiles[p + new CVec(0, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(0, -1), t))
|
||||
ret |= ClearSides.Top | ClearSides.TopLeft | ClearSides.TopRight;
|
||||
|
||||
if (Tiles[p + new CVec(-1, 0)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, 0), t))
|
||||
ret |= ClearSides.Left | ClearSides.TopLeft | ClearSides.BottomLeft;
|
||||
|
||||
if (Tiles[p + new CVec(1, 0)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, 0), t))
|
||||
ret |= ClearSides.Right | ClearSides.TopRight | ClearSides.BottomRight;
|
||||
|
||||
if (Tiles[p + new CVec(0, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(0, 1), t))
|
||||
ret |= ClearSides.Bottom | ClearSides.BottomLeft | ClearSides.BottomRight;
|
||||
|
||||
if (Tiles[p + new CVec(-1, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, -1), t))
|
||||
ret |= ClearSides.TopLeft;
|
||||
|
||||
if (Tiles[p + new CVec(1, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, -1), t))
|
||||
ret |= ClearSides.TopRight;
|
||||
|
||||
if (Tiles[p + new CVec(-1, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, 1), t))
|
||||
ret |= ClearSides.BottomLeft;
|
||||
|
||||
if (Tiles[p + new CVec(1, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, 1), t))
|
||||
ret |= ClearSides.BottomRight;
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -96,31 +96,36 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
{ ClearSides.Bottom | ClearSides.TopLeft | ClearSides.BottomLeft | ClearSides.BottomRight, 49 },
|
||||
};
|
||||
|
||||
bool CellContains(CPos c, ResourceType t)
|
||||
{
|
||||
return render.Contains(c) && render[c].Type == t;
|
||||
}
|
||||
|
||||
ClearSides FindClearSides(ResourceType t, CPos p)
|
||||
{
|
||||
var ret = ClearSides.None;
|
||||
if (render[p + new CVec(0, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(0, -1), t))
|
||||
ret |= ClearSides.Top | ClearSides.TopLeft | ClearSides.TopRight;
|
||||
|
||||
if (render[p + new CVec(-1, 0)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, 0), t))
|
||||
ret |= ClearSides.Left | ClearSides.TopLeft | ClearSides.BottomLeft;
|
||||
|
||||
if (render[p + new CVec(1, 0)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, 0), t))
|
||||
ret |= ClearSides.Right | ClearSides.TopRight | ClearSides.BottomRight;
|
||||
|
||||
if (render[p + new CVec(0, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(0, 1), t))
|
||||
ret |= ClearSides.Bottom | ClearSides.BottomLeft | ClearSides.BottomRight;
|
||||
|
||||
if (render[p + new CVec(-1, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, -1), t))
|
||||
ret |= ClearSides.TopLeft;
|
||||
|
||||
if (render[p + new CVec(1, -1)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, -1), t))
|
||||
ret |= ClearSides.TopRight;
|
||||
|
||||
if (render[p + new CVec(-1, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(-1, 1), t))
|
||||
ret |= ClearSides.BottomLeft;
|
||||
|
||||
if (render[p + new CVec(1, 1)].Type != t)
|
||||
if (!CellContains(p + new CVec(1, 1), t))
|
||||
ret |= ClearSides.BottomRight;
|
||||
|
||||
return ret;
|
||||
@@ -128,6 +133,9 @@ namespace OpenRA.Mods.D2k.Traits
|
||||
|
||||
void UpdateRenderedTileInner(CPos p)
|
||||
{
|
||||
if (!render.Contains(p))
|
||||
return;
|
||||
|
||||
var t = render[p];
|
||||
if (t.Density > 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user