Compare commits

..

9 Commits

Author SHA1 Message Date
Adrian d2960720bd Update command line app
* bmp2map: Assign unit IDs
* bmp2map: Check bitmap dimensions
* bmp2map, convert: Change random tree frame code
* convert: Insert values from src to ref, instead of vice-versa (more robust)
* convert: Move buildings is better
* convert: Small API changes
* convert/dumpunits: Correct rounding for tile position underneath a unit
* dumpunits: List player number for each unit
2016-04-26 15:17:34 +02:00
Adrian e56d02ae18 Rename Resources2 2016-04-26 15:16:34 +02:00
Adrian e1af13f4a9 Rename ConvertCommandHelper 2016-04-26 00:56:26 +02:00
Adrian e580e0d8ed Add reading of PlayerSettings2
Additionally:

* Reorder fields in Scenario for more convenient serialization order in JSON
* Use lists instead of arrays
2016-04-25 17:13:59 +02:00
Adrian 11f9804f24 Fix scenario compression commands 2016-04-25 17:11:49 +02:00
Adrian 01a1739496 Fix scenario compression 2016-04-25 17:11:21 +02:00
Adrian 5a19ea7103 Small fix
* Use specific bool reading/writing methods
* Fix reading of ResourceCopies
2016-04-25 17:09:12 +02:00
Adrian ad4bd15136 Refactor commands for new CmdApp interface 2016-04-23 02:42:51 +02:00
Adrian 621336afec Small syntactic changes 2016-04-23 02:42:14 +02:00
24 changed files with 411 additions and 415 deletions

View File

@ -32,20 +32,19 @@
</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>
@ -66,12 +65,11 @@
</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,13 +1,12 @@
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 : BaseCommand public class AddBitmapCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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]))
@ -23,20 +22,11 @@ namespace AdrianKousz.GenieEngine
GenieFile.Serialize(scn, output); GenieFile.Serialize(scn, output);
} }
} }
public AddBitmapCommand()
override public int GetArgumentCount()
{ {
return 3; MinArgumentCount = 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

@ -1,36 +0,0 @@
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,25 +9,24 @@ namespace AdrianKousz.GenieEngine
{ {
public static class BitmapHelpers public static class BitmapHelpers
{ {
public static unsafe void FillMap(Scenario scn, Bitmap bmp, Bitmap bmp2) public static unsafe void FillMap(Scenario scn, Bitmap bmp1, Bitmap bmp2)
{ {
using (var ubmp = new UnsafeBitmap(bmp)) using (var ubmp1 = new UnsafeBitmap(bmp1))
using (var ubmp2 = new UnsafeBitmap(bmp2)) using (var ubmp2 = new UnsafeBitmap(bmp2))
{ {
var factory = new ScnDefaultFactory(); var factory = new ScnDefaultFactory();
Check(ubmp); EnsureValid(ubmp1, ubmp2);
Check(ubmp2);
var ptr = ubmp.Scan0; var ptr1 = ubmp1.Scan0;
var last = ptr + ubmp.Stride * ubmp.Height; var last1 = ptr1 + ubmp1.Stride * ubmp1.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 = ubmp.Width; map.SizeX = ubmp1.Width;
map.SizeY = ubmp.Height; map.SizeY = ubmp1.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>();
@ -41,26 +40,37 @@ namespace AdrianKousz.GenieEngine
treemapping[20] = 349; treemapping[20] = 349;
var i = 0; var i = 0;
while (ptr < last && ptr2 < last2) { var id = 0;
var treeid = treemapping[*ptr]; while (ptr1 < last1 && ptr2 < last2) {
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 = (short)Util.Math.Rand(0, 13); unit.Rotation = unit.InitialFrame = (short)Util.Math.Rand(0, 14);
gaiaunits.Add(unit); gaiaunits.Add(unit);
} }
map.LinearTiles[i++] = new Scenario.ScnMap.Tile(*ptr++, (byte)(*ptr2++ / 37), 0); map.LinearTiles[i++] = new Scenario.ScnMap.Tile(*ptr1++, (byte)(*ptr2++ / 40), 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,13 +1,12 @@
using System; using System.IO;
using System.IO;
using System.Drawing; using System.Drawing;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class Bmp2MapCommand : BaseCommand public class Bmp2MapCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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]))
@ -23,24 +22,16 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public Bmp2MapCommand()
{ {
return 4; MinArgumentCount = 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 37 to generate elevations 0-6." + "\nThe index/gray values of the second bitmap are divided by 40 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,35 +1,28 @@
using System.IO; using System.IO;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class CompressCommand : BaseCommand public class CompressCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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.ScenarioCompression(input, output, false); GenieFile.ScenarioCompress(input, output);
} }
} }
override public int GetArgumentCount() public CompressCommand()
{ {
return 2; MinArgumentCount = 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,12 +1,11 @@
using System; using System.IO;
using System.IO;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class ConvertCommand : BaseCommand public class ConvertCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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]))
@ -15,37 +14,46 @@ 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);
srcscn.VersionString = refscn.VersionString; refscn.Filename = srcscn.Filename;
srcscn.VersionNumber = refscn.VersionNumber; refscn.InstructionsUncompressed = srcscn.InstructionsUncompressed;
srcscn.RawIndividualVictory = refscn.RawIndividualVictory; refscn.NextId = srcscn.NextId;
srcscn.RawDisables = refscn.RawDisables; refscn.PlayerCount = srcscn.PlayerCount;
srcscn.RawRemaining = refscn.RawRemaining;
srcscn.PlayerSettings.ForEach(x => { refscn.PlayerSettings = srcscn.PlayerSettings;
x.FilenameAI = x.FilenameCTY = x.FilenamePER = "RandomGame"; refscn.Resources2 = srcscn.Resources2;
x.ScriptAI = x.ScriptCTY = x.ScriptPER = ""; 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 = "";
}); });
var converter = new CopymapConverter(); Enumerables.ForBoth(refscn.PlayerSettings2, srcscn.PlayerSettings2, (r, s) => {
converter.Convert(srcscn); r.Name = s.Name;
r.CameraX = s.CameraX;
r.CameraY = s.CameraY;
r.AlliedVictory = s.AlliedVictory;
r.Stances = s.Stances;
});
GenieFile.Serialize(srcscn, outstream); var converter = new ConvertCommandHelper();
converter.Convert(refscn);
GenieFile.Serialize(refscn, outstream);
} }
} }
override public int GetArgumentCount() public ConvertCommand()
{ {
return 3; MinArgumentCount = 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,44 +4,20 @@ using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class CopymapConverter public class ConvertCommandHelper
{ {
public void Convert(Scenario scn) public void Convert(Scenario scn)
{ {
scn.Units = ChangeUnits_AOE1_AOE2(scn.Units); ChangeUnits_AOE1_AOE2(scn);
MoveUnits_AOE1_AOE2(scn.Units); MoveUnits_AOE1_AOE2(scn);
ChangeTiles_AOE1_AOE2(scn.Units, scn.Map); ChangeTiles_AOE1_AOE2(scn);
RandomizeTrees_AOE2(scn.Units); RandomizeTrees_AOE2(scn);
}
/**
* 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 List<Scenario.ScnUnit>[] ChangeUnits_AOE1_AOE2(IList<Scenario.ScnUnit>[] units) private void ChangeUnits_AOE1_AOE2(Scenario scn)
{ {
var mapping = new short[] { var mapping = new short[] {
// Resources // Resources
@ -141,26 +117,43 @@ namespace AdrianKousz.GenieEngine
129, 129, 129, 129,
}.ToDictionary(); }.ToDictionary();
var result = units.Map(list => { scn.Units = scn.Units.Map(list => {
return list return (IList<Scenario.ScnUnit>)list
.Filter(unit => mapping.ContainsKey(unit.UnitId)) .Filter(unit => mapping.ContainsKey(unit.UnitId))
.ForEach(unit => { .Map(unit => {
unit.UnitId = mapping[unit.UnitId]; unit.UnitId = mapping[unit.UnitId];
}).ToList(); return unit;
}).ToArray(); })
.ToList();
}).ToList();
}
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(IList<Scenario.ScnUnit>[] units, Scenario.ScnMap map) private void ChangeTiles_AOE1_AOE2(Scenario scn)
{ {
units.ForEach(list => { var map = scn.Map;
scn.Units.ForEach(list => {
list.ForEach(unit => { list.ForEach(unit => {
var posx = (int)(unit.PosX - 0.5); var posx = (int)unit.PosX;
var posy = (int)(unit.PosY - 0.5); var posy = (int)unit.PosY;
var linearpos = posy * map.SizeX + posx; var linearpos = posy * map.SizeX + posx;
if (false) { if (false) {
// switch // switch
@ -191,16 +184,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(IList<Scenario.ScnUnit>[] units) private void RandomizeTrees_AOE2(Scenario scn)
{ {
var treeids = new int[] { var treeids = new int[] {
411, 351, 414, 350, 348, 349, 411, 351, 414, 350, 348, 349,
}; };
units.ForEach(list => { scn.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 = (short)Util.Math.Rand(0, 13); // Whats the maximum? unit.Rotation = unit.InitialFrame = (short)Util.Math.Rand(0, 14);
} }
}); });
}); });

View File

@ -1,31 +1,24 @@
using System.IO; using System.IO;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class DecompressCommand : BaseCommand public class DecompressCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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.ScenarioCompression(input, output, true); GenieFile.ScenarioDecompress(input, output);
} }
} }
override public int GetArgumentCount() public DecompressCommand()
{ {
return 2; MinArgumentCount = 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,12 +1,11 @@
using System.IO; using System.IO;
using System.Drawing;
using AdrianKousz.Util; using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class DelBitmapCommand : BaseCommand public class DelBitmapCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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]))
@ -21,19 +20,11 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public DelBitmapCommand()
{ {
return 2; MinArgumentCount = 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,13 +1,12 @@
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 : BaseCommand public class DumpunitsCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
Scenario scn; Scenario scn;
using (var input = File.OpenRead(args[0])) using (var input = File.OpenRead(args[0]))
@ -15,29 +14,24 @@ namespace AdrianKousz.GenieEngine
scn = GenieFile.Deserialize<Scenario>(input); scn = GenieFile.Deserialize<Scenario>(input);
} }
Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position"); Console.WriteLine("{0,-8} {1,-8} {2,-8} {3,-8} {4}", "Player", "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 - 0.5); var tilex = (int)unit.PosX;
var tiley = (int)(unit.PosY - 0.5); var tiley = (int)unit.PosY;
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,6:0.##},{4,6:0.##})", unit.Id, unit.UnitId, tile.Id, unit.PosX, unit.PosY); 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(); i++;
}); });
} }
override public int GetArgumentCount() public DumpunitsCommand()
{ {
return 1; MinArgumentCount = 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 : BaseCommand public class ExtractCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
using (var file = File.OpenRead(args[0])) using (var file = File.OpenRead(args[0]))
{ {
@ -22,14 +22,10 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public ExtractCommand()
{ {
return 1; MinArgumentCount = 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 : BaseCommand public class FromJsonCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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,19 +18,11 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public FromJsonCommand()
{ {
return 2; MinArgumentCount = 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 : BaseCommand public class PackCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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,14 +33,10 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public PackCommand()
{ {
return 3; MinArgumentCount = 3;
} Description = "Pack files into a campaign file";
override public string GetDescription()
{
return "Pack files into a campaign file";
} }
} }
} }

View File

@ -1,51 +1,39 @@
using AdrianKousz.Util; using System.Collections.Generic;
using System.Collections.Generic; using System.Windows.Forms;
using AdrianKousz.Util;
namespace AdrianKousz.GenieEngine namespace AdrianKousz.GenieEngine
{ {
public class Program : IApp<string, string[]> public class Program
{ {
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();
if (System.Diagnostics.Debugger.IsAttached) { new CmdApp.Builder()
debug(); .Header("Scenario Editor")
return; .NoArg(new MessageBoxCommand())
} .Add("convert", new ConvertCommand())
.Add("bmp2map", new Bmp2MapCommand())
new CmdApp(new Program(), args).Run(); .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);
} }
public string GetHeader() private class MessageBoxCommand : CmdApp.Command
{ {
return "Scenario Editor"; public override void Run(string[] args)
} {
MessageBox.Show("Start the program on the command line like \n> GenieEdit.exe help");
public IDictionary<string, ICommand<string[]>> GetCommands()
{
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 : BaseCommand public class ToJsonCommand : CmdApp.Command
{ {
override public void Run() override public void Run(string[] args)
{ {
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,19 +18,11 @@ namespace AdrianKousz.GenieEngine
} }
} }
override public int GetArgumentCount() public ToJsonCommand()
{ {
return 2; MinArgumentCount = 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,14 +31,12 @@ namespace AdrianKousz.GenieEngine
number = reader.ReadInt32(); number = reader.ReadInt32();
result.Files = new PositionInfo() result.Files = new PositionInfo()
.CreateList() .CreateArray(number)
.Fill(number, () => { .Fill(() => new PositionInfo {
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();
@ -48,7 +46,7 @@ namespace AdrianKousz.GenieEngine
file.Filename = x.Filename; file.Filename = x.Filename;
return file; return file;
}) })
.ToArray(); .ToList();
return result; return result;
} }

View File

@ -101,13 +101,29 @@ namespace AdrianKousz.GenieEngine
return new ExtendedBinaryWriter(new NonDisposingStreamWrapper(stream), Scenario.Encoding); return new ExtendedBinaryWriter(new NonDisposingStreamWrapper(stream), Scenario.Encoding);
} }
public static void ScenarioCompression(Stream input, Stream output, bool decompress) public static void ScenarioDecompress(Stream input, Stream output)
{ {
var mode = decompress ? CompressionMode.Decompress : CompressionMode.Compress; CopyHeader(input, output);
byte[] buffer; using (var comp = new DeflateStream(input, CompressionMode.Decompress))
{
comp.CopyTo(output);
}
}
buffer = input.ReadBytes(8); 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);
output.Write(buffer); output.Write(buffer);
var headerLength = buffer[4] var headerLength = buffer[4]
@ -118,11 +134,6 @@ 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,10 +4,11 @@
{ {
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,16 +55,10 @@ namespace AdrianKousz.GenieEngine
public Int32 NameStringID; public Int32 NameStringID;
public Boolean Active; public Boolean Active;
public Boolean Human; public Boolean Human;
public Int32 Civ;
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 Byte AIType;
public Int32 Civ;
public Int32 StartingAge;
public Int32 UnknownInfo;
public Int32 ResourceWood; public Int32 ResourceWood;
public Int32 ResourceFood; public Int32 ResourceFood;
@ -73,9 +67,51 @@ namespace AdrianKousz.GenieEngine
public Int32 ResourceOre; public Int32 ResourceOre;
public Int32 UnknownResource; public Int32 UnknownResource;
public Int32[] Diplomacy;
public Boolean AlliedVictory; public Boolean AlliedVictory;
public Int32 StartingAge; 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 class ScnMessages public class ScnMessages
@ -127,19 +163,6 @@ 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,13 +32,10 @@ namespace AdrianKousz.GenieEngine
result.Cinematics = MakeCinematics(); result.Cinematics = MakeCinematics();
result.GlobalVictory = MakeGlobalVictory(); result.GlobalVictory = MakeGlobalVictory();
result.Map = MakeMap(); result.Map = MakeMap();
result.ResourceCopies = new Scenario.ScnResourceCopy[Scenario.NumPlayerSections - 1] result.PlayerSettings = result.PlayerSettings.NewList().Fill(Scenario.NumPlayers, MakePlayerSettings);
.Fill(MakeResourceCopy); result.Resources2 = result.Resources2.NewList().Fill(Scenario.NumPlayerSections - 1, MakeResources2);
result.PlayerSettings = new Scenario.ScnPlayerSettings[Scenario.NumPlayers] result.PlayerSettings2 = result.PlayerSettings2.NewList().Fill(Scenario.NumPlayerSections - 1, MakePlayerSettings2);
.Fill(MakePlayerSettings); result.Units = MakeUnitList(Scenario.NumPlayerSections);
result.Units = new List<Scenario.ScnUnit>[Scenario.NumPlayerSections]
.Fill();
} }
return result; return result;
@ -63,6 +60,25 @@ 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();
@ -101,19 +117,6 @@ 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();
@ -135,6 +138,13 @@ 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 = DateTimes.FromUnixTime(reader.ReadInt32()); result.Timestamp = reader.ReadInt32().ToDateTime();
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,8 +49,7 @@ namespace AdrianKousz.GenieEngine
result.VersionNumber = reader.ReadSingle(); result.VersionNumber = reader.ReadSingle();
Version = result.VersionNumber; Version = result.VersionNumber;
result.PlayerSettings = new Scenario.ScnPlayerSettings[Scenario.NumPlayers] result.PlayerSettings = result.PlayerSettings.NewList().Fill(Scenario.NumPlayers, factory.MakePlayerSettings);
.Fill(factory.MakePlayerSettings);
// PlayerSettings 1 // PlayerSettings 1
@ -65,8 +64,8 @@ namespace AdrianKousz.GenieEngine
} }
result.PlayerSettings.ForEach(x => { result.PlayerSettings.ForEach(x => {
x.Active = reader.ReadBoolean(); x.Active = reader.ReadBooleanInt32();
x.Human = reader.ReadBoolean(); x.Human = reader.ReadBooleanInt32();
x.Civ = reader.ReadInt32(); x.Civ = reader.ReadInt32();
x.UnknownInfo = reader.ReadInt32(); x.UnknownInfo = reader.ReadInt32();
}); });
@ -110,7 +109,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.ReadBoolean(); var hasBitmap = reader.ReadBooleanInt32();
result.Cinematics.BitmapWidth = reader.ReadInt32(); result.Cinematics.BitmapWidth = reader.ReadInt32();
result.Cinematics.BitmapHeight = reader.ReadInt32(); result.Cinematics.BitmapHeight = reader.ReadInt32();
@ -166,13 +165,13 @@ namespace AdrianKousz.GenieEngine
result.GlobalVictory = factory.MakeGlobalVictory(); result.GlobalVictory = factory.MakeGlobalVictory();
result.GlobalVictory.RequireConquest = reader.ReadBoolean(); result.GlobalVictory.RequireConquest = reader.ReadBooleanInt32();
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.ReadBoolean(); result.GlobalVictory.RequireAllCustom = reader.ReadBooleanInt32();
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();
@ -188,7 +187,7 @@ namespace AdrianKousz.GenieEngine
ReadSeparator(reader, "Player Environment"); ReadSeparator(reader, "Player Environment");
result.PlayerSettings.ForEach(x => { result.PlayerSettings.ForEach(x => {
x.AlliedVictory = reader.ReadBoolean(); x.AlliedVictory = reader.ReadBooleanInt32();
}); });
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*/;
@ -223,18 +222,17 @@ namespace AdrianKousz.GenieEngine
number = reader.ReadInt32(); number = reader.ReadInt32();
result.ResourceCopies = new Scenario.ScnResourceCopy[number - 1] result.Resources2 = result.Resources2.NewList().Fill(number - 1, factory.MakeResources2);
.Fill(factory.MakeResourceCopy);
result.ResourceCopies.ForEach(x => { result.Resources2.ForEach(x => {
x.ResourceFood = reader.ReadSingle(); x.Food = reader.ReadSingle();
x.ResourceWood = reader.ReadSingle(); x.Wood = reader.ReadSingle();
x.ResourceGold = reader.ReadSingle(); x.Gold = reader.ReadSingle();
x.ResourceStone = reader.ReadSingle(); x.Stone = reader.ReadSingle();
if (Version >= 1.18f) { if (Version >= 1.18f) {
x.ResourceOre = reader.ReadInt32(); x.Ore = reader.ReadSingle();
if (Version < 1.3f) { if (Version < 1.3f) {
x.UnknownResource = reader.ReadInt32(); x.Unknown = reader.ReadSingle();
} }
} }
if (Version >= 1.22f) { if (Version >= 1.22f) {
@ -244,7 +242,7 @@ namespace AdrianKousz.GenieEngine
// Units // Units
result.Units = new List<Scenario.ScnUnit>[number].Fill(); result.Units = ScnDefaultFactory.MakeUnitList(number);
result.Units.ForEach(x => { result.Units.ForEach(x => {
var count = reader.ReadInt32(); var count = reader.ReadInt32();
@ -265,7 +263,39 @@ namespace AdrianKousz.GenieEngine
}); });
}); });
// More Player Settings and Triggers // 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
var bytestream = new MemoryStream(); var bytestream = new MemoryStream();
reader.BaseStream.CopyTo(bytestream); reader.BaseStream.CopyTo(bytestream);

View File

@ -17,13 +17,15 @@ 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((int)UncompressedHeaderLength); writer.Write((System.Int32)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);
@ -53,8 +55,8 @@ namespace AdrianKousz.GenieEngine
} }
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.Write(x.Active); writer.WriteBooleanInt32(x.Active);
writer.Write(x.Human); writer.WriteBooleanInt32(x.Human);
writer.Write(x.Civ); writer.Write(x.Civ);
writer.Write(x.UnknownInfo); writer.Write(x.UnknownInfo);
}); });
@ -96,7 +98,7 @@ namespace AdrianKousz.GenieEngine
var hasBitmap = value.Cinematics.RawBitmap.Length > 0; var hasBitmap = value.Cinematics.RawBitmap.Length > 0;
writer.Write(hasBitmap); writer.WriteBooleanInt32(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);
@ -113,9 +115,9 @@ namespace AdrianKousz.GenieEngine
}); });
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.Write((int)writer.GetByteCount(x.ScriptAI)); writer.Write((System.Int32)writer.GetByteCount(x.ScriptAI));
writer.Write((int)writer.GetByteCount(x.ScriptCTY)); writer.Write((System.Int32)writer.GetByteCount(x.ScriptCTY));
writer.Write((int)writer.GetByteCount(x.ScriptPER)); writer.Write((System.Int32)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);
@ -148,13 +150,13 @@ namespace AdrianKousz.GenieEngine
// Diplomacy // Diplomacy
writer.Write(value.GlobalVictory.RequireConquest); writer.WriteBooleanInt32(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.Write(value.GlobalVictory.RequireAllCustom); writer.WriteBooleanInt32(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);
@ -172,7 +174,7 @@ namespace AdrianKousz.GenieEngine
WriteSeparator(writer, "Player Environment"); WriteSeparator(writer, "Player Environment");
value.PlayerSettings.ForEach(x => { value.PlayerSettings.ForEach(x => {
writer.Write(x.AlliedVictory); writer.WriteBooleanInt32(x.AlliedVictory);
}); });
writer.Write(value.RawDisables); writer.Write(value.RawDisables);
@ -203,17 +205,17 @@ namespace AdrianKousz.GenieEngine
// ResourceCopies // ResourceCopies
writer.Write((int)value.Units.Length); writer.Write((System.Int32)value.Units.Count);
value.ResourceCopies.ForEach(x => { value.Resources2.ForEach(x => {
writer.Write(x.ResourceFood); writer.Write(x.Food);
writer.Write(x.ResourceWood); writer.Write(x.Wood);
writer.Write(x.ResourceGold); writer.Write(x.Gold);
writer.Write(x.ResourceStone); writer.Write(x.Stone);
if (Version >= 1.18f) { if (Version >= 1.18f) {
writer.Write(x.ResourceOre); writer.Write(x.Ore);
if (Version < 1.3f) { if (Version < 1.3f) {
writer.Write(x.UnknownResource); writer.Write(x.Unknown);
} }
} }
if (Version >= 1.22f) { if (Version >= 1.22f) {
@ -224,7 +226,7 @@ namespace AdrianKousz.GenieEngine
// Units // Units
value.Units.ForEach(x => { value.Units.ForEach(x => {
writer.Write((int)x.Count); writer.Write((System.Int32)x.Count);
x.ForEach(y => { x.ForEach(y => {
writer.Write(y.PosX); writer.Write(y.PosX);
writer.Write(y.PosY); writer.Write(y.PosY);
@ -240,7 +242,31 @@ namespace AdrianKousz.GenieEngine
}); });
}); });
// More Player Settings and Triggers // 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
writer.Write(value.RawRemaining); writer.Write(value.RawRemaining);
@ -256,6 +282,14 @@ 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.5")] [assembly: AssemblyVersion("0.6")]