Compare commits

..

No commits in common. "d2960720bdd7420ba6bd795068b599db75df79fa" and "d1593f38c5e1adaf466cd23a5d592b06d96f4235" have entirely different histories.

24 changed files with 414 additions and 410 deletions

View File

@ -32,19 +32,20 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="src\Program.cs" /> <Compile Include="src\Program.cs" />
<Compile Include="src\BaseCommand.cs" />
<Compile Include="src\ExtractCommand.cs" /> <Compile Include="src\ExtractCommand.cs" />
<Compile Include="src\ToJsonCommand.cs" /> <Compile Include="src\ToJsonCommand.cs" />
<Compile Include="src\FromJsonCommand.cs" /> <Compile Include="src\FromJsonCommand.cs" />
<Compile Include="src\CompressCommand.cs" /> <Compile Include="src\CompressCommand.cs" />
<Compile Include="src\DecompressCommand.cs" /> <Compile Include="src\DecompressCommand.cs" />
<Compile Include="src\DumpunitsCommand.cs" /> <Compile Include="src\DumpunitsCommand.cs" />
<Compile Include="src\CopymapConverter.cs" />
<Compile Include="src\ConvertCommand.cs" /> <Compile Include="src\ConvertCommand.cs" />
<Compile Include="src\AddBitmapCommand.cs" /> <Compile Include="src\AddBitmapCommand.cs" />
<Compile Include="src\DelBitmapCommand.cs" /> <Compile Include="src\DelBitmapCommand.cs" />
<Compile Include="src\PackCommand.cs" /> <Compile Include="src\PackCommand.cs" />
<Compile Include="src\Bmp2MapCommand.cs" /> <Compile Include="src\Bmp2MapCommand.cs" />
<Compile Include="src\BitmapHelpers.cs" /> <Compile Include="src\BitmapHelpers.cs" />
<Compile Include="src\ConvertCommandHelper.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>
@ -65,11 +66,12 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" />
<Reference Include="System.Web.Extensions" />
<Reference Include="Newtonsoft.Json"> <Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath> <HintPath>..\packages\Newtonsoft.Json.8.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Drawing" /> <Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config" /> <None Include="packages.config" />

View File

@ -1,12 +1,13 @@
using System.IO; using System.IO;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var output = File.OpenWrite(args[1])) using (var output = File.OpenWrite(args[1]))
@ -22,11 +23,20 @@ namespace AdrianKousz.GenieEngine
GenieFile.Serialize(scn, output); GenieFile.Serialize(scn, output);
} }
} }
public AddBitmapCommand()
override public int GetArgumentCount()
{ {
MinArgumentCount = 3; return 3;
Description = "Add a pregame bitmap"; }
Help = "Add a pregame bitmap to a scenario."
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." + "\nThe bitmap has to be indexed, otherwise, the game will probably crash."
+ "\nAdditionally, a game-specific palette will be used to display the image." + "\nAdditionally, a game-specific palette will be used to display the image."
+ "\n" + "\n"

View File

@ -0,0 +1,36 @@
using System;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine
{
public class BaseCommand : ICommand<string[]>
{
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);
}
}
}

View File

@ -9,24 +9,25 @@ namespace AdrianKousz.GenieEngine
{ {
public static class BitmapHelpers 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)) using (var ubmp2 = new UnsafeBitmap(bmp2))
{ {
var factory = new ScnDefaultFactory(); var factory = new ScnDefaultFactory();
EnsureValid(ubmp1, ubmp2); Check(ubmp);
Check(ubmp2);
var ptr1 = ubmp1.Scan0; var ptr = ubmp.Scan0;
var last1 = ptr1 + ubmp1.Stride * ubmp1.Height; var last = ptr + ubmp.Stride * ubmp.Height;
var ptr2 = ubmp2.Scan0; var ptr2 = ubmp2.Scan0;
var last2 = ptr2 + ubmp2.Stride * ubmp2.Height; var last2 = ptr2 + ubmp2.Stride * ubmp2.Height;
var map = factory.MakeMap(); var map = factory.MakeMap();
map.SizeX = ubmp1.Width; map.SizeX = ubmp.Width;
map.SizeY = ubmp1.Height; map.SizeY = ubmp.Height;
map.LinearTiles = new Scenario.ScnMap.Tile[map.SizeX * map.SizeY]; map.LinearTiles = new Scenario.ScnMap.Tile[map.SizeX * map.SizeY];
var gaiaunits = new List<Scenario.ScnUnit>(); var gaiaunits = new List<Scenario.ScnUnit>();
@ -40,37 +41,26 @@ namespace AdrianKousz.GenieEngine
treemapping[20] = 349; treemapping[20] = 349;
var i = 0; var i = 0;
var id = 0; while (ptr < last && ptr2 < last2) {
while (ptr1 < last1 && ptr2 < last2) { var treeid = treemapping[*ptr];
var treeid = treemapping[*ptr1];
if (treeid != 0) { if (treeid != 0) {
var unit = factory.MakeUnit(); var unit = factory.MakeUnit();
var posy = i / map.SizeX; var posy = i / map.SizeX;
var posx = i - (posy * map.SizeX); var posx = i - (posy * map.SizeX);
unit.Id = id++;
unit.UnitId = treeid; unit.UnitId = treeid;
unit.PosX = posx + 0.5f; unit.PosX = posx + 0.5f;
unit.PosY = posy + 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); 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.Map = map;
scn.Units[0] = gaiaunits; 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) private static void Check(UnsafeBitmap ubmp)
{ {
if (ubmp.PixelFormat != PixelFormat.Format8bppIndexed) if (ubmp.PixelFormat != PixelFormat.Format8bppIndexed)

View File

@ -1,12 +1,13 @@
using System.IO; using System;
using System.IO;
using System.Drawing; using System.Drawing;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 srcstream = File.OpenRead(args[0]))
using (var outstream = File.OpenWrite(args[1])) using (var outstream = File.OpenWrite(args[1]))
@ -22,16 +23,24 @@ namespace AdrianKousz.GenieEngine
} }
} }
public Bmp2MapCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 4; return 4;
Description = "Generate a scenario map based on bitmaps"; }
Help = "Generate a scenario map based on bitmaps with automatic forest generation."
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" + "\n"
+ "\nTwo bitmaps need to be specified: One terrain map and one elevation map." + "\nTwo bitmaps need to be specified: One terrain map and one elevation map."
+ "\nBoth bitmaps need to be indexed or grayscale." + "\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 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" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input scenario> <output scenario> <terrain bitmap> <elevation bitmap>" + "\n<input scenario> <output scenario> <terrain bitmap> <elevation bitmap>"

