diff --git a/src/cmdapp/GenieEngineApp.csproj b/src/cmdapp/GenieEngineApp.csproj index da8f000..c09987b 100644 --- a/src/cmdapp/GenieEngineApp.csproj +++ b/src/cmdapp/GenieEngineApp.csproj @@ -32,19 +32,20 @@ + + - @@ -65,11 +66,12 @@ + + ..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll - diff --git a/src/cmdapp/src/AddBitmapCommand.cs b/src/cmdapp/src/AddBitmapCommand.cs index a1d2669..c910fd9 100644 --- a/src/cmdapp/src/AddBitmapCommand.cs +++ b/src/cmdapp/src/AddBitmapCommand.cs @@ -1,12 +1,13 @@ using System.IO; using System.Drawing; +using System.Drawing.Imaging; using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class AddBitmapCommand : CmdApp.Command + public class AddBitmapCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var output = File.OpenWrite(args[1])) @@ -22,11 +23,20 @@ namespace AdrianKousz.GenieEngine GenieFile.Serialize(scn, output); } } - public AddBitmapCommand() + + override public int GetArgumentCount() { - MinArgumentCount = 3; - Description = "Add a pregame bitmap"; - Help = "Add a pregame bitmap to a scenario." + return 3; + } + + override public string GetDescription() + { + return "Add a pregame bitmap"; + } + + override public string GetHelp() + { + return "Add a pregame bitmap to a scenario." + "\nThe bitmap has to be indexed, otherwise, the game will probably crash." + "\nAdditionally, a game-specific palette will be used to display the image." + "\n" diff --git a/src/cmdapp/src/BaseCommand.cs b/src/cmdapp/src/BaseCommand.cs new file mode 100644 index 0000000..7976ded --- /dev/null +++ b/src/cmdapp/src/BaseCommand.cs @@ -0,0 +1,36 @@ +using System; +using AdrianKousz.Util; + +namespace AdrianKousz.GenieEngine +{ + public class BaseCommand : ICommand + { + protected string[] args; + + virtual public string GetDescription() + { + return "(Empty description)"; + } + + virtual public string GetHelp() + { + return "(Empty help text)"; + } + + virtual public int GetArgumentCount() + { + return 1; + } + + virtual public void SetArguments(string[] args) + { + this.args = args; + } + + virtual public void Run() + { + foreach (var str in args) + Console.WriteLine(str); + } + } +} diff --git a/src/cmdapp/src/BitmapHelpers.cs b/src/cmdapp/src/BitmapHelpers.cs index 0e6a026..f4dc23a 100644 --- a/src/cmdapp/src/BitmapHelpers.cs +++ b/src/cmdapp/src/BitmapHelpers.cs @@ -9,24 +9,25 @@ namespace AdrianKousz.GenieEngine { public static class BitmapHelpers { - public static unsafe void FillMap(Scenario scn, Bitmap bmp1, Bitmap bmp2) + public static unsafe void FillMap(Scenario scn, Bitmap bmp, Bitmap bmp2) { - using (var ubmp1 = new UnsafeBitmap(bmp1)) + using (var ubmp = new UnsafeBitmap(bmp)) using (var ubmp2 = new UnsafeBitmap(bmp2)) { var factory = new ScnDefaultFactory(); - EnsureValid(ubmp1, ubmp2); + Check(ubmp); + Check(ubmp2); - var ptr1 = ubmp1.Scan0; - var last1 = ptr1 + ubmp1.Stride * ubmp1.Height; + var ptr = ubmp.Scan0; + var last = ptr + ubmp.Stride * ubmp.Height; var ptr2 = ubmp2.Scan0; var last2 = ptr2 + ubmp2.Stride * ubmp2.Height; var map = factory.MakeMap(); - map.SizeX = ubmp1.Width; - map.SizeY = ubmp1.Height; + map.SizeX = ubmp.Width; + map.SizeY = ubmp.Height; map.LinearTiles = new Scenario.ScnMap.Tile[map.SizeX * map.SizeY]; var gaiaunits = new List(); @@ -40,37 +41,26 @@ namespace AdrianKousz.GenieEngine treemapping[20] = 349; var i = 0; - var id = 0; - while (ptr1 < last1 && ptr2 < last2) { - var treeid = treemapping[*ptr1]; + while (ptr < last && ptr2 < last2) { + var treeid = treemapping[*ptr]; if (treeid != 0) { var unit = factory.MakeUnit(); var posy = i / map.SizeX; var posx = i - (posy * map.SizeX); - unit.Id = id++; unit.UnitId = treeid; unit.PosX = posx + 0.5f; unit.PosY = posy + 0.5f; - unit.Rotation = unit.InitialFrame = (short)Util.Math.Rand(0, 14); + unit.Rotation = (short)Util.Math.Rand(0, 13); gaiaunits.Add(unit); } - map.LinearTiles[i++] = new Scenario.ScnMap.Tile(*ptr1++, (byte)(*ptr2++ / 40), 0); + map.LinearTiles[i++] = new Scenario.ScnMap.Tile(*ptr++, (byte)(*ptr2++ / 37), 0); } - scn.NextId = id; scn.Map = map; scn.Units[0] = gaiaunits; } } - private static void EnsureValid(UnsafeBitmap ubmp1, UnsafeBitmap ubmp2) - { - if (ubmp1.Width != ubmp2.Width || ubmp1.Height != ubmp2.Height) - throw new ArgumentException("Bitmaps have unequal dimensions"); - Check(ubmp1); - Check(ubmp2); - } - private static void Check(UnsafeBitmap ubmp) { if (ubmp.PixelFormat != PixelFormat.Format8bppIndexed) diff --git a/src/cmdapp/src/Bmp2MapCommand.cs b/src/cmdapp/src/Bmp2MapCommand.cs index 42d94da..9946a28 100644 --- a/src/cmdapp/src/Bmp2MapCommand.cs +++ b/src/cmdapp/src/Bmp2MapCommand.cs @@ -1,12 +1,13 @@ -using System.IO; +using System; +using System.IO; using System.Drawing; using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class Bmp2MapCommand : CmdApp.Command + public class Bmp2MapCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var srcstream = File.OpenRead(args[0])) using (var outstream = File.OpenWrite(args[1])) @@ -22,16 +23,24 @@ namespace AdrianKousz.GenieEngine } } - public Bmp2MapCommand() + override public int GetArgumentCount() { - MinArgumentCount = 4; - Description = "Generate a scenario map based on bitmaps"; - Help = "Generate a scenario map based on bitmaps with automatic forest generation." + return 4; + } + + override public string GetDescription() + { + return "Generate a scenario map based on bitmaps"; + } + + override public string GetHelp() + { + return "Generate a scenario map based on bitmaps with automatic forest generation." + "\n" + "\nTwo bitmaps need to be specified: One terrain map and one elevation map." + "\nBoth bitmaps need to be indexed or grayscale." + "\nThe index/gray values of the first bitmap are translated directly to a terrain ID." - + "\nThe index/gray values of the second bitmap are divided by 40 to generate elevations 0-6." + + "\nThe index/gray values of the second bitmap are divided by 37 to generate elevations 0-6." + "\n" + "\nParameters:" + "\n " diff --git a/src/cmdapp/src/CompressCommand.cs b/src/cmdapp/src/CompressCommand.cs index 2098e7b..fbf0462 100644 --- a/src/cmdapp/src/CompressCommand.cs +++ b/src/cmdapp/src/CompressCommand.cs @@ -1,28 +1,35 @@ using System.IO; -using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class CompressCommand : CmdApp.Command + public class CompressCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var output = File.OpenWrite(args[1])) { - GenieFile.ScenarioCompress(input, output); + GenieFile.ScenarioCompression(input, output, false); } } - public CompressCommand() + override public int GetArgumentCount() { - MinArgumentCount = 2; - Description = "Recompress a decompressed scenario file"; - Help = "Recompress a previously decompressed scenario file." + return 2; + } + + override public string GetDescription() + { + return "Recompress a decompressed scenario file"; + } + + override public string GetHelp() + { + return "Recompress a previously decompressed scenario file." + "\n" + "\nParameters:" + "\n " - ; + ; } } } diff --git a/src/cmdapp/src/ConvertCommand.cs b/src/cmdapp/src/ConvertCommand.cs index 69acae3..723b9a4 100644 --- a/src/cmdapp/src/ConvertCommand.cs +++ b/src/cmdapp/src/ConvertCommand.cs @@ -1,11 +1,12 @@ -using System.IO; +using System; +using System.IO; using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class ConvertCommand : CmdApp.Command + public class ConvertCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var srcstream = File.OpenRead(args[0])) using (var outstream = File.OpenWrite(args[1])) @@ -14,46 +15,37 @@ namespace AdrianKousz.GenieEngine var refscn = GenieFile.Deserialize(refstream); var srcscn = GenieFile.Deserialize(srcstream); - refscn.Filename = srcscn.Filename; - refscn.InstructionsUncompressed = srcscn.InstructionsUncompressed; - refscn.NextId = srcscn.NextId; - refscn.PlayerCount = srcscn.PlayerCount; + srcscn.VersionString = refscn.VersionString; + srcscn.VersionNumber = refscn.VersionNumber; + srcscn.RawIndividualVictory = refscn.RawIndividualVictory; + srcscn.RawDisables = refscn.RawDisables; + srcscn.RawRemaining = refscn.RawRemaining; - refscn.PlayerSettings = srcscn.PlayerSettings; - refscn.Resources2 = srcscn.Resources2; - refscn.Messages = srcscn.Messages; - refscn.Cinematics = srcscn.Cinematics; - refscn.GlobalVictory = srcscn.GlobalVictory; - - refscn.Map = srcscn.Map; - refscn.Units = srcscn.Units; - - refscn.PlayerSettings.ForEach(x => { - x.NameStringID = -1; - x.FilenameAI = "RandomGame"; x.FilenameCTY = ""; x.FilenamePER = ""; - x.ScriptAI = ""; x.ScriptCTY = ""; x.ScriptPER = ""; + srcscn.PlayerSettings.ForEach(x => { + x.FilenameAI = x.FilenameCTY = x.FilenamePER = "RandomGame"; + x.ScriptAI = x.ScriptCTY = x.ScriptPER = ""; }); - Enumerables.ForBoth(refscn.PlayerSettings2, srcscn.PlayerSettings2, (r, s) => { - r.Name = s.Name; - r.CameraX = s.CameraX; - r.CameraY = s.CameraY; - r.AlliedVictory = s.AlliedVictory; - r.Stances = s.Stances; - }); + var converter = new CopymapConverter(); + converter.Convert(srcscn); - var converter = new ConvertCommandHelper(); - converter.Convert(refscn); - - GenieFile.Serialize(refscn, outstream); + GenieFile.Serialize(srcscn, outstream); } } - public ConvertCommand() + override public int GetArgumentCount() { - MinArgumentCount = 3; - Description = "Convert AOE1 scenario"; - Help = "Convert AOE1 scenario to AOE2" + return 3; + } + + override public string GetDescription() + { + return "Convert AOE1 scenario"; + } + + override public string GetHelp() + { + return "Convert AOE1 scenario to AOE2" + "\n" + "\nThe converter needs an existing AOE2 scenario to start with." + "\n" diff --git a/src/cmdapp/src/ConvertCommandHelper.cs b/src/cmdapp/src/CopymapConverter.cs similarity index 71% rename from src/cmdapp/src/ConvertCommandHelper.cs rename to src/cmdapp/src/CopymapConverter.cs index 5404e62..d2d74f3 100644 --- a/src/cmdapp/src/ConvertCommandHelper.cs +++ b/src/cmdapp/src/CopymapConverter.cs @@ -4,20 +4,44 @@ using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class ConvertCommandHelper + public class CopymapConverter { public void Convert(Scenario scn) { - ChangeUnits_AOE1_AOE2(scn); - MoveUnits_AOE1_AOE2(scn); - ChangeTiles_AOE1_AOE2(scn); - RandomizeTrees_AOE2(scn); + scn.Units = ChangeUnits_AOE1_AOE2(scn.Units); + MoveUnits_AOE1_AOE2(scn.Units); + ChangeTiles_AOE1_AOE2(scn.Units, scn.Map); + RandomizeTrees_AOE2(scn.Units); + } + + /** + * Some buildings are not the same size. + * They need to be moved by half a unit. + */ + private void MoveUnits_AOE1_AOE2(IList[] units) + { + var mapping = new int[] { + // Towers + 79, 199, 69, 278, + // Other Buildings + 109, 68, 103, + }; + units.ForEach(list => { + list.ForEach(unit => { + mapping.ForEach(buildingid => { + if (unit.UnitId == buildingid) { + unit.PosX -= 0.5f; + unit.PosY -= 0.5f; + } + }); + }); + }); } /** * Simple mapping of unit IDs */ - private void ChangeUnits_AOE1_AOE2(Scenario scn) + private List[] ChangeUnits_AOE1_AOE2(IList[] units) { var mapping = new short[] { // Resources @@ -117,43 +141,26 @@ namespace AdrianKousz.GenieEngine 129, 129, }.ToDictionary(); - scn.Units = scn.Units.Map(list => { - return (IList)list + var result = units.Map(list => { + return list .Filter(unit => mapping.ContainsKey(unit.UnitId)) - .Map(unit => { - unit.UnitId = mapping[unit.UnitId]; - return unit; - }) - .ToList(); - }).ToList(); - } + .ForEach(unit => { + unit.UnitId = mapping[unit.UnitId]; + }).ToList(); + }).ToArray(); - /** - * Some buildings are not the same size. - * They need to be moved by half a unit. - */ - private void MoveUnits_AOE1_AOE2(Scenario scn) - { - var minus = new int[] { 79, 68, 562, }; - var plus = new int[] { 109, }; - scn.Units.ForEach(list => { - list.ForEach(unit => { - minus.ForEach(buildingid => { if (unit.UnitId != buildingid) return; unit.PosX -= 0.5f; unit.PosY -= 0.5f; }); - plus.ForEach(buildingid => { if (unit.UnitId != buildingid) return; unit.PosX += 0.5f; unit.PosY += 0.5f; }); - }); - }); + return result; } /** * Farms need to be converted including the underlying terrain. */ - private void ChangeTiles_AOE1_AOE2(Scenario scn) + private void ChangeTiles_AOE1_AOE2(IList[] units, Scenario.ScnMap map) { - var map = scn.Map; - scn.Units.ForEach(list => { + units.ForEach(list => { list.ForEach(unit => { - var posx = (int)unit.PosX; - var posy = (int)unit.PosY; + var posx = (int)(unit.PosX - 0.5); + var posy = (int)(unit.PosY - 0.5); var linearpos = posy * map.SizeX + posx; if (false) { // switch @@ -184,16 +191,16 @@ namespace AdrianKousz.GenieEngine * Forests would contain the same tree graphic * without this function */ - private void RandomizeTrees_AOE2(Scenario scn) + private void RandomizeTrees_AOE2(IList[] units) { var treeids = new int[] { 411, 351, 414, 350, 348, 349, }; - scn.Units.ForEach(list => { + units.ForEach(list => { list.ForEach(unit => { treeids.ForEach(treeid => { if (unit.UnitId == treeid) { - unit.Rotation = unit.InitialFrame = (short)Util.Math.Rand(0, 14); + unit.Rotation = (short)Util.Math.Rand(0, 13); // Whats the maximum? } }); }); diff --git a/src/cmdapp/src/DecompressCommand.cs b/src/cmdapp/src/DecompressCommand.cs index e35325e..c21b301 100644 --- a/src/cmdapp/src/DecompressCommand.cs +++ b/src/cmdapp/src/DecompressCommand.cs @@ -1,24 +1,31 @@ using System.IO; -using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class DecompressCommand : CmdApp.Command + public class DecompressCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var output = File.OpenWrite(args[1])) { - GenieFile.ScenarioDecompress(input, output); + GenieFile.ScenarioCompression(input, output, true); } } - public DecompressCommand() + override public int GetArgumentCount() { - MinArgumentCount = 2; - Description = "Decompress a scenario file"; - Help = "Decompress a scenario file for hex editing." + return 2; + } + + override public string GetDescription() + { + return "Decompress a scenario file"; + } + + override public string GetHelp() + { + return "Decompress a scenario file for hex editing." + "\n" + "\nParameters:" + "\n " diff --git a/src/cmdapp/src/DelBitmapCommand.cs b/src/cmdapp/src/DelBitmapCommand.cs index 20d5e64..63e5f5c 100644 --- a/src/cmdapp/src/DelBitmapCommand.cs +++ b/src/cmdapp/src/DelBitmapCommand.cs @@ -1,11 +1,12 @@ using System.IO; +using System.Drawing; using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class DelBitmapCommand : CmdApp.Command + public class DelBitmapCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var output = File.OpenWrite(args[1])) @@ -20,11 +21,19 @@ namespace AdrianKousz.GenieEngine } } - public DelBitmapCommand() + override public int GetArgumentCount() { - MinArgumentCount = 2; - Description = "Remove the pregame bitmap"; - Help = "Remove the pregame bitmap from a scenario." + return 2; + } + + override public string GetDescription() + { + return "Remove the pregame bitmap"; + } + + override public string GetHelp() + { + return "Remove the pregame bitmap from a scenario." + "\n" + "\nParameters:" + "\n " diff --git a/src/cmdapp/src/DumpunitsCommand.cs b/src/cmdapp/src/DumpunitsCommand.cs index a13f17c..56eca5e 100644 --- a/src/cmdapp/src/DumpunitsCommand.cs +++ b/src/cmdapp/src/DumpunitsCommand.cs @@ -1,12 +1,13 @@ using System; using System.IO; +using System.Collections.Generic; using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class DumpunitsCommand : CmdApp.Command + public class DumpunitsCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { Scenario scn; using (var input = File.OpenRead(args[0])) @@ -14,24 +15,29 @@ namespace AdrianKousz.GenieEngine scn = GenieFile.Deserialize(input); } - Console.WriteLine("{0,-8} {1,-8} {2,-8} {3,-8} {4}", "Player", "ID", "UnitID", "TileID", "Position"); + Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position"); Console.WriteLine(); var i = 0; scn.Units.ForEach(list => { + Console.WriteLine("Units of player {0}:", i++); list.ForEach(unit => { - var tilex = (int)unit.PosX; - var tiley = (int)unit.PosY; + var tilex = (int)(unit.PosX - 0.5); + var tiley = (int)(unit.PosY - 0.5); var tile = scn.Map.LinearTiles[tiley * scn.Map.SizeX + tilex]; - Console.WriteLine("{0,-8} {1,-8} {2,-8} {3,-8} ({4,6:0.##},{5,6:0.##})", i, unit.Id, unit.UnitId, tile.Id, unit.PosX, unit.PosY); + Console.WriteLine("{0,-8} {1,-8} {2,-8} ({3,6:0.##},{4,6:0.##})", unit.Id, unit.UnitId, tile.Id, unit.PosX, unit.PosY); }); - i++; + Console.WriteLine(); }); } - public DumpunitsCommand() + override public int GetArgumentCount() { - MinArgumentCount = 1; - Description = "Dump units and underlying map tiles"; + return 1; + } + + override public string GetDescription() + { + return "Dump units and map tiles below"; } } } diff --git a/src/cmdapp/src/ExtractCommand.cs b/src/cmdapp/src/ExtractCommand.cs index 23d0275..514d895 100644 --- a/src/cmdapp/src/ExtractCommand.cs +++ b/src/cmdapp/src/ExtractCommand.cs @@ -4,9 +4,9 @@ using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class ExtractCommand : CmdApp.Command + public class ExtractCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var file = File.OpenRead(args[0])) { @@ -22,10 +22,14 @@ namespace AdrianKousz.GenieEngine } } - public ExtractCommand() + override public int GetArgumentCount() { - MinArgumentCount = 1; - Description = "Extract files from campaign file"; + return 1; + } + + override public string GetDescription() + { + return "Extract files from campaign file"; } } } diff --git a/src/cmdapp/src/FromJsonCommand.cs b/src/cmdapp/src/FromJsonCommand.cs index 641e0d8..7ad9ce8 100644 --- a/src/cmdapp/src/FromJsonCommand.cs +++ b/src/cmdapp/src/FromJsonCommand.cs @@ -4,9 +4,9 @@ using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class FromJsonCommand : CmdApp.Command + public class FromJsonCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var reader = input.GetReader()) @@ -18,11 +18,19 @@ namespace AdrianKousz.GenieEngine } } - public FromJsonCommand() + override public int GetArgumentCount() { - MinArgumentCount = 2; - Description = "Convert a JSON file to a scenario"; - Help = "Read a Scenario structure formatted as JSON and save it as a Scenario." + return 2; + } + + override public string GetDescription() + { + return "Convert a JSON file to a scenario"; + } + + override public string GetHelp() + { + return "Read a Scenario structure formatted as JSON and save it as a Scenario." + "\n" + "\nParameters:" + "\n " diff --git a/src/cmdapp/src/PackCommand.cs b/src/cmdapp/src/PackCommand.cs index 3f2aee8..57acae8 100644 --- a/src/cmdapp/src/PackCommand.cs +++ b/src/cmdapp/src/PackCommand.cs @@ -4,9 +4,9 @@ using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class PackCommand : CmdApp.Command + public class PackCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { var files = new List(); for (var i = 2; i < args.Length; i++) { @@ -33,10 +33,14 @@ namespace AdrianKousz.GenieEngine } } - public PackCommand() + override public int GetArgumentCount() { - MinArgumentCount = 3; - Description = "Pack files into a campaign file"; + return 3; + } + + override public string GetDescription() + { + return "Pack files into a campaign file"; } } } diff --git a/src/cmdapp/src/Program.cs b/src/cmdapp/src/Program.cs index f3f0d77..346cafd 100644 --- a/src/cmdapp/src/Program.cs +++ b/src/cmdapp/src/Program.cs @@ -1,39 +1,51 @@ -using System.Collections.Generic; -using System.Windows.Forms; -using AdrianKousz.Util; +using AdrianKousz.Util; +using System.Collections.Generic; namespace AdrianKousz.GenieEngine { - public class Program + public class Program : IApp { public static void Main(string[] args) { System.Threading.Thread.CurrentThread.Name = "main"; Log.SetUncaughtExceptionHandler(); - new CmdApp.Builder() - .Header("Scenario Editor") - .NoArg(new MessageBoxCommand()) - .Add("convert", new ConvertCommand()) - .Add("bmp2map", new Bmp2MapCommand()) - .Add("addbmp", new AddBitmapCommand()) - .Add("delbmp", new DelBitmapCommand()) - .Add("compress", new CompressCommand()) - .Add("decompress", new DecompressCommand()) - .Add("tojson", new ToJsonCommand()) - .Add("fromjson", new FromJsonCommand()) - .Add("dumpunits", new DumpunitsCommand()) - .Add("extract", new ExtractCommand()) - .Add("pack", new PackCommand()) - .Build() - .Run(args); + if (System.Diagnostics.Debugger.IsAttached) { + debug(); + return; + } + + new CmdApp(new Program(), args).Run(); } - private class MessageBoxCommand : CmdApp.Command + public string GetHeader() { - public override void Run(string[] args) - { - MessageBox.Show("Start the program on the command line like \n> GenieEdit.exe help"); + return "Scenario Editor"; + } + + public IDictionary> GetCommands() + { + var result = new Dictionary>(); + result.Add("convert", new ConvertCommand()); + result.Add("bmp2map", new Bmp2MapCommand()); + result.Add("addbmp", new AddBitmapCommand()); + result.Add("delbmp", new DelBitmapCommand()); + result.Add("compress", new CompressCommand()); + result.Add("decompress", new DecompressCommand()); + result.Add("tojson", new ToJsonCommand()); + result.Add("fromjson", new FromJsonCommand()); + result.Add("dumpunits", new DumpunitsCommand()); + result.Add("extract", new ExtractCommand()); + result.Add("pack", new PackCommand()); + return result; + } + + private static void debug() + { + var fn = ""; + using (var istream = System.IO.File.OpenRead(fn)) { + var scn = GenieFile.Deserialize(istream); + System.Diagnostics.Debugger.Break(); // Great to inspect scn } } } diff --git a/src/cmdapp/src/ToJsonCommand.cs b/src/cmdapp/src/ToJsonCommand.cs index 7c3b6e9..50805c7 100644 --- a/src/cmdapp/src/ToJsonCommand.cs +++ b/src/cmdapp/src/ToJsonCommand.cs @@ -4,9 +4,9 @@ using AdrianKousz.Util; namespace AdrianKousz.GenieEngine { - public class ToJsonCommand : CmdApp.Command + public class ToJsonCommand : BaseCommand { - override public void Run(string[] args) + override public void Run() { using (var input = File.OpenRead(args[0])) using (var output = File.OpenWrite(args[1])) @@ -18,11 +18,19 @@ namespace AdrianKousz.GenieEngine } } - public ToJsonCommand() + override public int GetArgumentCount() { - MinArgumentCount = 2; - Description = "Convert a scenario to a JSON file"; - Help = "Save a Scenario structure formatted as JSON." + return 2; + } + + override public string GetDescription() + { + return "Convert a scenario to a JSON file"; + } + + override public string GetHelp() + { + return "Save a Scenario structure formatted as JSON." + "\n" + "\nParameters:" + "\n " diff --git a/src/lib/AdrianKousz.GenieEngine/CpnSerializerReader.cs b/src/lib/AdrianKousz.GenieEngine/CpnSerializerReader.cs index 994678f..096e920 100644 --- a/src/lib/AdrianKousz.GenieEngine/CpnSerializerReader.cs +++ b/src/lib/AdrianKousz.GenieEngine/CpnSerializerReader.cs @@ -31,12 +31,14 @@ namespace AdrianKousz.GenieEngine number = reader.ReadInt32(); result.Files = new PositionInfo() - .CreateArray(number) - .Fill(() => new PositionInfo { - Size = reader.ReadInt32(), - Offset = reader.ReadInt32(), - Name = reader.ReadZString(255), - Filename = reader.ReadZString(257), + .CreateList() + .Fill(number, () => { + return new PositionInfo { + Size = reader.ReadInt32(), + Offset = reader.ReadInt32(), + Name = reader.ReadZString(255), + Filename = reader.ReadZString(257), + }; }) .Map(x => { var file = new Campaign.CpnFile(); @@ -46,7 +48,7 @@ namespace AdrianKousz.GenieEngine file.Filename = x.Filename; return file; }) - .ToList(); + .ToArray(); return result; } diff --git a/src/lib/AdrianKousz.GenieEngine/GenieFile.cs b/src/lib/AdrianKousz.GenieEngine/GenieFile.cs index 87981ad..cb8a40e 100644 --- a/src/lib/AdrianKousz.GenieEngine/GenieFile.cs +++ b/src/lib/AdrianKousz.GenieEngine/GenieFile.cs @@ -101,29 +101,13 @@ namespace AdrianKousz.GenieEngine return new ExtendedBinaryWriter(new NonDisposingStreamWrapper(stream), Scenario.Encoding); } - public static void ScenarioDecompress(Stream input, Stream output) + public static void ScenarioCompression(Stream input, Stream output, bool decompress) { - CopyHeader(input, output); + var mode = decompress ? CompressionMode.Decompress : CompressionMode.Compress; - using (var comp = new DeflateStream(input, CompressionMode.Decompress)) - { - comp.CopyTo(output); - } - } + byte[] buffer; - public static void ScenarioCompress(Stream input, Stream output) - { - CopyHeader(input, output); - - using (var comp = new DeflateStream(output, CompressionMode.Compress)) - { - input.CopyTo(comp); - } - } - - private static void CopyHeader(Stream input, Stream output) - { - var buffer = input.ReadBytes(8); + buffer = input.ReadBytes(8); output.Write(buffer); var headerLength = buffer[4] @@ -134,6 +118,11 @@ namespace AdrianKousz.GenieEngine buffer = input.ReadBytes(headerLength); output.Write(buffer); + + using (var comp = new DeflateStream(input, mode)) + { + comp.CopyTo(output); + } } #endregion diff --git a/src/lib/AdrianKousz.GenieEngine/IScnFactory.cs b/src/lib/AdrianKousz.GenieEngine/IScnFactory.cs index 6197f00..eee1a25 100644 --- a/src/lib/AdrianKousz.GenieEngine/IScnFactory.cs +++ b/src/lib/AdrianKousz.GenieEngine/IScnFactory.cs @@ -4,11 +4,10 @@ { Scenario MakeScenario(); Scenario.ScnPlayerSettings MakePlayerSettings(); - Scenario.ScnResource2 MakeResources2(); - Scenario.ScnPlayerSettings2 MakePlayerSettings2(); Scenario.ScnMessages MakeMessages(); Scenario.ScnCinematics MakeCinematics(); Scenario.ScnGlobalVictory MakeGlobalVictory(); + Scenario.ScnResourceCopy MakeResourceCopy(); Scenario.ScnMap MakeMap(); Scenario.ScnUnit MakeUnit(); } diff --git a/src/lib/AdrianKousz.GenieEngine/Scenario.cs b/src/lib/AdrianKousz.GenieEngine/Scenario.cs index 54fe077..3a9666b 100644 --- a/src/lib/AdrianKousz.GenieEngine/Scenario.cs +++ b/src/lib/AdrianKousz.GenieEngine/Scenario.cs @@ -22,30 +22,30 @@ namespace AdrianKousz.GenieEngine public String Filename; public DateTime Timestamp; public String InstructionsUncompressed; + public Int32 NextId; public Int32 PlayerCount; - - public IList PlayerSettings; - public IList Resources2; - public IList PlayerSettings2; - public ScnMessages Messages; public ScnCinematics Cinematics; public ScnGlobalVictory GlobalVictory; - public ScnMap Map; - public IList> Units; + public ScnPlayerSettings[] PlayerSettings; + public ScnResourceCopy[] ResourceCopies; + public IList[] Units; + + // NOTE: Raw byte arrays that do not have a parser (yet?) + public Byte[] RawIndividualVictory; + public Byte[] RawDisables; + public Byte[] RawRemaining; + + // NOTE: Unknown values public Int32 Unknown1; public Int32 Unknown2; public Int32 Unknown3; public Byte Unknown4; public Single Unknown5; - public Byte[] RawIndividualVictory; - public Byte[] RawDisables; - public Byte[] RawRemaining; - public class ScnPlayerSettings { public const Int32 ExpectedUnknownInfo = 4; @@ -55,11 +55,17 @@ namespace AdrianKousz.GenieEngine public Int32 NameStringID; public Boolean Active; public Boolean Human; - public Byte AIType; public Int32 Civ; - public Int32 StartingAge; public Int32 UnknownInfo; + public String FilenameAI; + public String FilenameCTY; + public String FilenamePER; + public String ScriptAI; + public String ScriptCTY; + public String ScriptPER; + public Byte AIType; + public Int32 ResourceWood; public Int32 ResourceFood; public Int32 ResourceGold; @@ -67,51 +73,9 @@ namespace AdrianKousz.GenieEngine public Int32 ResourceOre; public Int32 UnknownResource; - public Boolean AlliedVictory; public Int32[] Diplomacy; - - public String FilenameAI; - public String FilenameCTY; - public String FilenamePER; - public String ScriptAI; - public String ScriptCTY; - public String ScriptPER; - } - - public class ScnResource2 - { - public const Single ExpectedUnknown = 0; - - public Single Wood; - public Single Food; - public Single Gold; - public Single Stone; - public Single Ore; - public Single Unknown; - public Single PopulationLimit; - } - - public class ScnPlayerSettings2 - { - public String Name; - - public Single CameraX; - public Single CameraY; - public Int16 UnknownX; - public Int16 UnknownY; - public Int32 Color; - public Byte AlliedVictory; - public Stance[] Stances; - - public Single Unknown1; - public Int32 Unknown2; - public Byte[] Unknown; - - public class Stance - { - public Byte Stance1; - public Int32 Stance2; - } + public Boolean AlliedVictory; + public Int32 StartingAge; } public class ScnMessages @@ -163,6 +127,19 @@ namespace AdrianKousz.GenieEngine public Int32 Unknown; } + public class ScnResourceCopy + { + public const Single ExpectedUnknownResource = 0; + + public Single ResourceGold; + public Single ResourceWood; + public Single ResourceFood; + public Single ResourceStone; + public Single ResourceOre; + public Single UnknownResource; + public Single PopulationLimit; + } + public class ScnMap { public Int32 CameraX; diff --git a/src/lib/AdrianKousz.GenieEngine/ScnDefaultFactory.cs b/src/lib/AdrianKousz.GenieEngine/ScnDefaultFactory.cs index 3a19c69..3fa4e47 100644 --- a/src/lib/AdrianKousz.GenieEngine/ScnDefaultFactory.cs +++ b/src/lib/AdrianKousz.GenieEngine/ScnDefaultFactory.cs @@ -32,10 +32,13 @@ namespace AdrianKousz.GenieEngine result.Cinematics = MakeCinematics(); result.GlobalVictory = MakeGlobalVictory(); result.Map = MakeMap(); - result.PlayerSettings = result.PlayerSettings.NewList().Fill(Scenario.NumPlayers, MakePlayerSettings); - result.Resources2 = result.Resources2.NewList().Fill(Scenario.NumPlayerSections - 1, MakeResources2); - result.PlayerSettings2 = result.PlayerSettings2.NewList().Fill(Scenario.NumPlayerSections - 1, MakePlayerSettings2); - result.Units = MakeUnitList(Scenario.NumPlayerSections); + result.ResourceCopies = new Scenario.ScnResourceCopy[Scenario.NumPlayerSections - 1] + .Fill(MakeResourceCopy); + result.PlayerSettings = new Scenario.ScnPlayerSettings[Scenario.NumPlayers] + .Fill(MakePlayerSettings); + result.Units = new List[Scenario.NumPlayerSections] + .Fill(); + } return result; @@ -60,25 +63,6 @@ namespace AdrianKousz.GenieEngine return result; } - public Scenario.ScnResource2 MakeResources2() - { - // AOE2 standard - var result = new Scenario.ScnResource2(); - result.Unknown = Scenario.ScnResource2.ExpectedUnknown; - result.Food = 200; - result.Wood = 200; - result.Gold = 100; - result.Stone = 200; - result.PopulationLimit = 75; - return result; - } - - public Scenario.ScnPlayerSettings2 MakePlayerSettings2() - { - var result = new Scenario.ScnPlayerSettings2(); - return result; - } - public Scenario.ScnMessages MakeMessages() { var result = new Scenario.ScnMessages(); @@ -117,6 +101,19 @@ namespace AdrianKousz.GenieEngine return result; } + public Scenario.ScnResourceCopy MakeResourceCopy() + { + // AOE2 standard + var result = new Scenario.ScnResourceCopy(); + result.UnknownResource = Scenario.ScnResourceCopy.ExpectedUnknownResource; + result.ResourceFood = 200; + result.ResourceWood = 200; + result.ResourceGold = 100; + result.ResourceStone = 200; + result.PopulationLimit = 75; + return result; + } + public Scenario.ScnMap MakeMap() { var result = new Scenario.ScnMap(); @@ -138,13 +135,6 @@ namespace AdrianKousz.GenieEngine result.GarrisonnedInId = -1; return result; } - - public static IList> MakeUnitList(int count = Scenario.NumPlayerSections) - { - IList> result = new List>() - .Fill(count, () => (IList)new List()); - return result; - } } } diff --git a/src/lib/AdrianKousz.GenieEngine/ScnSerializerReader.cs b/src/lib/AdrianKousz.GenieEngine/ScnSerializerReader.cs index 98f34d1..9d4d967 100644 --- a/src/lib/AdrianKousz.GenieEngine/ScnSerializerReader.cs +++ b/src/lib/AdrianKousz.GenieEngine/ScnSerializerReader.cs @@ -33,7 +33,7 @@ namespace AdrianKousz.GenieEngine result.VersionString = reader.ReadString(4); reader.ReadInt32(); // Header Length result.Unknown1 = reader.ReadInt32(); - result.Timestamp = reader.ReadInt32().ToDateTime(); + result.Timestamp = DateTimes.FromUnixTime(reader.ReadInt32()); result.InstructionsUncompressed = reader.ReadZStringInt32(); result.Unknown2 = reader.ReadInt32(); result.PlayerCount = reader.ReadInt32(); @@ -49,7 +49,8 @@ namespace AdrianKousz.GenieEngine result.VersionNumber = reader.ReadSingle(); Version = result.VersionNumber; - result.PlayerSettings = result.PlayerSettings.NewList().Fill(Scenario.NumPlayers, factory.MakePlayerSettings); + result.PlayerSettings = new Scenario.ScnPlayerSettings[Scenario.NumPlayers] + .Fill(factory.MakePlayerSettings); // PlayerSettings 1 @@ -64,8 +65,8 @@ namespace AdrianKousz.GenieEngine } result.PlayerSettings.ForEach(x => { - x.Active = reader.ReadBooleanInt32(); - x.Human = reader.ReadBooleanInt32(); + x.Active = reader.ReadBoolean(); + x.Human = reader.ReadBoolean(); x.Civ = reader.ReadInt32(); x.UnknownInfo = reader.ReadInt32(); }); @@ -109,7 +110,7 @@ namespace AdrianKousz.GenieEngine result.Cinematics.FilenameLoss = reader.ReadStringInt16(); result.Cinematics.FilenameBitmap = reader.ReadStringInt16(); - var hasBitmap = reader.ReadBooleanInt32(); + var hasBitmap = reader.ReadBoolean(); result.Cinematics.BitmapWidth = reader.ReadInt32(); result.Cinematics.BitmapHeight = reader.ReadInt32(); @@ -165,13 +166,13 @@ namespace AdrianKousz.GenieEngine result.GlobalVictory = factory.MakeGlobalVictory(); - result.GlobalVictory.RequireConquest = reader.ReadBooleanInt32(); + result.GlobalVictory.RequireConquest = reader.ReadBoolean(); result.GlobalVictory.Ruins = reader.ReadInt32(); result.GlobalVictory.Artifacts = reader.ReadInt32(); result.GlobalVictory.Discovery = reader.ReadInt32(); result.GlobalVictory.PercentExplored = reader.ReadInt32(); result.GlobalVictory.Unknown = reader.ReadInt32(); - result.GlobalVictory.RequireAllCustom = reader.ReadBooleanInt32(); + result.GlobalVictory.RequireAllCustom = reader.ReadBoolean(); result.GlobalVictory.Mode = reader.ReadInt32(); result.GlobalVictory.Score = reader.ReadInt32(); result.GlobalVictory.Time = reader.ReadInt32(); @@ -187,7 +188,7 @@ namespace AdrianKousz.GenieEngine ReadSeparator(reader, "Player Environment"); result.PlayerSettings.ForEach(x => { - x.AlliedVictory = reader.ReadBooleanInt32(); + x.AlliedVictory = reader.ReadBoolean(); }); if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/; @@ -222,17 +223,18 @@ namespace AdrianKousz.GenieEngine number = reader.ReadInt32(); - result.Resources2 = result.Resources2.NewList().Fill(number - 1, factory.MakeResources2); + result.ResourceCopies = new Scenario.ScnResourceCopy[number - 1] + .Fill(factory.MakeResourceCopy); - result.Resources2.ForEach(x => { - x.Food = reader.ReadSingle(); - x.Wood = reader.ReadSingle(); - x.Gold = reader.ReadSingle(); - x.Stone = reader.ReadSingle(); + result.ResourceCopies.ForEach(x => { + x.ResourceFood = reader.ReadSingle(); + x.ResourceWood = reader.ReadSingle(); + x.ResourceGold = reader.ReadSingle(); + x.ResourceStone = reader.ReadSingle(); if (Version >= 1.18f) { - x.Ore = reader.ReadSingle(); + x.ResourceOre = reader.ReadInt32(); if (Version < 1.3f) { - x.Unknown = reader.ReadSingle(); + x.UnknownResource = reader.ReadInt32(); } } if (Version >= 1.22f) { @@ -242,7 +244,7 @@ namespace AdrianKousz.GenieEngine // Units - result.Units = ScnDefaultFactory.MakeUnitList(number); + result.Units = new List[number].Fill(); result.Units.ForEach(x => { var count = reader.ReadInt32(); @@ -263,39 +265,7 @@ namespace AdrianKousz.GenieEngine }); }); - // PlayerSettings2 - - number = reader.ReadInt32(); - - result.PlayerSettings2 = result.PlayerSettings2.NewList().Fill(number - 1, factory.MakePlayerSettings2); - - result.PlayerSettings2.ForEach(x => { - x.Name = reader.ReadZStringInt16(); - x.CameraX = reader.ReadSingle(); - x.CameraY = reader.ReadSingle(); - x.UnknownX = reader.ReadInt16(); - x.UnknownY = reader.ReadInt16(); - x.AlliedVictory = reader.ReadByte(); - number = reader.ReadInt16(); - x.Stances = new Scenario.ScnPlayerSettings2.Stance[number].Fill(); - x.Stances.ForEach(y => { y.Stance1 = reader.ReadByte(); }); - x.Stances.ForEach(y => { y.Stance2 = reader.ReadInt32(); }); - if (Version >= 1.18f) { - x.Color = reader.ReadInt32(); - } - - x.Unknown1 = reader.ReadSingle(); - x.Unknown2 = reader.ReadInt32(); - - if (x.Unknown1 == 1.0f || x.Unknown1 == 2.0f) { - x.Unknown = reader.ReadBytes(1 + (int)x.Unknown1 * 8 + x.Unknown2 * 44); - } else { - var msg = string.Format("Numbers {0}/{1} for {2}", x.Unknown1, x.Unknown2, x.Name); - throw new System.NotImplementedException(msg); - } - }); - - // Triggers + // More Player Settings and Triggers var bytestream = new MemoryStream(); reader.BaseStream.CopyTo(bytestream); diff --git a/src/lib/AdrianKousz.GenieEngine/ScnSerializerWriter.cs b/src/lib/AdrianKousz.GenieEngine/ScnSerializerWriter.cs index 6a59590..082a0f3 100644 --- a/src/lib/AdrianKousz.GenieEngine/ScnSerializerWriter.cs +++ b/src/lib/AdrianKousz.GenieEngine/ScnSerializerWriter.cs @@ -17,15 +17,13 @@ namespace AdrianKousz.GenieEngine public void Write(ExtendedBinaryWriter writer, Scenario value) { - EnsureValid(value); - var Version = value.VersionNumber; var UncompressedHeaderLength = 20 + writer.GetZByteCount(value.InstructionsUncompressed); // Uncompressed header writer.WriteStringRaw(value.VersionString); - writer.Write((System.Int32)UncompressedHeaderLength); + writer.Write((int)UncompressedHeaderLength); writer.Write(value.Unknown1); writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp)); writer.WriteZStringInt32(value.InstructionsUncompressed); @@ -55,8 +53,8 @@ namespace AdrianKousz.GenieEngine } value.PlayerSettings.ForEach(x => { - writer.WriteBooleanInt32(x.Active); - writer.WriteBooleanInt32(x.Human); + writer.Write(x.Active); + writer.Write(x.Human); writer.Write(x.Civ); writer.Write(x.UnknownInfo); }); @@ -98,7 +96,7 @@ namespace AdrianKousz.GenieEngine var hasBitmap = value.Cinematics.RawBitmap.Length > 0; - writer.WriteBooleanInt32(hasBitmap); + writer.Write(hasBitmap); writer.Write(value.Cinematics.BitmapWidth); writer.Write(value.Cinematics.BitmapHeight); writer.Write(value.Cinematics.BitmapUnknown); @@ -115,9 +113,9 @@ namespace AdrianKousz.GenieEngine }); value.PlayerSettings.ForEach(x => { - writer.Write((System.Int32)writer.GetByteCount(x.ScriptAI)); - writer.Write((System.Int32)writer.GetByteCount(x.ScriptCTY)); - writer.Write((System.Int32)writer.GetByteCount(x.ScriptPER)); + writer.Write((int)writer.GetByteCount(x.ScriptAI)); + writer.Write((int)writer.GetByteCount(x.ScriptCTY)); + writer.Write((int)writer.GetByteCount(x.ScriptPER)); writer.WriteStringRaw(x.ScriptAI); writer.WriteStringRaw(x.ScriptCTY); writer.WriteStringRaw(x.ScriptPER); @@ -150,13 +148,13 @@ namespace AdrianKousz.GenieEngine // Diplomacy - writer.WriteBooleanInt32(value.GlobalVictory.RequireConquest); + writer.Write(value.GlobalVictory.RequireConquest); writer.Write(value.GlobalVictory.Ruins); writer.Write(value.GlobalVictory.Artifacts); writer.Write(value.GlobalVictory.Discovery); writer.Write(value.GlobalVictory.PercentExplored); writer.Write(value.GlobalVictory.Unknown); - writer.WriteBooleanInt32(value.GlobalVictory.RequireAllCustom); + writer.Write(value.GlobalVictory.RequireAllCustom); writer.Write(value.GlobalVictory.Mode); writer.Write(value.GlobalVictory.Score); writer.Write(value.GlobalVictory.Time); @@ -174,7 +172,7 @@ namespace AdrianKousz.GenieEngine WriteSeparator(writer, "Player Environment"); value.PlayerSettings.ForEach(x => { - writer.WriteBooleanInt32(x.AlliedVictory); + writer.Write(x.AlliedVictory); }); writer.Write(value.RawDisables); @@ -205,17 +203,17 @@ namespace AdrianKousz.GenieEngine // ResourceCopies - writer.Write((System.Int32)value.Units.Count); + writer.Write((int)value.Units.Length); - value.Resources2.ForEach(x => { - writer.Write(x.Food); - writer.Write(x.Wood); - writer.Write(x.Gold); - writer.Write(x.Stone); + value.ResourceCopies.ForEach(x => { + writer.Write(x.ResourceFood); + writer.Write(x.ResourceWood); + writer.Write(x.ResourceGold); + writer.Write(x.ResourceStone); if (Version >= 1.18f) { - writer.Write(x.Ore); + writer.Write(x.ResourceOre); if (Version < 1.3f) { - writer.Write(x.Unknown); + writer.Write(x.UnknownResource); } } if (Version >= 1.22f) { @@ -226,7 +224,7 @@ namespace AdrianKousz.GenieEngine // Units value.Units.ForEach(x => { - writer.Write((System.Int32)x.Count); + writer.Write((int)x.Count); x.ForEach(y => { writer.Write(y.PosX); writer.Write(y.PosY); @@ -242,31 +240,7 @@ namespace AdrianKousz.GenieEngine }); }); - // PlayerSettings2 - - writer.Write((System.Int32)(value.PlayerSettings2.Count + 1)); - - value.PlayerSettings2.ForEach(x => { - writer.WriteZStringInt16(x.Name); - writer.Write(x.CameraX); - writer.Write(x.CameraY); - writer.Write(x.UnknownX); - writer.Write(x.UnknownY); - writer.Write(x.AlliedVictory); - writer.Write((System.Int16)x.Stances.Length); - x.Stances.ForEach(y => { writer.Write(y.Stance1); }); - x.Stances.ForEach(y => { writer.Write(y.Stance2); }); - if (Version >= 1.18f) { - writer.Write(x.Color); - } - - writer.Write(x.Unknown1); - writer.Write(x.Unknown2); - - writer.Write(x.Unknown); - }); - - // Triggers + // More Player Settings and Triggers writer.Write(value.RawRemaining); @@ -282,14 +256,6 @@ namespace AdrianKousz.GenieEngine { writer.Write(Scenario.Separator); } - - private void EnsureValid(Scenario value) - { - if (value.PlayerSettings.Count != Scenario.NumPlayers) - throw new System.InvalidOperationException("PlayerSettings.Count != 16"); - if (value.Units.Count - 1 != value.Resources2.Count) - throw new System.InvalidOperationException("Conflicting unit and resource copy count"); - } } } diff --git a/src/lib/AssemblyInfo.cs b/src/lib/AssemblyInfo.cs index 416259d..bbd4456 100644 --- a/src/lib/AssemblyInfo.cs +++ b/src/lib/AssemblyInfo.cs @@ -2,4 +2,4 @@ [assembly: AssemblyTitle("ScenLib")] [assembly: AssemblyDescription("Read and write scenario data from Genie Engine games")] -[assembly: AssemblyVersion("0.6")] +[assembly: AssemblyVersion("0.5")]