Added support for loading Land.dat files.

This commit is contained in:
Ray Koopa 2017-04-23 01:28:36 +02:00
parent a2a368baed
commit 5f40d63c03
19 changed files with 269 additions and 41 deletions

View File

@ -22,6 +22,7 @@ Formats of the second generation 2D games are mostly focused right now.
|-------------------|:---------:|:-----------:|:----:|:----:|
| Archive | DIR | W2, WA, WWP | Yes | Yes |
| Image | IMG | W2, WA, WWP | Yes | No |
| Land Data | LAND.DAT | W2, WA, WWP | Yes | No |
| Mission | DAT | W2 | No | No |
| Mission | WAM | WA, WWP | No | No |
| Monochrome Map | LEV | W2 | No | No |

View File

@ -18,8 +18,6 @@ namespace Syroot.Worms.Test
private static void Main(string[] args)
{
Palette palette = new Palette("C:\\Games\\Worms World Party\\graphics\\palettes\\wwp.pal");
Console.WriteLine("Done.");
Console.ReadLine();
}

View File

@ -14,12 +14,9 @@ namespace Syroot.Worms.UnitTest.Common
{
// ---- MEMBERS ------------------------------------------------------------------------------------------------
private static readonly string[] _gamePaths =
{
@"C:\Games\Worms2",
@"C:\Games\Worms Armageddon 3.7.2.1",
@"C:\Games\Worms World Party"
};
private static readonly string[] _gamePathsWorms2 = { @"C:\Games\Worms2" };
private static readonly string[] _gamePathsWormsArmageddon = { @"C:\Games\Worms Armageddon 3.7.2.1" };
private static readonly string[] _gamePathsWormsWorldParty = { @"C:\Games\Worms World Party" };
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
@ -28,11 +25,13 @@ namespace Syroot.Worms.UnitTest.Common
/// optional array <paramref name="excludedFiles"/>.
/// </summary>
/// <typeparam name="T">The type of the files to load.</typeparam>
/// <param name="games">The games to test.</param>
/// <param name="wildcard">The wildcard to match.</param>
/// <param name="excludedFiles">Optionally, the files to exclude.</param>
internal static void LoadFiles<T>(string wildcard, string[] excludedFiles = null) where T : ILoadableFile, new()
internal static void LoadFiles<T>(Game games, string wildcard, string[] excludedFiles = null)
where T : ILoadableFile, new()
{
foreach (string fileName in FindFiles(wildcard))
foreach (string fileName in FindFiles(games, wildcard))
{
if (excludedFiles?.Contains(Path.GetFileName(fileName), StringComparer.OrdinalIgnoreCase) == true)
{
@ -47,21 +46,46 @@ namespace Syroot.Worms.UnitTest.Common
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
/// <summary>
/// Returns a list of files found in any of the paths provided in the _gamePaths variable which match the
/// specified <paramref name="wildcard"/>.
/// </summary>
/// <param name="wildcard">The wildcard which files have to match.</param>
/// <returns>A list of files matching the search.</returns>
private static List<string> FindFiles(string wildcard)
private static List<string> FindFiles(Game games, string wildcard)
{
List<string> gamePaths = GetGamePaths(games);
List<string> files = new List<string>();
foreach (string testPath in _gamePaths)
foreach (string testPath in gamePaths)
{
files.AddRange(Directory.GetFiles(testPath, wildcard, SearchOption.AllDirectories));
}
return files;
}
private static List<string> GetGamePaths(Game game)
{
List<string> gamePaths = new List<string>();
if (game.HasFlag(Game.Worms2))
{
gamePaths.AddRange(_gamePathsWorms2);
}
if (game.HasFlag(Game.WormsArmageddon))
{
gamePaths.AddRange(_gamePathsWormsArmageddon);
}
if (game.HasFlag(Game.WormsWorldParty))
{
gamePaths.AddRange(_gamePathsWormsWorldParty);
}
return gamePaths;
}
}
[Flags]
internal enum Game
{
Worms2 = 1 << 0,
WormsArmageddon = 1 << 1,
WormsWorldParty = 1 << 2,
Gen2 = Worms2 | WormsArmageddon | WormsWorldParty,
Armageddon = WormsArmageddon | WormsWorldParty,
All = -1
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2
[TestMethod]
public void LoadArchives()
{
TestHelpers.LoadFiles<Archive>("*.dir");
TestHelpers.LoadFiles<Archive>(Game.Gen2, "*.dir");
}
}
}

View File

@ -0,0 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2.Armageddon;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.UnitTest.Gen2.Armageddon
{
/// <summary>
/// Represents a collection of tests for the <see cref="LandData"/> class.
/// </summary>
[TestCategory("LandData (Armageddon)")]
[TestClass]
public class LandDataTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadLandData()
{
TestHelpers.LoadFiles<LandData>(Game.Armageddon, "land.dat");
}
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2.Armageddon
[TestMethod]
public void LoadSchemes()
{
TestHelpers.LoadFiles<Scheme>("*.wsc");
TestHelpers.LoadFiles<Scheme>(Game.Armageddon, "*.wsc");
}
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2
[TestMethod]
public void LoadImages()
{
TestHelpers.LoadFiles<Image>("*.img");
TestHelpers.LoadFiles<Image>(Game.All, "*.img");
}
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2
[TestMethod]
public void LoadPalettes()
{
TestHelpers.LoadFiles<Palette>("*.pal", new string[]
TestHelpers.LoadFiles<Palette>(Game.Gen2, "*.pal", new string[]
{
"wwp.pal", // Contains 4 bytes of trash after the data chunk.
"wwpmaped.pal" // Contains 4 bytes of trash after the data chunk.

View File

@ -0,0 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2.Worms2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.UnitTest.Gen2.Worms2
{
/// <summary>
/// Represents a collection of tests for the <see cref="LandData"/> class.
/// </summary>
[TestCategory("LandData (Worms2)")]
[TestClass]
public class LandDataTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadLandData()
{
TestHelpers.LoadFiles<LandData>(Game.Worms2, "land.dat");
}
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2.Worms2
[TestMethod]
public void LoadSchemeOptions()
{
TestHelpers.LoadFiles<SchemeOptions>("*.opt");
TestHelpers.LoadFiles<SchemeOptions>(Game.Worms2, "*.opt");
}
}
}

View File

@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2.Worms2
[TestMethod]
public void LoadSchemeWeapons()
{
TestHelpers.LoadFiles<SchemeWeapons>("*.wep");
TestHelpers.LoadFiles<SchemeWeapons>(Game.Worms2, "*.wep");
}
}
}

View File

@ -40,7 +40,7 @@ namespace Syroot.Worms.Core
/// <param name="stream">The <see cref="Stream"/> to load the RIFF data from.</param>
protected void LoadRiff(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the file header.
if (reader.ReadString(_signature.Length) != _signature)

View File

@ -65,7 +65,7 @@ namespace Syroot.Worms.Gen2
}
Clear();
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)

View File

@ -7,8 +7,8 @@ using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Armageddon
{
/// <summary>
/// Represents scheme options stored in an OPT file which contains game settings.
/// S. https://worms2d.info/Options_file.
/// Represents map configuration stored by the land generator in LAND.DAT files.
/// Used by WA and WWP. S. https://worms2d.info/Land_Data_file.
/// </summary>
public class LandData : ILoadableFile
{
@ -18,6 +18,13 @@ namespace Syroot.Worms.Gen2.Armageddon
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class.
/// </summary>
public LandData()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given
/// <see cref="Stream"/>.
@ -92,7 +99,7 @@ namespace Syroot.Worms.Gen2.Armageddon
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
@ -107,8 +114,8 @@ namespace Syroot.Worms.Gen2.Armageddon
WaterHeight = reader.ReadInt32();
// Read the possible object coordinate array.
int badObjectLocations = reader.ReadInt32(); // TODO: Check what this is used for.
ObjectLocations = new Vector2[reader.ReadInt32()];
int objectLocationCountAgain = reader.ReadInt32(); // TODO: Repetitive or useful?
for (int i = 0; i < ObjectLocations.Length; i++)
{
ObjectLocations[i] = reader.ReadStruct<Vector2>();

View File

@ -608,7 +608,7 @@ namespace Syroot.Worms.Gen2.Armageddon
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadString(_signature.Length) != _signature)

View File

@ -80,7 +80,7 @@ namespace Syroot.Worms.Gen2
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
@ -117,10 +117,10 @@ namespace Syroot.Worms.Gen2
}
}
Size = reader.ReadStruct<Vector2>();
// Read the image data, which might be compressed.
byte[] data = new byte[Size.X * Size.Y * (BitsPerPixel / 8)];
Size = new Vector2(reader.ReadInt16(), reader.ReadInt16());
// Read the bytes, which might be compressed.
byte[] data = new byte[Size.X * Size.Y * BitsPerPixel / 8];
if (flags.HasFlag(Flags.Compressed))
{
Team17Compression.Decompress(reader.BaseStream, ref data);
@ -129,6 +129,7 @@ namespace Syroot.Worms.Gen2
{
data = reader.ReadBytes(data.Length);
}
Data = data;
}
}

View File

@ -0,0 +1,147 @@
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents map configuration stored by the land generator in LAND.DAT files.
/// Used by W2. S. https://worms2d.info/Land_Data_file.
/// </summary>
public class LandData : ILoadableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1A444E4C; // "LND", 0x1A
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class.
/// </summary>
public LandData()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given
/// <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public LandData(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public LandData(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the size of the landscape in pixels.
/// </summary>
public Vector2 Size { get; set; }
/// <summary>
/// Gets or sets a value indicating whether an indestructible top border will be enabled.
/// </summary>
public bool TopBorder { get; set; }
/// <summary>
/// Gets or sets an array of coordinates at which objects can be placed.
/// </summary>
public Vector2[] ObjectLocations { get; set; }
/// <summary>
/// Gets or sets the visual foreground image.
/// </summary>
public Image Foreground { get; set; }
/// <summary>
/// Gets or sets the collision mask of the landscape.
/// </summary>
public Image CollisionMask { get; set; }
/// <summary>
/// Gets or sets the visual background image.
/// </summary>
public Image Background { get; set; }
/// <summary>
/// Gets or sets an image of unknown use.
/// </summary>
public Image UnknownImage { get; set; }
/// <summary>
/// Gets or sets the path to the land image file.
/// </summary>
public string LandTexturePath { get; set; }
/// <summary>
/// Gets or sets the path to the Water.dir file.
/// </summary>
public string WaterDirPath { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid LND file signature.");
}
int fileLength = reader.ReadInt32();
// Read the data.
Size = reader.ReadStruct<Vector2>();
TopBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
// Read the possible object coordinate array.
ObjectLocations = new Vector2[reader.ReadInt32()];
for (int i = 0; i < ObjectLocations.Length; i++)
{
ObjectLocations[i] = reader.ReadStruct<Vector2>();
}
int unknown = reader.ReadInt32(); // Seems 0.
// Read the image data.
Foreground = new Image(stream);
CollisionMask = new Image(stream);
Background = new Image(stream);
UnknownImage = new Image(stream);
// Read the file paths.
LandTexturePath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
WaterDirPath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
}
}

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents scheme options stored in an OPT file which contains game settings.
/// S. https://worms2d.info/Options_file.
/// Used by W2. S. https://worms2d.info/Options_file.
/// </summary>
public class SchemeOptions : ILoadableFile, ISaveableFile
{
@ -221,7 +221,7 @@ namespace Syroot.Worms.Gen2.Worms2
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadString(_signature.Length) != _signature)

View File

@ -7,7 +7,7 @@ namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents scheme weapons stored in an WEP file which contains armory configuration.
/// S. https://worms2d.info/Weapons_file.
/// Used by W2. S. https://worms2d.info/Weapons_file.
/// </summary>
public class SchemeWeapons : ILoadableFile, ISaveableFile
{
@ -62,7 +62,7 @@ namespace Syroot.Worms.Gen2.Worms2
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
reader.Seek(_trashLength);