View File

@ -1,24 +1,31 @@
using System.IO; using System.IO;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var output = File.OpenWrite(args[1])) using (var output = File.OpenWrite(args[1]))
{ {
GenieFile.ScenarioCompress(input, output); GenieFile.ScenarioCompression(input, output, false);
} }
} }
public CompressCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 2; return 2;
Description = "Recompress a decompressed scenario file"; }
Help = "Recompress a previously decompressed scenario file."
override public string GetDescription()
{
return "Recompress a decompressed scenario file";
}
override public string GetHelp()
{
return "Recompress a previously decompressed scenario file."
+ "\n" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input binary file> <output scenario>" + "\n<input binary file> <output scenario>"

View File

@ -1,11 +1,12 @@
using System.IO; using System;
using System.IO;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 srcstream = File.OpenRead(args[0]))
using (var outstream = File.OpenWrite(args[1])) using (var outstream = File.OpenWrite(args[1]))
@ -14,46 +15,37 @@ namespace AdrianKousz.GenieEngine
var refscn = GenieFile.Deserialize<Scenario>(refstream); var refscn = GenieFile.Deserialize<Scenario>(refstream);
var srcscn = GenieFile.Deserialize<Scenario>(srcstream); var srcscn = GenieFile.Deserialize<Scenario>(srcstream);
refscn.Filename = srcscn.Filename; srcscn.VersionString = refscn.VersionString;
refscn.InstructionsUncompressed = srcscn.InstructionsUncompressed; srcscn.VersionNumber = refscn.VersionNumber;
refscn.NextId = srcscn.NextId; srcscn.RawIndividualVictory = refscn.RawIndividualVictory;
refscn.PlayerCount = srcscn.PlayerCount; srcscn.RawDisables = refscn.RawDisables;
srcscn.RawRemaining = refscn.RawRemaining;
refscn.PlayerSettings = srcscn.PlayerSettings; srcscn.PlayerSettings.ForEach(x => {
refscn.Resources2 = srcscn.Resources2; x.FilenameAI = x.FilenameCTY = x.FilenamePER = "RandomGame";
refscn.Messages = srcscn.Messages; x.ScriptAI = x.ScriptCTY = x.ScriptPER = "";
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 = "";
}); });
Enumerables.ForBoth(refscn.PlayerSettings2, srcscn.PlayerSettings2, (r, s) => { var converter = new CopymapConverter();
r.Name = s.Name; converter.Convert(srcscn);
r.CameraX = s.CameraX;
r.CameraY = s.CameraY;
r.AlliedVictory = s.AlliedVictory;
r.Stances = s.Stances;
});
var converter = new ConvertCommandHelper(); GenieFile.Serialize(srcscn, outstream);
converter.Convert(refscn);
GenieFile.Serialize(refscn, outstream);
} }
} }
public ConvertCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 3; return 3;
Description = "Convert AOE1 scenario"; }
Help = "Convert AOE1 scenario to AOE2"
override public string GetDescription()
{
return "Convert AOE1 scenario";
}
override public string GetHelp()
{
return "Convert AOE1 scenario to AOE2"
+ "\n" + "\n"
+ "\nThe converter needs an existing AOE2 scenario to start with." + "\nThe converter needs an existing AOE2 scenario to start with."
+ "\n" + "\n"

View File

@ -4,20 +4,44 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class ConvertCommandHelper public class CopymapConverter
{ {
public void Convert(Scenario scn) public void Convert(Scenario scn)
{ {
ChangeUnits_AOE1_AOE2(scn); scn.Units = ChangeUnits_AOE1_AOE2(scn.Units);
MoveUnits_AOE1_AOE2(scn); MoveUnits_AOE1_AOE2(scn.Units);
ChangeTiles_AOE1_AOE2(scn); ChangeTiles_AOE1_AOE2(scn.Units, scn.Map);
RandomizeTrees_AOE2(scn); 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<Scenario.ScnUnit>[] 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 * Simple mapping of unit IDs
*/ */
private void ChangeUnits_AOE1_AOE2(Scenario scn) private List<Scenario.ScnUnit>[] ChangeUnits_AOE1_AOE2(IList<Scenario.ScnUnit>[] units)
{ {
var mapping = new short[] { var mapping = new short[] {
// Resources // Resources
@ -117,43 +141,26 @@ namespace AdrianKousz.GenieEngine
129, 129, 129, 129,
}.ToDictionary(); }.ToDictionary();
scn.Units = scn.Units.Map(list => { var result = units.Map(list => {
return (IList<Scenario.ScnUnit>)list return list
.Filter(unit => mapping.ContainsKey(unit.UnitId)) .Filter(unit => mapping.ContainsKey(unit.UnitId))
.Map(unit => { .ForEach(unit => {
unit.UnitId = mapping[unit.UnitId]; unit.UnitId = mapping[unit.UnitId];
return unit;
})
.ToList();
}).ToList(); }).ToList();
} }).ToArray();
/** return result;
* 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; });
});
});
} }
/** /**
* Farms need to be converted including the underlying terrain. * Farms need to be converted including the underlying terrain.
*/ */
private void ChangeTiles_AOE1_AOE2(Scenario scn) private void ChangeTiles_AOE1_AOE2(IList<Scenario.ScnUnit>[] units, Scenario.ScnMap map)
{ {
var map = scn.Map; units.ForEach(list => {
scn.Units.ForEach(list => {
list.ForEach(unit => { list.ForEach(unit => {
var posx = (int)unit.PosX; var posx = (int)(unit.PosX - 0.5);
var posy = (int)unit.PosY; var posy = (int)(unit.PosY - 0.5);
var linearpos = posy * map.SizeX + posx; var linearpos = posy * map.SizeX + posx;
if (false) { if (false) {
// switch // switch
@ -184,16 +191,16 @@ namespace AdrianKousz.GenieEngine
* Forests would contain the same tree graphic * Forests would contain the same tree graphic
* without this function * without this function
*/ */
private void RandomizeTrees_AOE2(Scenario scn) private void RandomizeTrees_AOE2(IList<Scenario.ScnUnit>[] units)
{ {
var treeids = new int[] { var treeids = new int[] {
411, 351, 414, 350, 348, 349, 411, 351, 414, 350, 348, 349,
}; };
scn.Units.ForEach(list => { units.ForEach(list => {
list.ForEach(unit => { list.ForEach(unit => {
treeids.ForEach(treeid => { treeids.ForEach(treeid => {
if (unit.UnitId == 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?
} }
}); });
}); });

View File

@ -1,24 +1,31 @@
using System.IO; using System.IO;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var output = File.OpenWrite(args[1])) using (var output = File.OpenWrite(args[1]))
{ {
GenieFile.ScenarioDecompress(input, output); GenieFile.ScenarioCompression(input, output, true);
} }
} }
public DecompressCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 2; return 2;
Description = "Decompress a scenario file"; }
Help = "Decompress a scenario file for hex editing."
override public string GetDescription()
{
return "Decompress a scenario file";
}
override public string GetHelp()
{
return "Decompress a scenario file for hex editing."
+ "\n" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input scenario> <output binary file>" + "\n<input scenario> <output binary file>"

View File

@ -1,11 +1,12 @@
using System.IO; using System.IO;
using System.Drawing;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var output = File.OpenWrite(args[1])) using (var output = File.OpenWrite(args[1]))
@ -20,11 +21,19 @@ namespace AdrianKousz.GenieEngine
} }
} }
public DelBitmapCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 2; return 2;
Description = "Remove the pregame bitmap"; }
Help = "Remove the pregame bitmap from a scenario."
override public string GetDescription()
{
return "Remove the pregame bitmap";
}
override public string GetHelp()
{
return "Remove the pregame bitmap from a scenario."
+ "\n" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input scenario> <output scenario>" + "\n<input scenario> <output scenario>"

View File

@ -1,12 +1,13 @@
using System; using System;
using System.IO; using System.IO;
using System.Collections.Generic;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class DumpunitsCommand : CmdApp.Command public class DumpunitsCommand : BaseCommand
{ {
override public void Run(string[] args) override public void Run()
{ {
Scenario scn; Scenario scn;
using (var input = File.OpenRead(args[0])) using (var input = File.OpenRead(args[0]))
@ -14,24 +15,29 @@ namespace AdrianKousz.GenieEngine
scn = GenieFile.Deserialize<Scenario>(input); scn = GenieFile.Deserialize<Scenario>(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(); Console.WriteLine();
var i = 0; var i = 0;
scn.Units.ForEach(list => { scn.Units.ForEach(list => {
Console.WriteLine("Units of player {0}:", i++);
list.ForEach(unit => { list.ForEach(unit => {
var tilex = (int)unit.PosX; var tilex = (int)(unit.PosX - 0.5);
var tiley = (int)unit.PosY; var tiley = (int)(unit.PosY - 0.5);
var tile = scn.Map.LinearTiles[tiley * scn.Map.SizeX + tilex]; 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; return 1;
Description = "Dump units and underlying map tiles"; }
override public string GetDescription()
{
return "Dump units and map tiles below";
} }
} }
} }

View File

@ -4,9 +4,9 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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])) using (var file = File.OpenRead(args[0]))
{ {
@ -22,10 +22,14 @@ namespace AdrianKousz.GenieEngine
} }
} }
public ExtractCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 1; return 1;
Description = "Extract files from campaign file"; }
override public string GetDescription()
{
return "Extract files from campaign file";
} }
} }
} }

View File

@ -4,9 +4,9 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var reader = input.GetReader()) using (var reader = input.GetReader())
@ -18,11 +18,19 @@ namespace AdrianKousz.GenieEngine
} }
} }
public FromJsonCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 2; return 2;
Description = "Convert a JSON file to a scenario"; }
Help = "Read a Scenario structure formatted as JSON and save it as a Scenario."
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" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input json> <output scenario>" + "\n<input json> <output scenario>"

View File

@ -4,9 +4,9 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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<Campaign.CpnFile>(); var files = new List<Campaign.CpnFile>();
for (var i = 2; i < args.Length; i++) { for (var i = 2; i < args.Length; i++) {
@ -33,10 +33,14 @@ namespace AdrianKousz.GenieEngine
} }
} }
public PackCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 3; return 3;
Description = "Pack files into a campaign file"; }
override public string GetDescription()
{
return "Pack files into a campaign file";
} }
} }
} }

