diff --git a/src/Syroot.Worms.Test/Program.cs b/src/Syroot.Worms.Test/Program.cs
index 41d1cda..64df96a 100644
--- a/src/Syroot.Worms.Test/Program.cs
+++ b/src/Syroot.Worms.Test/Program.cs
@@ -2,7 +2,7 @@ using System;
using System.IO;
using System.Collections.Generic;
using Syroot.Worms.Gen2;
-using Syroot.Worms.Gen2.Armageddon;
+using Syroot.Worms.Gen2.WorldParty;
namespace Syroot.Worms.Test
{
@@ -19,8 +19,8 @@ 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");
+ TeamContainer teams = new TeamContainer(@"C:\Games\Worms World Party\User\Teams\Wg.wwp");
+ teams.Save(@"D:\Pictures\test.wwp");
Console.WriteLine("Done.");
Console.ReadLine();
diff --git a/src/Syroot.Worms/Gen2/Armageddon/Team.cs b/src/Syroot.Worms/Gen2/Armageddon/Team.cs
index fcb6e59..9f5f86b 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/Team.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/Team.cs
@@ -12,6 +12,26 @@ namespace Syroot.Worms.Gen2.Armageddon
///
public class Team : ILoadable, ISaveable
{
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const int _missionCount = 33;
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Team()
+ {
+ WormNames = new string[8];
+ MissionStatuses = new TeamMissionStatus[_missionCount];
+ TrainingMissionTimes = new int[6];
+ Unknown1 = new int[10];
+ TrainingMissionMedals = new byte[6];
+ Unknown2 = new byte[10];
+ Unknown3 = new int[7];
+ }
+
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
///
@@ -209,7 +229,7 @@ namespace Syroot.Worms.Gen2.Armageddon
DeathmatchKills = reader.ReadInt32();
Deaths = reader.ReadInt32();
DeathmatchDeaths = reader.ReadInt32();
- MissionStatuses = reader.ReadStructs(33);
+ MissionStatuses = reader.ReadStructs(_missionCount);
FlagFileName = reader.ReadFixedString(0x20);
Flag = new Bitmap()
diff --git a/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs b/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
index 4573300..2372899 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
@@ -9,7 +9,7 @@ namespace Syroot.Worms.Gen2.Armageddon
{
///
/// Represents the list of teams and unlocked game features stored in WGT files.
- /// Used by WA and WWP. S. https://worms2d.info/Team_file.
+ /// Used by WA. S. https://worms2d.info/Team_file.
///
public class TeamContainer : ILoadableFile, ISaveableFile
{
@@ -87,7 +87,7 @@ namespace Syroot.Worms.Gen2.Armageddon
// Read global settings.
byte teamCount = reader.ReadByte();
- UnlockedFeatures = reader.ReadEnum(true);
+ UnlockedFeatures = reader.ReadEnum(false);
Unknown = reader.ReadByte();
// Read the teams.
@@ -127,7 +127,7 @@ namespace Syroot.Worms.Gen2.Armageddon
// Write global settings.
writer.Write((byte)Teams.Count);
- writer.Write(UnlockedFeatures, true);
+ writer.Write(UnlockedFeatures, false);
writer.Write(Unknown);
// Write the teams.
@@ -223,13 +223,8 @@ namespace Syroot.Worms.Gen2.Armageddon
SheepHeaven = 1 << 18,
///
- /// Map terrain becomes indestructible. Has to be set together with .
+ /// Map terrain can be indestructible and Full Wormage scheme is accessible.
///
- IndestructibleMap1 = 1 << 24,
-
- ///
- /// Map terrain becomes indestructible. Has to be set together with .
- ///
- IndestructibleMap2 = 1 << 25
+ IndestructibleAndFullWormage = 1 << 24
}
}
diff --git a/src/Syroot.Worms/Gen2/WorldParty/Team.cs b/src/Syroot.Worms/Gen2/WorldParty/Team.cs
new file mode 100644
index 0000000..f5a377c
--- /dev/null
+++ b/src/Syroot.Worms/Gen2/WorldParty/Team.cs
@@ -0,0 +1,306 @@
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using Syroot.IO;
+using Syroot.Maths;
+using Syroot.Worms.Core;
+
+namespace Syroot.Worms.Gen2.WorldParty
+{
+ ///
+ /// Represents a team stored in a file.
+ ///
+ public class Team : ILoadable, ISaveable
+ {
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const int _missionCount = 45;
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public Team()
+ {
+ WormNames = new string[8];
+ MissionStatuses = new TeamMissionStatus[_missionCount];
+ TrainingMissionTimes = new int[6];
+ WeaponPoints = new byte[46];
+ Unknown2 = new int[7];
+ }
+
+ // ---- 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; }
+
+ public byte Unknown1 { 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 a possibly unused training mission time for a 35th mission.
+ ///
+ public int UnknownTrainingMissionTime { get; set; }
+
+ ///
+ /// Gets or sets the 46 weapons which were bought for points.
+ ///
+ public byte[] WeaponPoints { get; set; }
+
+ ///
+ /// Gets or sets the fort of the team.
+ ///
+ public byte Fort { get; set; }
+
+ ///
+ /// Gets or sets 7 unknown integer values.
+ ///
+ public int[] Unknown2 { 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(_missionCount);
+
+ FlagFileName = reader.ReadFixedString(0x20);
+ Flag = new Bitmap()
+ {
+ BitsPerPixel = 8,
+ Size = new Vector2(20, 17),
+ Palette = reader.ReadStructs(256),
+ Data = reader.ReadBytes(20 * 17)
+ };
+
+ Unknown1 = reader.ReadByte();
+ DeathmatchRank = reader.ReadByte();
+ TrainingMissionTimes = reader.ReadInt32s(34);
+ UnknownTrainingMissionTime = reader.ReadInt32(); // Possibly an unused time.
+ WeaponPoints = reader.ReadBytes(46);
+ Fort = reader.ReadByte();
+ Unknown2 = reader.ReadInt32s(7);
+ }
+ }
+
+ ///
+ /// 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(Unknown1);
+ writer.Write(DeathmatchRank);
+ writer.Write(TrainingMissionTimes);
+ writer.Write(UnknownTrainingMissionTime);
+ writer.Write(WeaponPoints);
+ writer.Write(Fort);
+ writer.Write(Unknown2);
+ }
+ }
+ }
+
+ [DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")]
+ public struct TeamMissionStatus
+ {
+ public int Attempts;
+ public int Medal;
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/WorldParty/TeamContainer.cs b/src/Syroot.Worms/Gen2/WorldParty/TeamContainer.cs
new file mode 100644
index 0000000..404968c
--- /dev/null
+++ b/src/Syroot.Worms/Gen2/WorldParty/TeamContainer.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Syroot.IO;
+using Syroot.Worms.Core;
+
+namespace Syroot.Worms.Gen2.WorldParty
+{
+ ///
+ /// Represents the list of teams and unlocked game features stored in WGT files.
+ /// Used by WWP. See https://worms2d.info/File_formats.
+ ///
+ public class TeamContainer : ILoadableFile, ISaveableFile
+ {
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const string _signature = "WWP"; // 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 an unknown value.
+ ///
+ public byte Unknown1 { get; set; }
+
+ ///
+ /// Gets or sets an unknown value.
+ ///
+ public byte Unknown2 { get; set; }
+
+ ///
+ /// Gets or sets 840 unknown bytes, all possibly 0.
+ ///
+ public byte[] Unknown3 { 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 WWP file signature.");
+ }
+ Version = reader.ReadByte(); // Really version?
+
+ // Read global settings.
+ byte teamCount = reader.ReadByte();
+ Unknown1 = reader.ReadByte();
+ Unknown2 = reader.ReadByte();
+ Unknown3 = reader.ReadBytes(840);
+
+ // 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(Unknown1);
+ writer.Write(Unknown2);
+ writer.Write(Unknown3);
+
+ // 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);
+ }
+ }
+ }
+}