diff --git a/README.md b/README.md
index 57dfd4c..ece4cc5 100644
--- a/README.md
+++ b/README.md
@@ -35,7 +35,7 @@ Formats of the second generation 2D games are mostly focused right now.
| Scheme Options | OPT | W2 | Yes | Yes |
| Scheme Weapons | WEP | W2 | Yes | Yes |
| Team Container | ST1 | W2 | Yes | Yes |
-| Team Container | WGT | WA, WWP | No | No |
+| Team Container | WGT | WA, WWP | WA | WA |
## Third Generation (3D)
Third generation file formats used by the 3D games have not yet been looked into.
diff --git a/src/NuGet.config b/src/NuGet.config
new file mode 100644
index 0000000..b1738fc
--- /dev/null
+++ b/src/NuGet.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Syroot.Worms.Test/Program.cs b/src/Syroot.Worms.Test/Program.cs
index dac17a5..41d1cda 100644
--- a/src/Syroot.Worms.Test/Program.cs
+++ b/src/Syroot.Worms.Test/Program.cs
@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Collections.Generic;
using Syroot.Worms.Gen2;
+using Syroot.Worms.Gen2.Armageddon;
namespace Syroot.Worms.Test
{
@@ -18,6 +19,9 @@ namespace Syroot.Worms.Test
private static void Main(string[] args)
{
+ TeamContainer teams = new TeamContainer(@"D:\Archive\Games\Worms\Worms Armageddon\3.7.2.1\User\Teams\WG.WGT");
+ teams.Save(@"D:\Pictures\test.wgt");
+
Console.WriteLine("Done.");
Console.ReadLine();
}
diff --git a/src/Syroot.Worms.UnitTest/Gen2/Armageddon/TeamContainerTests.cs b/src/Syroot.Worms.UnitTest/Gen2/Armageddon/TeamContainerTests.cs
new file mode 100644
index 0000000..dbe41c7
--- /dev/null
+++ b/src/Syroot.Worms.UnitTest/Gen2/Armageddon/TeamContainerTests.cs
@@ -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
+{
+ ///
+ /// Represents a collection of tests for the class.
+ ///
+ [TestCategory("TeamContainer (Armageddon)")]
+ [TestClass]
+ public class TeamContainerTests
+ {
+ // ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
+
+ ///
+ /// Loads all files found in any game directories.
+ ///
+ [TestMethod]
+ public void LoadTeamContainers()
+ {
+ TestHelpers.LoadFiles(Game.Armageddon, "*.wgt");
+ }
+ }
+}
diff --git a/src/Syroot.Worms/Bitmap.cs b/src/Syroot.Worms/Bitmap.cs
new file mode 100644
index 0000000..07359cc
--- /dev/null
+++ b/src/Syroot.Worms/Bitmap.cs
@@ -0,0 +1,32 @@
+using Syroot.Maths;
+
+namespace Syroot.Worms
+{
+ ///
+ /// Represents a pixel-based 2D image in different color formats.
+ ///
+ public class Bitmap
+ {
+ // ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ ///
+ /// Gets or sets the number of bits required to describe a color per pixel.
+ ///
+ public int BitsPerPixel { get; set; }
+
+ ///
+ /// Gets or sets the colors in the palette of the bitmap, if it has one.
+ ///
+ public Color[] Palette { get; set; }
+
+ ///
+ /// Gets or sets the size of the image in pixels.
+ ///
+ public Vector2 Size { get; set; }
+
+ ///
+ /// Gets or sets the data of the image pixels.
+ ///
+ public byte[] Data { get; set; }
+ }
+}
diff --git a/src/Syroot.Worms/Core/BinaryReaderExtensions.cs b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs
index db2135a..a76ffaf 100644
--- a/src/Syroot.Worms/Core/BinaryReaderExtensions.cs
+++ b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs
@@ -11,6 +11,37 @@ namespace Syroot.Worms.Core
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
+ ///
+ /// Reads a 0-terminated string which is stored in a fixed-size block of bytes.
+ ///
+ /// The extended .
+ /// The number of bytes the fixed-size blocks takes.
+ /// The read string.
+ internal static string ReadFixedString(this BinaryDataReader self, int length)
+ {
+ string str = self.ReadString(BinaryStringFormat.ZeroTerminated);
+ self.Seek(length - str.Length - 1);
+ return str;
+ }
+
+ ///
+ /// Reads 0-terminated strings which are stored in a fixed-size block of
+ /// bytes.
+ ///
+ /// The extended .
+ /// The number of values to read.
+ /// The number of bytes the fixed-size blocks takes.
+ /// The read string.
+ internal static string[] ReadFixedStrings(this BinaryDataReader self, int count, int length)
+ {
+ string[] strings = new string[count];
+ for (int i = 0; i < count; i++)
+ {
+ strings[i] = ReadFixedString(self, length);
+ }
+ return strings;
+ }
+
///
/// Reads a raw byte structure from the current stream and returns it.
///
@@ -29,5 +60,22 @@ namespace Syroot.Worms.Core
return instance;
}
+
+ ///
+ /// Reads raw byte structures from the current stream and returns them.
+ ///
+ /// The type of the structure to read.
+ /// The extended instance.
+ /// The number of values to read.
+ /// The structures of type .
+ internal static T[] ReadStructs(this BinaryReader self, int count) where T : struct
+ {
+ T[] values = new T[count];
+ for (int i = 0; i < count; i++)
+ {
+ values[i] = ReadStruct(self);
+ }
+ return values;
+ }
}
}
diff --git a/src/Syroot.Worms/Core/BinaryWriterExtensions.cs b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs
index 7ee352d..2cd894a 100644
--- a/src/Syroot.Worms/Core/BinaryWriterExtensions.cs
+++ b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs
@@ -1,5 +1,6 @@
using System.IO;
using System.Runtime.InteropServices;
+using Syroot.IO;
namespace Syroot.Worms.Core
{
@@ -9,24 +10,65 @@ namespace Syroot.Worms.Core
internal static class BinaryWriterExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
-
+
+ ///
+ /// Writes the given string into a fixed-size block of bytes and 0-terminates it.
+ ///
+ /// The extended instance.
+ /// The string to write.
+ /// The number of bytes the fixed-size block takes.
+ internal static void Write(this BinaryDataWriter self, string value, int length)
+ {
+ byte[] bytes = self.Encoding.GetBytes(value);
+ self.Write(bytes);
+ self.Write(new byte[length - bytes.Length]);
+ }
+
+ ///
+ /// Writes the given strings into fixed-size blocks of bytes and 0-terminates them.
+ ///
+ /// The extended instance.
+ /// The strings to write.
+ /// The number of bytes a fixed-size block takes.
+ internal static void Write(this BinaryDataWriter self, string[] values, int length)
+ {
+ foreach (string value in values)
+ {
+ Write(self, value, length);
+ }
+ }
+
///
/// Writes the bytes of a structure into the current stream.
///
/// The type of the structure to read.
/// The extended instance.
- /// The structure to write.
- internal static void Write(this BinaryWriter self, T instance) where T : struct
+ /// The structure to write.
+ internal static void Write(this BinaryWriter self, T value) where T : struct
{
// Get the raw bytes of the structure instance.
byte[] bytes = new byte[Marshal.SizeOf()];
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
- Marshal.StructureToPtr(instance, handle.AddrOfPinnedObject(), false);
+ Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
handle.Free();
// Write the bytes to the stream.
self.Write(bytes);
}
+
+ ///
+ /// Writes the bytes of structures into the current stream.
+ ///
+ /// The type of the structure to read.
+ /// The extended instance.
+ /// The structures to write.
+ internal static void Write(this BinaryWriter self, T[] values) where T : struct
+ {
+ foreach (T value in values)
+ {
+ Write(self, value);
+ }
+ }
}
}
diff --git a/src/Syroot.Worms/Gen2/Armageddon/Team.cs b/src/Syroot.Worms/Gen2/Armageddon/Team.cs
new file mode 100644
index 0000000..fcb6e59
--- /dev/null
+++ b/src/Syroot.Worms/Gen2/Armageddon/Team.cs
@@ -0,0 +1,291 @@
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using Syroot.IO;
+using Syroot.Maths;
+using Syroot.Worms.Core;
+
+namespace Syroot.Worms.Gen2.Armageddon
+{
+ ///
+ /// Represents a team stored in a file.
+ ///
+ public class Team : ILoadable, ISaveable
+ {
+ // ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ ///
+ /// Gets or sets the name of the team.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the 8 worm names.
+ ///
+ public string[] WormNames { get; set; }
+
+ ///
+ /// Gets or sets the AI intelligence difficulty level, from 0-5, where 0 is human-controlled.
+ ///
+ public byte CpuLevel { get; set; }
+
+ ///
+ /// Gets or sets the name of soundbank for the voice of team worms.
+ ///
+ public string SoundBankName { get; set; }
+
+ public byte SoundBankLocation { get; set; }
+
+ ///
+ /// Gets or sets the name of the team fanfare.
+ ///
+ public string FanfareName { get; set; }
+
+ ///
+ /// Gets or sets a value indicating whether the fanfare with the name stored in
+ /// (true) or the player's countries' fanfare should be played (false).
+ ///
+ public byte UseCustomFanfare { get; set; }
+
+ ///
+ /// Gets or sets the sprite index of the team grave, -1 being a custom bitmap grave.
+ ///
+ public sbyte GraveSprite { get; set; }
+
+ ///
+ /// Gets or sets the file name of the team grave bitmap if it uses a custom one.
+ ///
+ public string GraveFileName { get; set; }
+
+ ///
+ /// Gets or sets the team grave bitmap if it uses a custom one.
+ ///
+ public Bitmap Grave { get; set; }
+
+ ///
+ /// Gets or sets the team's special weapon.
+ ///
+ public byte TeamWeapon { get; set; }
+
+ ///
+ /// Gets or sets the number of games lost.
+ ///
+ public int GamesLost { get; set; }
+
+ ///
+ /// Gets or sets the number of deathmatch games lost.
+ ///
+ public int DeathmatchesLost { get; set; }
+
+ ///
+ /// Gets or sets the number of games won.
+ ///
+ public int GamesWon { get; set; }
+
+ ///
+ /// Gets or sets the number of deathmatch games won.
+ ///
+ public int DeathmatchesWon { get; set; }
+
+ ///
+ /// Gets or sets the number of games drawn.
+ ///
+ public int GamesDrawn { get; set; }
+
+ ///
+ /// Gets or sets the number of deathmatch games drawn.
+ ///
+ public int DeathmatchesDrawn { get; set; }
+
+ ///
+ /// Gets or sets the number of opponent worms killed by this team.
+ ///
+ public int Kills { get; set; }
+
+ ///
+ /// Gets or sets the number of opponent worms killed by this team in deathmatches.
+ ///
+ public int DeathmatchKills { get; set; }
+
+ ///
+ /// Gets or sets the number of worms which got killed in this team.
+ ///
+ public int Deaths { get; set; }
+
+ ///
+ /// Gets or sets the number of worms which got killed in this team in deathmatches.
+ ///
+ public int DeathmatchDeaths { get; set; }
+
+ ///
+ /// Gets or sets the array of 33 mission statuses.
+ ///
+ public TeamMissionStatus[] MissionStatuses { get; set; }
+
+ ///
+ /// Gets or sets the file name of the team flag.
+ ///
+ public string FlagFileName { get; set; }
+
+ ///
+ /// Gets or sets the bitmap of the team flag.
+ ///
+ public Bitmap Flag { get; set; }
+
+ ///
+ /// Gets or sets the deathmatch rank this team reached.
+ ///
+ public byte DeathmatchRank { get; set; }
+
+ ///
+ /// Gets or sets the seconds the team required to finish all 6 training missions.
+ ///
+ public int[] TrainingMissionTimes { get; set; }
+
+ ///
+ /// Gets or sets 10 unknown integer values.
+ ///
+ public int[] Unknown1 { get; set; }
+
+ ///
+ /// Gets or sets the medals the team achieved in all 6 training missions.
+ ///
+ public byte[] TrainingMissionMedals { get; set; }
+
+ ///
+ /// Gets or sets 10 unknown bytes.
+ ///
+ public byte[] Unknown2 { get; set; }
+
+ ///
+ /// Gets or sets 7 unknown integer values.
+ ///
+ public int[] Unknown3 { get; set; }
+
+ ///
+ /// Gets or sets an unknown byte.
+ ///
+ public byte Unknown4 { 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))
+ {
+ Name = reader.ReadFixedString(17);
+ WormNames = reader.ReadFixedStrings(8, 17);
+ CpuLevel = reader.ReadByte();
+ SoundBankName = reader.ReadFixedString(0x20);
+ SoundBankLocation = reader.ReadByte();
+ FanfareName = reader.ReadFixedString(0x20);
+ UseCustomFanfare = reader.ReadByte();
+
+ GraveSprite = reader.ReadSByte();
+ if (GraveSprite < 0)
+ {
+ GraveFileName = reader.ReadFixedString(0x20);
+ Grave = new Bitmap()
+ {
+ BitsPerPixel = 8,
+ Size = new Vector2(24, 32),
+ Palette = reader.ReadStructs(256),
+ Data = reader.ReadBytes(24 * 32)
+ };
+ }
+
+ TeamWeapon = reader.ReadByte();
+ GamesLost = reader.ReadInt32();
+ DeathmatchesLost = reader.ReadInt32();
+ GamesWon = reader.ReadInt32();
+ DeathmatchesWon = reader.ReadInt32();
+ GamesDrawn = reader.ReadInt32();
+ DeathmatchesDrawn = reader.ReadInt32();
+ Kills = reader.ReadInt32();
+ DeathmatchKills = reader.ReadInt32();
+ Deaths = reader.ReadInt32();
+ DeathmatchDeaths = reader.ReadInt32();
+ MissionStatuses = reader.ReadStructs(33);
+
+ FlagFileName = reader.ReadFixedString(0x20);
+ Flag = new Bitmap()
+ {
+ BitsPerPixel = 8,
+ Size = new Vector2(20, 17),
+ Palette = reader.ReadStructs(256),
+ Data = reader.ReadBytes(20 * 17)
+ };
+
+ DeathmatchRank = reader.ReadByte();
+ TrainingMissionTimes = reader.ReadInt32s(6);
+ Unknown1 = reader.ReadInt32s(10);
+ TrainingMissionMedals = reader.ReadBytes(6);
+ Unknown2 = reader.ReadBytes(10);
+ Unknown3 = reader.ReadInt32s(7);
+ Unknown4 = reader.ReadByte();
+ }
+ }
+
+ ///
+ /// Saves the data into the given .
+ ///
+ /// The to save the data to.
+ public void Save(Stream stream)
+ {
+ using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII, true))
+ {
+ writer.Write(Name, 17);
+ writer.Write(WormNames, 17);
+ writer.Write(CpuLevel);
+ writer.Write(SoundBankName, 0x20);
+ writer.Write(SoundBankLocation);
+ writer.Write(FanfareName, 0x20);
+ writer.Write(UseCustomFanfare);
+
+ writer.Write(GraveSprite);
+ if (GraveSprite < 0)
+ {
+ writer.Write(GraveFileName, 0x20);
+ writer.Write(Grave.Palette);
+ writer.Write(Grave.Data);
+ }
+
+ writer.Write(TeamWeapon);
+ writer.Write(GamesLost);
+ writer.Write(DeathmatchesLost);
+ writer.Write(GamesWon);
+ writer.Write(DeathmatchesWon);
+ writer.Write(GamesDrawn);
+ writer.Write(DeathmatchesDrawn);
+ writer.Write(Kills);
+ writer.Write(DeathmatchKills);
+ writer.Write(Deaths);
+ writer.Write(DeathmatchDeaths);
+ writer.Write(MissionStatuses);
+
+ writer.Write(FlagFileName, 0x20);
+ writer.Write(Flag.Palette);
+ writer.Write(Flag.Data);
+
+ writer.Write(DeathmatchRank);
+ writer.Write(TrainingMissionTimes);
+ writer.Write(Unknown1);
+ writer.Write(TrainingMissionMedals);
+ writer.Write(Unknown2);
+ writer.Write(Unknown3);
+ writer.Write(Unknown4);
+ }
+ }
+ }
+
+ [DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")]
+ public struct TeamMissionStatus
+ {
+ public int Attempts;
+ public int Medal;
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs b/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
index ff1f463..4573300 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
@@ -1,10 +1,235 @@
-using System;
+using System;
using System.Collections.Generic;
+using System.IO;
using System.Text;
+using Syroot.IO;
+using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Armageddon
{
- class TeamContainer
+ ///
+ /// Represents the list of teams and unlocked game features stored in WGT files.
+ /// Used by WA and WWP. S. https://worms2d.info/Team_file.
+ ///
+ public class TeamContainer : ILoadableFile, ISaveableFile
{
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const string _signature = "WGT"; // 0-terminated.
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TeamContainer()
+ {
+ Teams = new List();
+ }
+
+ ///
+ /// Initializes a new instance of the class, loading the data from the given
+ /// .
+ ///
+ /// The to load the data from.
+ public TeamContainer(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 TeamContainer(string fileName)
+ {
+ Load(fileName);
+ }
+
+ // ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ ///
+ /// Gets or sets a value possibly indicating a version of the file format.
+ ///
+ public byte Version { get; set; }
+
+ ///
+ /// Gets or sets the unlocked utilities, weapon upgrades, and game cheats.
+ ///
+ public UnlockedFeatures UnlockedFeatures { get; set; }
+
+ ///
+ /// Gets or sets an unknown value.
+ ///
+ public byte Unknown { get; set; }
+
+ ///
+ /// Gets or sets the list of instances stored.
+ ///
+ public List Teams { 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.ReadString(BinaryStringFormat.ZeroTerminated) != _signature)
+ {
+ throw new InvalidDataException("Invalid WGT file signature.");
+ }
+ Version = reader.ReadByte(); // Really version?
+
+ // Read global settings.
+ byte teamCount = reader.ReadByte();
+ UnlockedFeatures = reader.ReadEnum(true);
+ Unknown = reader.ReadByte();
+
+ // Read the teams.
+ Teams = new List(teamCount);
+ for (int i = 0; i < teamCount; i++)
+ {
+ Team team = new Team();
+ team.Load(reader.BaseStream);
+ Teams.Add(team);
+ }
+ }
+ }
+
+ ///
+ /// 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);
+ }
+ }
+
+ ///
+ /// Saves the data into the given .
+ ///
+ /// The to save the data to.
+ public void Save(Stream stream)
+ {
+ using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII))
+ {
+ // Write the header.
+ writer.Write(_signature, BinaryStringFormat.ZeroTerminated);
+ writer.Write(Version);
+
+ // Write global settings.
+ writer.Write((byte)Teams.Count);
+ writer.Write(UnlockedFeatures, true);
+ writer.Write(Unknown);
+
+ // Write the teams.
+ foreach (Team team in Teams)
+ {
+ team.Save(writer.BaseStream);
+ }
+ }
+ }
+
+ ///
+ /// Saves the data in the given file.
+ ///
+ /// The name of the file to save the data in.
+ public void Save(string fileName)
+ {
+ using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
+ {
+ Save(stream);
+ }
+ }
+ }
+
+ ///
+ /// Represents unlockable features of the game.
+ ///
+ [Flags]
+ public enum UnlockedFeatures : int
+ {
+ ///
+ /// The utility weapon Laser Sight can be configured.
+ ///
+ UtilityLaserSight = 1 << 0,
+
+ ///
+ /// The utility weapon Fast Walk can be configured.
+ ///
+ UtilityFastWalk = 1 << 1,
+
+ ///
+ /// The utility weapon Invisibility can be configured.
+ ///
+ UtilityInvisibility = 1 << 2,
+
+ ///
+ /// The utility weapon Low Gravity can be configured.
+ ///
+ UtilityLowGravity = 1 << 3,
+
+ ///
+ /// The utility weapon Jetpack can be configured.
+ ///
+ UtilityJetpack = 1 << 4,
+
+ ///
+ /// The Grenade upgrade can be enabled.
+ ///
+ UpgradedGrenade = 1 << 8,
+
+ ///
+ /// The Shotgun upgrade can be enabled.
+ ///
+ UpgradedShotgun = 1 << 9,
+
+ ///
+ /// The cluster upgrade can be enabled.
+ ///
+ UpgradedClusters = 1 << 10,
+
+ ///
+ /// The Longbow upgrade can be enabled.
+ ///
+ UpgradedLongbow = 1 << 11,
+
+ ///
+ /// The upgrade of Super Sheeps to become Aqua Sheeps can be enabled.
+ ///
+ AquaSheep = 1 << 12,
+
+ ///
+ /// Worms can have infinite health and are killable only by drowning them.
+ ///
+ GodWorms = 1 << 16,
+
+ ///
+ /// Blood effects when hitting worms can be enabled.
+ ///
+ BloodFx = 1 << 17,
+
+ ///
+ /// Every crate explodes with a sheep.
+ ///
+ SheepHeaven = 1 << 18,
+
+ ///
+ /// Map terrain becomes indestructible. Has to be set together with .
+ ///
+ IndestructibleMap1 = 1 << 24,
+
+ ///
+ /// Map terrain becomes indestructible. Has to be set together with .
+ ///
+ IndestructibleMap2 = 1 << 25
}
}
diff --git a/src/Syroot.Worms/Gen2/Image.cs b/src/Syroot.Worms/Gen2/Image.cs
index ef343c2..a1aa0af 100644
--- a/src/Syroot.Worms/Gen2/Image.cs
+++ b/src/Syroot.Worms/Gen2/Image.cs
@@ -11,7 +11,7 @@ namespace Syroot.Worms.Gen2
/// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
/// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
///
- public class Image : ILoadableFile
+ public class Image : Bitmap, ILoadableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
@@ -51,27 +51,7 @@ namespace Syroot.Worms.Gen2
/// Gets an optional description of the image contents.
///
public string Description { get; private set; }
-
- ///
- /// Gets the number of bits required to describe a color per pixel.
- ///
- public int BitsPerPixel { get; private set; }
-
- ///
- /// Gets the color palette of the image. The first color must always be black.
- ///
- public Color[] Palette { get; private set; }
-
- ///
- /// Gets the size of the image in pixels.
- ///
- public Vector2 Size { get; private set; }
- ///
- /// Gets the data of the image pixels.
- ///
- public byte[] Data { get; private set; }
-
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
///
@@ -118,7 +98,7 @@ namespace Syroot.Worms.Gen2
}
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))
@@ -145,7 +125,7 @@ namespace Syroot.Worms.Gen2
Load(stream);
}
}
-
+
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
[Flags]
diff --git a/src/Syroot.Worms/Gen2/Worms2/Team.cs b/src/Syroot.Worms/Gen2/Worms2/Team.cs
index f78e5f6..c5ff4b8 100644
--- a/src/Syroot.Worms/Gen2/Worms2/Team.cs
+++ b/src/Syroot.Worms/Gen2/Worms2/Team.cs
@@ -1,136 +1,213 @@
using System;
+using System.IO;
+using System.Text;
+using Syroot.IO;
+using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
///
/// Represents a team stored in a file.
///
- public struct Team
+ public class Team : ILoadable, ISaveable
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ public short Unknown1 { get; set; }
+
+ ///
+ /// Gets or sets the name of the team.
+ ///
+ public string Name { get; set; }
+
+ ///
+ /// Gets or sets the name of soundbank for the voice of team worms.
+ ///
+ public string SoundBankName { get; set; }
+
+ ///
+ /// Gets or sets the 8 worm names.
+ ///
+ public string[] WormNames { get; set; }
- public short Unknown1;
-
- ///
- /// The name of the team.
- ///
- public string Name;
-
- ///
- /// The name of soundbank for the voice of team worms.
- ///
- public string SoundBankName;
-
- ///
- /// The name of the first worm.
- ///
- public string Worm1Name;
-
- ///
- /// The name of the second worm.
- ///
- public string Worm2Name;
-
- ///
- /// The name of the third worm.
- ///
- public string Worm3Name;
-
- ///
- /// The name the fourth worm.
- ///
- public string Worm4Name;
-
- ///
- /// The name the fifth worm.
- ///
- public string Worm5Name;
-
- ///
- /// The name the second worm.
- ///
- public string Worm6Name;
-
- ///
- /// The name the seventh worm.
- ///
- public string Worm7Name;
-
- ///
- /// The name the eighth worm.
- ///
- public string Worm8Name;
-
- public int Unknown2;
- public int Unknown3;
- public int Unknown4;
- public int Unknown5;
- public int Unknown6;
- public int Unknown7;
- public int Unknown8;
- public int Unknown9;
- public int Unknown10;
- public int Unknown11;
- public int Unknown12;
- public int Unknown13;
- public int Unknown14;
- public int Unknown15;
- public int Unknown16;
- public int Unknown17;
- public int Unknown18;
- public int Unknown19;
- public int Unknown20;
- public int Unknown21;
- public int Unknown22;
- public int Unknown23;
- public int Unknown24;
- public int Unknown25;
+ public int Unknown2 { get; set; }
+ public int Unknown3 { get; set; }
+ public int Unknown4 { get; set; }
+ public int Unknown5 { get; set; }
+ public int Unknown6 { get; set; }
+ public int Unknown7 { get; set; }
+ public int Unknown8 { get; set; }
+ public int Unknown9 { get; set; }
+ public int Unknown10 { get; set; }
+ public int Unknown11 { get; set; }
+ public int Unknown12 { get; set; }
+ public int Unknown13 { get; set; }
+ public int Unknown14 { get; set; }
+ public int Unknown15 { get; set; }
+ public int Unknown16 { get; set; }
+ public int Unknown17 { get; set; }
+ public int Unknown18 { get; set; }
+ public int Unknown19 { get; set; }
+ public int Unknown20 { get; set; }
+ public int Unknown21 { get; set; }
+ public int Unknown22 { get; set; }
+ public int Unknown23 { get; set; }
+ public int Unknown24 { get; set; }
+ public int Unknown25 { get; set; }
///
- /// The number of games lost.
+ /// Gets or sets the number of games lost.
///
- public int GamesLost;
+ public int GamesLost { get; set; }
///
- /// The number of games won.
+ /// Gets or sets the number of games won.
///
- public int GamesWon;
+ public int GamesWon { get; set; }
- public int Unknown26;
- public int Unknown27;
+ public int Unknown26 { get; set; }
+ public int Unknown27 { get; set; }
///
- /// The number of opponent worms killed by this team.
+ /// Gets or sets the number of opponent worms killed by this team.
///
- public int WormsKilled;
+ public int Kills { get; set; }
///
- /// The number of worms which got killed in this team.
+ /// Gets or sets the number of worms which got killed in this team.
///
- public int WormsLost;
+ public int Deaths { get; set; }
///
- /// The AI intelligence difficulty level, from 0-100, where 0 is human-controlled.
+ /// Gets or sets the AI intelligence difficulty level, from 0-100, where 0 is human-controlled.
///
- public int CpuLevel;
+ public int CpuLevel { get; set; }
- public int Unknown28;
- public int Unknown29;
- public int Unknown30;
+ public int Unknown28 { get; set; }
+ public int Unknown29 { get; set; }
+ public int Unknown30 { get; set; }
///
- /// The "difference" statistics value.
+ /// Gets or sets the "difference" statistics value.
///
- public int Difference;
+ public int Difference { get; set; }
///
- /// The number of games played, always being 0 for AI controlled teams.
+ /// Gets or sets the number of games played, always being 0 for AI controlled teams.
///
- public int GamesPlayed;
+ public int GamesPlayed { get; set; }
///
- /// The points gained by this team.
+ /// Gets or sets the points gained by this team.
///
- public int Points;
+ public int Points { 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))
+ {
+ Unknown1 = reader.ReadInt16();
+ Name = reader.ReadFixedString(66);
+ SoundBankName = reader.ReadFixedString(36);
+ WormNames = reader.ReadFixedStrings(8, 20);
+ Unknown2 = reader.ReadInt32();
+ Unknown3 = reader.ReadInt32();
+ Unknown4 = reader.ReadInt32();
+ Unknown5 = reader.ReadInt32();
+ Unknown6 = reader.ReadInt32();
+ Unknown7 = reader.ReadInt32();
+ Unknown8 = reader.ReadInt32();
+ Unknown9 = reader.ReadInt32();
+ Unknown10 = reader.ReadInt32();
+ Unknown11 = reader.ReadInt32();
+ Unknown12 = reader.ReadInt32();
+ Unknown13 = reader.ReadInt32();
+ Unknown14 = reader.ReadInt32();
+ Unknown15 = reader.ReadInt32();
+ Unknown16 = reader.ReadInt32();
+ Unknown17 = reader.ReadInt32();
+ Unknown18 = reader.ReadInt32();
+ Unknown19 = reader.ReadInt32();
+ Unknown20 = reader.ReadInt32();
+ Unknown21 = reader.ReadInt32();
+ Unknown22 = reader.ReadInt32();
+ Unknown23 = reader.ReadInt32();
+ Unknown24 = reader.ReadInt32();
+ Unknown25 = reader.ReadInt32();
+ GamesLost = reader.ReadInt32();
+ GamesWon = reader.ReadInt32();
+ Unknown26 = reader.ReadInt32();
+ Unknown27 = reader.ReadInt32();
+ Kills = reader.ReadInt32();
+ Deaths = reader.ReadInt32();
+ CpuLevel = reader.ReadInt32();
+ Unknown28 = reader.ReadInt32();
+ Unknown29 = reader.ReadInt32();
+ Unknown30 = reader.ReadInt32();
+ Difference = reader.ReadInt32();
+ GamesPlayed = reader.ReadInt32();
+ Points = reader.ReadInt32();
+ }
+ }
+
+ ///
+ /// Saves the data into the given .
+ ///
+ /// The to save the data to.
+ public void Save(Stream stream)
+ {
+ using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII, true))
+ {
+ writer.Write(Unknown1);
+ writer.Write(Name, 66);
+ writer.Write(SoundBankName, 36);
+ writer.Write(WormNames, 20);
+ writer.Write(Unknown2);
+ writer.Write(Unknown3);
+ writer.Write(Unknown4);
+ writer.Write(Unknown5);
+ writer.Write(Unknown6);
+ writer.Write(Unknown7);
+ writer.Write(Unknown8);
+ writer.Write(Unknown9);
+ writer.Write(Unknown10);
+ writer.Write(Unknown11);
+ writer.Write(Unknown12);
+ writer.Write(Unknown13);
+ writer.Write(Unknown14);
+ writer.Write(Unknown15);
+ writer.Write(Unknown16);
+ writer.Write(Unknown17);
+ writer.Write(Unknown18);
+ writer.Write(Unknown19);
+ writer.Write(Unknown20);
+ writer.Write(Unknown21);
+ writer.Write(Unknown22);
+ writer.Write(Unknown23);
+ writer.Write(Unknown24);
+ writer.Write(Unknown25);
+ writer.Write(GamesLost);
+ writer.Write(GamesWon);
+ writer.Write(Unknown26);
+ writer.Write(Unknown27);
+ writer.Write(Kills);
+ writer.Write(Deaths);
+ writer.Write(CpuLevel);
+ writer.Write(Unknown28);
+ writer.Write(Unknown29);
+ writer.Write(Unknown30);
+ writer.Write(Kills);
+ writer.Write(Deaths);
+ writer.Write(Difference);
+ writer.Write(GamesPlayed);
+ writer.Write(Points);
+ }
+ }
}
}
diff --git a/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs b/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
index 2cdfca7..2e53ce0 100644
--- a/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
+++ b/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
@@ -1,9 +1,7 @@
using System.Collections.Generic;
using System.IO;
-using System.Runtime.InteropServices;
using System.Text;
using Syroot.IO;
-using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
@@ -14,10 +12,6 @@ namespace Syroot.Worms.Gen2.Worms2
///
public class TeamContainer : ILoadableFile, ISaveableFile
{
- // ---- CONSTANTS ----------------------------------------------------------------------------------------------
-
- private static readonly char[] _trimChars = new char[] { (char)0x00 };
-
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
///
@@ -67,57 +61,9 @@ namespace Syroot.Worms.Gen2.Worms2
Teams = new List();
while (!reader.EndOfStream)
{
- Teams.Add(new Team()
- {
- Unknown1 = reader.ReadInt16(),
- Name = ReadFixedString(reader, 66),
- SoundBankName = ReadFixedString(reader, 36),
- Worm1Name = ReadFixedString(reader, 20),
- Worm2Name = ReadFixedString(reader, 20),
- Worm3Name = ReadFixedString(reader, 20),
- Worm4Name = ReadFixedString(reader, 20),
- Worm5Name = ReadFixedString(reader, 20),
- Worm6Name = ReadFixedString(reader, 20),
- Worm7Name = ReadFixedString(reader, 20),
- Worm8Name = ReadFixedString(reader, 20),
- Unknown2 = reader.ReadInt32(),
- Unknown3 = reader.ReadInt32(),
- Unknown4 = reader.ReadInt32(),
- Unknown5 = reader.ReadInt32(),
- Unknown6 = reader.ReadInt32(),
- Unknown7 = reader.ReadInt32(),
- Unknown8 = reader.ReadInt32(),
- Unknown9 = reader.ReadInt32(),
- Unknown10 = reader.ReadInt32(),
- Unknown11 = reader.ReadInt32(),
- Unknown12 = reader.ReadInt32(),
- Unknown13 = reader.ReadInt32(),
- Unknown14 = reader.ReadInt32(),
- Unknown15 = reader.ReadInt32(),
- Unknown16 = reader.ReadInt32(),
- Unknown17 = reader.ReadInt32(),
- Unknown18 = reader.ReadInt32(),
- Unknown19 = reader.ReadInt32(),
- Unknown20 = reader.ReadInt32(),
- Unknown21 = reader.ReadInt32(),
- Unknown22 = reader.ReadInt32(),
- Unknown23 = reader.ReadInt32(),
- Unknown24 = reader.ReadInt32(),
- Unknown25 = reader.ReadInt32(),
- GamesLost = reader.ReadInt32(),
- GamesWon = reader.ReadInt32(),
- Unknown26 = reader.ReadInt32(),
- Unknown27 = reader.ReadInt32(),
- WormsKilled = reader.ReadInt32(),
- WormsLost = reader.ReadInt32(),
- CpuLevel = reader.ReadInt32(),
- Unknown28 = reader.ReadInt32(),
- Unknown29 = reader.ReadInt32(),
- Unknown30 = reader.ReadInt32(),
- Difference = reader.ReadInt32(),
- GamesPlayed = reader.ReadInt32(),
- Points = reader.ReadInt32(),
- });
+ Team team = new Team();
+ team.Load(reader.BaseStream);
+ Teams.Add(team);
}
}
}
@@ -144,56 +90,7 @@ namespace Syroot.Worms.Gen2.Worms2
{
foreach (Team team in Teams)
{
- writer.Write(team.Unknown1);
- WriteFixedString(writer, team.Name, 66);
- WriteFixedString(writer, team.SoundBankName, 36);
- WriteFixedString(writer, team.Worm1Name, 20);
- WriteFixedString(writer, team.Worm2Name, 20);
- WriteFixedString(writer, team.Worm3Name, 20);
- WriteFixedString(writer, team.Worm4Name, 20);
- WriteFixedString(writer, team.Worm5Name, 20);
- WriteFixedString(writer, team.Worm6Name, 20);
- WriteFixedString(writer, team.Worm7Name, 20);
- WriteFixedString(writer, team.Worm8Name, 20);
- writer.Write(team.Unknown2);
- writer.Write(team.Unknown3);
- writer.Write(team.Unknown4);
- writer.Write(team.Unknown5);
- writer.Write(team.Unknown6);
- writer.Write(team.Unknown7);
- writer.Write(team.Unknown8);
- writer.Write(team.Unknown9);
- writer.Write(team.Unknown10);
- writer.Write(team.Unknown11);
- writer.Write(team.Unknown12);
- writer.Write(team.Unknown13);
- writer.Write(team.Unknown14);
- writer.Write(team.Unknown15);
- writer.Write(team.Unknown16);
- writer.Write(team.Unknown17);
- writer.Write(team.Unknown18);
- writer.Write(team.Unknown19);
- writer.Write(team.Unknown20);
- writer.Write(team.Unknown21);
- writer.Write(team.Unknown22);
- writer.Write(team.Unknown23);
- writer.Write(team.Unknown24);
- writer.Write(team.Unknown25);
- writer.Write(team.GamesLost);
- writer.Write(team.GamesWon);
- writer.Write(team.Unknown26);
- writer.Write(team.Unknown27);
- writer.Write(team.WormsKilled);
- writer.Write(team.WormsLost);
- writer.Write(team.CpuLevel);
- writer.Write(team.Unknown28);
- writer.Write(team.Unknown29);
- writer.Write(team.Unknown30);
- writer.Write(team.WormsKilled);
- writer.Write(team.WormsLost);
- writer.Write(team.Difference);
- writer.Write(team.GamesPlayed);
- writer.Write(team.Points);
+ team.Save(writer.BaseStream);
}
}
}
@@ -209,21 +106,5 @@ namespace Syroot.Worms.Gen2.Worms2
Save(stream);
}
}
-
- // ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
-
- private static string ReadFixedString(BinaryDataReader reader, int length)
- {
- string str = reader.ReadString(BinaryStringFormat.ZeroTerminated);
- reader.Seek(length - str.Length - 1);
- return str;
- }
-
- private static void WriteFixedString(BinaryDataWriter writer, string value, int length)
- {
- byte[] bytes = writer.Encoding.GetBytes(value);
- writer.Write(bytes);
- writer.Write(new byte[length - bytes.Length]);
- }
}
}
diff --git a/src/Syroot.Worms/Syroot.Worms.csproj b/src/Syroot.Worms/Syroot.Worms.csproj
index 4a9b84b..d231161 100644
--- a/src/Syroot.Worms/Syroot.Worms.csproj
+++ b/src/Syroot.Worms/Syroot.Worms.csproj
@@ -21,6 +21,7 @@
+