View File

@ -1,39 +1,51 @@
using System.Collections.Generic; using AdrianKousz.Util;
using System.Windows.Forms; using System.Collections.Generic;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class Program public class Program : IApp<string, string[]>
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
System.Threading.Thread.CurrentThread.Name = "main"; System.Threading.Thread.CurrentThread.Name = "main";
Log.SetUncaughtExceptionHandler(); Log.SetUncaughtExceptionHandler();
new CmdApp.Builder() if (System.Diagnostics.Debugger.IsAttached) {
.Header("Scenario Editor") debug();
.NoArg(new MessageBoxCommand()) return;
.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);
} }
private class MessageBoxCommand : CmdApp.Command new CmdApp(new Program(), args).Run();
}
public string GetHeader()
{ {
public override void Run(string[] args) return "Scenario Editor";
}
public IDictionary<string, ICommand<string[]>> GetCommands()
{ {
MessageBox.Show("Start the program on the command line like \n> GenieEdit.exe help"); var result = new Dictionary<string, ICommand<string[]>>();
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<Scenario>(istream);
System.Diagnostics.Debugger.Break(); // Great to inspect scn
} }
} }
} }

View File

@ -4,9 +4,9 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine 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 input = File.OpenRead(args[0]))
using (var output = File.OpenWrite(args[1])) using (var output = File.OpenWrite(args[1]))
@ -18,11 +18,19 @@ namespace AdrianKousz.GenieEngine
} }
} }
public ToJsonCommand() override public int GetArgumentCount()
{ {
MinArgumentCount = 2; return 2;
Description = "Convert a scenario to a JSON file"; }
Help = "Save a Scenario structure formatted as JSON."
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" + "\n"
+ "\nParameters:" + "\nParameters:"
+ "\n<input scenario> <output json>" + "\n<input scenario> <output json>"

View File

@ -31,12 +31,14 @@ namespace AdrianKousz.GenieEngine
number = reader.ReadInt32(); number = reader.ReadInt32();
result.Files = new PositionInfo() result.Files = new PositionInfo()
.CreateArray(number) .CreateList()
.Fill(() => new PositionInfo { .Fill(number, () => {
return new PositionInfo {
Size = reader.ReadInt32(), Size = reader.ReadInt32(),
Offset = reader.ReadInt32(), Offset = reader.ReadInt32(),
Name = reader.ReadZString(255), Name = reader.ReadZString(255),
Filename = reader.ReadZString(257), Filename = reader.ReadZString(257),
};
}) })
.Map(x => { .Map(x => {
var file = new Campaign.CpnFile(); var file = new Campaign.CpnFile();
@ -46,7 +48,7 @@ namespace AdrianKousz.GenieEngine
file.Filename = x.Filename; file.Filename = x.Filename;
return file; return file;
}) })
.ToList(); .ToArray();
return result; return result;
} }

