Compare commits
5 Commits
233d0c9c89
...
82d8551ab1
Author | SHA1 | Date |
---|---|---|
Adrian | 82d8551ab1 | |
Adrian | 41cb3e798b | |
Adrian | bb5ac298a4 | |
Adrian | b65cbcd980 | |
Adrian | 4f98f03cfa |
54
README.md
54
README.md
|
@ -4,7 +4,61 @@ Command line application and library to edit scenario and campaign files.
|
||||||
|
|
||||||
**Alpha version**
|
**Alpha version**
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Available commands are:
|
||||||
|
copymap Copy parts of scenarios
|
||||||
|
compress Recompress a decompressed scenario file
|
||||||
|
decompress Decompress a scenario file for hex editing
|
||||||
|
extract Extract scenarios from campaign file
|
||||||
|
dump Dump a scenario file to JSON
|
||||||
|
dumpunits Dump units and map tiles below
|
||||||
|
|
||||||
|
The command `copymap` is able convert an AOE1 to an AOE2 scenario.
|
||||||
|
There seem to be some issues with cliffs.
|
||||||
|
|
||||||
|
[OpeningMoves-AOE2.scx](files/OpeningMoves-AOE2.scx)
|
||||||
|
is a fully automated conversion of a scenario from the AOE1 demo version:
|
||||||
|
|
||||||
|
$ GenieEdit.exe copymap files/examples/aoe2x-Empty.scx "files/examples/aoe1demo-Reigno_1-Opening Moves.scn" files/OpeningMoves-AOE2.scx
|
||||||
|
|
||||||
|
(Stone are set to 100 to be able to build a town center from the beginning.)
|
||||||
|
|
||||||
|
It can also be used to dump units from any version of a scenario:
|
||||||
|
|
||||||
|
$ GenieEdit.exe dumpunits Debug2.scx
|
||||||
|
Scenario Editor
|
||||||
|
|
||||||
|
ID UnitID TileID Position
|
||||||
|
|
||||||
|
Units of player 0:
|
||||||
|
0 69 23 ( 1,5, 11,5)
|
||||||
|
1 69 23 ( 2,5, 11,5)
|
||||||
|
...
|
||||||
|
|
||||||
|
### Code
|
||||||
|
|
||||||
|
Have a look at the command implementations. They are very short.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Clone my projects MainUtil.cs ExUtil.cs and this repository
|
Clone my projects MainUtil.cs ExUtil.cs and this repository
|
||||||
and build `src/GenieEdit.sln`.
|
and build `src/GenieEdit.sln`.
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Contributions are very welcome. ☺
|
||||||
|
Keep in mind that the API is still very unstable.
|
||||||
|
|
||||||
|
Suggestions:
|
||||||
|
|
||||||
|
1. Gather UnitIDs of AOE1
|
||||||
|
2. Much help is appreciated to figure out ID mappings
|
||||||
|
for the conversion process.
|
||||||
|
3. Ideas how to configure the converter (mapping tables).
|
||||||
|
There are some notes in German:
|
||||||
|
[AOE1](files/units-aoe1.txt),
|
||||||
|
[AOE2](files/units-aoe2.txt)
|
||||||
|
3. The application should be able to generate maps from images
|
||||||
|
in the future. How should units be placed using the image?
|
||||||
|
4. Feedback about the API.
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,59 @@
|
||||||
|
Gold 66
|
||||||
|
Bush 59
|
||||||
|
Stone 102
|
||||||
|
Klippe 3x3 264
|
||||||
|
Dorfbewohner 83
|
||||||
|
|
||||||
|
Kleiner Wall 72
|
||||||
|
Mittelgrosser Wall 117
|
||||||
|
Befestigungsanlage 155
|
||||||
|
|
||||||
|
Beobachtungsturm 2x2 79
|
||||||
|
Abwehrturm 2x2 199
|
||||||
|
Wachturm 2x2 69
|
||||||
|
Geschützturm 2x2 278
|
||||||
|
|
||||||
|
Haus 2x2 70
|
||||||
|
Artefakt 159
|
||||||
|
Bauernhof=>Feld 3x3 50
|
||||||
|
Dorfzentrum 3x3 109
|
||||||
|
Kaserne 3x3 12
|
||||||
|
Kornspeicher 3x3 68
|
||||||
|
Lagergrube 3x3 103
|
||||||
|
Stall 101
|
||||||
|
|
||||||
|
Baum 134
|
||||||
|
Buche 140
|
||||||
|
Eiche 141 144 145 146
|
||||||
|
Esche, Fichte 148 136
|
||||||
|
Kiefer 197 194 193 192 135 137 138 139 391 392
|
||||||
|
Palme 150-153
|
||||||
|
|
||||||
|
Wald Gelaende TileID=10:
|
||||||
|
142 143 147 195 365 366 367 393
|
||||||
|
|
||||||
|
Palmenhain Gelaende TileID=13:
|
||||||
|
113 114 121 129
|
||||||
|
|
||||||
|
Dschungel TileID=20:
|
||||||
|
113 114 121 129
|
||||||
|
|
||||||
|
Kiefernwald TileID=19:
|
||||||
|
161 198 203 226 391 392
|
||||||
|
|
||||||
|
Fisch Kueste 260
|
||||||
|
Fisch Kueste 263
|
||||||
|
Fisch Lachs 53
|
||||||
|
Fisch Thun 52
|
||||||
|
Fisch Wal 370
|
||||||
|
|
||||||
|
Aligator 1
|
||||||
|
Aligator Koenig 362
|
||||||
|
Elefant 48
|
||||||
|
Elefant Koenig 90
|
||||||
|
Gazelle 65
|
||||||
|
Gazelle Koenig 384
|
||||||
|
Loewe 126
|
||||||
|
Loewe Koenig 89
|
||||||
|
Vogel Adler 96
|
||||||
|
Vogel Habicht 95
|
|
@ -0,0 +1,74 @@
|
||||||
|
Gold 66
|
||||||
|
Bush 59
|
||||||
|
Stone 102
|
||||||
|
Klippe 3x3 264
|
||||||
|
Dorfbewohner 83
|
||||||
|
|
||||||
|
Palisadenwall 72
|
||||||
|
Steinwallall 117
|
||||||
|
Befestigter Wall 155
|
||||||
|
|
||||||
|
Aussenposten 1x1 598
|
||||||
|
Beobachtungsturm 1x1 79
|
||||||
|
Wachturm 1x1 79
|
||||||
|
Hauptturm 1x1 79
|
||||||
|
|
||||||
|
Haus 2x2 70
|
||||||
|
Reliquie 285
|
||||||
|
Bauernhof=>Feld 3x3 50 (TileID=7)
|
||||||
|
Dorfzentrum 4x4 109
|
||||||
|
Kaserne 3x3 12
|
||||||
|
Muehle 2x2 68
|
||||||
|
Holzlager 2x2 562
|
||||||
|
Stall 3x3 101
|
||||||
|
|
||||||
|
Bambus 348
|
||||||
|
Baum A-L 399-410
|
||||||
|
Baum TD 248
|
||||||
|
Dschungelbaum 414
|
||||||
|
Eiche 349
|
||||||
|
Kiefer 350
|
||||||
|
Palme 351
|
||||||
|
Verschneiter Kiefer 413
|
||||||
|
Waldbaum 411
|
||||||
|
|
||||||
|
Wald Gelaende TileID=10:
|
||||||
|
411
|
||||||
|
|
||||||
|
Palmenhain Gelaende TileID=13:
|
||||||
|
351
|
||||||
|
|
||||||
|
Dschungel TileID=17:
|
||||||
|
414
|
||||||
|
|
||||||
|
Kiefernwald TileID=19:
|
||||||
|
350
|
||||||
|
|
||||||
|
Bambus TileID=18:
|
||||||
|
348
|
||||||
|
|
||||||
|
Eichenwald TileID=20:
|
||||||
|
349
|
||||||
|
|
||||||
|
Fisch Barsch 53
|
||||||
|
Fisch Dorado 455
|
||||||
|
Fisch Lachs 456
|
||||||
|
Fisch Schnapper 458
|
||||||
|
Fisch Thun 457
|
||||||
|
|
||||||
|
Fisch Marlin 1 451
|
||||||
|
Fisch Marlin 2 450
|
||||||
|
Fisch Kueste 69
|
||||||
|
|
||||||
|
Tiere:
|
||||||
|
Vogel Falke 96
|
||||||
|
Jaguar 812
|
||||||
|
Wildes Pferd 835
|
||||||
|
Pferd 814
|
||||||
|
Reh 65
|
||||||
|
Schaf 594
|
||||||
|
Truthahn 833
|
||||||
|
Urwolf 89
|
||||||
|
Wolf 126
|
||||||
|
Wilder Eber 810
|
||||||
|
Wildschwein 48
|
|
@ -36,6 +36,9 @@
|
||||||
<Compile Include="src\CompressCommand.cs" />
|
<Compile Include="src\CompressCommand.cs" />
|
||||||
<Compile Include="src\ExtractCommand.cs" />
|
<Compile Include="src\ExtractCommand.cs" />
|
||||||
<Compile Include="src\DumpCommand.cs" />
|
<Compile Include="src\DumpCommand.cs" />
|
||||||
|
<Compile Include="src\CopymapCommand.cs" />
|
||||||
|
<Compile Include="src\DumpunitsCommand.cs" />
|
||||||
|
<Compile Include="src\CopymapConverter.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -50,6 +53,10 @@
|
||||||
<Project>{662FDCF9-3F6C-48DA-BFE9-F317BEFED692}</Project>
|
<Project>{662FDCF9-3F6C-48DA-BFE9-F317BEFED692}</Project>
|
||||||
<Name>ExUtil</Name>
|
<Name>ExUtil</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\MainUtil.cs\src\main\MainUtil.csproj">
|
||||||
|
<Project>{8306E345-3A99-4F22-AF14-3CEA7425C2EF}</Project>
|
||||||
|
<Name>MainUtil</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
var reader = new ScnReader(file);
|
var reader = new ScnReader(file);
|
||||||
var writer = new ScnWriter(outfile);
|
var writer = new ScnWriter(outfile);
|
||||||
|
|
||||||
var header = reader.ReadScenarioHeader(null);
|
var header = reader.ReadScenarioHeader();
|
||||||
reader.ReadSeparator("Custom");
|
reader.ReadSeparator("Custom");
|
||||||
writer.Write(header);
|
writer.Write(header);
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class CopymapCommand : BaseCommand
|
||||||
|
{
|
||||||
|
override public void Run()
|
||||||
|
{
|
||||||
|
Data.Scenario result;
|
||||||
|
using (var dststream = File.OpenRead(args[0]))
|
||||||
|
using (var srcstream = File.OpenRead(args[1]))
|
||||||
|
{
|
||||||
|
var srcreader = new ScnReader(srcstream);
|
||||||
|
var src = srcreader.ReadScenario();
|
||||||
|
var dstreader = new ScnReader(dststream);
|
||||||
|
var dst = dstreader.ReadScenario();
|
||||||
|
var converter = new CopymapConverter();
|
||||||
|
dst.PlayerNames = src.PlayerNames;
|
||||||
|
dst.StringTablePlayerNames = src.StringTablePlayerNames;
|
||||||
|
dst.Players = src.Players;
|
||||||
|
dst.Resources = src.Resources;
|
||||||
|
dst.ResourcesCopy = src.ResourcesCopy;
|
||||||
|
dst.Messages = src.Messages;
|
||||||
|
converter.Convert(dst, src);
|
||||||
|
result = dst;
|
||||||
|
}
|
||||||
|
using (var outstream = File.OpenWrite(args[2])) {
|
||||||
|
var outwriter = new ScnWriter(outstream);
|
||||||
|
outwriter.Write(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override public int GetArgumentCount()
|
||||||
|
{
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetDescription()
|
||||||
|
{
|
||||||
|
return "Copy parts of scenarios";
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetHelp()
|
||||||
|
{
|
||||||
|
return "Copy the parts below from scenario file 2 into scenario file 1."
|
||||||
|
+ "\nThe result is written to scenario file 3."
|
||||||
|
+ "\n- Messages"
|
||||||
|
+ "\n- Player information"
|
||||||
|
+ "\n- Resources"
|
||||||
|
+ "\n- Map"
|
||||||
|
+ "\n- Units"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class CopymapConverter
|
||||||
|
{
|
||||||
|
public void Convert(Scenario dst, Scenario src)
|
||||||
|
{
|
||||||
|
dst.Map = src.Map;
|
||||||
|
dst.Units = ChangeUnits_AOE1_AOE2(src.Units);
|
||||||
|
MoveUnits_AOE1_AOE2(dst.Units);
|
||||||
|
ChangeTiles_AOE1_AOE2(dst.Units, dst.Map);
|
||||||
|
RandomizeTrees_AOE2(dst.Units);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some buildings are not the same size.
|
||||||
|
* They need to be moved by half a unit.
|
||||||
|
*/
|
||||||
|
private void MoveUnits_AOE1_AOE2(IList<UnitInfo>[] units)
|
||||||
|
{
|
||||||
|
var mapping = new int[] {
|
||||||
|
// Towers
|
||||||
|
79, 199, 69, 278,
|
||||||
|
// Other Buildings
|
||||||
|
109, 68, 103,
|
||||||
|
};
|
||||||
|
units.ForEach((i, list) => {
|
||||||
|
list.ForEach((j, unit) => {
|
||||||
|
mapping.ForEach((k, buildingid) => {
|
||||||
|
if (unit.UnitId == buildingid) {
|
||||||
|
unit.PosX -= 0.5f;
|
||||||
|
unit.PosY -= 0.5f;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple mapping of unit IDs
|
||||||
|
*/
|
||||||
|
private List<UnitInfo>[] ChangeUnits_AOE1_AOE2(IList<UnitInfo>[] units)
|
||||||
|
{
|
||||||
|
var array = new int[] {
|
||||||
|
66, 66,
|
||||||
|
59, 59,
|
||||||
|
102, 102,
|
||||||
|
264, 264,
|
||||||
|
83, 83,
|
||||||
|
125, 125,
|
||||||
|
|
||||||
|
// Buildings
|
||||||
|
72, 72,
|
||||||
|
117, 117,
|
||||||
|
155, 155,
|
||||||
|
79, 598,
|
||||||
|
199, 79,
|
||||||
|
69, 79,
|
||||||
|
278, 79,
|
||||||
|
70, 70,
|
||||||
|
159, 285,
|
||||||
|
109, 109,
|
||||||
|
12, 12,
|
||||||
|
68, 68,
|
||||||
|
103, 562,
|
||||||
|
101, 101,
|
||||||
|
|
||||||
|
// Trees
|
||||||
|
141, 349,
|
||||||
|
144, 349,
|
||||||
|
145, 349,
|
||||||
|
146, 349,
|
||||||
|
197, 350,
|
||||||
|
194, 350,
|
||||||
|
193, 350,
|
||||||
|
192, 350,
|
||||||
|
135, 350,
|
||||||
|
137, 350,
|
||||||
|
138, 350,
|
||||||
|
139, 350,
|
||||||
|
161, 350,
|
||||||
|
198, 350,
|
||||||
|
203, 350,
|
||||||
|
226, 350,
|
||||||
|
391, 350,
|
||||||
|
392, 350,
|
||||||
|
150, 351,
|
||||||
|
151, 351,
|
||||||
|
152, 351,
|
||||||
|
153, 351,
|
||||||
|
134, 411,
|
||||||
|
140, 411,
|
||||||
|
148, 411,
|
||||||
|
136, 411,
|
||||||
|
142, 411,
|
||||||
|
143, 411,
|
||||||
|
147, 411,
|
||||||
|
195, 411,
|
||||||
|
365, 411,
|
||||||
|
366, 411,
|
||||||
|
367, 411,
|
||||||
|
393, 411,
|
||||||
|
|
||||||
|
// Fish
|
||||||
|
260, 69,
|
||||||
|
263, 69,
|
||||||
|
53, 456,
|
||||||
|
52, 457,
|
||||||
|
370, 451,
|
||||||
|
|
||||||
|
// Animals
|
||||||
|
48, 48,
|
||||||
|
90, 48,
|
||||||
|
65, 65,
|
||||||
|
384, 65,
|
||||||
|
126, 126,
|
||||||
|
89, 126,
|
||||||
|
96, 96,
|
||||||
|
|
||||||
|
// Keep and process later
|
||||||
|
50, 50,
|
||||||
|
113, 113,
|
||||||
|
114, 114,
|
||||||
|
121, 121,
|
||||||
|
129, 129,
|
||||||
|
};
|
||||||
|
var mapping = new Dictionary<int, int>();
|
||||||
|
var ai = 0;
|
||||||
|
while (ai < array.Length)
|
||||||
|
mapping.Add(array[ai++], array[ai++]);
|
||||||
|
|
||||||
|
var result = new List<UnitInfo>[Scenario.NumPlayerSections];
|
||||||
|
result.Fill();
|
||||||
|
|
||||||
|
units.ForEach((i, list) => {
|
||||||
|
list.ForEach((j, unit) => {
|
||||||
|
if (mapping.ContainsKey(unit.UnitId)) {
|
||||||
|
unit.UnitId = (short)mapping[unit.UnitId];
|
||||||
|
result[i].Add(unit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Farms need to be converted including the underlying terrain.
|
||||||
|
*/
|
||||||
|
private void ChangeTiles_AOE1_AOE2(IList<UnitInfo>[] units, Map map)
|
||||||
|
{
|
||||||
|
units.ForEach((i, list) => {
|
||||||
|
list.ForEach((j, unit) => {
|
||||||
|
var posx = (int)(unit.PosX - 0.5);
|
||||||
|
var posy = (int)(unit.PosY - 0.5);
|
||||||
|
var linearpos = posy * map.SizeX + posx;
|
||||||
|
if (false) {
|
||||||
|
// switch
|
||||||
|
} else if (unit.UnitId == 50) {
|
||||||
|
map.LinearTiles[linearpos].Id = 7;
|
||||||
|
map.LinearTiles[linearpos - 1].Id = 7;
|
||||||
|
map.LinearTiles[linearpos + 1].Id = 7;
|
||||||
|
map.LinearTiles[linearpos - map.SizeX].Id = 7;
|
||||||
|
map.LinearTiles[linearpos - map.SizeX - 1].Id = 7;
|
||||||
|
map.LinearTiles[linearpos - map.SizeX + 1].Id = 7;
|
||||||
|
map.LinearTiles[linearpos + map.SizeX].Id = 7;
|
||||||
|
map.LinearTiles[linearpos + map.SizeX - 1].Id = 7;
|
||||||
|
map.LinearTiles[linearpos + map.SizeX + 1].Id = 7;
|
||||||
|
} else if (unit.UnitId == 113 || unit.UnitId == 114 || unit.UnitId == 121 || unit.UnitId == 129) {
|
||||||
|
if (map.LinearTiles[linearpos].Id == 20) {
|
||||||
|
map.LinearTiles[linearpos].Id = 17;
|
||||||
|
unit.UnitId = 414;
|
||||||
|
} else {
|
||||||
|
unit.UnitId = 351;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forests would contain the same tree graphic
|
||||||
|
* without this function
|
||||||
|
*/
|
||||||
|
private void RandomizeTrees_AOE2(IList<UnitInfo>[] units)
|
||||||
|
{
|
||||||
|
var treeids = new int[] {
|
||||||
|
411, 351, 414, 350, 348, 349,
|
||||||
|
};
|
||||||
|
units.ForEach((i, list) => {
|
||||||
|
list.ForEach((j, unit) => {
|
||||||
|
treeids.ForEach((k, treeid) => {
|
||||||
|
if (unit.UnitId == treeid) {
|
||||||
|
unit.InitialFrame = (short)Util.Math.Rand(0, 13); // Whats the maximum?
|
||||||
|
unit.Rotation = unit.InitialFrame;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,9 +12,9 @@ namespace AdrianKousz.GenieEngine
|
||||||
var reader = new ScnReader(file);
|
var reader = new ScnReader(file);
|
||||||
var writer = new ScnWriter(outfile);
|
var writer = new ScnWriter(outfile);
|
||||||
|
|
||||||
var header = reader.ReadScenarioHeader(null);
|
var header = reader.ReadScenarioHeader();
|
||||||
writer.Write(header);
|
writer.Write(header);
|
||||||
writer.WriteSeperator();
|
writer.WriteSeperator("Custom");
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
|
|
||||||
using (var comp = new DeflateStream(file, CompressionMode.Decompress)) {
|
using (var comp = new DeflateStream(file, CompressionMode.Decompress)) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
using (var stream = File.OpenRead(args[0])) {
|
using (var stream = File.OpenRead(args[0])) {
|
||||||
var aoereader = new ScnReader(stream);
|
var aoereader = new ScnReader(stream);
|
||||||
var scn = aoereader.ReadScenario(null);
|
var scn = aoereader.ReadScenario();
|
||||||
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
|
var ser = new System.Web.Script.Serialization.JavaScriptSerializer();
|
||||||
var result = ser.Serialize(scn);
|
var result = ser.Serialize(scn);
|
||||||
Console.WriteLine(result);
|
Console.WriteLine(result);
|
||||||
|
@ -23,7 +23,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
override public string GetDescription()
|
override public string GetDescription()
|
||||||
{
|
{
|
||||||
return "Dump a scenario file to XML";
|
return "Dump a scenario file to JSON";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class DumpunitsCommand : BaseCommand
|
||||||
|
{
|
||||||
|
override public void Run()
|
||||||
|
{
|
||||||
|
Scenario scn;
|
||||||
|
using (var stream = File.OpenRead(args[0])) {
|
||||||
|
var aoereader = new ScnReader(stream);
|
||||||
|
scn = aoereader.ReadScenario();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("{0,-8} {1,-8} {2,-8} {3}", "ID", "UnitID", "TileID", "Position");
|
||||||
|
Console.WriteLine();
|
||||||
|
scn.Units.ForEach((i, list) => {
|
||||||
|
Console.WriteLine("Units of player {0}:", i);
|
||||||
|
list.ForEach((j, unit) => {
|
||||||
|
var tilex = (int)(unit.PosX - 0.5);
|
||||||
|
var tiley = (int)(unit.PosY - 0.5);
|
||||||
|
var tile = scn.Map.LinearTiles[tiley * scn.Map.SizeX + tilex];
|
||||||
|
Console.WriteLine("{0,-8} {1,-8} {2,-8} ({3,6:0.##},{4,6:0.##})", unit.Id, unit.UnitId, tile.Id, unit.PosX, unit.PosY);
|
||||||
|
});
|
||||||
|
Console.WriteLine();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
override public int GetArgumentCount()
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public string GetDescription()
|
||||||
|
{
|
||||||
|
return "Dump units and map tiles below";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,11 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
System.Threading.Thread.CurrentThread.Name = "main";
|
System.Threading.Thread.CurrentThread.Name = "main";
|
||||||
|
|
||||||
|
if (System.Diagnostics.Debugger.IsAttached) {
|
||||||
|
debug();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
new CmdApp(new Program(), args).Run();
|
new CmdApp(new Program(), args).Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,11 +25,23 @@ namespace AdrianKousz.GenieEngine
|
||||||
public IDictionary<string, ICommand<string[]>> GetCommands()
|
public IDictionary<string, ICommand<string[]>> GetCommands()
|
||||||
{
|
{
|
||||||
var result = new Dictionary<string, ICommand<string[]>>();
|
var result = new Dictionary<string, ICommand<string[]>>();
|
||||||
|
result.Add("copymap", new CopymapCommand());
|
||||||
result.Add("compress", new CompressCommand());
|
result.Add("compress", new CompressCommand());
|
||||||
result.Add("decompress", new DecompressCommand());
|
result.Add("decompress", new DecompressCommand());
|
||||||
result.Add("extract", new ExtractCommand());
|
result.Add("extract", new ExtractCommand());
|
||||||
result.Add("dump", new DumpCommand());
|
result.Add("dump", new DumpCommand());
|
||||||
|
result.Add("dumpunits", new DumpunitsCommand());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void debug()
|
||||||
|
{
|
||||||
|
var fn = "";
|
||||||
|
using (var istream = System.IO.File.OpenRead(fn)) {
|
||||||
|
var ireader = new ScnReader(istream);
|
||||||
|
var scn = ireader.ReadScenario();
|
||||||
|
System.Diagnostics.Debugger.Break(); // Great to inspect scn
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace AdrianKousz.GenieEngine.Data
|
||||||
public String[] PlayerCustomAIs;
|
public String[] PlayerCustomAIs;
|
||||||
public String[] PlayerCustomCTYs;
|
public String[] PlayerCustomCTYs;
|
||||||
public String[] PlayerCustomPERs;
|
public String[] PlayerCustomPERs;
|
||||||
public Byte[] RawAITypes;
|
public Byte[] AITypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,10 @@ namespace AdrianKousz.GenieEngine.Data
|
||||||
public String CinemaLossFn;
|
public String CinemaLossFn;
|
||||||
public String BackgroundFn;
|
public String BackgroundFn;
|
||||||
|
|
||||||
|
public Int32 BitmapWidth;
|
||||||
|
public Int32 BitmapHeight;
|
||||||
|
public Int16 BitmapUnknown;
|
||||||
|
|
||||||
public Byte[] RawBitmap;
|
public Byte[] RawBitmap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine.Data
|
|
||||||
{
|
|
||||||
public static class Consts
|
|
||||||
{
|
|
||||||
public const Int32 Separator = -99;
|
|
||||||
public const Int32 NumPlayers = 16;
|
|
||||||
public const Int32 NumUnitSections = 9;
|
|
||||||
public static readonly Encoding Encoding = Encoding.GetEncoding(1252);
|
|
||||||
public static readonly Char[] NullChar = new Char[] { '\0' };
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine.Data
|
||||||
|
{
|
||||||
|
public class GlobalVictoryInfo
|
||||||
|
{
|
||||||
|
public Boolean RequireConquest;
|
||||||
|
public Int32 Ruins;
|
||||||
|
public Int32 Artifacts;
|
||||||
|
public Int32 Discovery;
|
||||||
|
public Int32 PercentExplored;
|
||||||
|
public Int32 Unknown;
|
||||||
|
public Boolean RequireAllCustom;
|
||||||
|
public Int32 Mode;
|
||||||
|
public Int32 Score;
|
||||||
|
public Int32 Time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@ namespace AdrianKousz.GenieEngine.Data
|
||||||
{
|
{
|
||||||
public const Int32 ExpectedUnknown = 4;
|
public const Int32 ExpectedUnknown = 4;
|
||||||
|
|
||||||
public String Name;
|
|
||||||
public Int32 StringTable;
|
|
||||||
public Boolean Active;
|
public Boolean Active;
|
||||||
public Boolean Human;
|
public Boolean Human;
|
||||||
public Int32 Civ;
|
public Int32 Civ;
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
using System.Text;
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine.Data
|
namespace AdrianKousz.GenieEngine.Data
|
||||||
{
|
{
|
||||||
public class Scenario
|
public class Scenario
|
||||||
{
|
{
|
||||||
public const Int32 PlayerSections = 9;
|
public const Int32 Separator = -99;
|
||||||
|
public const Int32 NumPlayers = 16;
|
||||||
|
public const Int32 NumPlayerSections = 9;
|
||||||
|
public static readonly Encoding Encoding = Encoding.GetEncoding(1252);
|
||||||
|
|
||||||
public ScenarioHeader Header;
|
public ScenarioHeader Header;
|
||||||
|
|
||||||
|
@ -15,22 +18,36 @@ namespace AdrianKousz.GenieEngine.Data
|
||||||
public Int32 NextId;
|
public Int32 NextId;
|
||||||
public Single OriginalVersion;
|
public Single OriginalVersion;
|
||||||
|
|
||||||
|
public String[] PlayerNames;
|
||||||
|
public Int32[] StringTablePlayerNames;
|
||||||
public PlayerInfo[] Players;
|
public PlayerInfo[] Players;
|
||||||
public Messages Messages;
|
public Messages Messages;
|
||||||
public Cinematics Cinematics;
|
public Cinematics Cinematics;
|
||||||
public AIData AIData;
|
public AIData AIData;
|
||||||
|
|
||||||
|
// Seperator "Resources"
|
||||||
|
|
||||||
public ResourceInfo[] Resources;
|
public ResourceInfo[] Resources;
|
||||||
|
|
||||||
|
// Seperator "Victory"
|
||||||
|
|
||||||
|
public GlobalVictoryInfo GlobalVictory;
|
||||||
|
public Int32[] LinearDiplomacy;
|
||||||
|
public Byte[] RawIndividualVictory;
|
||||||
|
|
||||||
|
// Seperator "Player Settings"
|
||||||
|
|
||||||
|
public Int32[] AlliedVictory;
|
||||||
|
public Byte[] RawDisables;
|
||||||
|
public Int32[] StartingAges;
|
||||||
|
|
||||||
|
// Seperator "Map"
|
||||||
|
|
||||||
public Map Map;
|
public Map Map;
|
||||||
public ResourceInfoCopy[] ResourcesCopy;
|
public ResourceInfoCopy[] ResourcesCopy;
|
||||||
public IList<UnitInfo>[] Units;
|
public IList<UnitInfo>[] Units;
|
||||||
|
|
||||||
public Byte[] RawGlobalVictory;
|
public byte[] RawRemaining;
|
||||||
public Byte[] RawDiplomacy;
|
|
||||||
public Byte[] RawIndividualVictory;
|
|
||||||
public Byte[] RawAlliedVictory;
|
|
||||||
public Byte[] RawDisables;
|
|
||||||
|
|
||||||
public Int32[] StartingAges;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,14 @@ namespace AdrianKousz.GenieEngine.Data
|
||||||
{
|
{
|
||||||
public class UnitInfo
|
public class UnitInfo
|
||||||
{
|
{
|
||||||
public const Single ExpectedUnknown = 2f;
|
public const Single ExpectedUnknown1 = 1f;
|
||||||
|
public const Byte ExpectedUnknown2 = 2;
|
||||||
|
|
||||||
public Single PosX;
|
public Single PosX;
|
||||||
public Single PosY;
|
public Single PosY;
|
||||||
public Single Unknown1;
|
public Single Unknown1;
|
||||||
public Int32 Id;
|
public Int32 Id;
|
||||||
public Int32 UnitId;
|
public Int16 UnitId;
|
||||||
public Byte Unknown2;
|
public Byte Unknown2;
|
||||||
public Single Rotation;
|
public Single Rotation;
|
||||||
public Int16 InitialFrame;
|
public Int16 InitialFrame;
|
||||||
|
|
|
@ -12,7 +12,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
public CpnReader(Stream input)
|
public CpnReader(Stream input)
|
||||||
{
|
{
|
||||||
reader = new ExtendedBinaryReader(input, Data.Consts.Encoding);
|
reader = new ExtendedBinaryReader(input, Scenario.Encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ExtractFiles()
|
public void ExtractFiles()
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public interface IScnFactory
|
||||||
|
{
|
||||||
|
Scenario MakeScenario(bool deep);
|
||||||
|
ScenarioHeader MakeScenarioHeader();
|
||||||
|
PlayerInfo MakePlayerInfo();
|
||||||
|
Messages MakeMessages();
|
||||||
|
Cinematics MakeCinematics();
|
||||||
|
AIData MakeAIData();
|
||||||
|
ResourceInfo MakeResourceInfo();
|
||||||
|
ResourceInfoCopy MakeResourceInfoCopy();
|
||||||
|
GlobalVictoryInfo MakeGlobalVictoryInfo();
|
||||||
|
Map MakeMap();
|
||||||
|
UnitInfo MakeUnitInfo();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
using System;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class ScnConvert
|
||||||
|
{
|
||||||
|
public void Convert(Scenario value, float version)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public void Convert(UnitInfo value, float from, float to)
|
||||||
|
{
|
||||||
|
if (from < 1.18f && to >= 1.18f) {
|
||||||
|
value.InitialFrame = 0;
|
||||||
|
value.GarrisonnedInId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,148 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AdrianKousz.Util;
|
||||||
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
namespace AdrianKousz.GenieEngine
|
||||||
|
{
|
||||||
|
public class ScnDefaultFactory : IScnFactory
|
||||||
|
{
|
||||||
|
public Scenario MakeScenario(bool deep)
|
||||||
|
{
|
||||||
|
var result = new Scenario();
|
||||||
|
result.OriginalVersion = 0;
|
||||||
|
result.NextId = 1;
|
||||||
|
|
||||||
|
result.StringTablePlayerNames = new int[Scenario.NumPlayers];
|
||||||
|
|
||||||
|
result.Units = new IList<UnitInfo>[Scenario.NumPlayerSections]
|
||||||
|
.Fill(() => new List<UnitInfo>());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScenarioHeader MakeScenarioHeader()
|
||||||
|
{
|
||||||
|
var result = new ScenarioHeader();
|
||||||
|
result.Unknown1 = ScenarioHeader.ExpectedUnknown1;
|
||||||
|
result.Unknown2 = ScenarioHeader.ExpectedUnknown2;
|
||||||
|
result.OriginalVersion = "0.00";
|
||||||
|
result.Timestamp = System.DateTime.Now;
|
||||||
|
result.Instructions = "";
|
||||||
|
result.PlayerCount = 2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerInfo MakePlayerInfo()
|
||||||
|
{
|
||||||
|
var result = new PlayerInfo();
|
||||||
|
result.Unknown = PlayerInfo.ExpectedUnknown;
|
||||||
|
result.Active = false;
|
||||||
|
result.Human = false;
|
||||||
|
result.Civ = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Messages MakeMessages()
|
||||||
|
{
|
||||||
|
var result = new Messages();
|
||||||
|
result.Unknown1 = Messages.ExpectedUnknown1;
|
||||||
|
result.Unknown2 = Messages.ExpectedUnknown2;
|
||||||
|
result.Unknown3 = Messages.ExpectedUnknown3;
|
||||||
|
result.OriginalFilename = "";
|
||||||
|
result.TextInstructions = "";
|
||||||
|
result.TextHints = "";
|
||||||
|
result.TextVictory = "";
|
||||||
|
result.TextLoss = "";
|
||||||
|
result.TextHistory = "";
|
||||||
|
result.TextScouts = "";
|
||||||
|
result.StringTableInstructions = -1;
|
||||||
|
result.StringTableHints = -1;
|
||||||
|
result.StringTableVictory = -1;
|
||||||
|
result.StringTableLoss = -1;
|
||||||
|
result.StringTableHistory = -1;
|
||||||
|
result.StringTableScouts = -1;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cinematics MakeCinematics()
|
||||||
|
{
|
||||||
|
var result = new Cinematics();
|
||||||
|
result.CinemaPregameFn = "";
|
||||||
|
result.CinemaVictoryFn = "";
|
||||||
|
result.CinemaLossFn = "";
|
||||||
|
result.BackgroundFn = "";
|
||||||
|
result.RawBitmap = new byte[0];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AIData MakeAIData()
|
||||||
|
{
|
||||||
|
var result = new AIData();
|
||||||
|
result.PlayerAIs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.PlayerCTYs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.PlayerPERs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.PlayerCustomAIs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.PlayerCustomCTYs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.PlayerCustomPERs = new string[Scenario.NumPlayers].Fill("");
|
||||||
|
result.AITypes = new byte[Scenario.NumPlayers].Fill((byte)1);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalVictoryInfo MakeGlobalVictoryInfo()
|
||||||
|
{
|
||||||
|
var result = new GlobalVictoryInfo();
|
||||||
|
result.RequireConquest = true;
|
||||||
|
result.RequireAllCustom = false;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceInfo MakeResourceInfo()
|
||||||
|
{
|
||||||
|
// AOE2 standard
|
||||||
|
var result = new ResourceInfo();
|
||||||
|
result.Unknown = ResourceInfo.ExpectedUnknown;
|
||||||
|
result.Food = 200;
|
||||||
|
result.Wood = 200;
|
||||||
|
result.Gold = 100;
|
||||||
|
result.Stone = 200;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceInfoCopy MakeResourceInfoCopy()
|
||||||
|
{
|
||||||
|
// AOE2 standard
|
||||||
|
var result = new ResourceInfoCopy();
|
||||||
|
result.Unknown = ResourceInfoCopy.ExpectedUnknown;
|
||||||
|
result.Food = 200;
|
||||||
|
result.Wood = 200;
|
||||||
|
result.Gold = 100;
|
||||||
|
result.Stone = 200;
|
||||||
|
result.PopulationLimit = 75;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map MakeMap()
|
||||||
|
{
|
||||||
|
var result = new Map();
|
||||||
|
var size = 144;
|
||||||
|
result.CameraX = -1;
|
||||||
|
result.CameraY = -1;
|
||||||
|
result.GeneratorId = 2;
|
||||||
|
result.SizeX = size;
|
||||||
|
result.SizeY = size;
|
||||||
|
result.LinearTiles = new Map.Tile[size*size].Fill(() => new Map.Tile(0, 1, 0));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitInfo MakeUnitInfo()
|
||||||
|
{
|
||||||
|
var result = new UnitInfo();
|
||||||
|
result.Unknown1 = UnitInfo.ExpectedUnknown1;
|
||||||
|
result.Unknown2 = UnitInfo.ExpectedUnknown2;
|
||||||
|
result.GarrisonnedInId = -1;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
using System.Collections.Generic;
|
|
||||||
using AdrianKousz.Util;
|
|
||||||
using AdrianKousz.GenieEngine.Data;
|
|
||||||
|
|
||||||
namespace AdrianKousz.GenieEngine
|
|
||||||
{
|
|
||||||
public class ScnFactory
|
|
||||||
{
|
|
||||||
public Scenario GetScenario()
|
|
||||||
{
|
|
||||||
var result = new Scenario();
|
|
||||||
result.OriginalVersion = -1;
|
|
||||||
result.NextId = 1;
|
|
||||||
|
|
||||||
result.Header = GetScenarioHeader();
|
|
||||||
|
|
||||||
result.Players = new PlayerInfo[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.Players.Fill(GetPlayerInfo);
|
|
||||||
|
|
||||||
result.Messages = GetMessages();
|
|
||||||
result.Cinematics = GetCinematics();
|
|
||||||
result.AIData = GetAIData();
|
|
||||||
|
|
||||||
result.Resources = new ResourceInfo[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.Resources.Fill(GetResourceInfo);
|
|
||||||
result.Units = new List<UnitInfo>[Scenario.PlayerSections];
|
|
||||||
result.Units.Fill(() => new List<UnitInfo>());
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScenarioHeader GetScenarioHeader()
|
|
||||||
{
|
|
||||||
var result = new ScenarioHeader();
|
|
||||||
result.Unknown1 = ScenarioHeader.ExpectedUnknown1;
|
|
||||||
result.Unknown2 = ScenarioHeader.ExpectedUnknown2;
|
|
||||||
result.OriginalVersion = "0.99";
|
|
||||||
result.Timestamp = System.DateTime.Now;
|
|
||||||
result.Instructions = "";
|
|
||||||
result.PlayerCount = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerInfo GetPlayerInfo(int number)
|
|
||||||
{
|
|
||||||
var result = new PlayerInfo();
|
|
||||||
result.Unknown = PlayerInfo.ExpectedUnknown;
|
|
||||||
result.Name = "Player " + number;
|
|
||||||
result.StringTable = -1;
|
|
||||||
result.Active = true;
|
|
||||||
result.Human = true;
|
|
||||||
result.Civ = number;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Messages GetMessages()
|
|
||||||
{
|
|
||||||
var result = new Messages();
|
|
||||||
result.Unknown1 = Messages.ExpectedUnknown1;
|
|
||||||
result.Unknown2 = Messages.ExpectedUnknown2;
|
|
||||||
result.Unknown3 = Messages.ExpectedUnknown3;
|
|
||||||
result.OriginalFilename = "";
|
|
||||||
result.TextInstructions = "";
|
|
||||||
result.TextHints = "";
|
|
||||||
result.TextVictory = "";
|
|
||||||
result.TextLoss = "";
|
|
||||||
result.TextHistory = "";
|
|
||||||
result.TextScouts = "";
|
|
||||||
result.StringTableInstructions = -1;
|
|
||||||
result.StringTableHints = -1;
|
|
||||||
result.StringTableVictory = -1;
|
|
||||||
result.StringTableLoss = -1;
|
|
||||||
result.StringTableHistory = -1;
|
|
||||||
result.StringTableScouts = -1;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Cinematics GetCinematics()
|
|
||||||
{
|
|
||||||
var result = new Cinematics();
|
|
||||||
result.CinemaPregameFn = "";
|
|
||||||
result.CinemaVictoryFn = "";
|
|
||||||
result.CinemaLossFn = "";
|
|
||||||
result.BackgroundFn = "";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AIData GetAIData()
|
|
||||||
{
|
|
||||||
var result = new AIData();
|
|
||||||
result.PlayerAIs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCTYs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerPERs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCustomAIs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCustomCTYs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCustomPERs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerAIs.Fill("");
|
|
||||||
result.PlayerCTYs.Fill("");
|
|
||||||
result.PlayerPERs.Fill("");
|
|
||||||
result.PlayerCustomAIs.Fill("");
|
|
||||||
result.PlayerCustomCTYs.Fill("");
|
|
||||||
result.PlayerCustomPERs.Fill("");
|
|
||||||
result.RawAITypes = new byte[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.RawAITypes.Fill((byte)1);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceInfo GetResourceInfo()
|
|
||||||
{
|
|
||||||
// AOE2 standard
|
|
||||||
var result = new ResourceInfo();
|
|
||||||
result.Unknown = ResourceInfo.ExpectedUnknown;
|
|
||||||
result.Food = 200;
|
|
||||||
result.Wood = 200;
|
|
||||||
result.Gold = 100;
|
|
||||||
result.Stone = 200;
|
|
||||||
result.Ore = 0;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map GetMap()
|
|
||||||
{
|
|
||||||
var result = new Map();
|
|
||||||
var size = 200;
|
|
||||||
result.CameraX = 0;
|
|
||||||
result.CameraY = 0;
|
|
||||||
result.GeneratorId = 0;
|
|
||||||
result.SizeX = size;
|
|
||||||
result.SizeY = size;
|
|
||||||
result.LinearTiles = new Map.Tile[size*size];
|
|
||||||
result.LinearTiles.Fill();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,81 +8,90 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
public class ScnReader
|
public class ScnReader
|
||||||
{
|
{
|
||||||
private static readonly string TAG = typeof(ScnReader).Name;
|
public float Version = 0;
|
||||||
|
|
||||||
private float version = 0.99f;
|
|
||||||
private ExtendedBinaryReader reader;
|
private ExtendedBinaryReader reader;
|
||||||
|
private IScnFactory factory;
|
||||||
|
|
||||||
public ScnReader(Stream input)
|
public ScnReader(Stream input) : this (input, new ScnDefaultFactory())
|
||||||
{
|
{
|
||||||
reader = new ExtendedBinaryReader(input, Data.Consts.Encoding);
|
}
|
||||||
|
|
||||||
|
public ScnReader(Stream input, IScnFactory factory)
|
||||||
|
{
|
||||||
|
reader = new ExtendedBinaryReader(input, Scenario.Encoding);
|
||||||
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Reader Methods
|
#region Reader Methods
|
||||||
|
|
||||||
public Scenario ReadScenario(Scenario result)
|
public Scenario ReadScenario()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeScenario(false);
|
||||||
int number = 0;
|
int number = 0;
|
||||||
|
|
||||||
result.Header = ReadScenarioHeader(result.Header);
|
result.Header = ReadScenarioHeader();
|
||||||
|
|
||||||
var comp = new DeflateStream(reader.BaseStream, CompressionMode.Decompress);
|
var comp = new DeflateStream(reader.BaseStream, CompressionMode.Decompress);
|
||||||
reader = new ExtendedBinaryReader(comp, Data.Consts.Encoding);
|
reader = new ExtendedBinaryReader(comp, Scenario.Encoding);
|
||||||
|
|
||||||
result.NextId = reader.ReadInt32();
|
result.NextId = reader.ReadInt32();
|
||||||
|
|
||||||
version = reader.ReadSingle();
|
Version = reader.ReadSingle();
|
||||||
result.OriginalVersion = version;
|
result.OriginalVersion = Version;
|
||||||
Log.i(TAG, "Detected version {0}", version);
|
|
||||||
|
|
||||||
|
result.PlayerNames = FillArray(() => reader.ReadZString(256), result.PlayerNames, Scenario.NumPlayers);
|
||||||
result.Players = FillArray(ReadPlayerInfo, result.Players, AdrianKousz.GenieEngine.Data.Consts.NumPlayers);
|
if (Version >= 1.18f) {
|
||||||
result.Messages = ReadMessages(result.Messages);
|
result.StringTablePlayerNames = FillArray(reader.ReadInt32, result.StringTablePlayerNames, Scenario.NumPlayers);
|
||||||
result.Cinematics = ReadCinematics(result.Cinematics);
|
}
|
||||||
result.AIData = ReadAIData(result.AIData);
|
result.Players = FillArray(ReadPlayerInfo, result.Players, Scenario.NumPlayers);
|
||||||
|
result.Messages = ReadMessages();
|
||||||
|
result.Cinematics = ReadCinematics();
|
||||||
|
result.AIData = ReadAIData();
|
||||||
|
|
||||||
ReadSeparator("Resources");
|
ReadSeparator("Resources");
|
||||||
|
|
||||||
result.Resources = FillArray(ReadResourceInfo, result.Resources, AdrianKousz.GenieEngine.Data.Consts.NumPlayers);
|
result.Resources = FillArray(ReadResourceInfo, result.Resources, Scenario.NumPlayers);
|
||||||
|
|
||||||
ReadSeparator("Victory");
|
ReadSeparator("Victory");
|
||||||
|
|
||||||
result.RawGlobalVictory = reader.ReadBytes(10 * 4);
|
result.GlobalVictory = ReadGlobalVictoryInfo();
|
||||||
result.RawDiplomacy = reader.ReadBytes(AdrianKousz.GenieEngine.Data.Consts.NumPlayers * AdrianKousz.GenieEngine.Data.Consts.NumPlayers * 4);
|
result.LinearDiplomacy = FillArray(reader.ReadInt32, result.LinearDiplomacy, Scenario.NumPlayers * Scenario.NumPlayers);
|
||||||
result.RawIndividualVictory = reader.ReadBytes(11520);
|
result.RawIndividualVictory = reader.ReadBytes(11520);
|
||||||
|
|
||||||
ReadSeparator("Player Settings");
|
ReadSeparator("Player Settings");
|
||||||
|
|
||||||
result.RawAlliedVictory = reader.ReadBytes(AdrianKousz.GenieEngine.Data.Consts.NumPlayers * 4);
|
result.AlliedVictory = FillArray(reader.ReadInt32, result.AlliedVictory, Scenario.NumPlayers);
|
||||||
|
|
||||||
if (1.15f <= version) number = (AdrianKousz.GenieEngine.Data.Consts.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
if (Version >= 1.15f) number = (Scenario.NumPlayers * ( 20 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
||||||
if (1.18f <= version) number = (AdrianKousz.GenieEngine.Data.Consts.NumPlayers * (3 /*Lengths*/ + 80 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
if (Version >= 1.18f) number = (Scenario.NumPlayers * (3 /*Lengths*/ + 80 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
||||||
if (1.30f <= version) number = (AdrianKousz.GenieEngine.Data.Consts.NumPlayers * (3 /*Lengths*/ + 180 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
if (Version >= 1.30f) number = (Scenario.NumPlayers * (3 /*Lengths*/ + 180 /*Disables*/) + 3 /*Unknowns*/) * 4 /*Intsize*/;
|
||||||
result.RawDisables = reader.ReadBytes(number);
|
result.RawDisables = reader.ReadBytes(number);
|
||||||
|
|
||||||
result.StartingAges = new int[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
result.StartingAges = FillArray(reader.ReadInt32, result.StartingAges, Scenario.NumPlayers);
|
||||||
result.StartingAges.Fill(reader.ReadInt32);
|
|
||||||
|
|
||||||
ReadSeparator("Map");
|
ReadSeparator("Map");
|
||||||
|
|
||||||
result.Map = ReadMap(result.Map);
|
result.Map = ReadMap();
|
||||||
|
|
||||||
number = reader.ReadInt32();
|
number = reader.ReadInt32();
|
||||||
result.ResourcesCopy = FillArray(ReadResourceInfoCopy, result.ResourcesCopy, number - 1);
|
result.ResourcesCopy = FillArray(ReadResourceInfoCopy, result.ResourcesCopy, number - 1);
|
||||||
|
|
||||||
result.Units = new IList<UnitInfo>[number];
|
result.Units = FillArray(ReadUnitInfoList, result.Units, number);
|
||||||
result.Units.Fill(ReadUnitInfo);
|
|
||||||
|
var bytestream = new MemoryStream();
|
||||||
|
reader.BaseStream.CopyTo(bytestream);
|
||||||
|
result.RawRemaining = bytestream.ToArray();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScenarioHeader ReadScenarioHeader(ScenarioHeader result)
|
public ScenarioHeader ReadScenarioHeader()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeScenarioHeader();
|
||||||
|
|
||||||
result.OriginalVersion = reader.ReadString(4);
|
result.OriginalVersion = reader.ReadString(4);
|
||||||
Skip(4, "Header Length");
|
reader.ReadInt32(); // Header Length
|
||||||
result.Unknown1 = reader.ReadInt32();
|
result.Unknown1 = reader.ReadInt32();
|
||||||
result.Timestamp = DateTimes.FromUnixTime(reader.ReadInt32());
|
result.Timestamp = DateTimes.FromUnixTime(reader.ReadInt32());
|
||||||
result.Instructions = reader.ReadZStringInt32();
|
result.Instructions = reader.ReadZStringInt32();
|
||||||
|
@ -92,14 +101,10 @@ namespace AdrianKousz.GenieEngine
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerInfo ReadPlayerInfo(PlayerInfo result)
|
public PlayerInfo ReadPlayerInfo()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakePlayerInfo();
|
||||||
|
|
||||||
result.Name = reader.ReadZString(256);
|
|
||||||
if (1.18f <= version) {
|
|
||||||
result.StringTable = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
result.Active = reader.ReadBoolean();
|
result.Active = reader.ReadBoolean();
|
||||||
result.Human = reader.ReadBoolean();
|
result.Human = reader.ReadBoolean();
|
||||||
result.Civ = reader.ReadInt32();
|
result.Civ = reader.ReadInt32();
|
||||||
|
@ -108,23 +113,23 @@ namespace AdrianKousz.GenieEngine
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Messages ReadMessages(Messages result)
|
public Messages ReadMessages()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeMessages();
|
||||||
|
|
||||||
result.Unknown1 = reader.ReadInt32();
|
result.Unknown1 = reader.ReadInt32();
|
||||||
result.Unknown2 = reader.ReadByte();
|
result.Unknown2 = reader.ReadByte();
|
||||||
result.Unknown3 = reader.ReadSingle();
|
result.Unknown3 = reader.ReadSingle();
|
||||||
result.OriginalFilename = reader.ReadStringInt16();
|
result.OriginalFilename = reader.ReadStringInt16();
|
||||||
|
|
||||||
if (1.18f <= version) {
|
if (Version >= 1.18f) {
|
||||||
result.StringTableInstructions = reader.ReadInt32();
|
result.StringTableInstructions = reader.ReadInt32();
|
||||||
result.StringTableHints = reader.ReadInt32();
|
result.StringTableHints = reader.ReadInt32();
|
||||||
result.StringTableVictory = reader.ReadInt32();
|
result.StringTableVictory = reader.ReadInt32();
|
||||||
result.StringTableLoss = reader.ReadInt32();
|
result.StringTableLoss = reader.ReadInt32();
|
||||||
result.StringTableHistory = reader.ReadInt32();
|
result.StringTableHistory = reader.ReadInt32();
|
||||||
}
|
}
|
||||||
if (1.22f <= version) {
|
if (Version >= 1.22f) {
|
||||||
result.StringTableScouts = reader.ReadInt32();
|
result.StringTableScouts = reader.ReadInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,16 +138,16 @@ namespace AdrianKousz.GenieEngine
|
||||||
result.TextVictory = reader.ReadZStringInt16();
|
result.TextVictory = reader.ReadZStringInt16();
|
||||||
result.TextLoss = reader.ReadZStringInt16();
|
result.TextLoss = reader.ReadZStringInt16();
|
||||||
result.TextHistory = reader.ReadZStringInt16();
|
result.TextHistory = reader.ReadZStringInt16();
|
||||||
if (1.22f <= version) {
|
if (Version >= 1.22f) {
|
||||||
result.TextScouts = reader.ReadZStringInt16();
|
result.TextScouts = reader.ReadZStringInt16();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cinematics ReadCinematics(Cinematics result)
|
public Cinematics ReadCinematics()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeCinematics();
|
||||||
|
|
||||||
result.CinemaPregameFn = reader.ReadStringInt16();
|
result.CinemaPregameFn = reader.ReadStringInt16();
|
||||||
result.CinemaVictoryFn = reader.ReadStringInt16();
|
result.CinemaVictoryFn = reader.ReadStringInt16();
|
||||||
|
@ -151,37 +156,31 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
var hasBitmap = reader.ReadBoolean();
|
var hasBitmap = reader.ReadBoolean();
|
||||||
|
|
||||||
Skip(4, "Bitmap width");
|
result.BitmapWidth = reader.ReadInt32();
|
||||||
Skip(4, "Bitmap height");
|
result.BitmapHeight = reader.ReadInt32();
|
||||||
Skip(2, "Bitmap Unknown");
|
result.BitmapUnknown = reader.ReadInt16();
|
||||||
|
|
||||||
if (hasBitmap) {
|
if (hasBitmap) {
|
||||||
result.RawBitmap = BitmapUtil.ReadRawBitmap(reader.BaseStream);
|
result.RawBitmap = BitmapUtil.ReadRawBitmap(reader.BaseStream);
|
||||||
} else {
|
|
||||||
result.RawBitmap = new byte[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AIData ReadAIData(AIData result)
|
public AIData ReadAIData()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeAIData();
|
||||||
|
|
||||||
result.PlayerAIs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
result.PlayerAIs = FillArray(reader.ReadStringInt16, result.PlayerAIs, Scenario.NumPlayers);
|
||||||
result.PlayerCTYs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
result.PlayerCTYs = FillArray(reader.ReadStringInt16, result.PlayerCTYs, Scenario.NumPlayers);
|
||||||
result.PlayerPERs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
result.PlayerPERs = FillArray(reader.ReadStringInt16, result.PlayerPERs, Scenario.NumPlayers);
|
||||||
result.PlayerCustomAIs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCustomCTYs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.PlayerCustomPERs = new string[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
result.RawAITypes = new byte[AdrianKousz.GenieEngine.Data.Consts.NumPlayers];
|
|
||||||
|
|
||||||
result.PlayerAIs.Fill(reader.ReadStringInt16);
|
result.PlayerCustomAIs = new string[Scenario.NumPlayers];
|
||||||
result.PlayerCTYs.Fill(reader.ReadStringInt16);
|
result.PlayerCustomCTYs = new string[Scenario.NumPlayers];
|
||||||
result.PlayerPERs.Fill(reader.ReadStringInt16);
|
result.PlayerCustomPERs = new string[Scenario.NumPlayers];
|
||||||
|
|
||||||
int l1, l2, l3;
|
int l1, l2, l3;
|
||||||
for (var i = 0; i < AdrianKousz.GenieEngine.Data.Consts.NumPlayers; ++i) {
|
for (var i = 0; i < Scenario.NumPlayers; ++i) {
|
||||||
l1 = reader.ReadInt32();
|
l1 = reader.ReadInt32();
|
||||||
l2 = reader.ReadInt32();
|
l2 = reader.ReadInt32();
|
||||||
l3 = reader.ReadInt32();
|
l3 = reader.ReadInt32();
|
||||||
|
@ -190,88 +189,112 @@ namespace AdrianKousz.GenieEngine
|
||||||
result.PlayerCustomPERs[i] = reader.ReadString(l3);
|
result.PlayerCustomPERs[i] = reader.ReadString(l3);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1.18f <= version) {
|
if (Version >= 1.18f) {
|
||||||
result.RawAITypes.Fill(reader.ReadByte);
|
result.AITypes = FillArray(reader.ReadByte, result.AITypes, Scenario.NumPlayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceInfo ReadResourceInfo(ResourceInfo result)
|
public ResourceInfo ReadResourceInfo()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeResourceInfo();
|
||||||
|
|
||||||
result.Gold = reader.ReadInt32();
|
result.Gold = reader.ReadInt32();
|
||||||
result.Wood = reader.ReadInt32();
|
result.Wood = reader.ReadInt32();
|
||||||
result.Food = reader.ReadInt32();
|
result.Food = reader.ReadInt32();
|
||||||
result.Stone = reader.ReadInt32();
|
result.Stone = reader.ReadInt32();
|
||||||
if (1.18f <= version) {
|
if (Version >= 1.18f) {
|
||||||
result.Ore = reader.ReadInt32();
|
result.Ore = reader.ReadInt32();
|
||||||
result.Unknown = reader.ReadInt32();
|
if (Version < 1.3f) {
|
||||||
|
result.Unknown = reader.ReadInt32();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map ReadMap(Map result)
|
public ResourceInfoCopy ReadResourceInfoCopy()
|
||||||
{
|
{
|
||||||
result = Misc.MayNew(result);
|
var result = factory.MakeResourceInfoCopy();
|
||||||
|
|
||||||
if (1.18f <= version) {
|
|
||||||
result.CameraX = reader.ReadInt32();
|
|
||||||
result.CameraY = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
if (1.22f <= version) {
|
|
||||||
result.GeneratorId = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.SizeX = reader.ReadInt32();
|
|
||||||
result.SizeY = reader.ReadInt32();
|
|
||||||
|
|
||||||
result.LinearTiles = new Map.Tile[result.SizeX * result.SizeY];
|
|
||||||
result.LinearTiles.Fill(() => new Map.Tile(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceInfoCopy ReadResourceInfoCopy(ResourceInfoCopy result)
|
|
||||||
{
|
|
||||||
result = Misc.MayNew(result);
|
|
||||||
|
|
||||||
result.Food = reader.ReadSingle();
|
result.Food = reader.ReadSingle();
|
||||||
result.Wood = reader.ReadSingle();
|
result.Wood = reader.ReadSingle();
|
||||||
result.Gold = reader.ReadSingle();
|
result.Gold = reader.ReadSingle();
|
||||||
result.Stone = reader.ReadSingle();
|
result.Stone = reader.ReadSingle();
|
||||||
if (1.18f <= version) {
|
if (Version >= 1.18f) {
|
||||||
result.Ore = reader.ReadInt32();
|
result.Ore = reader.ReadInt32();
|
||||||
result.Unknown = reader.ReadInt32();
|
if (Version < 1.3f) {
|
||||||
|
result.Unknown = reader.ReadInt32();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (1.22f <= version) {
|
if (Version >= 1.22f) {
|
||||||
result.PopulationLimit = reader.ReadSingle();
|
result.PopulationLimit = reader.ReadSingle();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IList<UnitInfo> ReadUnitInfo()
|
public GlobalVictoryInfo ReadGlobalVictoryInfo()
|
||||||
{
|
{
|
||||||
var number = reader.ReadInt32();
|
var result = factory.MakeGlobalVictoryInfo();
|
||||||
var result = new List<UnitInfo>(number);
|
|
||||||
|
|
||||||
for (var i = 0; i < number; i++) {
|
result.RequireConquest = reader.ReadBoolean();
|
||||||
var unit = new UnitInfo();
|
result.Ruins = reader.ReadInt32();
|
||||||
unit.PosX = reader.ReadSingle();
|
result.Artifacts = reader.ReadInt32();
|
||||||
unit.PosY = reader.ReadSingle();
|
result.Discovery = reader.ReadInt32();
|
||||||
unit.Unknown1 = reader.ReadSingle();
|
result.PercentExplored = reader.ReadInt32();
|
||||||
unit.Id = reader.ReadInt32();
|
result.Unknown = reader.ReadInt32();
|
||||||
unit.UnitId = reader.ReadInt16();
|
result.RequireAllCustom = reader.ReadBoolean();
|
||||||
unit.Unknown2 = reader.ReadByte();
|
result.Mode = reader.ReadInt32();
|
||||||
unit.Rotation = reader.ReadSingle();
|
result.Score = reader.ReadInt32();
|
||||||
if (1.18f <= version) {
|
result.Time = reader.ReadInt32();
|
||||||
unit.InitialFrame = reader.ReadInt16();
|
|
||||||
unit.GarrisonnedInId = reader.ReadInt32();
|
return result;
|
||||||
}
|
}
|
||||||
result.Add(unit);
|
|
||||||
|
public Map ReadMap()
|
||||||
|
{
|
||||||
|
var result = factory.MakeMap();
|
||||||
|
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
result.CameraX = reader.ReadInt32();
|
||||||
|
result.CameraY = reader.ReadInt32();
|
||||||
|
}
|
||||||
|
if (Version >= 1.22f) {
|
||||||
|
result.GeneratorId = reader.ReadInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.SizeX = reader.ReadInt32();
|
||||||
|
result.SizeY = reader.ReadInt32();
|
||||||
|
|
||||||
|
result.LinearTiles = new Map.Tile[result.SizeX * result.SizeY]
|
||||||
|
.Fill(() => new Map.Tile(reader.ReadByte(), reader.ReadByte(), reader.ReadByte()));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IList<UnitInfo> ReadUnitInfoList()
|
||||||
|
{
|
||||||
|
var count = reader.ReadInt32();
|
||||||
|
var result = new List<UnitInfo>().Fill(ReadUnitInfo, count);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnitInfo ReadUnitInfo()
|
||||||
|
{
|
||||||
|
var result = factory.MakeUnitInfo();
|
||||||
|
|
||||||
|
result.PosX = reader.ReadSingle();
|
||||||
|
result.PosY = reader.ReadSingle();
|
||||||
|
result.Unknown1 = reader.ReadSingle();
|
||||||
|
result.Id = reader.ReadInt32();
|
||||||
|
result.UnitId = reader.ReadInt16();
|
||||||
|
result.Unknown2 = reader.ReadByte();
|
||||||
|
result.Rotation = reader.ReadSingle();
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
result.InitialFrame = reader.ReadInt16();
|
||||||
|
result.GarrisonnedInId = reader.ReadInt32();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -279,7 +302,7 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
public void ReadSeparator(string name) {
|
public void ReadSeparator(string name) {
|
||||||
int v = reader.ReadInt32();
|
int v = reader.ReadInt32();
|
||||||
if (v != AdrianKousz.GenieEngine.Data.Consts.Separator) {
|
if (v != Scenario.Separator) {
|
||||||
var msg = "Separator \"{0}\" = {1}";
|
var msg = "Separator \"{0}\" = {1}";
|
||||||
msg = string.Format(msg, name, v);
|
msg = string.Format(msg, name, v);
|
||||||
throw new InvalidDataException(msg);
|
throw new InvalidDataException(msg);
|
||||||
|
@ -290,26 +313,14 @@ namespace AdrianKousz.GenieEngine
|
||||||
|
|
||||||
#region Debug Methods
|
#region Debug Methods
|
||||||
|
|
||||||
private T[] FillArray<T>(System.Func<T, T> f, T[] array, int length) where T : new()
|
private T[] FillArray<T>(System.Func<T> f, T[] array, int length)
|
||||||
{
|
{
|
||||||
if (array == null) {
|
if (array == null || array.Length != length)
|
||||||
array = new T[length];
|
array = new T[length];
|
||||||
} else if (array.Length != length) {
|
|
||||||
var temp = new T[length];
|
|
||||||
System.Array.Copy(array, temp, System.Math.Min(array.Length, temp.Length));
|
|
||||||
}
|
|
||||||
|
|
||||||
array.Fill(f);
|
array.Fill(f);
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Skip(int count, string name)
|
|
||||||
{
|
|
||||||
Log.d(TAG, "Skipping {0} bytes in \"{1}\"", count, name);
|
|
||||||
reader.ReadBytes(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Collections.Generic;
|
||||||
using AdrianKousz.Util;
|
using AdrianKousz.Util;
|
||||||
using AdrianKousz.GenieEngine.Data;
|
using AdrianKousz.GenieEngine.Data;
|
||||||
|
|
||||||
|
@ -6,18 +8,76 @@ namespace AdrianKousz.GenieEngine
|
||||||
{
|
{
|
||||||
public class ScnWriter
|
public class ScnWriter
|
||||||
{
|
{
|
||||||
private static readonly string TAG = typeof(ScnWriter).Name;
|
public float Version = 0;
|
||||||
|
|
||||||
private ExtendedBinaryWriter writer;
|
private ExtendedBinaryWriter writer;
|
||||||
|
|
||||||
public ScnWriter(Stream input)
|
public ScnWriter(Stream output)
|
||||||
{
|
{
|
||||||
writer = new ExtendedBinaryWriter(input, Data.Consts.Encoding);
|
writer = new ExtendedBinaryWriter(output, Scenario.Encoding);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Scenario value)
|
||||||
|
{
|
||||||
|
Version = Version == 0 ? value.OriginalVersion : Version;
|
||||||
|
|
||||||
|
Write(value.Header);
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// TODO: Make wrapper.
|
||||||
|
// This is a workaround for now. A wrapper for the reader and writer will be created.
|
||||||
|
var originalWriter = writer;
|
||||||
|
var compressedPart = new MemoryStream();
|
||||||
|
var comp = new DeflateStream(compressedPart, CompressionMode.Compress);
|
||||||
|
writer = new ExtendedBinaryWriter(comp, Scenario.Encoding);
|
||||||
|
|
||||||
|
writer.Write(value.NextId);
|
||||||
|
writer.Write(Version);
|
||||||
|
|
||||||
|
value.PlayerNames.ForEach((x) => writer.WriteStringPadded(x, 256));
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
value.StringTablePlayerNames.ForEach(writer.Write);
|
||||||
|
}
|
||||||
|
value.Players.ForEach(Write);
|
||||||
|
Write(value.Messages);
|
||||||
|
Write(value.Cinematics);
|
||||||
|
Write(value.AIData);
|
||||||
|
|
||||||
|
WriteSeperator("Resources");
|
||||||
|
|
||||||
|
value.Resources.ForEach(Write);
|
||||||
|
|
||||||
|
WriteSeperator("Victory");
|
||||||
|
|
||||||
|
Write(value.GlobalVictory);
|
||||||
|
value.LinearDiplomacy.ForEach(writer.Write);
|
||||||
|
writer.Write(value.RawIndividualVictory);
|
||||||
|
|
||||||
|
WriteSeperator("Player Settings");
|
||||||
|
|
||||||
|
value.AlliedVictory.ForEach(writer.Write);
|
||||||
|
writer.Write(value.RawDisables);
|
||||||
|
value.StartingAges.ForEach(writer.Write);
|
||||||
|
|
||||||
|
WriteSeperator("Map");
|
||||||
|
|
||||||
|
Write(value.Map);
|
||||||
|
|
||||||
|
writer.Write((int)value.Units.Length);
|
||||||
|
value.ResourcesCopy.ForEach(Write);
|
||||||
|
value.Units.ForEach(Write);
|
||||||
|
|
||||||
|
writer.Write(value.RawRemaining);
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
comp.Dispose();
|
||||||
|
originalWriter.Write(compressedPart.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(ScenarioHeader value)
|
public void Write(ScenarioHeader value)
|
||||||
{
|
{
|
||||||
var instructionlength = writer.GetByteCount(value.Instructions + " ");
|
var instructionlength = writer.GetZByteCount(value.Instructions);
|
||||||
writer.WriteStringRaw(value.OriginalVersion);
|
writer.WriteStringRaw(value.OriginalVersion);
|
||||||
writer.Write(20 + instructionlength);
|
writer.Write(20 + instructionlength);
|
||||||
writer.Write(value.Unknown1);
|
writer.Write(value.Unknown1);
|
||||||
|
@ -27,15 +87,180 @@ namespace AdrianKousz.GenieEngine
|
||||||
writer.Write(value.PlayerCount);
|
writer.Write(value.PlayerCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteSeperator()
|
public void Write(PlayerInfo value)
|
||||||
{
|
{
|
||||||
writer.Write(AdrianKousz.GenieEngine.Data.Consts.Separator);
|
writer.Write(value.Active);
|
||||||
|
writer.Write(value.Human);
|
||||||
|
writer.Write(value.Civ);
|
||||||
|
writer.Write(value.Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Messages value)
|
||||||
|
{
|
||||||
|
writer.Write(value.Unknown1);
|
||||||
|
writer.Write(value.Unknown2);
|
||||||
|
writer.Write(value.Unknown3);
|
||||||
|
writer.WriteStringInt16(value.OriginalFilename);
|
||||||
|
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
writer.Write(value.StringTableInstructions);
|
||||||
|
writer.Write(value.StringTableHints);
|
||||||
|
writer.Write(value.StringTableVictory);
|
||||||
|
writer.Write(value.StringTableLoss);
|
||||||
|
writer.Write(value.StringTableHistory);
|
||||||
|
}
|
||||||
|
if (Version >= 1.22f) {
|
||||||
|
writer.Write(value.StringTableScouts);
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.WriteZStringInt16(value.TextInstructions);
|
||||||
|
writer.WriteZStringInt16(value.TextHints);
|
||||||
|
writer.WriteZStringInt16(value.TextVictory);
|
||||||
|
writer.WriteZStringInt16(value.TextLoss);
|
||||||
|
writer.WriteZStringInt16(value.TextHistory);
|
||||||
|
if (Version >= 1.22f) {
|
||||||
|
writer.WriteZStringInt16(value.TextScouts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Cinematics value)
|
||||||
|
{
|
||||||
|
writer.WriteStringInt16(value.CinemaPregameFn);
|
||||||
|
writer.WriteStringInt16(value.CinemaVictoryFn);
|
||||||
|
writer.WriteStringInt16(value.CinemaLossFn);
|
||||||
|
writer.WriteStringInt16(value.BackgroundFn);
|
||||||
|
|
||||||
|
var hasBitmap = value.RawBitmap.Length > 0;
|
||||||
|
|
||||||
|
writer.Write(hasBitmap);
|
||||||
|
writer.Write(value.BitmapWidth);
|
||||||
|
writer.Write(value.BitmapHeight);
|
||||||
|
writer.Write(value.BitmapUnknown);
|
||||||
|
|
||||||
|
if (hasBitmap)
|
||||||
|
writer.Write(value.RawBitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(AIData value)
|
||||||
|
{
|
||||||
|
value.PlayerAIs.ForEach(writer.WriteStringInt16);
|
||||||
|
value.PlayerCTYs.ForEach(writer.WriteStringInt16);
|
||||||
|
value.PlayerPERs.ForEach(writer.WriteStringInt16);
|
||||||
|
|
||||||
|
for (var i = 0; i < Scenario.NumPlayers; ++i) {
|
||||||
|
var str1 = value.PlayerCustomAIs[i];
|
||||||
|
var str2 = value.PlayerCustomCTYs[i];
|
||||||
|
var str3 = value.PlayerCustomPERs[i];
|
||||||
|
writer.Write(writer.GetByteCount(str1));
|
||||||
|
writer.Write(writer.GetByteCount(str2));
|
||||||
|
writer.Write(writer.GetByteCount(str3));
|
||||||
|
writer.WriteStringRaw(str1);
|
||||||
|
writer.WriteStringRaw(str2);
|
||||||
|
writer.WriteStringRaw(str3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
value.AITypes.ForEach(writer.Write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(ResourceInfo value)
|
||||||
|
{
|
||||||
|
writer.Write(value.Gold);
|
||||||
|
writer.Write(value.Wood);
|
||||||
|
writer.Write(value.Food);
|
||||||
|
writer.Write(value.Stone);
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
writer.Write(value.Ore);
|
||||||
|
if (Version < 1.3f) {
|
||||||
|
writer.Write(value.Unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(ResourceInfoCopy value)
|
||||||
|
{
|
||||||
|
writer.Write(value.Food);
|
||||||
|
writer.Write(value.Wood);
|
||||||
|
writer.Write(value.Gold);
|
||||||
|
writer.Write(value.Stone);
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
writer.Write(value.Ore);
|
||||||
|
if (Version < 1.3f) {
|
||||||
|
writer.Write(value.Unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Version >= 1.22f) {
|
||||||
|
writer.Write(value.PopulationLimit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(GlobalVictoryInfo value)
|
||||||
|
{
|
||||||
|
writer.Write(value.RequireConquest);
|
||||||
|
writer.Write(value.Ruins);
|
||||||
|
writer.Write(value.Artifacts);
|
||||||
|
writer.Write(value.Discovery);
|
||||||
|
writer.Write(value.PercentExplored);
|
||||||
|
writer.Write(value.Unknown);
|
||||||
|
writer.Write(value.RequireAllCustom);
|
||||||
|
writer.Write(value.Mode);
|
||||||
|
writer.Write(value.Score);
|
||||||
|
writer.Write(value.Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Map value)
|
||||||
|
{
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
writer.Write(value.CameraX);
|
||||||
|
writer.Write(value.CameraY);
|
||||||
|
}
|
||||||
|
if (Version >= 1.22f) {
|
||||||
|
writer.Write(value.GeneratorId);
|
||||||
|
}
|
||||||
|
writer.Write(value.SizeX);
|
||||||
|
writer.Write(value.SizeY);
|
||||||
|
|
||||||
|
value.LinearTiles.ForEach(x => { writer.Write(x.Id); writer.Write(x.Elevation); writer.Write(x.Unknown); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(IList<UnitInfo> value)
|
||||||
|
{
|
||||||
|
int number = value.Count;
|
||||||
|
writer.Write(number);
|
||||||
|
value.ForEach(Write);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(UnitInfo value)
|
||||||
|
{
|
||||||
|
writer.Write(value.PosX);
|
||||||
|
writer.Write(value.PosY);
|
||||||
|
writer.Write(value.Unknown1);
|
||||||
|
writer.Write(value.Id);
|
||||||
|
writer.Write(value.UnitId);
|
||||||
|
writer.Write(value.Unknown2);
|
||||||
|
writer.Write(value.Rotation);
|
||||||
|
if (Version >= 1.18f) {
|
||||||
|
writer.Write(value.InitialFrame);
|
||||||
|
writer.Write(value.GarrisonnedInId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteSeperator(string name)
|
||||||
|
{
|
||||||
|
writer.Write(Scenario.Separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Flush()
|
public void Flush()
|
||||||
{
|
{
|
||||||
writer.Flush();
|
writer.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void EnsureSetVersion()
|
||||||
|
{
|
||||||
|
if (Version <= 1)
|
||||||
|
throw new System.InvalidOperationException("Set output version");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,13 +34,11 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AdrianKousz.GenieEngine\BitmapUtil.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\BitmapUtil.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\CpnReader.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\CpnReader.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnFactory.cs" />
|
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnReader.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnReader.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnValidator.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnValidator.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine\ScnWriter.cs" />
|
<Compile Include="AdrianKousz.GenieEngine\ScnWriter.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\AIData.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\AIData.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\Cinematics.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\Cinematics.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\Consts.cs" />
|
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\Map.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\Map.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\Messages.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\Messages.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\PlayerInfo.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\PlayerInfo.cs" />
|
||||||
|
@ -50,6 +48,10 @@
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\ScenarioHeader.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\ScenarioHeader.cs" />
|
||||||
<Compile Include="AdrianKousz.GenieEngine.Data\UnitInfo.cs" />
|
<Compile Include="AdrianKousz.GenieEngine.Data\UnitInfo.cs" />
|
||||||
<Compile Include="AssemblyInfo.cs" />
|
<Compile Include="AssemblyInfo.cs" />
|
||||||
|
<Compile Include="AdrianKousz.GenieEngine.Data\GlobalVictoryInfo.cs" />
|
||||||
|
<Compile Include="AdrianKousz.GenieEngine\ScnConvert.cs" />
|
||||||
|
<Compile Include="AdrianKousz.GenieEngine\ScnDefaultFactory.cs" />
|
||||||
|
<Compile Include="AdrianKousz.GenieEngine\IScnFactory.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in New Issue