From ade95d4cd07faa175507ad4840157c2cd62f9745 Mon Sep 17 00:00:00 2001 From: Ray Koopa Date: Wed, 26 Apr 2017 11:05:53 +0200 Subject: [PATCH] Add enums for simple team file editing, fix LandData for WWP. --- .../Gen2/Armageddon/LandDataTests.cs | 2 +- .../Gen2/WorldParty/LandDataTests.cs | 25 +++ .../Gen2/WorldParty/TeamContainerTests.cs | 25 +++ src/Syroot.Worms/Gen2/Armageddon/LandData.cs | 2 +- src/Syroot.Worms/Gen2/Armageddon/Team.cs | 75 +++++++-- src/Syroot.Worms/Gen2/Image.cs | 48 ++++-- src/Syroot.Worms/Gen2/WorldParty/LandData.cs | 146 ++++++++++++++++++ src/Syroot.Worms/Gen2/WorldParty/Team.cs | 73 ++++++++- 8 files changed, 365 insertions(+), 31 deletions(-) create mode 100644 src/Syroot.Worms.UnitTest/Gen2/WorldParty/LandDataTests.cs create mode 100644 src/Syroot.Worms.UnitTest/Gen2/WorldParty/TeamContainerTests.cs create mode 100644 src/Syroot.Worms/Gen2/WorldParty/LandData.cs diff --git a/src/Syroot.Worms.UnitTest/Gen2/Armageddon/LandDataTests.cs b/src/Syroot.Worms.UnitTest/Gen2/Armageddon/LandDataTests.cs index 787d64e..37b955e 100644 --- a/src/Syroot.Worms.UnitTest/Gen2/Armageddon/LandDataTests.cs +++ b/src/Syroot.Worms.UnitTest/Gen2/Armageddon/LandDataTests.cs @@ -19,7 +19,7 @@ namespace Syroot.Worms.UnitTest.Gen2.Armageddon [TestMethod] public void LoadLandData() { - TestHelpers.LoadFiles(Game.Armageddon, "land.dat"); + TestHelpers.LoadFiles(Game.WormsArmageddon, "land.dat"); } } } diff --git a/src/Syroot.Worms.UnitTest/Gen2/WorldParty/LandDataTests.cs b/src/Syroot.Worms.UnitTest/Gen2/WorldParty/LandDataTests.cs new file mode 100644 index 0000000..bba37db --- /dev/null +++ b/src/Syroot.Worms.UnitTest/Gen2/WorldParty/LandDataTests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Syroot.Worms.Gen2.WorldParty; +using Syroot.Worms.UnitTest.Common; + +namespace Syroot.Worms.UnitTest.Gen2.WorldParty +{ + /// + /// Represents a collection of tests for the class. + /// + [TestCategory("LandData (WorldParty)")] + [TestClass] + public class LandDataTests + { + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- + + /// + /// Loads all files found in any game directories. + /// + [TestMethod] + public void LoadLandData() + { + TestHelpers.LoadFiles(Game.WormsWorldParty, "land.dat"); + } + } +} diff --git a/src/Syroot.Worms.UnitTest/Gen2/WorldParty/TeamContainerTests.cs b/src/Syroot.Worms.UnitTest/Gen2/WorldParty/TeamContainerTests.cs new file mode 100644 index 0000000..9a10001 --- /dev/null +++ b/src/Syroot.Worms.UnitTest/Gen2/WorldParty/TeamContainerTests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Syroot.Worms.Gen2.WorldParty; +using Syroot.Worms.UnitTest.Common; + +namespace Syroot.Worms.UnitTest.Gen2.WorldParty +{ + /// + /// Represents a collection of tests for the class. + /// + [TestCategory("TeamContainer (WorldParty)")] + [TestClass] + public class TeamContainerTests + { + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- + + /// + /// Loads all files found in any game directories. + /// + [TestMethod] + public void LoadTeamContainers() + { + TestHelpers.LoadFiles(Game.WormsWorldParty, "*.wwp"); + } + } +} diff --git a/src/Syroot.Worms/Gen2/Armageddon/LandData.cs b/src/Syroot.Worms/Gen2/Armageddon/LandData.cs index 4817f55..b800956 100644 --- a/src/Syroot.Worms/Gen2/Armageddon/LandData.cs +++ b/src/Syroot.Worms/Gen2/Armageddon/LandData.cs @@ -114,7 +114,7 @@ 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. + int unknown = reader.ReadInt32(); ObjectLocations = new Vector2[reader.ReadInt32()]; for (int i = 0; i < ObjectLocations.Length; i++) { diff --git a/src/Syroot.Worms/Gen2/Armageddon/Team.cs b/src/Syroot.Worms/Gen2/Armageddon/Team.cs index 9f5f86b..7592702 100644 --- a/src/Syroot.Worms/Gen2/Armageddon/Team.cs +++ b/src/Syroot.Worms/Gen2/Armageddon/Team.cs @@ -15,6 +15,7 @@ namespace Syroot.Worms.Gen2.Armageddon // ---- CONSTANTS ---------------------------------------------------------------------------------------------- private const int _missionCount = 33; + private const int _trainingMissionCount = 6; // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ @@ -25,9 +26,9 @@ namespace Syroot.Worms.Gen2.Armageddon { WormNames = new string[8]; MissionStatuses = new TeamMissionStatus[_missionCount]; - TrainingMissionTimes = new int[6]; + TrainingMissionTimes = new int[_trainingMissionCount]; Unknown1 = new int[10]; - TrainingMissionMedals = new byte[6]; + TrainingMissionMedals = new byte[_trainingMissionCount]; Unknown2 = new byte[10]; Unknown3 = new int[7]; } @@ -85,7 +86,7 @@ namespace Syroot.Worms.Gen2.Armageddon /// /// Gets or sets the team's special weapon. /// - public byte TeamWeapon { get; set; } + public TeamWeapon TeamWeapon { get; set; } /// /// Gets or sets the number of games lost. @@ -158,7 +159,7 @@ namespace Syroot.Worms.Gen2.Armageddon public byte DeathmatchRank { get; set; } /// - /// Gets or sets the seconds the team required to finish all 6 training missions. + /// Gets or sets the seconds the team required to finish all 6 training missions. /// public int[] TrainingMissionTimes { get; set; } @@ -217,8 +218,8 @@ namespace Syroot.Worms.Gen2.Armageddon Data = reader.ReadBytes(24 * 32) }; } - - TeamWeapon = reader.ReadByte(); + + TeamWeapon = reader.ReadEnum(true); GamesLost = reader.ReadInt32(); DeathmatchesLost = reader.ReadInt32(); GamesWon = reader.ReadInt32(); @@ -241,9 +242,9 @@ namespace Syroot.Worms.Gen2.Armageddon }; DeathmatchRank = reader.ReadByte(); - TrainingMissionTimes = reader.ReadInt32s(6); + TrainingMissionTimes = reader.ReadInt32s(_trainingMissionCount); Unknown1 = reader.ReadInt32s(10); - TrainingMissionMedals = reader.ReadBytes(6); + TrainingMissionMedals = reader.ReadBytes(_trainingMissionCount); Unknown2 = reader.ReadBytes(10); Unknown3 = reader.ReadInt32s(7); Unknown4 = reader.ReadByte(); @@ -274,7 +275,7 @@ namespace Syroot.Worms.Gen2.Armageddon writer.Write(Grave.Data); } - writer.Write(TeamWeapon); + writer.Write(TeamWeapon, true); writer.Write(GamesLost); writer.Write(DeathmatchesLost); writer.Write(GamesWon); @@ -302,10 +303,66 @@ namespace Syroot.Worms.Gen2.Armageddon } } + /// + /// Represents a team's progress in a mission. + /// [DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")] public struct TeamMissionStatus { + /// + /// The number of attempts the team required to solve the mission. + /// public int Attempts; + + /// + /// The medal the team got to solve the mission. + /// public int Medal; } + + /// + /// Represents the special weapon of a team. + /// + public enum TeamWeapon : byte + { + /// + /// The Flame Thrower weapon. + /// + FlameThrower, + + /// + /// The Mole Bomb weapon. + /// + MoleBomb, + + /// + /// The Old Woman weapon. + /// + OldWoman, + + /// + /// The Homing Pigeon weapon. + /// + HomingPigeon, + + /// + /// The Sheep Launcher weapon. + /// + SheepLauncher, + + /// + /// The Mad Cow weapon. + /// + MadCow, + + /// + /// The Holy Hand Grenade weapon. + /// + HolyHandGrenade, + + /// + /// The Super Sheep or Aqua Sheep weapon. + /// + SuperSheep + } } diff --git a/src/Syroot.Worms/Gen2/Image.cs b/src/Syroot.Worms/Gen2/Image.cs index a1aa0af..3481ea1 100644 --- a/src/Syroot.Worms/Gen2/Image.cs +++ b/src/Syroot.Worms/Gen2/Image.cs @@ -45,13 +45,25 @@ namespace Syroot.Worms.Gen2 Load(fileName); } + /// + /// Initializes a new instance of the class, loading the data from the given + /// . + /// + /// The to load the data from. + /// true to start reading the image data at a 4-byte boundary. Used by WWP in + /// LAND.DAT files. + internal Image(Stream stream, bool alignData) + { + Load(stream); + } + // ---- PROPERTIES --------------------------------------------------------------------------------------------- /// /// Gets an optional description of the image contents. /// public string Description { get; private set; } - + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- /// @@ -59,6 +71,24 @@ namespace Syroot.Worms.Gen2 /// /// The to load the data from. public void Load(Stream stream) + { + } + + /// + /// Loads the data from the given file. + /// + /// The name of the file to load the data from. + public void Load(string fileName) + { + using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + Load(stream); + } + } + + // ---- METHODS (PRIVATE) -------------------------------------------------------------------------------------- + + private void Load(Stream stream, bool alignData) { using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true)) { @@ -98,6 +128,10 @@ namespace Syroot.Worms.Gen2 } Size = new Vector2(reader.ReadInt16(), reader.ReadInt16()); + if (alignData) + { + reader.Align(4); + } // Read the bytes, which might be compressed. byte[] data = new byte[Size.X * Size.Y * BitsPerPixel / 8]; @@ -114,18 +148,6 @@ namespace Syroot.Worms.Gen2 } } - /// - /// Loads the data from the given file. - /// - /// The name of the file to load the data from. - public void Load(string fileName) - { - using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - Load(stream); - } - } - // ---- ENUMERATIONS ------------------------------------------------------------------------------------------- [Flags] diff --git a/src/Syroot.Worms/Gen2/WorldParty/LandData.cs b/src/Syroot.Worms/Gen2/WorldParty/LandData.cs new file mode 100644 index 0000000..eb8b74b --- /dev/null +++ b/src/Syroot.Worms/Gen2/WorldParty/LandData.cs @@ -0,0 +1,146 @@ +using System.IO; +using System.Text; +using Syroot.IO; +using Syroot.Maths; +using Syroot.Worms.Core; + +namespace Syroot.Worms.Gen2.WorldParty +{ + /// + /// Represents map configuration stored by the land generator in LAND.DAT files. + /// Used by WWP. S. https://worms2d.info/Land_Data_file. + /// + public class LandData : ILoadableFile + { + // ---- CONSTANTS ---------------------------------------------------------------------------------------------- + + private const int _signature = 0x1A444E4C; // "LND", 0x1A + + // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ + + /// + /// Initializes a new instance of the class. + /// + public LandData() + { + } + + /// + /// Initializes a new instance of the class, loading the data from the given + /// . + /// + /// The to load the data from. + public LandData(Stream stream) + { + Load(stream); + } + + /// + /// Initializes a new instance of the class, loading the data from the given file. + /// + /// The name of the file to load the data from. + public LandData(string fileName) + { + Load(fileName); + } + + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + /// + /// Gets or sets the size of the landscape in pixels. + /// + public Vector2 Size { get; set; } + + /// + /// Gets or sets a value indicating whether an indestructible top border will be enabled. + /// + public bool TopBorder { get; set; } + + /// + /// Gets or sets the height of the water in pixels. + /// + public int WaterHeight { get; set; } + + /// + /// Gets or sets an array of coordinates at which objects can be placed. + /// + public Vector2[] ObjectLocations { get; set; } + + /// + /// Gets or sets the visual foreground image. + /// + public Image Foreground { get; set; } + + /// + /// Gets or sets the collision mask of the landscape. + /// + public Image CollisionMask { get; set; } + + /// + /// Gets or sets the visual background image. + /// + public Image Background { get; set; } + + /// + /// Gets or sets the path to the land image file. + /// + public string LandTexturePath { get; set; } + + /// + /// Gets or sets the path to the Water.dir file. + /// + public string WaterDirPath { get; set; } + + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- + + /// + /// Loads the data from the given . + /// + /// The to load the data from. + 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(); + TopBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword); + WaterHeight = reader.ReadInt32(); + + // Read the possible object coordinate array. + ObjectLocations = new Vector2[reader.ReadInt32()]; + for (int i = 0; i < ObjectLocations.Length; i++) + { + ObjectLocations[i] = reader.ReadStruct(); + } + + // Read the image data. + Foreground = new Image(stream, true); + CollisionMask = new Image(stream, true); + Background = new Image(stream, true); + + // Read the file paths. + LandTexturePath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix); + WaterDirPath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix); + } + } + + /// + /// Loads the data from the given file. + /// + /// The name of the file to load the data from. + public void Load(string fileName) + { + using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + Load(stream); + } + } + } +} diff --git a/src/Syroot.Worms/Gen2/WorldParty/Team.cs b/src/Syroot.Worms/Gen2/WorldParty/Team.cs index 8241341..545464f 100644 --- a/src/Syroot.Worms/Gen2/WorldParty/Team.cs +++ b/src/Syroot.Worms/Gen2/WorldParty/Team.cs @@ -15,6 +15,7 @@ namespace Syroot.Worms.Gen2.WorldParty // ---- CONSTANTS ---------------------------------------------------------------------------------------------- private const int _missionCount = 45; + private const int _trainingMissionCount = 35; // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ @@ -25,7 +26,7 @@ namespace Syroot.Worms.Gen2.WorldParty { WormNames = new string[8]; MissionStatuses = new TeamMissionStatus[_missionCount]; - TrainingMissionTimes = new int[6]; + TrainingMissionTimes = new int[_trainingMissionCount]; WeaponPoints = new byte[46]; Unknown2 = new int[7]; } @@ -83,7 +84,7 @@ namespace Syroot.Worms.Gen2.WorldParty /// /// Gets or sets the team's special weapon. /// - public byte TeamWeapon { get; set; } + public TeamWeapon TeamWeapon { get; set; } /// /// Gets or sets the number of games lost. @@ -150,6 +151,9 @@ namespace Syroot.Worms.Gen2.WorldParty /// public Bitmap Flag { get; set; } + /// + /// Gets or sets an unknown value. + /// public byte Unknown1 { get; set; } /// @@ -158,7 +162,7 @@ namespace Syroot.Worms.Gen2.WorldParty public byte DeathmatchRank { get; set; } /// - /// Gets or sets the seconds the team required to finish all 6 training missions. + /// Gets or sets the seconds the team required to finish all 35 training missions. The last one is unused. /// public int[] TrainingMissionTimes { get; set; } @@ -214,7 +218,7 @@ namespace Syroot.Worms.Gen2.WorldParty }; } - TeamWeapon = reader.ReadByte(); + TeamWeapon = reader.ReadEnum(true); GamesLost = reader.ReadInt32(); DeathmatchesLost = reader.ReadInt32(); GamesWon = reader.ReadInt32(); @@ -238,8 +242,7 @@ namespace Syroot.Worms.Gen2.WorldParty Unknown1 = reader.ReadByte(); DeathmatchRank = reader.ReadByte(); - TrainingMissionTimes = reader.ReadInt32s(34); - UnknownTrainingMissionTime = reader.ReadInt32(); // Possibly an unused time. + TrainingMissionTimes = reader.ReadInt32s(_trainingMissionCount); WeaponPoints = reader.ReadBytes(46); Fort = reader.ReadByte(); Unknown2 = reader.ReadInt32s(7); @@ -270,7 +273,7 @@ namespace Syroot.Worms.Gen2.WorldParty writer.Write(Grave.Data); } - writer.Write(TeamWeapon); + writer.Write(TeamWeapon, true); writer.Write(GamesLost); writer.Write(DeathmatchesLost); writer.Write(GamesWon); @@ -298,13 +301,69 @@ namespace Syroot.Worms.Gen2.WorldParty } } + /// + /// Represents a team's progress in a mission. + /// [DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")] public struct TeamMissionStatus { + /// + /// The number of attempts the team required to solve the mission. + /// public int Attempts; + + /// + /// The medal the team got to solve the mission. + /// public int Medal; } + /// + /// Represents the special weapon of a team. + /// + public enum TeamWeapon : byte + { + /// + /// The Flame Thrower weapon. + /// + FlameThrower, + + /// + /// The Mole Bomb weapon. + /// + MoleBomb, + + /// + /// The Old Woman weapon. + /// + OldWoman, + + /// + /// The Homing Pigeon weapon. + /// + HomingPigeon, + + /// + /// The Sheep Launcher weapon. + /// + SheepLauncher, + + /// + /// The Mad Cow weapon. + /// + MadCow, + + /// + /// The Holy Hand Grenade weapon. + /// + HolyHandGrenade, + + /// + /// The Super Sheep or Aqua Sheep weapon. + /// + SuperSheep + } + /// /// Represents the weapons and utilities being an index into the array to store the /// amount the team bought.