diff --git a/OpenRA.Game/Map/ActorReference.cs b/OpenRA.Game/Map/ActorReference.cs index 192d1c5f16..058efe3f2e 100755 --- a/OpenRA.Game/Map/ActorReference.cs +++ b/OpenRA.Game/Map/ActorReference.cs @@ -48,7 +48,7 @@ namespace OpenRA return info; } - public MiniYaml Save() + public MiniYaml Save(Func initFilter = null) { var ret = new MiniYaml(Type); foreach (var init in InitDict) @@ -56,6 +56,9 @@ namespace OpenRA if (init is ISuppressInitExport) continue; + if (initFilter != null && !initFilter(init)) + continue; + var initName = init.GetType().Name; ret.Nodes.Add(new MiniYamlNode(initName.Substring(0, initName.Length - 4), FieldSaver.Save(init))); } diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index c1933e3cc2..a53a2163d1 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -170,7 +170,8 @@ namespace OpenRA TileSet = map.Rules.TileSets[Map.Tileset]; SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed); - WorldActor = CreateActor("World", new TypeDictionary()); + var worldActorType = type == WorldType.Editor ? "EditorWorld" : "World"; + WorldActor = CreateActor(worldActorType, new TypeDictionary()); ActorMap = WorldActor.Trait(); ScreenMap = WorldActor.Trait(); diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 893e2eb317..d109070c18 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -627,6 +627,9 @@ + + + diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs new file mode 100644 index 0000000000..d3d63db563 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs @@ -0,0 +1,268 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("Required for the map editor to work. Attach this to the world actor.")] + public class EditorActorLayerInfo : ITraitInfo + { + [Desc("Size of partition bins (world pixels)")] + public readonly int BinSize = 250; + + public object Create(ActorInitializer init) { return new EditorActorLayer(init.Self, this); } + } + + public class EditorActorLayer : IWorldLoaded, ITickRender, IRender, IRadarSignature, ICreatePlayers + { + readonly EditorActorLayerInfo info; + readonly Dictionary previews = new Dictionary(); + readonly Dictionary> cellMap = new Dictionary>(); + + SpatiallyPartitioned screenMap; + WorldRenderer worldRenderer; + + public MapPlayers Players { get; private set; } + + public EditorActorLayer(Actor self, EditorActorLayerInfo info) + { + this.info = info; + } + + public void CreatePlayers(World w) + { + if (w.Type != WorldType.Editor) + return; + + Players = new MapPlayers(w.Map.PlayerDefinitions); + } + + public void WorldLoaded(World world, WorldRenderer wr) + { + if (world.Type != WorldType.Editor) + return; + + worldRenderer = wr; + + foreach (var pr in Players.Players.Values) + wr.UpdatePalettesForPlayer(pr.Name, pr.Color, false); + + var ts = Game.ModData.Manifest.TileSize; + var width = world.Map.MapSize.X * ts.Width; + var height = world.Map.MapSize.Y * ts.Height; + screenMap = new SpatiallyPartitioned(width, height, info.BinSize); + + foreach (var kv in world.Map.ActorDefinitions) + Add(kv.Key, new ActorReference(kv.Value.Value, kv.Value.ToDictionary()), true); + + // Update neighbours in one pass + foreach (var p in previews.Values) + UpdateNeighbours(p.Footprint); + } + + public void TickRender(WorldRenderer wr, Actor self) + { + if (wr.World.Type != WorldType.Editor) + return; + + foreach (var kv in previews.Values) + kv.Tick(); + } + + static readonly IEnumerable NoRenderables = Enumerable.Empty(); + public virtual IEnumerable Render(Actor self, WorldRenderer wr) + { + if (wr.World.Type != WorldType.Editor) + return NoRenderables; + + return PreviewsInBox(wr.Viewport.TopLeft, wr.Viewport.BottomRight) + .SelectMany(p => p.Render()); + } + + public EditorActorPreview Add(ActorReference reference) { return Add(NextActorName(), reference); } + + EditorActorPreview Add(string id, ActorReference reference, bool initialSetup = false) + { + var owner = Players.Players[reference.InitDict.Get().PlayerName]; + + var preview = new EditorActorPreview(worldRenderer, id, reference, owner); + previews.Add(id, preview); + screenMap.Add(preview, preview.Bounds); + + foreach (var kv in preview.Footprint) + { + List list; + if (!cellMap.TryGetValue(kv.Key, out list)) + { + list = new List(); + cellMap.Add(kv.Key, list); + } + + list.Add(preview); + } + + if (!initialSetup) + { + UpdateNeighbours(preview.Footprint); + + if (reference.Type == "mpspawn") + SyncMultiplayerCount(); + } + + return preview; + } + + public void Remove(EditorActorPreview preview) + { + previews.Remove(preview.ID); + screenMap.Remove(preview); + + foreach (var kv in preview.Footprint) + { + List list; + if (!cellMap.TryGetValue(kv.Key, out list)) + continue; + + list.Remove(preview); + + if (!list.Any()) + cellMap.Remove(kv.Key); + } + + UpdateNeighbours(preview.Footprint); + + if (preview.Info.Name == "mpspawn") + SyncMultiplayerCount(); + } + + void SyncMultiplayerCount() + { + var newCount = previews.Count(p => p.Value.Info.Name == "mpspawn"); + var mp = Players.Players.Where(p => p.Key.StartsWith("Multi")).ToList(); + foreach (var kv in mp) + { + var name = kv.Key; + var index = int.Parse(name.Substring(5)); + + if (index >= newCount) + { + Players.Players.Remove(name); + worldRenderer.World.Players.RemoveAll(pp => pp.InternalName == name); + } + } + + for (var index = 0; index < newCount; index++) + { + if (Players.Players.ContainsKey("Multi{0}".F(index))) + continue; + + var pr = new PlayerReference + { + Name = "Multi{0}".F(index), + Race = "Random", + Playable = true, + Enemies = new[] { "Creeps" } + }; + + Players.Players.Add(pr.Name, pr); + worldRenderer.UpdatePalettesForPlayer(pr.Name, pr.Color, true); + } + } + + void UpdateNeighbours(IReadOnlyDictionary footprint) + { + // Include actors inside the footprint too + var cells = OpenRA.Traits.Util.ExpandFootprint(footprint.Keys, true); + foreach (var p in cells.SelectMany(c => PreviewsAt(c))) + p.ReplaceInit(new RuntimeNeighbourInit(NeighbouringPreviews(p.Footprint))); + } + + Dictionary NeighbouringPreviews(IReadOnlyDictionary footprint) + { + var cells = OpenRA.Traits.Util.ExpandFootprint(footprint.Keys, true).Except(footprint.Keys); + return cells.ToDictionary(c => c, c => PreviewsAt(c).Select(p => p.Info.Name).ToArray()); + } + + public IEnumerable PreviewsInBox(int2 a, int2 b) + { + return screenMap.InBox(Rectangle.FromLTRB(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Max(a.X, b.X), Math.Max(a.Y, b.Y))); + } + + public IEnumerable PreviewsInBox(Rectangle r) + { + return screenMap.InBox(r); + } + + public IEnumerable PreviewsAt(CPos cell) + { + List list; + if (cellMap.TryGetValue(cell, out list)) + return list; + + return Enumerable.Empty(); + } + + public SubCell FreeSubCellAt(CPos cell) + { + var map = worldRenderer.World.Map; + var previews = PreviewsAt(cell).ToList(); + if (!previews.Any()) + return map.DefaultSubCell; + + for (var i = (int)SubCell.First; i < map.SubCellOffsets.Length; i++) + if (!previews.Any(p => p.Footprint[cell] == (SubCell)i)) + return (SubCell)i; + + return SubCell.Invalid; + } + + public IEnumerable PreviewsAt(int2 worldPx) + { + return screenMap.At(worldPx); + } + + string NextActorName() + { + var id = previews.Count(); + var possibleName = "Actor" + id.ToString(); + + while (previews.ContainsKey(possibleName)) + { + id++; + possibleName = "Actor" + id.ToString(); + } + + return possibleName; + } + + public List Save() + { + var nodes = new List(); + foreach (var a in previews) + nodes.Add(new MiniYamlNode(a.Key, a.Value.Save())); + + return nodes; + } + + public IEnumerable> RadarSignatureCells(Actor self) + { + return cellMap.SelectMany(c => c.Value.Select(p => Pair.New(c.Key, p.Owner.Color.RGB))); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs new file mode 100644 index 0000000000..db5011915a --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/EditorActorPreview.cs @@ -0,0 +1,164 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + public class EditorActorPreview + { + public readonly string Tooltip; + public readonly string ID; + public readonly ActorInfo Info; + public readonly PlayerReference Owner; + public readonly WPos CenterPosition; + public readonly IReadOnlyDictionary Footprint; + public readonly Rectangle Bounds; + + public SubCell SubCell { get; private set; } + + readonly ActorReference actor; + readonly WorldRenderer worldRenderer; + IActorPreview[] previews; + + public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner) + { + ID = id; + this.actor = actor; + this.Owner = owner; + this.worldRenderer = worldRenderer; + + if (!actor.InitDict.Contains()) + actor.InitDict.Add(new RaceInit(owner.Race)); + + if (!actor.InitDict.Contains()) + actor.InitDict.Add(new OwnerInit(owner.Name)); + + var world = worldRenderer.World; + if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) + throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); + + CenterPosition = PreviewPosition(world, actor.InitDict); + + var location = actor.InitDict.Get().Value(worldRenderer.World); + var ios = Info.Traits.GetOrDefault(); + + var subCellInit = actor.InitDict.GetOrDefault(); + var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; + + if (ios != null) + Footprint = ios.OccupiedCells(Info, location, subCell); + else + { + var footprint = new Dictionary() { { location, SubCell.FullCell } }; + Footprint = new ReadOnlyDictionary(footprint); + } + + var tooltipInfo = Info.Traits.GetOrDefault(); + Tooltip = "{0} ({1})".F(tooltipInfo != null ? tooltipInfo.TooltipForPlayerStance(Stance.None) : Info.Name, ID); + + GeneratePreviews(); + + // Bounds are fixed from the initial render. + // If this is a problem, then we may need to fetch the area from somewhere else + var r = previews + .SelectMany(p => p.Render(worldRenderer, CenterPosition)) + .Select(rr => rr.PrepareRender(worldRenderer)); + + if (r.Any()) + { + Bounds = r.First().ScreenBounds(worldRenderer); + foreach (var rr in r.Skip(1)) + Bounds = Rectangle.Union(Bounds, rr.ScreenBounds(worldRenderer)); + } + } + + public void Tick() + { + foreach (var p in previews) + p.Tick(); + } + + public IEnumerable Render() + { + return previews.SelectMany(p => p.Render(worldRenderer, CenterPosition)); + } + + public void ReplaceInit(T init) + { + var original = actor.InitDict.GetOrDefault(); + if (original != null) + actor.InitDict.Remove(original); + + actor.InitDict.Add(init); + GeneratePreviews(); + } + + public T Init() + { + return actor.InitDict.GetOrDefault(); + } + + public MiniYaml Save() + { + Func saveInit = init => + { + var race = init as RaceInit; + if (race != null && race.Race == Owner.Race) + return false; + + // TODO: Other default values will need to be filtered + // here after we have built a properties panel + return true; + }; + + return actor.Save(saveInit); + } + + WPos PreviewPosition(World world, TypeDictionary init) + { + if (init.Contains()) + return init.Get().Value(world); + + if (init.Contains()) + { + var cell = init.Get().Value(world); + var offset = WVec.Zero; + + var subCellInit = actor.InitDict.GetOrDefault(); + var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; + + var buildingInfo = Info.Traits.GetOrDefault(); + if (buildingInfo != null) + offset = FootprintUtils.CenterOffset(world, buildingInfo); + + return world.Map.CenterOfSubCell(cell, subCell) + offset; + } + else + throw new InvalidDataException("Actor {0} must define Location or CenterPosition".F(ID)); + } + + void GeneratePreviews() + { + var init = new ActorPreviewInitializer(Info, worldRenderer, actor.InitDict); + previews = Info.Traits.WithInterface() + .SelectMany(rpi => rpi.RenderPreview(init)) + .ToArray(); + } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs new file mode 100644 index 0000000000..e38dd1403e --- /dev/null +++ b/OpenRA.Mods.Common/Traits/World/EditorResourceLayer.cs @@ -0,0 +1,148 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Graphics; +using OpenRA.Primitives; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + using CellContents = ResourceLayer.CellContents; + + [Desc("Required for the map editor to work. Attach this to the world actor.")] + public class EditorResourceLayerInfo : ITraitInfo, Requires + { + public virtual object Create(ActorInitializer init) { return new EditorResourceLayer(init.Self); } + } + + public class EditorResourceLayer : IWorldLoaded, IRenderOverlay + { + protected readonly Map Map; + protected readonly TileSet Tileset; + protected readonly Dictionary Resources; + protected readonly CellLayer Tiles; + protected readonly HashSet Dirty = new HashSet(); + + public EditorResourceLayer(Actor self) + { + if (self.World.Type != WorldType.Editor) + return; + + Map = self.World.Map; + Tileset = self.World.TileSet; + + Tiles = new CellLayer(Map); + Resources = self.TraitsImplementing() + .ToDictionary(r => r.Info.ResourceType, r => r); + + Map.MapResources.Value.CellEntryChanged += UpdateCell; + } + + public void WorldLoaded(World w, WorldRenderer wr) + { + if (w.Type != WorldType.Editor) + return; + + foreach (var cell in Map.Cells) + UpdateCell(cell); + } + + public void UpdateCell(CPos cell) + { + var uv = cell.ToMPos(Map); + var tile = Map.MapResources.Value[uv]; + + ResourceType type; + if (Resources.TryGetValue(tile.Type, out type)) + { + Tiles[uv] = new CellContents + { + Type = type, + Variant = ChooseRandomVariant(type), + }; + + Map.CustomTerrain[uv] = Tileset.GetTerrainIndex(type.Info.TerrainType); + } + else + { + Tiles[uv] = CellContents.Empty; + Map.CustomTerrain[uv] = byte.MaxValue; + } + + // Ingame resource rendering is a giant hack (#6395), + // 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); + } + } + + protected virtual string ChooseRandomVariant(ResourceType t) + { + return t.Variants.Keys.Random(Game.CosmeticRandom); + } + + public virtual CellContents UpdateDirtyTile(CPos c) + { + var t = Tiles[c]; + + // Empty tile + if (t.Type == null) + { + t.Sprite = null; + return t; + } + + // Set density based on the number of neighboring resources + var adjacent = 0; + var type = t.Type; + 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) + adjacent++; + + t.Density = Math.Max(int2.Lerp(0, type.Info.MaxDensity, adjacent, 9), 1); + + var sprites = type.Variants[t.Variant]; + var frame = int2.Lerp(0, sprites.Length - 1, t.Density - 1, type.Info.MaxDensity); + t.Sprite = sprites[frame]; + + return t; + } + + public void Render(WorldRenderer wr) + { + if (wr.World.Type != WorldType.Editor) + return; + + foreach (var c in Dirty) + Tiles[c] = UpdateDirtyTile(c); + + Dirty.Clear(); + + foreach (var uv in wr.Viewport.VisibleCells.MapCoords) + { + var t = Tiles[uv]; + if (t.Sprite != null) + new SpriteRenderable(t.Sprite, wr.World.Map.CenterOfCell(uv.ToCPos(Map)), + WVec.Zero, -511, t.Type.Palette, 1f, true).Render(wr); + } + } + } +} diff --git a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs index da226d769b..cff197e5b2 100644 --- a/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/ResourceLayer.cs @@ -248,6 +248,7 @@ namespace OpenRA.Mods.Common.Traits public struct CellContents { + public static readonly CellContents Empty = new CellContents(); public ResourceType Type; public int Density; public string Variant; diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs index 3b060bf450..eb6b21c99f 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs @@ -102,8 +102,9 @@ namespace OpenRA.Mods.Common.Widgets { leaveButton.Disabled = true; - Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", - world.LocalPlayer == null ? null : world.LocalPlayer.Country.Race); + if (world.Type == WorldType.Regular) + Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", + world.LocalPlayer == null ? null : world.LocalPlayer.Country.Race); var exitDelay = 1200; if (mpe != null) diff --git a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj index 08e23c5c17..a951482a96 100644 --- a/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj +++ b/OpenRA.Mods.D2k/OpenRA.Mods.D2k.csproj @@ -90,6 +90,7 @@ + diff --git a/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs b/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs new file mode 100644 index 0000000000..c44441ed6a --- /dev/null +++ b/OpenRA.Mods.D2k/Traits/World/D2kEditorResourceLayer.cs @@ -0,0 +1,96 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 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. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.D2k.Traits +{ + using CellContents = D2kResourceLayer.CellContents; + using ClearSides = D2kResourceLayer.ClearSides; + + [Desc("Used to render spice with round borders.")] + public class D2kEditorResourceLayerInfo : EditorResourceLayerInfo + { + public override object Create(ActorInitializer init) { return new D2kEditorResourceLayer(init.Self); } + } + + public class D2kEditorResourceLayer : EditorResourceLayer + { + public D2kEditorResourceLayer(Actor self) + : base(self) { } + + public override CellContents UpdateDirtyTile(CPos c) + { + var t = Tiles[c]; + + // Empty tile + if (t.Type == null) + { + t.Sprite = null; + return t; + } + + int index; + var clear = FindClearSides(t.Type, c); + if (clear == ClearSides.None) + { + var sprites = D2kResourceLayer.Variants[t.Variant]; + var frame = t.Density > t.Type.Info.MaxDensity / 2 ? 1 : 0; + t.Sprite = t.Type.Variants.First().Value[sprites[frame]]; + } + else if (D2kResourceLayer.SpriteMap.TryGetValue(clear, out index)) + t.Sprite = t.Type.Variants.First().Value[index]; + else + t.Sprite = null; + + return t; + } + + protected override string ChooseRandomVariant(ResourceType t) + { + return D2kResourceLayer.Variants.Keys.Random(Game.CosmeticRandom); + } + + ClearSides FindClearSides(ResourceType t, CPos p) + { + var ret = ClearSides.None; + if (Tiles[p + new CVec(0, -1)].Type != t) + ret |= ClearSides.Top | ClearSides.TopLeft | ClearSides.TopRight; + + if (Tiles[p + new CVec(-1, 0)].Type != t) + ret |= ClearSides.Left | ClearSides.TopLeft | ClearSides.BottomLeft; + + if (Tiles[p + new CVec(1, 0)].Type != t) + ret |= ClearSides.Right | ClearSides.TopRight | ClearSides.BottomRight; + + if (Tiles[p + new CVec(0, 1)].Type != t) + ret |= ClearSides.Bottom | ClearSides.BottomLeft | ClearSides.BottomRight; + + if (Tiles[p + new CVec(-1, -1)].Type != t) + ret |= ClearSides.TopLeft; + + if (Tiles[p + new CVec(1, -1)].Type != t) + ret |= ClearSides.TopRight; + + if (Tiles[p + new CVec(-1, 1)].Type != t) + ret |= ClearSides.BottomLeft; + + if (Tiles[p + new CVec(1, 1)].Type != t) + ret |= ClearSides.BottomRight; + + return ret; + } + } +} diff --git a/OpenRA.Mods.D2k/Traits/World/D2kResourceLayer.cs b/OpenRA.Mods.D2k/Traits/World/D2kResourceLayer.cs index 070cab02f7..dce447e39c 100644 --- a/OpenRA.Mods.D2k/Traits/World/D2kResourceLayer.cs +++ b/OpenRA.Mods.D2k/Traits/World/D2kResourceLayer.cs @@ -21,7 +21,7 @@ namespace OpenRA.Mods.D2k.Traits public class D2kResourceLayer : ResourceLayer { - [Flags] enum ClearSides : byte + [Flags] public enum ClearSides : byte { None = 0x0, Left = 0x1, @@ -37,7 +37,7 @@ namespace OpenRA.Mods.D2k.Traits All = 0xFF } - static readonly Dictionary Variants = new Dictionary() + public static readonly Dictionary Variants = new Dictionary() { { "cleara", new[] { 0, 50 } }, { "clearb", new[] { 1, 51 } }, @@ -45,7 +45,7 @@ namespace OpenRA.Mods.D2k.Traits { "cleard", new[] { 0, 53 } }, }; - static readonly Dictionary SpriteMap = new Dictionary() + public static readonly Dictionary SpriteMap = new Dictionary() { { ClearSides.None, 0 }, { ClearSides.Left | ClearSides.Top | ClearSides.TopLeft | ClearSides.TopRight | ClearSides.BottomLeft | ClearSides.BottomRight, 2 }, diff --git a/mods/cnc/rules/world.yaml b/mods/cnc/rules/world.yaml index 67426dead2..772c8218b8 100644 --- a/mods/cnc/rules/world.yaml +++ b/mods/cnc/rules/world.yaml @@ -1,17 +1,8 @@ -World: +^BaseWorld: Inherits: ^Palettes - ChatCommands: - DevCommands: - PlayerCommands: - HelpCommand: ScreenMap: ActorMap: - LoadWidgetAtGameStart: - ShellmapRoot: MENU_BACKGROUND - ScreenShaker: - BuildingInfluence: - BridgeLayer: - Bridges: bridge1, bridge2, bridge3, bridge4 + TerrainGeometryOverlay: ShroudRenderer: ShroudVariants: typea, typeb, typec, typed FogVariants: typea, typeb, typec, typed @@ -30,18 +21,6 @@ World: Name: Nod Race: nod Description: Brotherhood of Nod\nThe Brotherhood is a religious cult centered around their leader Kane\nand the alien substance Tiberium. They utilize stealth technology\nand guerilla tactics to defeat those who oppose them. - ProductionQueueFromSelection: - ProductionTabsWidget: PRODUCTION_TABS - DomainIndex: - SmudgeLayer@SCORCH: - Type: Scorch - Sequence: scorches - SmokePercentage: 50 - SmudgeLayer@CRATER: - Type: Crater - Sequence: craters - ResourceLayer: - ResourceClaimLayer: ResourceType@green-tib: ResourceType: 1 Palette: staticterrain @@ -66,8 +45,33 @@ World: PipColor: Blue AllowedTerrainTypes: Clear,Road AllowUnderActors: true + LoadWidgetAtGameStart: + ShellmapRoot: MENU_BACKGROUND + +World: + Inherits: ^BaseWorld + ChatCommands: + DevCommands: + PlayerCommands: + HelpCommand: + ScreenShaker: + NukePaletteEffect: + BuildingInfluence: + BridgeLayer: + Bridges: bridge1, bridge2, bridge3, bridge4 + ProductionQueueFromSelection: + ProductionTabsWidget: PRODUCTION_TABS + DomainIndex: + SmudgeLayer@SCORCH: + Type: Scorch + Sequence: scorches + SmokePercentage: 50 + SmudgeLayer@CRATER: + Type: Crater + Sequence: craters + ResourceLayer: + ResourceClaimLayer: PathfinderDebugOverlay: - TerrainGeometryOverlay: SpawnMapActors: MPStartLocations: CreateMPPlayers: @@ -143,3 +147,7 @@ World: PanelName: SKIRMISH_STATS RadarPings: +EditorWorld: + Inherits: ^BaseWorld + EditorActorLayer: + EditorResourceLayer: diff --git a/mods/d2k/rules/world.yaml b/mods/d2k/rules/world.yaml index bdaab89409..26f85db217 100644 --- a/mods/d2k/rules/world.yaml +++ b/mods/d2k/rules/world.yaml @@ -1,23 +1,8 @@ -World: +^BaseWorld: Inherits: ^Palettes - ChatCommands: - DevCommands: - PlayerCommands: - HelpCommand: ScreenMap: ActorMap: - LoadWidgetAtGameStart: - ScreenShaker: - BuildingInfluence: - ProductionQueueFromSelection: - ProductionPaletteWidget: PRODUCTION_PALETTE - WormManager: - CrateSpawner: - Minimum: 0 - Maximum: 2 - SpawnInterval: 60 - WaterChance: 0 - ValidGround: Sand, Dune, Rock + TerrainGeometryOverlay: ShroudRenderer: ShroudVariants: typea, typeb, typec, typed FogVariants: typea, typeb, typec, typed @@ -46,12 +31,6 @@ World: Name: Corrino Race: corrino Selectable: false - DomainIndex: - PathfinderDebugOverlay: - BuildableTerrainLayer: - D2kResourceLayer: - TerrainGeometryOverlay: - ResourceClaimLayer: ResourceType@Spice: ResourceType: 1 Palette: d2k @@ -64,6 +43,30 @@ World: PipColor: green AllowedTerrainTypes: Sand AllowUnderActors: true + LoadWidgetAtGameStart: + +World: + Inherits: ^BaseWorld + ChatCommands: + DevCommands: + PlayerCommands: + HelpCommand: + ScreenShaker: + BuildingInfluence: + ProductionQueueFromSelection: + ProductionPaletteWidget: PRODUCTION_PALETTE + WormManager: + CrateSpawner: + Minimum: 0 + Maximum: 2 + SpawnInterval: 60 + WaterChance: 0 + ValidGround: Sand, Dune, Rock + DomainIndex: + PathfinderDebugOverlay: + BuildableTerrainLayer: + D2kResourceLayer: + ResourceClaimLayer: SmudgeLayer@Rock: Type: RockCrater Sequence: rockcraters @@ -135,3 +138,8 @@ World: RadarPings: ObjectivesPanel: PanelName: SKIRMISH_STATS + +EditorWorld: + Inherits: ^BaseWorld + EditorActorLayer: + D2kEditorResourceLayer: diff --git a/mods/ra/rules/world.yaml b/mods/ra/rules/world.yaml index 5bf84686a4..4b92667286 100644 --- a/mods/ra/rules/world.yaml +++ b/mods/ra/rules/world.yaml @@ -1,25 +1,9 @@ -World: +^BaseWorld: Inherits: ^Palettes - ChatCommands: - DevCommands: - PlayerCommands: - HelpCommand: - ScreenMap: ActorMap: + ScreenMap: + TerrainGeometryOverlay: LoadWidgetAtGameStart: - ScreenShaker: - BuildingInfluence: - ProductionQueueFromSelection: - ProductionPaletteWidget: PRODUCTION_PALETTE - BridgeLayer: - Bridges: bridge1, bridge2, br1, br2, br3, sbridge1, sbridge2, sbridge3, sbridge4 - CrateSpawner: - DeliveryAircraft: badr - QuantizedFacings: 16 - Minimum: 1 - Maximum: 3 - SpawnInterval: 120 - WaterChance: .2 ShroudRenderer: FogVariants: shroud Index: 255, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 20, 40, 56, 65, 97, 130, 148, 194, 24, 33, 66, 132, 28, 41, 67, 134, 1, 2, 4, 8, 3, 6, 12, 9, 7, 14, 13, 11, 5, 10, 15, 255 @@ -77,16 +61,6 @@ World: RandomRaceMembers: russia, ukraine Side: Random Description: A random Soviet country. - DomainIndex: - SmudgeLayer@SCORCH: - Type: Scorch - Sequence: scorches - SmokePercentage: 50 - SmudgeLayer@CRATER: - Type: Crater - Sequence: craters - ResourceLayer: - ResourceClaimLayer: ResourceType@ore: ResourceType: 1 Palette: player @@ -111,8 +85,37 @@ World: AllowedTerrainTypes: Clear,Road AllowUnderActors: true TerrainType: Gems + +World: + Inherits: ^BaseWorld + ChatCommands: + DevCommands: + PlayerCommands: + HelpCommand: + ScreenShaker: + BuildingInfluence: + ProductionQueueFromSelection: + ProductionPaletteWidget: PRODUCTION_PALETTE + BridgeLayer: + Bridges: bridge1, bridge2, br1, br2, br3, sbridge1, sbridge2, sbridge3, sbridge4 + CrateSpawner: + DeliveryAircraft: badr + QuantizedFacings: 16 + Minimum: 1 + Maximum: 3 + SpawnInterval: 120 + WaterChance: .2 + DomainIndex: + SmudgeLayer@SCORCH: + Type: Scorch + Sequence: scorches + SmokePercentage: 50 + SmudgeLayer@CRATER: + Type: Crater + Sequence: craters + ResourceLayer: + ResourceClaimLayer: PathfinderDebugOverlay: - TerrainGeometryOverlay: SpawnMapActors: CreateMPPlayers: MPStartUnits@mcvonly: @@ -162,3 +165,7 @@ World: ObjectivesPanel: PanelName: SKIRMISH_STATS +EditorWorld: + Inherits: ^BaseWorld + EditorActorLayer: + EditorResourceLayer: diff --git a/mods/ts/rules/world.yaml b/mods/ts/rules/world.yaml index afbbc93f43..d6beedbf5f 100644 --- a/mods/ts/rules/world.yaml +++ b/mods/ts/rules/world.yaml @@ -1,15 +1,8 @@ -World: +^BaseWorld: Inherits: ^Palettes - ChatCommands: - DevCommands: - PlayerCommands: - HelpCommand: ScreenMap: ActorMap: LoadWidgetAtGameStart: - BuildingInfluence: - ProductionQueueFromSelection: - ProductionPaletteWidget: PRODUCTION_PALETTE ShroudRenderer: Index: 255, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 20, 40, 56, 65, 97, 130, 148, 194, 24, 33, 66, 132, 28, 41, 67, 134, 1, 2, 4, 8, 3, 6, 12, 9, 7, 14, 13, 11, 5, 10, 15, 255 UseExtendedIndex: true @@ -25,6 +18,41 @@ World: Country@1: Name: Nod Race: nod + ResourceType@Tiberium: + ResourceType: 1 + Palette: greentiberium + EditorSprite: waypoint # TODO: editor can't handle the real ones + Variants: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12, tib13, tib14, tib15, tib16, tib17, tib18, tib19, tib20 + MaxDensity: 12 + ValuePerUnit: 50 + Name: Tiberium + PipColor: Green + AllowedTerrainTypes: Clear, Rough, DirtRoad + AllowUnderActors: true + TerrainType: Tiberium + ResourceType@BlueTiberium: + ResourceType: 2 + Palette: bluetiberium + EditorSprite: waypoint # TODO: editor can't handle the real ones + Variants: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12, tib13, tib14, tib15, tib16, tib17, tib18, tib19, tib20 + MaxDensity: 12 + ValuePerUnit: 100 + Name: BlueTiberium + PipColor: Blue + AllowedTerrainTypes: Clear, Rough, DirtRoad + AllowUnderActors: true + TerrainType: BlueTiberium + TerrainGeometryOverlay: + +World: + Inherits: ^BaseWorld + ChatCommands: + DevCommands: + PlayerCommands: + HelpCommand: + BuildingInfluence: + ProductionQueueFromSelection: + ProductionPaletteWidget: PRODUCTION_PALETTE DomainIndex: SmudgeLayer@SMALLSCORCH: Type: SmallScorch @@ -55,32 +83,7 @@ World: Sequence: largecraters ResourceLayer: ResourceClaimLayer: - ResourceType@Tiberium: - ResourceType: 1 - Palette: greentiberium - EditorSprite: waypoint # TODO: editor can't handle the real ones - Variants: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12, tib13, tib14, tib15, tib16, tib17, tib18, tib19, tib20 - MaxDensity: 12 - ValuePerUnit: 50 - Name: Tiberium - PipColor: Green - AllowedTerrainTypes: Clear, Rough, DirtRoad - AllowUnderActors: true - TerrainType: Tiberium - ResourceType@BlueTiberium: - ResourceType: 2 - Palette: bluetiberium - EditorSprite: waypoint # TODO: editor can't handle the real ones - Variants: tib01, tib02, tib03, tib04, tib05, tib06, tib07, tib08, tib09, tib10, tib11, tib12, tib13, tib14, tib15, tib16, tib17, tib18, tib19, tib20 - MaxDensity: 12 - ValuePerUnit: 100 - Name: BlueTiberium - PipColor: Blue - AllowedTerrainTypes: Clear, Rough, DirtRoad - AllowUnderActors: true - TerrainType: BlueTiberium PathfinderDebugOverlay: - TerrainGeometryOverlay: SpawnMapActors: CreateMPPlayers: MPStartUnits@MCV: @@ -151,3 +154,7 @@ World: RadarPings: StartGameNotification: +EditorWorld: + Inherits: ^BaseWorld + EditorActorLayer: + EditorResourceLayer: