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,31 +1,24 @@
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];
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(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())
.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);
} }
new CmdApp(new Program(), args).Run(); private class MessageBoxCommand : CmdApp.Command
}
public string GetHeader()
{ {
return "Scenario Editor"; public override void Run(string[] args)
}
public IDictionary<string, ICommand<string[]>> GetCommands()
{ {
var result = new Dictionary<string, ICommand<string[]>>(); MessageBox.Show("Start the program on the command line like \n> GenieEdit.exe help");
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")]