View File

@ -101,29 +101,13 @@ namespace AdrianKousz.GenieEngine
return new ExtendedBinaryWriter(new NonDisposingStreamWrapper(stream), Scenario.Encoding); 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)) byte[] buffer;
{
comp.CopyTo(output);
}
}
public static void ScenarioCompress(Stream input, Stream output) buffer = input.ReadBytes(8);
{
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);
output.Write(buffer); output.Write(buffer);
var headerLength = buffer[4] var headerLength = buffer[4]
@ -134,6 +118,11 @@ namespace AdrianKousz.GenieEngine
buffer = input.ReadBytes(headerLength); buffer = input.ReadBytes(headerLength);
output.Write(buffer); output.Write(buffer);
using (var comp = new DeflateStream(input, mode))
{
comp.CopyTo(output);
}
} }
#endregion #endregion

View File

@ -4,11 +4,10 @@
{ {
Scenario MakeScenario(); Scenario MakeScenario();
Scenario.ScnPlayerSettings MakePlayerSettings(); Scenario.ScnPlayerSettings MakePlayerSettings();
Scenario.ScnResource2 MakeResources2();
Scenario.ScnPlayerSettings2 MakePlayerSettings2();
Scenario.ScnMessages MakeMessages(); Scenario.ScnMessages MakeMessages();
Scenario.ScnCinematics MakeCinematics(); Scenario.ScnCinematics MakeCinematics();
Scenario.ScnGlobalVictory MakeGlobalVictory(); Scenario.ScnGlobalVictory MakeGlobalVictory();
Scenario.ScnResourceCopy MakeResourceCopy();
Scenario.ScnMap MakeMap(); Scenario.ScnMap MakeMap();
Scenario.ScnUnit MakeUnit(); Scenario.ScnUnit MakeUnit();
} }

