diff --git a/OpenRA.Mods.Common/MapGenerator/Terraformer.cs b/OpenRA.Mods.Common/MapGenerator/Terraformer.cs index 67068c009a..75ca8e2ffe 100644 --- a/OpenRA.Mods.Common/MapGenerator/Terraformer.cs +++ b/OpenRA.Mods.Common/MapGenerator/Terraformer.cs @@ -176,7 +176,7 @@ namespace OpenRA.Mods.Common.MapGenerator { var maxTerrainHeight = Map.Grid.MaximumTerrainHeight; var tl = new PPos(1, 1 + maxTerrainHeight); - var br = new PPos(Map.MapSize.Width - 2, Map.MapSize.Height + maxTerrainHeight - 2); + var br = new PPos(Map.MapSize.Width - 2, Map.MapSize.Height - maxTerrainHeight - 2); Map.SetBounds(tl, br); Map.Title = MapGenerationArgs.Title; Map.Author = MapGenerationArgs.Author; @@ -185,12 +185,26 @@ namespace OpenRA.Mods.Common.MapGenerator /// /// Commits draft data to the map, such as player and actor definitions. + /// This may trigger some initialization of map data structures that could become invalid + /// if further edits to the map are made. /// public void BakeMap() { var playerCount = ActorsOfType("mpspawn").Count(); Map.PlayerDefinitions = new MapPlayers(Map.Rules, playerCount).ToMiniYaml(); + + // Return true iff any of the actors projected footprint satisfies Map.Contains(PPos). + // Note that this is not the same as Map.Tiles.Contains or Map.Bounds.Contains. + // Note that calling this initializes cell projections. + bool HasProjectedFootprintInMap(ActorPlan plan) + { + return plan.Footprint() + .SelectMany(f => Map.ProjectedCellsCovering(f.Key.ToMPos(Map))) + .Any(Map.Contains); + } + Map.ActorDefinitions = ActorPlans + .Where(HasProjectedFootprintInMap) .Select((plan, i) => new MiniYamlNode($"Actor{i}", plan.Reference.Save())) .ToImmutableArray(); } @@ -261,10 +275,13 @@ namespace OpenRA.Mods.Common.MapGenerator zoneable[mpos] = value; } + /// + /// Zone based on Map.Bounds.Contains. This is stricter than Map.Contains, ignoring height. + /// public void ZoneFromOutOfBounds(CellLayer zoneable, T value) { foreach (var mpos in Map.AllCells.MapCoords) - if (!Map.Contains(mpos)) + if (!Map.Bounds.Contains(mpos.U, mpos.V)) zoneable[mpos] = value; } @@ -1687,10 +1704,10 @@ namespace OpenRA.Mods.Common.MapGenerator throw new ArgumentException("fillSide was not In or Out"); var notFillSide = fillSide == Side.In ? Side.Out : Side.In; - var fillSeeds = CellLayerUtils.Create(Map, (MPos mpos) => + var fillSeeds = CellLayerUtils.Create(Map, mpos => sides[mpos] == fillSide && !mask[mpos] && - Map.Contains(mpos)); + Map.Bounds.Contains(mpos.U, mpos.V)); fillSeeds = ImproveSymmetry(fillSeeds, false, (a, b) => a || b); var fillable = CellLayerUtils.Map(sides, side => side != notFillSide); CellLayerUtils.SimpleFloodFill( diff --git a/OpenRA.Mods.Common/Traits/World/ExperimentalMapGenerator.cs b/OpenRA.Mods.Common/Traits/World/ExperimentalMapGenerator.cs index 740766a9e1..437a1d5a58 100644 --- a/OpenRA.Mods.Common/Traits/World/ExperimentalMapGenerator.cs +++ b/OpenRA.Mods.Common/Traits/World/ExperimentalMapGenerator.cs @@ -747,7 +747,7 @@ namespace OpenRA.Mods.Common.Traits var replace = PlayableToReplaceable(); foreach (var mpos in map.AllCells.MapCoords) - if (playable[mpos] || !map.Contains(mpos)) + if (playable[mpos] || !map.Bounds.Contains(mpos.U, mpos.V)) replace[mpos] = MultiBrush.Replaceability.None; terraformer.PaintArea(debrisTilingRandom, replace, param.UnplayableObstacles); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapGeneratorToolLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapGeneratorToolLogic.cs index 1497c84817..211b745208 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/MapGeneratorToolLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/MapGeneratorToolLogic.cs @@ -261,8 +261,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { var map = world.Map; var terrainInfo = modData.DefaultTerrainInfo[map.Tileset]; - var size = new Size(map.Bounds.Width + 2, map.Bounds.Height + 2); - var args = settings.Compile(terrainInfo, size); + var args = settings.Compile(terrainInfo, map.MapSize); // Run main generator logic. May throw. var generateStopwatch = Stopwatch.StartNew(); @@ -301,12 +300,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic previews.Add(kv.Key, preview); } - var offset = map.CellContaining(map.ProjectedTopLeft) - generatedMap.CellContaining(generatedMap.ProjectedTopLeft); - var blitSource = new EditorBlitSource(generatedMap.AllCells, previews, tiles); + var cellBounds = CellLayerUtils.CellBounds(map); + var topLeft = new CPos(cellBounds.TopLeft.X, cellBounds.TopLeft.Y); + var bottomRight = new CPos(cellBounds.BottomRight.X, cellBounds.BottomRight.Y); + var cellRegion = new CellRegion(map.Grid.Type, topLeft, bottomRight); + var blitSource = new EditorBlitSource(cellRegion, previews, tiles); var editorBlit = new EditorBlit( MapBlitFilters.All, resourceLayer, - new CPos(offset.X, offset.Y), + topLeft, map, blitSource, editorActorLayer, diff --git a/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs index 3622081bf9..9fb859bd4f 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MapGeneratorLogic.cs @@ -234,9 +234,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic void RandomizeSize() { + var mapGrid = modData.Manifest.Get(); var sizeRange = MapSizes[selectedSize]; var width = Game.CosmeticRandom.Next(sizeRange.X, sizeRange.Y); - size = new Size(width + 2, width + 2); + var height = + mapGrid.Type == MapGridType.RectangularIsometric + ? width * 2 + : width; + + size = new Size(width + 2, height + mapGrid.MaximumTerrainHeight * 2 + 2); } void RefreshSettings()