diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d07f90..3a8e1dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,6 +4,9 @@ on: push: pull_request: +permissions: + contents: read # to fetch code (actions/checkout) + jobs: linux: name: Linux (.NET 6.0) @@ -11,10 +14,10 @@ jobs: steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Install .NET 6.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.0.x' @@ -46,7 +49,7 @@ jobs: steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Prepare Environment run: | @@ -66,14 +69,14 @@ jobs: windows: name: Windows (.NET 6.0) - runs-on: windows-2019 + runs-on: windows-2022 steps: - name: Clone Repository - uses: actions/checkout@v3 + uses: actions/checkout@v6 - name: Install .NET 6.0 - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v5 with: dotnet-version: '6.0.x' @@ -94,7 +97,7 @@ jobs: - name: Check Mods run: | - choco install lua --version 5.1.5.52 + choco install lua --version 5.1.5.52 --no-progress $ENV:Path = $ENV:Path + ";C:\Program Files (x86)\Lua\5.1\" .\make.ps1 check-scripts .\make.ps1 test diff --git a/OpenRA.Mods.D2/FileFormats/WsaReader.cs b/OpenRA.Mods.D2/FileFormats/WsaReader.cs index 23ca1e5..85cbbb8 100644 --- a/OpenRA.Mods.D2/FileFormats/WsaReader.cs +++ b/OpenRA.Mods.D2/FileFormats/WsaReader.cs @@ -19,16 +19,13 @@ namespace OpenRA.Mods.D2.FileFormats { public class WsaReader { - int width; - int height; - int currentFrame; ISpriteFrame[] frames; public int Length { get { return frames == null ? 0 : frames.Length; } } - public int CurrentFrame { get { return currentFrame; } } + public int CurrentFrame { get; private set; } public ISpriteFrame Frame { get { return CurrentSpriteFrame(); } } - public int Width { get { return width; } } - public int Height { get { return height; } } + public int Width { get; private set; } + public int Height { get; private set; } public WsaReader() { @@ -38,24 +35,19 @@ public WsaReader() public WsaReader(Stream stream) { - TypeDictionary metadata; - - Read(stream, out metadata); + Read(stream, out _); Reset(); } public void Read(Stream stream, out TypeDictionary metadata) { - ISpriteFrame[] videoFrames; ISpriteFrame prev = null; var wsaLoader = new WsaLoader(); - metadata = null; - if (frames != null) - prev = frames[frames.Length - 1]; + prev = frames[^1]; - wsaLoader.TryParseSpriteWithPrevFrame(stream, prev, out videoFrames, out metadata); + wsaLoader.TryParseSpriteWithPrevFrame(stream, prev, out var videoFrames, out metadata); if (frames == null) { @@ -64,8 +56,8 @@ public void Read(Stream stream, out TypeDictionary metadata) if (Length > 0) { var frame = frames[0]; - width = frame.Size.Width; - height = frame.Size.Height; + Width = frame.Size.Width; + Height = frame.Size.Height; } } else @@ -74,21 +66,21 @@ public void Read(Stream stream, out TypeDictionary metadata) public void Reset() { - currentFrame = 0; + CurrentFrame = 0; } public void AdvanceFrame() { - if (frames != null && currentFrame < frames.Length - 1) - currentFrame++; + if (frames != null && CurrentFrame < frames.Length - 1) + CurrentFrame++; else - currentFrame = 0; + CurrentFrame = 0; } ISpriteFrame CurrentSpriteFrame() { - if (frames != null && currentFrame < frames.Length) - return frames[currentFrame]; + if (frames != null && CurrentFrame < frames.Length) + return frames[CurrentFrame]; return null; } diff --git a/OpenRA.Mods.D2/Graphics/D2BuildingPlacementRenderable.cs b/OpenRA.Mods.D2/Graphics/D2BuildingPlacementRenderable.cs index fe5f660..60e6800 100644 --- a/OpenRA.Mods.D2/Graphics/D2BuildingPlacementRenderable.cs +++ b/OpenRA.Mods.D2/Graphics/D2BuildingPlacementRenderable.cs @@ -14,9 +14,8 @@ namespace OpenRA.Mods.D2.Graphics { - public struct D2BuildingPlacementRenderable : IRenderable, IFinalizedRenderable + public readonly struct D2BuildingPlacementRenderable : IRenderable, IFinalizedRenderable { - readonly WPos pos; readonly Rectangle bounds; readonly Color color; readonly bool crossEnabled; @@ -26,13 +25,13 @@ public D2BuildingPlacementRenderable(Actor actor, Rectangle bounds, Color color, public D2BuildingPlacementRenderable(WPos pos, Rectangle bounds, Color color, bool crossEnabled) { - this.pos = pos; + Pos = pos; this.bounds = bounds; this.color = color; this.crossEnabled = crossEnabled; } - public WPos Pos { get { return pos; } } + public WPos Pos { get; } public PaletteReference Palette { get { return null; } } public int ZOffset { get { return 0; } } @@ -40,7 +39,7 @@ public D2BuildingPlacementRenderable(WPos pos, Rectangle bounds, Color color, bo public IRenderable WithPalette(PaletteReference newPalette) { return this; } public IRenderable WithZOffset(int newOffset) { return this; } - public IRenderable OffsetBy(in WVec vec) { return new D2BuildingPlacementRenderable(pos + vec, bounds, color, crossEnabled); } + public IRenderable OffsetBy(in WVec vec) { return new D2BuildingPlacementRenderable(Pos + vec, bounds, color, crossEnabled); } public IRenderable AsDecoration() { return this; } public IFinalizedRenderable PrepareRender(WorldRenderer wr) { return this; } @@ -50,14 +49,14 @@ public void Render(WorldRenderer wr) var rect = ScreenBounds(wr); var tl = new float3(rect.Left, rect.Top, 1024.0f); var br = new float3(rect.Right, rect.Bottom, 1024.0f); - var width = 1.0f; - Game.Renderer.WorldRgbaColorRenderer.DrawRect(tl, br, width, color); + const float Width = 1.0f; + Game.Renderer.WorldRgbaColorRenderer.DrawRect(tl, br, Width, color); if (crossEnabled) { - Game.Renderer.WorldRgbaColorRenderer.DrawLine(tl, br, width, color); + Game.Renderer.WorldRgbaColorRenderer.DrawLine(tl, br, Width, color); var tr = new float3(br.X, tl.Y, 1024.0f); var bl = new float3(tl.X, br.Y, 1024.0f); - Game.Renderer.WorldRgbaColorRenderer.DrawLine(tr, bl, width, color); + Game.Renderer.WorldRgbaColorRenderer.DrawLine(tr, bl, Width, color); } } @@ -65,8 +64,8 @@ public void RenderDebugGeometry(WorldRenderer wr) { } public Rectangle ScreenBounds(WorldRenderer wr) { - var tl = new WPos(pos.X + bounds.Left, pos.Y + bounds.Top - 1, 0); - var br = new WPos(pos.X + bounds.Right, pos.Y + bounds.Bottom - 1, 0); + var tl = new WPos(Pos.X + bounds.Left, Pos.Y + bounds.Top - 1, 0); + var br = new WPos(Pos.X + bounds.Right, Pos.Y + bounds.Bottom - 1, 0); var tlOffset = wr.ScreenPxPosition(tl); var brOffset = wr.ScreenPxPosition(br); diff --git a/OpenRA.Mods.D2/Graphics/D2ChromeProvider.cs b/OpenRA.Mods.D2/Graphics/D2ChromeProvider.cs index 20cbd6e..c48f200 100644 --- a/OpenRA.Mods.D2/Graphics/D2ChromeProvider.cs +++ b/OpenRA.Mods.D2/Graphics/D2ChromeProvider.cs @@ -155,15 +155,10 @@ static ISpriteFrame LoadSpriteFrame(Stream stream) { foreach (var loader in Game.ModData.SpriteLoaders) { - ISpriteFrame[] frames; - TypeDictionary metadata; - if (loader.TryParseSprite(stream, string.Empty, out frames, out metadata)) + if (loader.TryParseSprite(stream, string.Empty, out var frames, out _) && frames.Length > 0) { - if (frames.Length > 0) - { - // Will use only first frame if multiple frames available - return frames[0]; - } + // Will use only first frame if multiple frames available + return frames[0]; } } diff --git a/OpenRA.Mods.D2/ImportData/D2ImportOriginalMaps.cs b/OpenRA.Mods.D2/ImportData/D2ImportOriginalMaps.cs index ab80f5a..21f3b60 100644 --- a/OpenRA.Mods.D2/ImportData/D2ImportOriginalMaps.cs +++ b/OpenRA.Mods.D2/ImportData/D2ImportOriginalMaps.cs @@ -20,7 +20,7 @@ public static class D2ImportOriginalMaps { public static int ImportOriginalMaps(ModData modData, Dictionary info) { - string[] files = Array.Empty(); + var files = Array.Empty(); var unpackedFilesCount = 0; if (info.ContainsKey("OriginalMaps")) @@ -49,18 +49,16 @@ public static int ImportOriginalMaps(ModData modData, Dictionary var mapFilename = Path.Combine(originalPath, Path.GetFileNameWithoutExtension(filename) + ".oramap"); try { - if (!File.Exists(mapFilename)) + if (!File.Exists(mapFilename) && modData.DefaultFileSystem.Exists(filename)) { - if (modData.DefaultFileSystem.Exists(filename)) - { - var rules = Ruleset.LoadDefaults(modData); - var map = D2MapImporter.Import(filename, modData.Manifest.Id, "arrakis2", rules); + var rules = Ruleset.LoadDefaults(modData); + var map = D2MapImporter.Import(filename, modData.Manifest.Id, "arrakis2", rules); - if (map != null) - { - map.Save(ZipFileLoader.Create(mapFilename)); - Console.WriteLine("Original map {0} saved to {1}", filename, mapFilename); - } + if (map != null) + { + map.Save(ZipFileLoader.Create(mapFilename)); + unpackedFilesCount++; + Console.WriteLine("Original map {0} saved to {1}", filename, mapFilename); } } } diff --git a/OpenRA.Mods.D2/ImportData/D2MapImporter.cs b/OpenRA.Mods.D2/ImportData/D2MapImporter.cs index 4adf6c4..54e4ba7 100644 --- a/OpenRA.Mods.D2/ImportData/D2MapImporter.cs +++ b/OpenRA.Mods.D2/ImportData/D2MapImporter.cs @@ -25,12 +25,9 @@ namespace OpenRA.Mods.D2.ImportData { - public class D2MapImporter + public sealed class D2MapImporter { - readonly Ruleset rules; readonly IniFile iniFile; - readonly string tilesetName; - readonly TerrainTile clearTile; Map map; Size mapSize; @@ -40,18 +37,14 @@ public class D2MapImporter ushort[] m; D2MapSeed seed; - D2MapImporter(string filename, string tileset, Ruleset rules) + D2MapImporter(string filename) { - tilesetName = tileset; - this.rules = rules; - try { - clearTile = new TerrainTile(0, 0); using (var stream = Game.ModData.DefaultFileSystem.Open(filename)) { if (stream.Length == 0) - throw new ArgumentException("The map is in an unrecognized format!", "filename"); + throw new ArgumentException("The map is in an unrecognized format!", nameof(filename)); iniFile = new IniFile(stream); @@ -82,7 +75,7 @@ public class D2MapImporter public static Map Import(string filename, string mod, string tileset, Ruleset rules) { - var importer = new D2MapImporter(filename, tileset, rules); + var importer = new D2MapImporter(filename); var map = importer.map; if (map == null) return null; @@ -102,8 +95,7 @@ void Initialize(string mapFile) */ var mapScaleValue = iniFile.GetSection("BASIC").GetValue("MapScale", "0"); - var mapScale = 0; - int.TryParse(mapScaleValue, out mapScale); + int.TryParse(mapScaleValue, out var mapScale); mapSize = new Size(64, 64); m = new ushort[64 * 64]; @@ -247,9 +239,12 @@ void CreateMapPlayers() /* Initialises every fourth x/y tile in the map. */ void MakeRoughLandscape() { - byte[] memory = new byte[273]; - ushort i = 0; - + /* The first 16 * 16 entries become the rough 4-tile grid. + * The original algorithm also clamps neighbour offsets to 272 + * inclusive, so keep the extra entries as edge/sentinel storage. + */ + var memory = new byte[273]; + ushort i; for (i = 0; i < 272; i++) { memory[i] = (byte)(seed.Random() & 0xF); @@ -342,8 +337,8 @@ void AverageRoughLandscape() /* Average a tile and its immediate neighbours. */ void Average() { - ushort[] currRow = new ushort[64]; - ushort[] prevRow = new ushort[64]; + var currRow = new ushort[64]; + var prevRow = new ushort[64]; for (var j = 0; j < 64; j++) { @@ -351,7 +346,7 @@ void Average() Array.Copy(currRow, prevRow, currRow.Length); for (var i = 0; i < 64; i++) - currRow[i] = (ushort)(m[d + i]); + currRow[i] = m[d + i]; for (var i = 0; i < 64; i++) { @@ -363,9 +358,9 @@ void Average() sum += (i == 0) ? currRow[i] : currRow[i - 1]; sum += currRow[i]; sum += (i == 63) ? currRow[i] : currRow[i + 1]; - sum += (i == 0 || j == 63) ? currRow[i] : (ushort)(m[d + i + 63]); - sum += (j == 63) ? currRow[i] : (ushort)(m[d + i + 64]); - sum += (i == 63 || j == 63) ? currRow[i] : (ushort)(m[d + i + 65]); + sum += (i == 0 || j == 63) ? currRow[i] : m[d + i + 63]; + sum += (j == 63) ? currRow[i] : m[d + i + 64]; + sum += (i == 63 || j == 63) ? currRow[i] : m[d + i + 65]; m[d + i] = (ushort)(sum / 9); } @@ -438,8 +433,8 @@ TilePos MoveByRandom(TilePos pos, int distance) newDistance /= 2; var orient256 = seed.Random(); - var x = pos.X + ((stepX[orient256] * newDistance * 16) / 128); - var y = pos.Y - ((stepY[orient256] * newDistance * 16) / 128); + var x = pos.X + stepX[orient256] * newDistance * 16 / 128; + var y = pos.Y - stepY[orient256] * newDistance * 16 / 128; /* Out of map size check: 64 * 256 = 16384 */ if (x > 16384 || y > 16384) @@ -453,7 +448,7 @@ TilePos MoveByRandom(TilePos pos, int distance) bool IsOutOfMap(CPos pos) { - return (pos.X < 0 || pos.X >= map.MapSize.X || pos.Y < 0 || pos.Y >= map.MapSize.Y); + return pos.X < 0 || pos.X >= map.MapSize.X || pos.Y < 0 || pos.Y >= map.MapSize.Y; } /* Creates a spice field of the given radius at the given location. */ @@ -487,11 +482,8 @@ void CreateSpiceField(CPos pos, int radius, bool centerIsThickSpice) { if (map.Resources[coord].Index == 2) map.Resources[coord] = new ResourceTile(1, 2); - else - { - if (tile == D2MapUtils.SandTile) - map.Resources[coord] = new ResourceTile(1, 1); - } + else if (tile == D2MapUtils.SandTile) + map.Resources[coord] = new ResourceTile(1, 1); } } } @@ -502,15 +494,15 @@ void CreateSpiceField(CPos pos, int radius, bool centerIsThickSpice) public static bool CanBecomeSpice(ushort tileType) { - return (tileType == D2MapUtils.SandTile || tileType == D2MapUtils.DuneTile); + return tileType == D2MapUtils.SandTile || tileType == D2MapUtils.DuneTile; } /* Adds spice fields to the map. */ void AddSpice(uint minSpiceFields, uint maxSpiceFields) { - const uint maxCount = 65535; + const uint MaxCount = 65535; var count = 0; - var i = 0L; + long i; /* ENHANCEMENT: spice field controls. */ if ((minSpiceFields == 0) && (maxSpiceFields == 0)) @@ -521,15 +513,15 @@ void AddSpice(uint minSpiceFields, uint maxSpiceFields) var b = Math.Min(maxSpiceFields, 255); minSpiceFields = Math.Min(a, b); maxSpiceFields = Math.Max(a, b); - var range = (maxSpiceFields - minSpiceFields + 1); + var range = maxSpiceFields - minSpiceFields + 1; - i = (int)(seed.Random()) * range / 256 + minSpiceFields; + i = (int)seed.Random() * range / 256 + minSpiceFields; } while (i-- != 0) { - ushort y = 0; - ushort x = 0; + ushort y; + ushort x; while (true) { @@ -543,20 +535,20 @@ void AddSpice(uint minSpiceFields, uint maxSpiceFields) /* ENHANCEMENT: ensure termination. */ count++; - if (count > maxCount) + if (count > MaxCount) return; } var x1 = ((x & 0x3F) << 8) | 0x80; var y1 = ((y & 0x3F) << 8) | 0x80; - var j = (ushort)seed.Random() & 0x1F; + var j = seed.Random() & 0x1F; while (j-- != 0) { CPos coord; - while (true) + do { var dist = seed.Random() & 0x3F; @@ -566,17 +558,11 @@ void AddSpice(uint minSpiceFields, uint maxSpiceFields) var y2 = (pos.Y >> 8) & 0x3F; coord = new CPos(x2, y2); - - if (!IsOutOfMap(coord)) - break; } + while (IsOutOfMap(coord)); - var tile = m[PackXY((ushort)coord.X, (ushort)coord.Y)]; - - if (map.Resources[coord].Type == 1) - CreateSpiceField(coord, 2, true); - else - CreateSpiceField(coord, 1, true); + var radius = map.Resources[coord].Type == 1 ? 2 : 1; + CreateSpiceField(coord, radius, true); } } } @@ -642,8 +628,7 @@ void CreateLandscape(uint seed, uint minSpiceFields, uint maxSpiceFields) void FillMap() { var seedStr = iniFile.GetSection("MAP").GetValue("Seed", "0"); - var seedValue = 0U; - uint.TryParse(seedStr, out seedValue); + uint.TryParse(seedStr, out var seedValue); CreateLandscape(seedValue, 0, 0); } @@ -655,13 +640,12 @@ void AddAdditionalSpiceFields() foreach (var field in fields) { var str = field.Trim(); - ushort fieldPacked = 0; - ushort.TryParse(str, out fieldPacked); + ushort.TryParse(str, out var fieldPacked); var x = PackedX(fieldPacked); var y = PackedY(fieldPacked); - CPos pos = new CPos(x, y); + var pos = new CPos(x, y); CreateSpiceField(pos, 5, true); } @@ -687,8 +671,7 @@ void AddBloom() foreach (var bloom in blooms) { var str = bloom.Trim(); - ushort bloomPacked = 0; - ushort.TryParse(str, out bloomPacked); + ushort.TryParse(str, out var bloomPacked); var x = PackedX(bloomPacked); var y = PackedY(bloomPacked); @@ -721,22 +704,22 @@ void AddSpawnPoints() { var value = structure.Value; var substrs = value.Split(','); - if (substrs.Length >= 4) - { - var structureType = substrs[1]; - if (structureType.ToLower() == "const yard") - { - var positionStr = substrs[3].Trim(); - ushort packed = 0; - ushort.TryParse(positionStr, out packed); + /* Structure records must include the packed map position in the fourth field. */ + var hasPackedPosition = substrs.Length >= 4; - var x = PackedX(packed); - var y = PackedY(packed); + /* Original Dune II maps use Const Yard records as multiplayer spawn points. */ + var isConstructionYard = string.Equals(substrs[1], "const yard", StringComparison.OrdinalIgnoreCase); + if (!hasPackedPosition || !isConstructionYard) + continue; - CreateSpawnPoint(new CPos(x, y)); - playerCount++; - } - } + var positionStr = substrs[3].Trim(); + ushort.TryParse(positionStr, out var packed); + + var x = PackedX(packed); + var y = PackedY(packed); + + CreateSpawnPoint(new CPos(x, y)); + playerCount++; } } } diff --git a/OpenRA.Mods.D2/ImportData/D2MapSeed.cs b/OpenRA.Mods.D2/ImportData/D2MapSeed.cs index 624b6e8..3d05d38 100644 --- a/OpenRA.Mods.D2/ImportData/D2MapSeed.cs +++ b/OpenRA.Mods.D2/ImportData/D2MapSeed.cs @@ -24,7 +24,7 @@ public uint Seed { get { - return (uint)(seed[0]) + return seed[0] + (uint)(seed[1] << 8) + (uint)(seed[2] << 16) + (uint)(seed[3] << 24); diff --git a/OpenRA.Mods.D2/ImportData/D2UnpackContent.cs b/OpenRA.Mods.D2/ImportData/D2UnpackContent.cs index f5e1cb2..959de7e 100644 --- a/OpenRA.Mods.D2/ImportData/D2UnpackContent.cs +++ b/OpenRA.Mods.D2/ImportData/D2UnpackContent.cs @@ -19,7 +19,7 @@ public static class D2UnpackContent { public static int UnpackFiles(ModData modData, Dictionary info) { - string[] files = Array.Empty(); + var files = Array.Empty(); var unpackedFilesCount = 0; if (info.ContainsKey("UnpackFiles")) @@ -50,8 +50,8 @@ public static int UnpackFiles(ModData modData, Dictionary info) var explicitSplit = s.IndexOf(':'); if (explicitSplit > 0) { - originalFileName = s.Substring(0, explicitSplit).Trim(); - fileName = s.Substring(explicitSplit + 1).Trim(); + originalFileName = s[..explicitSplit].Trim(); + fileName = s[(explicitSplit + 1)..].Trim(); } try @@ -66,7 +66,7 @@ public static int UnpackFiles(ModData modData, Dictionary info) using (var fs = new FileStream(newFileName, FileMode.CreateNew, FileAccess.Write)) { stream.CopyTo(fs); - unpackedFilesCount += 1; + unpackedFilesCount++; Console.WriteLine("Successfully unpacked file: {0}", fileName); } } diff --git a/OpenRA.Mods.D2/LoadScreens/D2LoadScreen.cs b/OpenRA.Mods.D2/LoadScreens/D2LoadScreen.cs index 01ecf07..9b136be 100644 --- a/OpenRA.Mods.D2/LoadScreens/D2LoadScreen.cs +++ b/OpenRA.Mods.D2/LoadScreens/D2LoadScreen.cs @@ -114,10 +114,9 @@ public override void Init(ModData modData, Dictionary info) using (stream) { - CpsD2Loader loader = new CpsD2Loader(); - TypeDictionary metadata; + var loader = new CpsD2Loader(); - if (!loader.TryParseSprite(stream, string.Empty, out frames, out metadata)) + if (!loader.TryParseSprite(stream, string.Empty, out frames, out var metadata)) return; } diff --git a/OpenRA.Mods.D2/MapUtils/D2MapUtils.cs b/OpenRA.Mods.D2/MapUtils/D2MapUtils.cs index 8161720..0214ae2 100644 --- a/OpenRA.Mods.D2/MapUtils/D2MapUtils.cs +++ b/OpenRA.Mods.D2/MapUtils/D2MapUtils.cs @@ -65,7 +65,7 @@ public static ushort SmoothTileTypeForPos(ushort[] m, ushort width, ushort heigh if (tile == RockTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (x > 0) { @@ -113,7 +113,7 @@ public static ushort SmoothTileTypeForPos(ushort[] m, ushort width, ushort heigh if (tile == DuneTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (x > 0) { @@ -153,7 +153,7 @@ public static ushort SmoothTileTypeForPos(ushort[] m, ushort width, ushort heigh if (tile == RoughTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (x > 0) { @@ -200,7 +200,7 @@ public static ushort SmoothIndexForPos(CellLayer tiles, MPos pos) if (tile == RockTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (pos.U > 0) { @@ -248,7 +248,7 @@ public static ushort SmoothIndexForPos(CellLayer tiles, MPos pos) if (tile == DuneTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (pos.U > 0) { @@ -288,7 +288,7 @@ public static ushort SmoothIndexForPos(CellLayer tiles, MPos pos) if (tile == RoughTile) { - ClearSides clear = ClearSides.None; + var clear = ClearSides.None; if (pos.U > 0) { diff --git a/OpenRA.Mods.D2/SpriteLoaders/WsaLoader.cs b/OpenRA.Mods.D2/SpriteLoaders/WsaLoader.cs index 97afb51..e019817 100644 --- a/OpenRA.Mods.D2/SpriteLoaders/WsaLoader.cs +++ b/OpenRA.Mods.D2/SpriteLoaders/WsaLoader.cs @@ -81,7 +81,7 @@ bool IsWsa(Stream s) if (offsets[0] == 0) { - numTiles -= 1; + numTiles--; for (var i = 1; i <= numTiles; i++) offsets[i - 1] = offsets[i]; } diff --git a/OpenRA.Mods.D2/Traits/Buildings/D2Building.cs b/OpenRA.Mods.D2/Traits/Buildings/D2Building.cs index 2aadb03..3bbb4f1 100644 --- a/OpenRA.Mods.D2/Traits/Buildings/D2Building.cs +++ b/OpenRA.Mods.D2/Traits/Buildings/D2Building.cs @@ -179,49 +179,58 @@ protected override void AddedToWorld(Actor self) { base.AddedToWorld(self); - if (info.LaysOnConcrete) + if (info.LaysOnConcrete + && layer != null + && (info.ConcretePrerequisites.Length == 0 + || techTree == null + || techTree.HasPrerequisites(info.ConcretePrerequisites))) { - if (layer != null && (!info.ConcretePrerequisites.Any() || techTree == null || techTree.HasPrerequisites(info.ConcretePrerequisites))) - { - var map = self.World.Map; + var map = self.World.Map; - if (!(self.World.Map.Rules.TerrainInfo is ITemplatedTerrainInfo terrainInfo)) - throw new InvalidDataException("D2Building requires a template-based tileset."); + if (self.World.Map.Rules.TerrainInfo is not ITemplatedTerrainInfo terrainInfo) + throw new InvalidDataException("D2Building requires a template-based tileset."); - var template = terrainInfo.Templates[info.ConcreteTemplate]; - if (template.PickAny) + var template = terrainInfo.Templates[info.ConcreteTemplate]; + if (template.PickAny) + { + // Fill the footprint with random variants + foreach (var c in info.Tiles(self.Location)) { - // Fill the footprint with random variants - foreach (var c in info.Tiles(self.Location)) + // Only place on allowed terrain types + if (!map.Contains(c) + || map.CustomTerrain[c] != byte.MaxValue + || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) { - // Only place on allowed terrain types - if (!map.Contains(c) || map.CustomTerrain[c] != byte.MaxValue || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) - continue; + continue; + } - // Don't place under other buildings (or their bib) - if (bi.GetBuildingsAt(c).Any(a => a != self)) - continue; + // Don't place under other buildings (or their bib) + if (bi.GetBuildingsAt(c).Any(a => a != self)) + continue; - var index = Game.CosmeticRandom.Next(template.TilesCount); - layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); - } + var index = Game.CosmeticRandom.Next(template.TilesCount); + layer.AddTile(c, new TerrainTile(template.Id, (byte)index)); } - else + } + else + { + for (var i = 0; i < template.TilesCount; i++) { - for (var i = 0; i < template.TilesCount; i++) - { - var c = self.Location + new CVec(i % template.Size.X, i / template.Size.X); + var c = self.Location + new CVec(i % template.Size.X, i / template.Size.X); - // Only place on allowed terrain types - if (!map.Contains(c) || map.CustomTerrain[c] != byte.MaxValue || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) - continue; + // Only place on allowed terrain types + if (!map.Contains(c) + || map.CustomTerrain[c] != byte.MaxValue + || !info.TerrainTypes.Contains(map.GetTerrainInfo(c).Type)) + { + continue; + } - // Don't place under other buildings (or their bib) - if (bi.GetBuildingsAt(c).Any(a => a != self)) - continue; + // Don't place under other buildings (or their bib) + if (bi.GetBuildingsAt(c).Any(a => a != self)) + continue; - layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); - } + layer.AddTile(c, new TerrainTile(template.Id, (byte)i)); } } } diff --git a/OpenRA.Mods.D2/Traits/Buildings/D2PlaceBuildingPreview.cs b/OpenRA.Mods.D2/Traits/Buildings/D2PlaceBuildingPreview.cs index 17f42b1..de5f900 100644 --- a/OpenRA.Mods.D2/Traits/Buildings/D2PlaceBuildingPreview.cs +++ b/OpenRA.Mods.D2/Traits/Buildings/D2PlaceBuildingPreview.cs @@ -44,45 +44,42 @@ public class D2PlaceBuildingPreview { } public class D2PlaceBuildingPreviewPreview : FootprintPlaceBuildingPreviewPreview { - protected readonly D2PlaceBuildingPreviewInfo info; - protected readonly ActorInfo ai; - protected readonly D2BuildingInfo bi; + protected readonly D2PlaceBuildingPreviewInfo Info; + protected readonly D2BuildingInfo BuildingInfo; - protected readonly int cols; - protected readonly int rows; - protected readonly Rectangle bounds; + protected readonly int Cols; + protected readonly int Rows; + protected readonly Rectangle Bounds; protected float t = 0.0f; public D2PlaceBuildingPreviewPreview(WorldRenderer wr, ActorInfo ai, D2PlaceBuildingPreviewInfo info) : base(wr, ai, info) { - this.info = info; - this.ai = ai; + Info = info; + BuildingInfo = ai.TraitInfo(); - bi = ai.TraitInfo(); + Cols = BuildingInfo.Dimensions.X; + Rows = BuildingInfo.Dimensions.Y; - cols = bi.Dimensions.X; - rows = bi.Dimensions.Y; - - var halfWidth = cols * 512; - var halfHeight = rows * 512; + var halfWidth = Cols * 512; + var halfHeight = Rows * 512; var width = halfWidth * 2; var height = halfHeight * 2; - bounds = new Rectangle(-halfWidth, -halfHeight, width, height); + Bounds = new Rectangle(-halfWidth, -halfHeight, width, height); } protected override void TickInner() { - if (info.ColorAnimationStep == 0.0f) + if (Info.ColorAnimationStep == 0.0f) return; - t += info.ColorAnimationStep; + t += Info.ColorAnimationStep; if (t >= 1.0f || t <= 0) - info.ColorAnimationStep = -info.ColorAnimationStep; + Info.ColorAnimationStep = -Info.ColorAnimationStep; if (t > 1.0f) t = 1.0f; @@ -93,37 +90,37 @@ protected override void TickInner() protected bool IsCloseEnoughAndBuildable(World w, ActorInfo ai, CPos topLeft) { - var isCloseEnough = bi.IsCloseEnoughToBase(w, w.LocalPlayer, ai, topLeft); + var isCloseEnough = BuildingInfo.IsCloseEnoughToBase(w, w.LocalPlayer, ai, topLeft); var isAllBuildable = true; var isAnyBuildable = false; - for (var y = 0; y < rows; y++) + for (var y = 0; y < Rows; y++) { - for (var x = 0; x < cols; x++) + for (var x = 0; x < Cols; x++) { var cellPos = new CPos(topLeft.X + x, topLeft.Y + y); - if (w.IsCellBuildable(cellPos, ai, bi)) + if (w.IsCellBuildable(cellPos, ai, BuildingInfo)) { isAnyBuildable = true; - if (!info.StrictBuildableChecks) + if (!Info.StrictBuildableChecks) break; } else { isAllBuildable = false; - if (info.StrictBuildableChecks) + if (Info.StrictBuildableChecks) break; } } - if (isAnyBuildable && !info.StrictBuildableChecks) + if (isAnyBuildable && !Info.StrictBuildableChecks) break; - if (!isAllBuildable && info.StrictBuildableChecks) + if (!isAllBuildable && Info.StrictBuildableChecks) break; } - if (info.StrictBuildableChecks) + if (Info.StrictBuildableChecks) return isCloseEnough && isAllBuildable; else return isCloseEnough && isAnyBuildable; @@ -138,7 +135,7 @@ protected override IEnumerable RenderInner(WorldRenderer wr, CPos t var cross = !IsCloseEnoughAndBuildable(wr.World, ActorInfo, topLeft); - yield return new D2BuildingPlacementRenderable(centerPosition, bounds, color, cross); + yield return new D2BuildingPlacementRenderable(centerPosition, Bounds, color, cross); } } } diff --git a/OpenRA.Mods.D2/Traits/D2AffectsShroud.cs b/OpenRA.Mods.D2/Traits/D2AffectsShroud.cs index 331c5f7..63a56b0 100644 --- a/OpenRA.Mods.D2/Traits/D2AffectsShroud.cs +++ b/OpenRA.Mods.D2/Traits/D2AffectsShroud.cs @@ -19,13 +19,16 @@ namespace OpenRA.Mods.D2.Traits { public abstract class D2AffectsShroudInfo : ConditionalTraitInfo { + // D2 reveals only a short area around moving units: 1280 world units is 1.25 cells. + const int DefaultMovingRange = 1280; + public readonly WDist MinRange = WDist.Zero; [Desc("Range applied then idle.")] public readonly WDist Range = WDist.Zero; [Desc("Range applied then moving.")] - public readonly WDist MovingRange = new WDist(1280); + public readonly WDist MovingRange = new(DefaultMovingRange); [Desc("If >= 0, prevent cells that are this much higher than the actor from being revealed.")] public readonly int MaxHeightDelta = -1; @@ -58,7 +61,7 @@ public abstract class D2AffectsShroud : ConditionalTrait, I protected abstract void RemoveCellsFromPlayerShroud(Actor self, Player player); protected virtual bool IsDisabled(Actor self) { return false; } - public D2AffectsShroud(Actor self, D2AffectsShroudInfo info) + protected D2AffectsShroud(Actor self, D2AffectsShroudInfo info) : base(info) { this.info = info; @@ -67,7 +70,7 @@ public D2AffectsShroud(Actor self, D2AffectsShroudInfo info) footprint = new HashSet(); } - bool IsIdleRange(Actor self) + static bool IsIdleRange(Actor self) { /* * Can't use isIdle because some activities like Harvest should not use IdleRange @@ -75,12 +78,12 @@ bool IsIdleRange(Actor self) * Check that CurrentActivity is any activity from Activities/Move directory */ - if (self.CurrentActivity as AttackMoveActivity != null - || self.CurrentActivity as Drag != null - || self.CurrentActivity as Follow != null - || self.CurrentActivity as Move != null - || self.CurrentActivity as MoveAdjacentTo != null - || self.CurrentActivity as MoveWithinRange != null) + if (self.CurrentActivity is AttackMoveActivity + || self.CurrentActivity is Drag + || self.CurrentActivity is Follow + || self.CurrentActivity is Move + || self.CurrentActivity is MoveAdjacentTo + || self.CurrentActivity is MoveWithinRange) { return false; } diff --git a/OpenRA.Mods.D2/Traits/PaletteEffects/D2WindtrapPaletteEffect.cs b/OpenRA.Mods.D2/Traits/PaletteEffects/D2WindtrapPaletteEffect.cs index 78d3653..bca6705 100644 --- a/OpenRA.Mods.D2/Traits/PaletteEffects/D2WindtrapPaletteEffect.cs +++ b/OpenRA.Mods.D2/Traits/PaletteEffects/D2WindtrapPaletteEffect.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using System.Collections.Generic; using OpenRA.Graphics; using OpenRA.Traits; @@ -33,7 +34,7 @@ class D2WindtrapPaletteEffectInfo : TraitInfo [Desc("Step towards next color index per tick.")] public readonly float RotationStep = .2f; - public override object Create(ActorInitializer init) { return new D2WindtrapPaletteEffect(init.World, this); } + public override object Create(ActorInitializer init) { return new D2WindtrapPaletteEffect(this); } } class D2WindtrapPaletteEffect : ITick, IPaletteModifier @@ -42,7 +43,7 @@ class D2WindtrapPaletteEffect : ITick, IPaletteModifier float t = 0; float step; - public D2WindtrapPaletteEffect(World world, D2WindtrapPaletteEffectInfo info) + public D2WindtrapPaletteEffect(D2WindtrapPaletteEffectInfo info) { this.info = info; step = info.RotationStep; @@ -60,7 +61,7 @@ public void AdjustPalette(IReadOnlyDictionary palettes) foreach (var kvp in palettes) { - if (kvp.Key.StartsWith(info.PaletteName)) + if (kvp.Key.StartsWith(info.PaletteName, StringComparison.Ordinal)) { var palette = kvp.Value; palette[info.RotationIndex] = palette[info.RotationBase + rotate]; diff --git a/OpenRA.Mods.D2/Traits/Render/D2LeavesTracks.cs b/OpenRA.Mods.D2/Traits/Render/D2LeavesTracks.cs index 7ddb0cd..03f7b99 100644 --- a/OpenRA.Mods.D2/Traits/Render/D2LeavesTracks.cs +++ b/OpenRA.Mods.D2/Traits/Render/D2LeavesTracks.cs @@ -28,7 +28,7 @@ public class D2LeavesTracksInfo : ConditionalTraitInfo public readonly string Palette = TileSet.TerrainPaletteInternalName; [Desc("Only leave trail on listed terrain types. Leave empty to leave trail on all terrain types.")] - public readonly HashSet TerrainTypes = new HashSet(); + public readonly HashSet TerrainTypes = new(); [Desc("Should the trail be visible through fog.")] public readonly bool VisibleThroughFog = false; @@ -45,7 +45,6 @@ public class D2LeavesTracksInfo : ConditionalTraitInfo public class D2LeavesTracks : ConditionalTrait, ITick { - BodyOrientation body; IFacing facing; WAngle cachedFacing; int cachedInterval; @@ -68,7 +67,6 @@ public D2LeavesTracks(Actor self, D2LeavesTracksInfo info) protected override void Created(Actor self) { - body = self.Trait(); facing = self.TraitOrDefault(); cachedFacing = facing != null ? facing.Facing : WAngle.Zero; cachedCell = self.World.Map.CellContaining(self.CenterPosition); @@ -100,7 +98,7 @@ void ITick.Tick(Actor self) { if (self.World.Map.Contains(cachedCell) && (Info.TerrainTypes.Count == 0 || Info.TerrainTypes.Contains(self.World.Map.GetTerrainInfo(cachedCell).Type))) { - WAngle spawnFacing = previouslySpawned && previosSpawnCell.Equals(cachedCell) ? previousSpawnFacing : cachedFacing; + var spawnFacing = previouslySpawned && previosSpawnCell.Equals(cachedCell) ? previousSpawnFacing : cachedFacing; var pos = self.World.Map.CenterOfCell(cachedCell); self.World.AddFrameEndTask(w => w.Add(new SpriteEffect(pos, spawnFacing, self.World, Info.Image, diff --git a/OpenRA.Mods.D2/Traits/Render/WithTilesetBody.cs b/OpenRA.Mods.D2/Traits/Render/WithTilesetBody.cs index 7a31a4f..87cbc04 100644 --- a/OpenRA.Mods.D2/Traits/Render/WithTilesetBody.cs +++ b/OpenRA.Mods.D2/Traits/Render/WithTilesetBody.cs @@ -43,7 +43,7 @@ public IEnumerable RenderPreviewSprites(ActorPreviewInitializer i var cols = bi.Dimensions.X; var rows = bi.Dimensions.Y; - for (var index = 0; index < (cols * rows); index++) + for (var index = 0; index < cols * rows; index++) { if (SkipFrames == null || !SkipFrames.Contains(index)) { @@ -51,14 +51,14 @@ public IEnumerable RenderPreviewSprites(ActorPreviewInitializer i var x = index % cols; var anim = new Animation(init.World, image); - Func offset = () => new WVec(x * 1024 - 512, y * 1024 - 512, 0); - Func zOffset = () => 0; + WVec Offset() => new(x * 1024 - 512, y * 1024 - 512, 0); + int ZOffset() => 0; var frameIndex = index; anim.PlayFetchIndex(Sequence, () => frameIndex); anim.IsDecoration = true; - yield return new SpriteActorPreview(anim, offset, zOffset, p); + yield return new SpriteActorPreview(anim, Offset, ZOffset, p); } } } @@ -74,7 +74,7 @@ public WithTilesetBody(Actor self, WithTilesetBodyInfo info) var cols = bi.Dimensions.X; var rows = bi.Dimensions.Y; - for (var index = 0; index < (cols * rows); index++) + for (var index = 0; index < cols * rows; index++) { if (info.SkipFrames == null || !info.SkipFrames.Contains(index)) { diff --git a/OpenRA.Mods.D2/Traits/World/D2BuildableTerrainLayer.cs b/OpenRA.Mods.D2/Traits/World/D2BuildableTerrainLayer.cs index 9e4d3c9..88fc0d9 100644 --- a/OpenRA.Mods.D2/Traits/World/D2BuildableTerrainLayer.cs +++ b/OpenRA.Mods.D2/Traits/World/D2BuildableTerrainLayer.cs @@ -74,7 +74,7 @@ public void HitTile(CPos cell, int damage) if (world.ActorMap.GetActorsAt(cell).Any(a => a.TraitOrDefault() != null)) return; - strength[cell] = strength[cell] - damage; + strength[cell] -= damage; if (strength[cell] < 1) RemoveTile(cell); } diff --git a/OpenRA.Mods.D2/Traits/World/D2ResourceRenderer.cs b/OpenRA.Mods.D2/Traits/World/D2ResourceRenderer.cs index 164b5a7..4a7cd36 100644 --- a/OpenRA.Mods.D2/Traits/World/D2ResourceRenderer.cs +++ b/OpenRA.Mods.D2/Traits/World/D2ResourceRenderer.cs @@ -58,30 +58,30 @@ public enum ClearSides : byte static readonly CVec[] Directions = { - new CVec(-1, -1), - new CVec(-1, 0), - new CVec(-1, 1), - new CVec(0, -1), - new CVec(0, 1), - new CVec(1, -1), - new CVec(1, 0), - new CVec(1, 1), - new CVec(-2, -2), - new CVec(-1, -2), - new CVec(0, -2), - new CVec(1, -2), - new CVec(2, -2), - new CVec(2, -1), - new CVec(2, 0), - new CVec(2, 1), - new CVec(2, 2), - new CVec(1, 2), - new CVec(0, 2), - new CVec(-1, 2), - new CVec(-2, 2), - new CVec(-2, 1), - new CVec(-2, 0), - new CVec(-2, -1) + new(-1, -1), + new(-1, 0), + new(-1, 1), + new(0, -1), + new(0, 1), + new(1, -1), + new(1, 0), + new(1, 1), + new(-2, -2), + new(-1, -2), + new(0, -2), + new(1, -2), + new(2, -2), + new(2, -1), + new(2, 0), + new(2, 1), + new(2, 2), + new(1, 2), + new(0, 2), + new(-1, 2), + new(-2, 2), + new(-2, 1), + new(-2, 0), + new(-2, -1), }; public D2ResourceRenderer(Actor self, D2ResourceRendererInfo info) diff --git a/OpenRA.Mods.D2/Traits/World/D2Selection.cs b/OpenRA.Mods.D2/Traits/World/D2Selection.cs index eb2ff38..bf6fd76 100644 --- a/OpenRA.Mods.D2/Traits/World/D2Selection.cs +++ b/OpenRA.Mods.D2/Traits/World/D2Selection.cs @@ -54,8 +54,8 @@ public class D2Selection : Selection readonly World world; bool initialized = false; - bool singleSelection = true; - public bool SingleSelection { get { return singleSelection; } } + + public bool SingleSelection { get; private set; } = true; public D2Selection(World world, D2SelectionInfo info) { @@ -68,7 +68,7 @@ void Init() if (!initialized) { var gs = world.LobbyInfo.GlobalSettings; - singleSelection = gs.OptionOrDefault("singleselection", info.CheckboxEnabled); + SingleSelection = gs.OptionOrDefault("singleselection", info.CheckboxEnabled); initialized = true; } } diff --git a/OpenRA.Mods.D2/Traits/World/D2ShroudRenderer.cs b/OpenRA.Mods.D2/Traits/World/D2ShroudRenderer.cs index 3075573..c4b0409 100644 --- a/OpenRA.Mods.D2/Traits/World/D2ShroudRenderer.cs +++ b/OpenRA.Mods.D2/Traits/World/D2ShroudRenderer.cs @@ -60,7 +60,7 @@ enum Edges : byte BottomRight = Bottom | Right } - struct TileInfo + readonly struct TileInfo { public readonly float3 ScreenPosition; @@ -192,7 +192,7 @@ Edges GetEdges(PPos puv, Func isVisible) void WorldOnRenderPlayerChanged(Player player) { - var newShroud = player != null ? player.Shroud : null; + var newShroud = player?.Shroud; if (shroud != newShroud) { @@ -272,7 +272,7 @@ void UpdateShroudCell(PPos puv) cellsDirty[cell + direction] = true; } - Sprite GetSprite(Sprite[] sprites, Edges edges) + static Sprite GetSprite(Sprite[] sprites, Edges edges) { if (edges == Edges.None) return null; diff --git a/OpenRA.Mods.D2/Traits/World/D2TerrainLayer.cs b/OpenRA.Mods.D2/Traits/World/D2TerrainLayer.cs index ff52108..32a5bfe 100644 --- a/OpenRA.Mods.D2/Traits/World/D2TerrainLayer.cs +++ b/OpenRA.Mods.D2/Traits/World/D2TerrainLayer.cs @@ -60,7 +60,7 @@ public D2TerrainLayer(Actor self, D2TerrainLayerInfo info) public void WorldLoaded(World w, WorldRenderer wr) { /* based on SmudgeLayer.cs */ - var first = sideSprites.First().Value.First(); + var first = sideSprites.First().Value[0]; var sheet = first.Sheet; if (sideSprites.Values.Any(sprites => sprites.Any(s => s.Sheet != sheet))) throw new InvalidDataException("Resource sprites span multiple sheets. Try loading their sequences earlier."); diff --git a/OpenRA.Mods.D2/Widgets/D2ImageWidget.cs b/OpenRA.Mods.D2/Widgets/D2ImageWidget.cs index c0a133b..37b708d 100644 --- a/OpenRA.Mods.D2/Widgets/D2ImageWidget.cs +++ b/OpenRA.Mods.D2/Widgets/D2ImageWidget.cs @@ -80,7 +80,7 @@ public override void Draw() var collection = GetImageCollection(); var paletteName = GetPaletteName(); - if (paletteName == null || paletteName.Length == 0) + if (string.IsNullOrEmpty(paletteName)) paletteName = "player" + world.LocalPlayer.InternalName; PaletteReference p = null; if (paletteName != null) diff --git a/OpenRA.Mods.D2/Widgets/D2ProgressBarWidget.cs b/OpenRA.Mods.D2/Widgets/D2ProgressBarWidget.cs index 55fe6cd..9b594e3 100644 --- a/OpenRA.Mods.D2/Widgets/D2ProgressBarWidget.cs +++ b/OpenRA.Mods.D2/Widgets/D2ProgressBarWidget.cs @@ -55,10 +55,10 @@ public override void Draw() D2WidgetUtils.DrawYellowTriangle(new int2((r.Left + r.Right) / 2, r.Bottom), BarMargin); D2WidgetUtils.DrawGreenTriangle(new int2(r.Right - 2 * BarMargin, r.Bottom), BarMargin); - var minBarWidth = 1; + const int MinBarWidth = 1; var maxBarWidth = r.Width - BarMargin * 2; var barWidth = percentage * maxBarWidth / 100; - barWidth = Math.Max(barWidth, minBarWidth); + barWidth = Math.Max(barWidth, MinBarWidth); var barRect = new Rectangle(r.X + BarMargin, r.Y + BarMargin, barWidth, r.Height - 2 * BarMargin); var barColor = Color.FromArgb(85, 254, 81); diff --git a/OpenRA.Mods.D2/Widgets/D2SpriteWidget.cs b/OpenRA.Mods.D2/Widgets/D2SpriteWidget.cs index f3acbcf..947744d 100644 --- a/OpenRA.Mods.D2/Widgets/D2SpriteWidget.cs +++ b/OpenRA.Mods.D2/Widgets/D2SpriteWidget.cs @@ -24,13 +24,10 @@ public class D2SpriteWidget : Widget public float2 Offset = float2.Zero; public float Scale = 1.0f; - readonly WorldRenderer worldRenderer; - [ObjectCreator.UseCtor] - public D2SpriteWidget(World world, WorldRenderer worldRenderer) + public D2SpriteWidget(World world) { World = world; - this.worldRenderer = worldRenderer; } public override void Draw() diff --git a/OpenRA.Mods.D2/Widgets/Logic/D2AssetBrowserLogic.cs b/OpenRA.Mods.D2/Widgets/Logic/D2AssetBrowserLogic.cs index 824c0f2..450cd72 100644 --- a/OpenRA.Mods.D2/Widgets/Logic/D2AssetBrowserLogic.cs +++ b/OpenRA.Mods.D2/Widgets/Logic/D2AssetBrowserLogic.cs @@ -18,7 +18,6 @@ using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Mods.Common.Widgets; -using OpenRA.Mods.Common.Widgets.Logic; using OpenRA.Primitives; using OpenRA.Widgets; @@ -26,6 +25,9 @@ namespace OpenRA.Mods.D2.Widgets.Logic { public class D2AssetBrowserLogic : ChromeLogic { + const int MaxDisplayNameLength = 18; + const int TruncatedNameLength = 15; + readonly string[] allowedExtensions; readonly IEnumerable acceptablePackages; @@ -95,7 +97,7 @@ public D2AssetBrowserLogic(Widget widget, Action onExit, ModData modData, WorldR var spriteWidget = panel.GetOrNull("SPRITE"); if (spriteWidget != null) { - spriteWidget.GetSprite = () => currentSprites != null ? currentSprites[currentFrame] : null; + spriteWidget.GetSprite = () => currentSprites?[currentFrame]; currentPalette = spriteWidget.Palette; spriteWidget.GetPalette = () => currentPalette; spriteWidget.IsVisible = () => !isVideoLoaded && !isLoadError; @@ -112,7 +114,7 @@ public D2AssetBrowserLogic(Widget widget, Action onExit, ModData modData, WorldR var paletteDropDown = panel.GetOrNull("PALETTE_SELECTOR"); if (paletteDropDown != null) { - paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world); + paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown); paletteDropDown.GetText = () => currentPalette; } @@ -274,7 +276,7 @@ void SelectPreviousFrame() currentFrame = currentSprites.Length - 1; } - readonly Dictionary assetVisByName = new Dictionary(); + readonly Dictionary assetVisByName = new(); bool FilterAsset(string filename) { @@ -283,7 +285,7 @@ bool FilterAsset(string filename) if (string.IsNullOrWhiteSpace(filter)) return true; - if (filename.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0) + if (filename.Contains(filter, StringComparison.OrdinalIgnoreCase)) return true; return false; @@ -297,10 +299,8 @@ void ApplyFilter() // Select the first visible var firstVisible = assetVisByName.FirstOrDefault(kvp => kvp.Value); - IReadOnlyPackage package; - string filename; - if (firstVisible.Key != null && modData.DefaultFileSystem.TryGetPackageContaining(firstVisible.Key, out package, out filename)) + if (firstVisible.Key != null && modData.DefaultFileSystem.TryGetPackageContaining(firstVisible.Key, out var package, out var filename)) LoadAsset(package, filename); } @@ -308,13 +308,12 @@ void AddAsset(ScrollPanelWidget list, string filepath, IReadOnlyPackage package, { var item = ScrollItemWidget.Setup(template, () => currentFilename == filepath && currentPackage == package, - () => { LoadAsset(package, filepath); }); + () => LoadAsset(package, filepath)); item.Get("TITLE").GetText = () => filepath; item.IsVisible = () => { - bool visible; - if (assetVisByName.TryGetValue(filepath, out visible)) + if (assetVisByName.TryGetValue(filepath, out var visible)) return visible; visible = FilterAsset(filepath); @@ -347,9 +346,8 @@ bool LoadAsset(IReadOnlyPackage package, string filename) currentPackage = package; currentFilename = filename; var prefix = ""; - var fs = modData.DefaultFileSystem as OpenRA.FileSystem.FileSystem; - if (fs != null) + if (modData.DefaultFileSystem is OpenRA.FileSystem.FileSystem fs) { prefix = fs.GetPrefix(package); if (prefix != null) @@ -399,7 +397,7 @@ protected override void Dispose(bool disposing) bool ShowSourceDropdown(DropDownButtonWidget dropdown) { var sourceName = new CachedTransform(GetSourceDisplayName); - Func setupItem = (source, itemTemplate) => + ScrollItemWidget SetupItem(IReadOnlyPackage source, ScrollItemWidget itemTemplate) { var item = ScrollItemWidget.Setup(itemTemplate, () => assetSource == source, @@ -407,10 +405,10 @@ bool ShowSourceDropdown(DropDownButtonWidget dropdown) item.Get("LABEL").GetText = () => sourceName.Update(source); return item; - }; + } var sources = new[] { (IReadOnlyPackage)null }.Concat(acceptablePackages); - dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, setupItem); + dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, sources, SetupItem); return true; } @@ -447,9 +445,9 @@ void PopulateAssetList() } } - bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world) + bool ShowPaletteDropdown(DropDownButtonWidget dropdown) { - Func setupItem = (name, itemTemplate) => + ScrollItemWidget SetupItem(string name, ScrollItemWidget itemTemplate) { var item = ScrollItemWidget.Setup(itemTemplate, () => currentPalette == name, @@ -457,9 +455,9 @@ bool ShowPaletteDropdown(DropDownButtonWidget dropdown, World world) item.Get("LABEL").GetText = () => name; return item; - }; + } - dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, setupItem); + dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 280, palettes, SetupItem); return true; } @@ -478,15 +476,15 @@ string GetSourceDisplayName(IReadOnlyPackage source) name = source.Name; var compare = Platform.CurrentPlatform == PlatformType.Windows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; if (name.StartsWith(modData.Manifest.Package.Name, compare)) - name = "$" + modData.Manifest.Id + "/" + name.Substring(modData.Manifest.Package.Name.Length + 1); + name = "$" + modData.Manifest.Id + "/" + name[(modData.Manifest.Package.Name.Length + 1)..]; else if (name.StartsWith(Platform.EngineDir, compare)) - name = "./" + name.Substring(Platform.EngineDir.Length); + name = "./" + name[Platform.EngineDir.Length..]; else if (name.StartsWith(Platform.SupportDir, compare)) - name = "^" + name.Substring(Platform.SupportDir.Length); + name = "^" + name[Platform.SupportDir.Length..]; } - if (name.Length > 18) - name = "..." + name.Substring(name.Length - 15); + if (name.Length > MaxDisplayNameLength) + name = "..." + name[^TruncatedNameLength..]; return name; } diff --git a/OpenRA.Mods.D2/Widgets/Logic/D2MissionBrowserLogic.cs b/OpenRA.Mods.D2/Widgets/Logic/D2MissionBrowserLogic.cs index 1365dc7..adc5f2b 100644 --- a/OpenRA.Mods.D2/Widgets/Logic/D2MissionBrowserLogic.cs +++ b/OpenRA.Mods.D2/Widgets/Logic/D2MissionBrowserLogic.cs @@ -99,7 +99,7 @@ public D2MissionBrowserLogic(Widget widget, ModData modData, World world, Action missionList.RemoveChildren(); // Add a group for each campaign - if (modData.Manifest.Missions.Any()) + if (modData.Manifest.Missions.Length != 0) { var yaml = MiniYaml.Merge(modData.Manifest.Missions.Select( m => MiniYaml.FromStream(modData.DefaultFileSystem.Open(m), m))); @@ -137,8 +137,8 @@ public D2MissionBrowserLogic(Widget widget, ModData modData, World world, Action allPreviews.AddRange(loosePreviews); } - if (allPreviews.Any()) - SelectMap(allPreviews.First()); + if (allPreviews.Count != 0) + SelectMap(allPreviews[0]); // Preload map preview and rules to reduce jank new Thread(() => @@ -269,14 +269,14 @@ void SelectMap(MapPreview preview) OnClick = () => difficulty = kv.Key }); - Func setupItem = (option, template) => + ScrollItemWidget SetupItem(DropDownOption option, ScrollItemWidget template) { var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick); item.Get("LABEL").GetText = () => option.Title; return item; - }; + } - difficultyButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, setupItem); + difficultyButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, SetupItem); }; } @@ -295,14 +295,14 @@ void SelectMap(MapPreview preview) OnClick = () => gameSpeed = s.Key }); - Func setupItem = (option, template) => + ScrollItemWidget SetupItem(DropDownOption option, ScrollItemWidget template) { var item = ScrollItemWidget.Setup(template, option.IsSelected, option.OnClick); item.Get("LABEL").GetText = () => option.Title; return item; - }; + } - gameSpeedButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, setupItem); + gameSpeedButton.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", options.Count() * 30, options, SetupItem); }; } } @@ -332,8 +332,8 @@ void PlayVideo(WsaPlayerWidget player, string video, PlayingVideo pv, Action onC ConfirmationDialogs.ButtonPrompt(modData, title: "Video not installed", text: "The game videos can be installed from the\n\"Manage Content\" menu in the mod chooser.", - cancelText: "Back", - onCancel: () => { }); + onCancel: () => { }, + cancelText: "Back"); } else { @@ -346,8 +346,7 @@ void PlayVideo(WsaPlayerWidget player, string video, PlayingVideo pv, Action onC player.PlayThen(() => { StopVideo(player); - if (onComplete != null) - onComplete(); + onComplete?.Invoke(); }); // Mute other distracting sounds @@ -392,10 +391,7 @@ void StartMissionClicked(Action onExit) { var fsPlayer = fullscreenVideoPlayer.Get("PLAYER"); fullscreenVideoPlayer.Visible = true; - PlayVideo(fsPlayer, missionData.StartVideo, PlayingVideo.GameStart, () => - { - Game.CreateAndStartLocalServer(selectedMap.Uid, orders); - }); + PlayVideo(fsPlayer, missionData.StartVideo, PlayingVideo.GameStart, () => Game.CreateAndStartLocalServer(selectedMap.Uid, orders)); } else Game.CreateAndStartLocalServer(selectedMap.Uid, orders); diff --git a/OpenRA.Mods.D2/Widgets/Logic/Ingame/D2IngameActorLogic.cs b/OpenRA.Mods.D2/Widgets/Logic/Ingame/D2IngameActorLogic.cs index ae508a8..dcb8358 100644 --- a/OpenRA.Mods.D2/Widgets/Logic/Ingame/D2IngameActorLogic.cs +++ b/OpenRA.Mods.D2/Widgets/Logic/Ingame/D2IngameActorLogic.cs @@ -10,6 +10,7 @@ #endregion using System; +using System.Globalization; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Orders; @@ -27,7 +28,6 @@ public class D2IngameActorLogic : ChromeLogic readonly World world; readonly WorldRenderer worldRenderer; - readonly D2PanelWidget panel; readonly LabelWidget label; readonly D2SpriteWidget preview; readonly D2ProgressBarWidget health; @@ -56,8 +56,6 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere var textColor = Color.FromArgb(71, 71, 55); - panel = widget.GetOrNull("PANEL"); - label = widget.GetOrNull("NAME"); if (label != null) { @@ -128,18 +126,18 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere { attackButton.Visible = false; attackButton.IsHighlighted = () => IsForceModifiersActive(Modifiers.Ctrl) - && !(world.OrderGenerator is AttackMoveOrderGenerator); + && world.OrderGenerator is not AttackMoveOrderGenerator; - Action toggle = allowCancel => + void Toggle(bool allowCancel) { if (attackButton.IsHighlighted()) world.CancelInputMode(); else world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Ctrl, true); - }; + } - attackButton.OnClick = () => toggle(true); - attackButton.OnKeyPress = _ => toggle(false); + attackButton.OnClick = () => Toggle(true); + attackButton.OnKeyPress = _ => Toggle(false); } moveButton = widget.GetOrNull("MOVE"); @@ -147,16 +145,16 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere { moveButton.Visible = false; moveButton.IsHighlighted = () => !moveButton.IsDisabled() && IsForceModifiersActive(Modifiers.Alt); - Action toggle = allowCancel => + void Toggle(bool allowCancel) { if (moveButton.IsHighlighted()) world.CancelInputMode(); else world.OrderGenerator = new ForceModifiersOrderGenerator(Modifiers.Alt, true); - }; + } - moveButton.OnClick = () => toggle(true); - moveButton.OnKeyPress = _ => toggle(false); + moveButton.OnClick = () => Toggle(true); + moveButton.OnKeyPress = _ => Toggle(false); } retreatButton = widget.GetOrNull("RETREAT"); @@ -164,12 +162,9 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere { retreatButton.Visible = false; - retreatButton.OnClick = () => - { - PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false)); - }; + retreatButton.OnClick = () => PerformKeyboardOrderOnSelection(a => new Order("Stop", a, false)); - retreatButton.OnKeyPress = ki => { retreatButton.OnClick(); }; + retreatButton.OnKeyPress = ki => retreatButton.OnClick(); } guardButton = widget.GetOrNull("GUARD"); @@ -178,7 +173,7 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere guardButton.Visible = false; guardButton.IsHighlighted = () => world.OrderGenerator is GuardOrderGenerator; - Action toggle = allowCancel => + void Toggle(bool allowCancel) { if (guardButton.IsHighlighted()) { @@ -188,10 +183,10 @@ public D2IngameActorLogic(Widget widget, World world, WorldRenderer worldRendere else world.OrderGenerator = new GuardOrderGenerator(selectedActors, "Guard", "guard", Game.Settings.Game.MouseButtonPreference.Action); - }; + } - guardButton.OnClick = () => toggle(true); - guardButton.OnKeyPress = _ => toggle(false); + guardButton.OnClick = () => Toggle(true); + guardButton.OnKeyPress = _ => Toggle(false); } } @@ -204,12 +199,10 @@ public override void Tick() bool IsForceModifiersActive(Modifiers modifiers) { - var fmog = world.OrderGenerator as ForceModifiersOrderGenerator; - if (fmog != null && fmog.Modifiers.HasFlag(modifiers)) + if (world.OrderGenerator is ForceModifiersOrderGenerator fmog && fmog.Modifiers.HasFlag(modifiers)) return true; - var uog = world.OrderGenerator as UnitOrderGenerator; - if (uog != null && Game.GetModifierKeys().HasFlag(modifiers)) + if (world.OrderGenerator is UnitOrderGenerator && Game.GetModifierKeys().HasFlag(modifiers)) return true; return false; @@ -272,12 +265,12 @@ void UpdateSpiceInfo(Actor actor) line1a.Text = "HOLDS:"; line1a.Visible = true; - line1b.GetText = () => store.ContentsSum.ToString(); + line1b.GetText = () => store.ContentsSum.ToString(CultureInfo.InvariantCulture); line1b.Visible = true; line2a.Text = "MAX:"; line2a.Visible = true; - line2b.GetText = () => store.Capacity.ToString(); + line2b.GetText = () => store.Capacity.ToString(CultureInfo.InvariantCulture); line2b.Visible = true; } } @@ -292,25 +285,24 @@ void UpdatePowerInfo(Actor actor) if (powers.Any()) { var power = powers.FirstOrDefault(t => !t.IsTraitDisabled); - if (power != null) + if (power != null && power.Info.Amount > 0) { - if (power.Info.Amount > 0) - { - title.Text = "POWER INFO"; - title.Visible = true; + title.Text = "POWER INFO"; + title.Visible = true; - separator.Visible = true; + separator.Visible = true; - line1a.Text = "NEEDED:"; - line1a.Visible = true; - line1b.GetText = () => (power.PlayerPower.PowerProvided != 0 ? power.PlayerPower.PowerDrained * power.GetEnabledPower() / power.PlayerPower.PowerProvided : 0).ToString(); - line1b.Visible = true; + line1a.Text = "NEEDED:"; + line1a.Visible = true; + line1b.GetText = () => (power.PlayerPower.PowerProvided != 0 + ? power.PlayerPower.PowerDrained * power.GetEnabledPower() / power.PlayerPower.PowerProvided + : 0).ToString(CultureInfo.InvariantCulture); + line1b.Visible = true; - line2a.Text = "OUTPUT:"; - line2a.Visible = true; - line2b.GetText = () => power.GetEnabledPower().ToString(); - line2b.Visible = true; - } + line2a.Text = "OUTPUT:"; + line2a.Visible = true; + line2b.GetText = () => power.GetEnabledPower().ToString(CultureInfo.InvariantCulture); + line2b.Visible = true; } } } diff --git a/OpenRA.Mods.D2/Widgets/WsaPlayerWidget.cs b/OpenRA.Mods.D2/Widgets/WsaPlayerWidget.cs index 400b5a3..a30928e 100644 --- a/OpenRA.Mods.D2/Widgets/WsaPlayerWidget.cs +++ b/OpenRA.Mods.D2/Widgets/WsaPlayerWidget.cs @@ -18,19 +18,16 @@ namespace OpenRA.Mods.D2.Widgets { public class WsaPlayerWidget : Widget { - public Hotkey CancelKey = new Hotkey(Keycode.ESCAPE, Modifiers.None); + public Hotkey CancelKey = new(Keycode.ESCAPE, Modifiers.None); public float AspectRatio = 1.2f; public bool Skippable = true; - public bool Paused { get { return paused; } } - public WsaReader Video { get { return video; } } + public bool Paused { get; private set; } + public WsaReader Video { get; private set; } = null; - WsaReader video = null; string cachedVideo; - float2 videoOrigin, videoSize; + float2 videoOrigin; bool stopped; - bool paused; - ImmutablePalette palette; HardwarePalette hardwarePalette; PaletteReference pr; @@ -66,55 +63,43 @@ void LoadPalette() public void Open(WsaReader video) { - this.video = video; + Video = video; stopped = true; - paused = true; + Paused = true; onComplete = () => { }; - var size = Math.Max(video.Width, video.Height); - var textureSize = Exts.NextPowerOf2(size); - var scale = Math.Min((float)RenderBounds.Width / video.Width, (float)RenderBounds.Height / video.Height * AspectRatio); videoOrigin = new float2( RenderBounds.X + (RenderBounds.Width - scale * video.Width) / 2, RenderBounds.Y + (RenderBounds.Height - scale * video.Height * AspectRatio) / 2); - - // Round size to integer pixels. Round up to be consistent with the scale calculation. - videoSize = new float2((int)Math.Ceiling(video.Width * scale), (int)Math.Ceiling(video.Height * AspectRatio * scale)); } public override void Draw() { - if (video == null) + if (Video == null) return; var sheetBuilder = new SheetBuilder(SheetType.Indexed, 512); - var videoSprite = sheetBuilder.Add(video.Frame); + var videoSprite = sheetBuilder.Add(Video.Frame); Game.Renderer.EnableScissor(RenderBounds); Game.Renderer.RgbaColorRenderer.FillRect( new float2(RenderBounds.Left, RenderBounds.Top), - new float2(RenderBounds.Right, RenderBounds.Bottom), OpenRA.Primitives.Color.Black); + new float2(RenderBounds.Right, RenderBounds.Bottom), Primitives.Color.Black); Game.Renderer.DisableScissor(); Game.Renderer.SpriteRenderer.DrawSprite(videoSprite, pr, videoOrigin); -/* - Game.Renderer.RgbaSpriteRenderer.DrawSprite( - videoSprite, - videoOrigin, - videoSize); -*/ - if (!stopped && !paused) + if (!stopped && !Paused) { - if (video.CurrentFrame >= video.Length - 1) + if (Video.CurrentFrame >= Video.Length - 1) { Stop(); return; } - video.AdvanceFrame(); + Video.AdvanceFrame(); } } @@ -144,37 +129,37 @@ public void Play() public void PlayThen(Action after) { - if (video == null) + if (Video == null) return; onComplete = after; - stopped = paused = false; + stopped = Paused = false; } public void Pause() { - if (stopped || paused || video == null) + if (stopped || Paused || Video == null) return; - paused = true; + Paused = true; } public void Stop() { - if (stopped || video == null) + if (stopped || Video == null) return; stopped = true; - paused = true; - video.Reset(); + Paused = true; + Video.Reset(); Game.RunAfterTick(onComplete); } public void CloseVideo() { Stop(); - video = null; + Video = null; } } } diff --git a/make.ps1 b/make.ps1 index c1b315d..84efd8d 100644 --- a/make.ps1 +++ b/make.ps1 @@ -123,6 +123,7 @@ function Check-Command if ($lastexitcode -ne 0) { Write-Host "Build failed." -ForegroundColor Red + exit 1 } if ((CheckForUtility) -eq 0)