View File

@ -22,30 +22,30 @@ namespace AdrianKousz.GenieEngine
public String Filename; public String Filename;
public DateTime Timestamp; public DateTime Timestamp;
public String InstructionsUncompressed; public String InstructionsUncompressed;
public Int32 NextId; public Int32 NextId;
public Int32 PlayerCount; public Int32 PlayerCount;
public IList<ScnPlayerSettings> PlayerSettings;
public IList<ScnResource2> Resources2;
public IList<ScnPlayerSettings2> PlayerSettings2;
public ScnMessages Messages; public ScnMessages Messages;
public ScnCinematics Cinematics; public ScnCinematics Cinematics;
public ScnGlobalVictory GlobalVictory; public ScnGlobalVictory GlobalVictory;
public ScnMap Map; public ScnMap Map;
public IList<IList<ScnUnit>> Units;
public ScnPlayerSettings[] PlayerSettings;
public ScnResourceCopy[] ResourceCopies;
public IList<ScnUnit>[] 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 Unknown1;
public Int32 Unknown2; public Int32 Unknown2;
public Int32 Unknown3; public Int32 Unknown3;
public Byte Unknown4; public Byte Unknown4;
public Single Unknown5; public Single Unknown5;
public Byte[] RawIndividualVictory;
public Byte[] RawDisables;
public Byte[] RawRemaining;
public class ScnPlayerSettings public class ScnPlayerSettings
{ {
public const Int32 ExpectedUnknownInfo = 4; public const Int32 ExpectedUnknownInfo = 4;
@ -55,11 +55,17 @@ namespace AdrianKousz.GenieEngine
public Int32 NameStringID; public Int32 NameStringID;
public Boolean Active; public Boolean Active;
public Boolean Human; public Boolean Human;
public Byte AIType;
public Int32 Civ; public Int32 Civ;
public Int32 StartingAge;
public Int32 UnknownInfo; 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 ResourceWood;
public Int32 ResourceFood; public Int32 ResourceFood;
public Int32 ResourceGold; public Int32 ResourceGold;
@ -67,51 +73,9 @@ namespace AdrianKousz.GenieEngine
public Int32 ResourceOre; public Int32 ResourceOre;
public Int32 UnknownResource; public Int32 UnknownResource;
public Boolean AlliedVictory;
public Int32[] Diplomacy; public Int32[] Diplomacy;
public Boolean AlliedVictory;
public String FilenameAI; public Int32 StartingAge;
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 class ScnMessages public class ScnMessages
@ -163,6 +127,19 @@ namespace AdrianKousz.GenieEngine
public Int32 Unknown; 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 class ScnMap
{ {
public Int32 CameraX; public Int32 CameraX;

View File

@ -32,10 +32,13 @@ namespace AdrianKousz.GenieEngine
result.Cinematics = MakeCinematics(); result.Cinematics = MakeCinematics();
result.GlobalVictory = MakeGlobalVictory(); result.GlobalVictory = MakeGlobalVictory();
result.Map = MakeMap(); result.Map = MakeMap();
result.PlayerSettings = result.PlayerSettings.NewList().Fill(Scenario.NumPlayers, MakePlayerSettings); result.ResourceCopies = new Scenario.ScnResourceCopy[Scenario.NumPlayerSections - 1]
result.Resources2 = result.Resources2.NewList().Fill(Scenario.NumPlayerSections - 1, MakeResources2); .Fill(MakeResourceCopy);
result.PlayerSettings2 = result.PlayerSettings2.NewList().Fill(Scenario.NumPlayerSections - 1, MakePlayerSettings2); result.PlayerSettings = new Scenario.ScnPlayerSettings[Scenario.NumPlayers]
result.Units = MakeUnitList(Scenario.NumPlayerSections); .Fill(MakePlayerSettings);
result.Units = new List<Scenario.ScnUnit>[Scenario.NumPlayerSections]
.Fill();
} }
return result; return result;
@ -60,25 +63,6 @@ namespace AdrianKousz.GenieEngine
return result; 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() public Scenario.ScnMessages MakeMessages()
{ {
var result = new Scenario.ScnMessages(); var result = new Scenario.ScnMessages();
@ -117,6 +101,19 @@ namespace AdrianKousz.GenieEngine
return result; 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() public Scenario.ScnMap MakeMap()
{ {
var result = new Scenario.ScnMap(); var result = new Scenario.ScnMap();
@ -138,13 +135,6 @@ namespace AdrianKousz.GenieEngine
result.GarrisonnedInId = -1; result.GarrisonnedInId = -1;
return result; return result;
} }
public static IList<IList<Scenario.ScnUnit>> MakeUnitList(int count = Scenario.NumPlayerSections)
{
IList<IList<Scenario.ScnUnit>> result = new List<IList<Scenario.ScnUnit>>()
.Fill(count, () => (IList<Scenario.ScnUnit>)new List<Scenario.ScnUnit>());
return result;
}
} }
} }

View File

@ -33,7 +33,7 @@ namespace AdrianKousz.GenieEngine
result.VersionString = reader.ReadString(4); result.VersionString = reader.ReadString(4);
reader.ReadInt32(); // Header Length reader.ReadInt32(); // Header Length
result.Unknown1 = reader.ReadInt32(); result.Unknown1 = reader.ReadInt32();
result.Timestamp = reader.ReadInt32().ToDateTime(); result.Timestamp = DateTimes.FromUnixTime(reader.ReadInt32());
result.InstructionsUncompressed = reader.ReadZStringInt32(); result.InstructionsUncompressed = reader.ReadZStringInt32();
result.Unknown2 = reader.ReadInt32(); result.Unknown2 = reader.ReadInt32();
result.PlayerCount = reader.ReadInt32(); result.PlayerCount = reader.ReadInt32();
@ -49,7 +49,8 @@ namespace AdrianKousz.GenieEngine
result.VersionNumber = reader.ReadSingle(); result.VersionNumber = reader.ReadSingle();
Version = result.VersionNumber; 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 // PlayerSettings 1
@ -64,8 +65,8 @@ namespace AdrianKousz.GenieEngine
} }
result.PlayerSettings.ForEach(x => { result.PlayerSettings.ForEach(x => {
x.Active = reader.ReadBooleanInt32(); x.Active = reader.ReadBoolean();
x.Human = reader.ReadBooleanInt32(); x.Human = reader.ReadBoolean();
x.Civ = reader.ReadInt32(); x.Civ = reader.ReadInt32();
x.UnknownInfo = reader.ReadInt32(); x.UnknownInfo = reader.ReadInt32();
}); });
@ -109,7 +110,7 @@ namespace AdrianKousz.GenieEngine
result.Cinematics.FilenameLoss = reader.ReadStringInt16(); result.Cinematics.FilenameLoss = reader.ReadStringInt16();
result.Cinematics.FilenameBitmap = reader.ReadStringInt16(); result.Cinematics.FilenameBitmap = reader.ReadStringInt16();
var hasBitmap = reader.ReadBooleanInt32(); var hasBitmap = reader.ReadBoolean();
result.Cinematics.BitmapWidth = reader.ReadInt32(); result.Cinematics.BitmapWidth = reader.ReadInt32();
result.Cinematics.BitmapHeight = reader.ReadInt32(); result.Cinematics.BitmapHeight = reader.ReadInt32();
@ -165,13 +166,13 @@ namespace AdrianKousz.GenieEngine
result.GlobalVictory = factory.MakeGlobalVictory(); result.GlobalVictory = factory.MakeGlobalVictory();
result.GlobalVictory.RequireConquest = reader.ReadBooleanInt32(); result.GlobalVictory.RequireConquest = reader.ReadBoolean();
result.GlobalVictory.Ruins = reader.ReadInt32(); result.GlobalVictory.Ruins = reader.ReadInt32();
result.GlobalVictory.Artifacts = reader.ReadInt32(); result.GlobalVictory.Artifacts = reader.ReadInt32();
result.GlobalVictory.Discovery = reader.ReadInt32(); result.GlobalVictory.Discovery = reader.ReadInt32();
result.GlobalVictory.PercentExplored = reader.ReadInt32(); result.GlobalVictory.PercentExplored = reader.ReadInt32();
result.GlobalVictory.Unknown = reader.ReadInt32(); result.GlobalVictory.Unknown = reader.ReadInt32();
result.GlobalVictory.RequireAllCustom = reader.ReadBooleanInt32(); result.GlobalVictory.RequireAllCustom = reader.ReadBoolean();
result.GlobalVictory.Mode = reader.ReadInt32(); result.GlobalVictory.Mode = reader.ReadInt32();
result.GlobalVictory.Score = reader.ReadInt32(); result.GlobalVictory.Score = reader.ReadInt32();
result.GlobalVictory.Time = reader.ReadInt32(); result.GlobalVictory.Time = reader.ReadInt32();
@ -187,7 +188,7 @@ namespace AdrianKousz.GenieEngine
ReadSeparator(reader, "Player Environment"); ReadSeparator(reader, "Player Environment");
result.PlayerSettings.ForEach(x => { 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*/; if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
@ -222,17 +223,18 @@ namespace AdrianKousz.GenieEngine
number = reader.ReadInt32(); 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 => { result.ResourceCopies.ForEach(x => {
x.Food = reader.ReadSingle(); x.ResourceFood = reader.ReadSingle();
x.Wood = reader.ReadSingle(); x.ResourceWood = reader.ReadSingle();
x.Gold = reader.ReadSingle(); x.ResourceGold = reader.ReadSingle();
x.Stone = reader.ReadSingle(); x.ResourceStone = reader.ReadSingle();
if (Version >= 1.18f) { if (Version >= 1.18f) {
x.Ore = reader.ReadSingle(); x.ResourceOre = reader.ReadInt32();
if (Version < 1.3f) { if (Version < 1.3f) {
x.Unknown = reader.ReadSingle(); x.UnknownResource = reader.ReadInt32();
} }
} }
if (Version >= 1.22f) { if (Version >= 1.22f) {
@ -242,7 +244,7 @@ namespace AdrianKousz.GenieEngine
// Units // Units
result.Units = ScnDefaultFactory.MakeUnitList(number); result.Units = new List<Scenario.ScnUnit>[number].Fill();
result.Units.ForEach(x => { result.Units.ForEach(x => {
var count = reader.ReadInt32(); var count = reader.ReadInt32();
@ -263,39 +265,7 @@ namespace AdrianKousz.GenieEngine
}); });
}); });
// PlayerSettings2 // More Player Settings and Triggers
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
var bytestream = new MemoryStream(); var bytestream = new MemoryStream();
reader.BaseStream.CopyTo(bytestream); reader.BaseStream.CopyTo(bytestream);

View File

@ -17,15 +17,13 @@ namespace AdrianKousz.GenieEngine
public void Write(ExtendedBinaryWriter writer, Scenario value) public void Write(ExtendedBinaryWriter writer, Scenario value)
{ {
EnsureValid(value);
var Version = value.VersionNumber; var Version = value.VersionNumber;
var UncompressedHeaderLength = 20 + writer.GetZByteCount(value.InstructionsUncompressed); var UncompressedHeaderLength = 20 + writer.GetZByteCount(value.InstructionsUncompressed);
// Uncompressed header // Uncompressed header
writer.WriteStringRaw(value.VersionString); writer.WriteStringRaw(value.VersionString);
writer.Write((System.Int32)UncompressedHeaderLength); writer.Write((int)UncompressedHeaderLength);
writer.Write(value.Unknown1); writer.Write(value.Unknown1);
writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp)); writer.Write((System.Int32)DateTimes.ToUnixTime(value.Timestamp));
writer.WriteZStringInt32(value.InstructionsUncompressed); writer.WriteZStringInt32(value.InstructionsUncompressed);
@ -55,8 +53,8 @@ namespace AdrianKousz.GenieEngine
} }
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.WriteBooleanInt32(x.Active); writer.Write(x.Active);
writer.WriteBooleanInt32(x.Human); writer.Write(x.Human);
writer.Write(x.Civ); writer.Write(x.Civ);
writer.Write(x.UnknownInfo); writer.Write(x.UnknownInfo);
}); });
@ -98,7 +96,7 @@ namespace AdrianKousz.GenieEngine
var hasBitmap = value.Cinematics.RawBitmap.Length > 0; var hasBitmap = value.Cinematics.RawBitmap.Length > 0;
writer.WriteBooleanInt32(hasBitmap); writer.Write(hasBitmap);
writer.Write(value.Cinematics.BitmapWidth); writer.Write(value.Cinematics.BitmapWidth);
writer.Write(value.Cinematics.BitmapHeight); writer.Write(value.Cinematics.BitmapHeight);
writer.Write(value.Cinematics.BitmapUnknown); writer.Write(value.Cinematics.BitmapUnknown);
@ -115,9 +113,9 @@ namespace AdrianKousz.GenieEngine
}); });
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.Write((System.Int32)writer.GetByteCount(x.ScriptAI)); writer.Write((int)writer.GetByteCount(x.ScriptAI));
writer.Write((System.Int32)writer.GetByteCount(x.ScriptCTY)); writer.Write((int)writer.GetByteCount(x.ScriptCTY));
writer.Write((System.Int32)writer.GetByteCount(x.ScriptPER)); writer.Write((int)writer.GetByteCount(x.ScriptPER));
writer.WriteStringRaw(x.ScriptAI); writer.WriteStringRaw(x.ScriptAI);
writer.WriteStringRaw(x.ScriptCTY); writer.WriteStringRaw(x.ScriptCTY);
writer.WriteStringRaw(x.ScriptPER); writer.WriteStringRaw(x.ScriptPER);
@ -150,13 +148,13 @@ namespace AdrianKousz.GenieEngine
// Diplomacy // Diplomacy
writer.WriteBooleanInt32(value.GlobalVictory.RequireConquest); writer.Write(value.GlobalVictory.RequireConquest);
writer.Write(value.GlobalVictory.Ruins); writer.Write(value.GlobalVictory.Ruins);
writer.Write(value.GlobalVictory.Artifacts); writer.Write(value.GlobalVictory.Artifacts);
writer.Write(value.GlobalVictory.Discovery); writer.Write(value.GlobalVictory.Discovery);
writer.Write(value.GlobalVictory.PercentExplored); writer.Write(value.GlobalVictory.PercentExplored);
writer.Write(value.GlobalVictory.Unknown); writer.Write(value.GlobalVictory.Unknown);
writer.WriteBooleanInt32(value.GlobalVictory.RequireAllCustom); writer.Write(value.GlobalVictory.RequireAllCustom);
writer.Write(value.GlobalVictory.Mode); writer.Write(value.GlobalVictory.Mode);
writer.Write(value.GlobalVictory.Score); writer.Write(value.GlobalVictory.Score);
writer.Write(value.GlobalVictory.Time); writer.Write(value.GlobalVictory.Time);
@ -174,7 +172,7 @@ namespace AdrianKousz.GenieEngine
WriteSeparator(writer, "Player Environment"); WriteSeparator(writer, "Player Environment");
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.WriteBooleanInt32(x.AlliedVictory); writer.Write(x.AlliedVictory);
}); });
writer.Write(value.RawDisables); writer.Write(value.RawDisables);
@ -205,17 +203,17 @@ namespace AdrianKousz.GenieEngine
// ResourceCopies // ResourceCopies
writer.Write((System.Int32)value.Units.Count); writer.Write((int)value.Units.Length);
value.Resources2.ForEach(x => { value.ResourceCopies.ForEach(x => {
writer.Write(x.Food); writer.Write(x.ResourceFood);
writer.Write(x.Wood); writer.Write(x.ResourceWood);
writer.Write(x.Gold); writer.Write(x.ResourceGold);
writer.Write(x.Stone); writer.Write(x.ResourceStone);
if (Version >= 1.18f) { if (Version >= 1.18f) {
writer.Write(x.Ore); writer.Write(x.ResourceOre);
if (Version < 1.3f) { if (Version < 1.3f) {
writer.Write(x.Unknown); writer.Write(x.UnknownResource);
} }
} }
if (Version >= 1.22f) { if (Version >= 1.22f) {
@ -226,7 +224,7 @@ namespace AdrianKousz.GenieEngine
// Units // Units
value.Units.ForEach(x => { value.Units.ForEach(x => {
writer.Write((System.Int32)x.Count); writer.Write((int)x.Count);
x.ForEach(y => { x.ForEach(y => {
writer.Write(y.PosX); writer.Write(y.PosX);
writer.Write(y.PosY); writer.Write(y.PosY);
@ -242,31 +240,7 @@ namespace AdrianKousz.GenieEngine
}); });
}); });
// PlayerSettings2 // More Player Settings and Triggers
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
writer.Write(value.RawRemaining); writer.Write(value.RawRemaining);
@ -282,14 +256,6 @@ namespace AdrianKousz.GenieEngine
{ {
writer.Write(Scenario.Separator); 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");
}
} }
} }

View File

@ -2,4 +2,4 @@
[assembly: AssemblyTitle("ScenLib")] [assembly: AssemblyTitle("ScenLib")]
[assembly: AssemblyDescription("Read and write scenario data from Genie Engine games")] [assembly: AssemblyDescription("Read and write scenario data from Genie Engine games")]
[assembly: AssemblyVersion("0.6")] [assembly: AssemblyVersion("0.5")]