Added support for WGT team files (at least for WA).

This commit is contained in:
Ray Koopa 2017-04-25 17:28:29 +02:00
parent ec3e79f8e1
commit 364d6c53c6
13 changed files with 863 additions and 251 deletions

View File

@ -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.

6
src/NuGet.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="ImageSharp Nightly" value="https://www.myget.org/F/imagesharp/api/v3/index.json" />
</packageSources>
</configuration>

View File

@ -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();
}

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="TeamContainer"/> class.
/// </summary>
[TestCategory("TeamContainer (Armageddon)")]
[TestClass]
public class TeamContainerTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadTeamContainers()
{
TestHelpers.LoadFiles<TeamContainer>(Game.Armageddon, "*.wgt");
}
}
}

View File

@ -0,0 +1,32 @@
using Syroot.Maths;
namespace Syroot.Worms
{
/// <summary>
/// Represents a pixel-based 2D image in different color formats.
/// </summary>
public class Bitmap
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the number of bits required to describe a color per pixel.
/// </summary>
public int BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets the colors in the palette of the bitmap, if it has one.
/// </summary>
public Color[] Palette { get; set; }
/// <summary>
/// Gets or sets the size of the image in pixels.
/// </summary>
public Vector2 Size { get; set; }
/// <summary>
/// Gets or sets the data of the image pixels.
/// </summary>
public byte[] Data { get; set; }
}
}

View File

@ -11,6 +11,37 @@ namespace Syroot.Worms.Core
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Reads a 0-terminated string which is stored in a fixed-size block of <paramref name="length"/> bytes.
/// </summary>
/// <param name="self">The extended <see cref="BinaryDataReader"/>.</param>
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
/// <returns>The read string.</returns>
internal static string ReadFixedString(this BinaryDataReader self, int length)
{
string str = self.ReadString(BinaryStringFormat.ZeroTerminated);
self.Seek(length - str.Length - 1);
return str;
}
/// <summary>
/// Reads <paramref name="count"/> 0-terminated strings which are stored in a fixed-size block of
/// <paramref name="length"/> bytes.
/// </summary>
/// <param name="self">The extended <see cref="BinaryDataReader"/>.</param>
/// <param name="count">The number of values to read.</param>
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
/// <returns>The read string.</returns>
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;
}
/// <summary>
/// Reads a raw byte structure from the current stream and returns it.
/// </summary>
@ -29,5 +60,22 @@ namespace Syroot.Worms.Core
return instance;
}
/// <summary>
/// Reads raw byte structures from the current stream and returns them.
/// </summary>
/// <typeparam name="T">The type of the structure to read.</typeparam>
/// <param name="self">The extended <see cref="BinaryReader"/> instance.</param>
/// <param name="count">The number of values to read.</param>
/// <returns>The structures of type <typeparamref name="T"/>.</returns>
internal static T[] ReadStructs<T>(this BinaryReader self, int count) where T : struct
{
T[] values = new T[count];
for (int i = 0; i < count; i++)
{
values[i] = ReadStruct<T>(self);
}
return values;
}
}
}

View File

@ -1,5 +1,6 @@
using System.IO;
using System.Runtime.InteropServices;
using Syroot.IO;
namespace Syroot.Worms.Core
{
@ -10,23 +11,64 @@ namespace Syroot.Worms.Core
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Writes the given string into a fixed-size block of <paramref name="length"/> bytes and 0-terminates it.
/// </summary>
/// <param name="self">The extended <see cref="BinaryDataWriter"/> instance.</param>
/// <param name="value">The string to write.</param>
/// <param name="length">The number of bytes the fixed-size block takes.</param>
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]);
}
/// <summary>
/// Writes the given strings into fixed-size blocks of <paramref name="length"/> bytes and 0-terminates them.
/// </summary>
/// <param name="self">The extended <see cref="BinaryDataWriter"/> instance.</param>
/// <param name="values">The strings to write.</param>
/// <param name="length">The number of bytes a fixed-size block takes.</param>
internal static void Write(this BinaryDataWriter self, string[] values, int length)
{
foreach (string value in values)
{
Write(self, value, length);
}
}
/// <summary>
/// Writes the bytes of a structure into the current stream.
/// </summary>
/// <typeparam name="T">The type of the structure to read.</typeparam>
/// <param name="self">The extended <see cref="BinaryWriter"/> instance.</param>
/// <param name="instance">The structure to write.</param>
internal static void Write<T>(this BinaryWriter self, T instance) where T : struct
/// <param name="value">The structure to write.</param>
internal static void Write<T>(this BinaryWriter self, T value) where T : struct
{
// Get the raw bytes of the structure instance.
byte[] bytes = new byte[Marshal.SizeOf<T>()];
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);
}
/// <summary>
/// Writes the bytes of structures into the current stream.
/// </summary>
/// <typeparam name="T">The type of the structure to read.</typeparam>
/// <param name="self">The extended <see cref="BinaryWriter"/> instance.</param>
/// <param name="values">The structures to write.</param>
internal static void Write<T>(this BinaryWriter self, T[] values) where T : struct
{
foreach (T value in values)
{
Write(self, value);
}
}
}
}

View File

@ -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
{
/// <summary>
/// Represents a team stored in a <see cref="TeamContainer"/> file.
/// </summary>
public class Team : ILoadable, ISaveable
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the name of the team.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the 8 worm names.
/// </summary>
public string[] WormNames { get; set; }
/// <summary>
/// Gets or sets the AI intelligence difficulty level, from 0-5, where 0 is human-controlled.
/// </summary>
public byte CpuLevel { get; set; }
/// <summary>
/// Gets or sets the name of soundbank for the voice of team worms.
/// </summary>
public string SoundBankName { get; set; }
public byte SoundBankLocation { get; set; }
/// <summary>
/// Gets or sets the name of the team fanfare.
/// </summary>
public string FanfareName { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the fanfare with the name stored in <see cref="FanfareName"/>
/// (<c>true</c>) or the player's countries' fanfare should be played (<c>false</c>).
/// </summary>
public byte UseCustomFanfare { get; set; }
/// <summary>
/// Gets or sets the sprite index of the team grave, -1 being a custom bitmap grave.
/// </summary>
public sbyte GraveSprite { get; set; }
/// <summary>
/// Gets or sets the file name of the team grave bitmap if it uses a custom one.
/// </summary>
public string GraveFileName { get; set; }
/// <summary>
/// Gets or sets the team grave bitmap if it uses a custom one.
/// </summary>
public Bitmap Grave { get; set; }
/// <summary>
/// Gets or sets the team's special weapon.
/// </summary>
public byte TeamWeapon { get; set; }
/// <summary>
/// Gets or sets the number of games lost.
/// </summary>
public int GamesLost { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games lost.
/// </summary>
public int DeathmatchesLost { get; set; }
/// <summary>
/// Gets or sets the number of games won.
/// </summary>
public int GamesWon { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games won.
/// </summary>
public int DeathmatchesWon { get; set; }
/// <summary>
/// Gets or sets the number of games drawn.
/// </summary>
public int GamesDrawn { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games drawn.
/// </summary>
public int DeathmatchesDrawn { get; set; }
/// <summary>
/// Gets or sets the number of opponent worms killed by this team.
/// </summary>
public int Kills { get; set; }
/// <summary>
/// Gets or sets the number of opponent worms killed by this team in deathmatches.
/// </summary>
public int DeathmatchKills { get; set; }
/// <summary>
/// Gets or sets the number of worms which got killed in this team.
/// </summary>
public int Deaths { get; set; }
/// <summary>
/// Gets or sets the number of worms which got killed in this team in deathmatches.
/// </summary>
public int DeathmatchDeaths { get; set; }
/// <summary>
/// Gets or sets the array of 33 mission statuses.
/// </summary>
public TeamMissionStatus[] MissionStatuses { get; set; }
/// <summary>
/// Gets or sets the file name of the team flag.
/// </summary>
public string FlagFileName { get; set; }
/// <summary>
/// Gets or sets the bitmap of the team flag.
/// </summary>
public Bitmap Flag { get; set; }
/// <summary>
/// Gets or sets the deathmatch rank this team reached.
/// </summary>
public byte DeathmatchRank { get; set; }
/// <summary>
/// Gets or sets the seconds the team required to finish all 6 training missions.
/// </summary>
public int[] TrainingMissionTimes { get; set; }
/// <summary>
/// Gets or sets 10 unknown integer values.
/// </summary>
public int[] Unknown1 { get; set; }
/// <summary>
/// Gets or sets the medals the team achieved in all 6 training missions.
/// </summary>
public byte[] TrainingMissionMedals { get; set; }
/// <summary>
/// Gets or sets 10 unknown bytes.
/// </summary>
public byte[] Unknown2 { get; set; }
/// <summary>
/// Gets or sets 7 unknown integer values.
/// </summary>
public int[] Unknown3 { get; set; }
/// <summary>
/// Gets or sets an unknown byte.
/// </summary>
public byte Unknown4 { 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))
{
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<Color>(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<TeamMissionStatus>(33);
FlagFileName = reader.ReadFixedString(0x20);
Flag = new Bitmap()
{
BitsPerPixel = 8,
Size = new Vector2(20, 17),
Palette = reader.ReadStructs<Color>(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();
}
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
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;
}
}

View File

@ -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
/// <summary>
/// Represents the list of teams and unlocked game features stored in WGT files.
/// Used by WA and WWP. S. https://worms2d.info/Team_file.
/// </summary>
public class TeamContainer : ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const string _signature = "WGT"; // 0-terminated.
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> class.
/// </summary>
public TeamContainer()
{
Teams = new List<Team>();
}
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> 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 TeamContainer(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public TeamContainer(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets a value possibly indicating a version of the file format.
/// </summary>
public byte Version { get; set; }
/// <summary>
/// Gets or sets the unlocked utilities, weapon upgrades, and game cheats.
/// </summary>
public UnlockedFeatures UnlockedFeatures { get; set; }
/// <summary>
/// Gets or sets an unknown value.
/// </summary>
public byte Unknown { get; set; }
/// <summary>
/// Gets or sets the list of <see cref="Team"/> instances stored.
/// </summary>
public List<Team> Teams { 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.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<UnlockedFeatures>(true);
Unknown = reader.ReadByte();
// Read the teams.
Teams = new List<Team>(teamCount);
for (int i = 0; i < teamCount; i++)
{
Team team = new Team();
team.Load(reader.BaseStream);
Teams.Add(team);
}
}
}
/// <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);
}
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
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);
}
}
}
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
}
/// <summary>
/// Represents unlockable features of the game.
/// </summary>
[Flags]
public enum UnlockedFeatures : int
{
/// <summary>
/// The utility weapon Laser Sight can be configured.
/// </summary>
UtilityLaserSight = 1 << 0,
/// <summary>
/// The utility weapon Fast Walk can be configured.
/// </summary>
UtilityFastWalk = 1 << 1,
/// <summary>
/// The utility weapon Invisibility can be configured.
/// </summary>
UtilityInvisibility = 1 << 2,
/// <summary>
/// The utility weapon Low Gravity can be configured.
/// </summary>
UtilityLowGravity = 1 << 3,
/// <summary>
/// The utility weapon Jetpack can be configured.
/// </summary>
UtilityJetpack = 1 << 4,
/// <summary>
/// The Grenade upgrade can be enabled.
/// </summary>
UpgradedGrenade = 1 << 8,
/// <summary>
/// The Shotgun upgrade can be enabled.
/// </summary>
UpgradedShotgun = 1 << 9,
/// <summary>
/// The cluster upgrade can be enabled.
/// </summary>
UpgradedClusters = 1 << 10,
/// <summary>
/// The Longbow upgrade can be enabled.
/// </summary>
UpgradedLongbow = 1 << 11,
/// <summary>
/// The upgrade of Super Sheeps to become Aqua Sheeps can be enabled.
/// </summary>
AquaSheep = 1 << 12,
/// <summary>
/// Worms can have infinite health and are killable only by drowning them.
/// </summary>
GodWorms = 1 << 16,
/// <summary>
/// Blood effects when hitting worms can be enabled.
/// </summary>
BloodFx = 1 << 17,
/// <summary>
/// Every crate explodes with a sheep.
/// </summary>
SheepHeaven = 1 << 18,
/// <summary>
/// Map terrain becomes indestructible. Has to be set together with <see cref="IndestructibleMap2"/>.
/// </summary>
IndestructibleMap1 = 1 << 24,
/// <summary>
/// Map terrain becomes indestructible. Has to be set together with <see cref="IndestructibleMap1"/>.
/// </summary>
IndestructibleMap2 = 1 << 25
}
}

View File

@ -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.
/// </summary>
public class Image : ILoadableFile
public class Image : Bitmap, ILoadableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
@ -52,26 +52,6 @@ namespace Syroot.Worms.Gen2
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets the number of bits required to describe a color per pixel.
/// </summary>
public int BitsPerPixel { get; private set; }
/// <summary>
/// Gets the color palette of the image. The first color must always be black.
/// </summary>
public Color[] Palette { get; private set; }
/// <summary>
/// Gets the size of the image in pixels.
/// </summary>
public Vector2 Size { get; private set; }
/// <summary>
/// Gets the data of the image pixels.
/// </summary>
public byte[] Data { get; private set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>

View File

@ -1,136 +1,213 @@
using System;
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents a team stored in a <see cref="TeamContainer"/> file.
/// </summary>
public struct Team
public class Team : ILoadable, ISaveable
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public short Unknown1;
public short Unknown1 { get; set; }
/// <summary>
/// The name of the team.
/// Gets or sets the name of the team.
/// </summary>
public string Name;
public string Name { get; set; }
/// <summary>
/// The name of soundbank for the voice of team worms.
/// Gets or sets the name of soundbank for the voice of team worms.
/// </summary>
public string SoundBankName;
public string SoundBankName { get; set; }
/// <summary>
/// The name of the first worm.
/// Gets or sets the 8 worm names.
/// </summary>
public string Worm1Name;
public string[] WormNames { get; set; }
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; }
/// <summary>
/// The name of the second worm.
/// Gets or sets the number of games lost.
/// </summary>
public string Worm2Name;
public int GamesLost { get; set; }
/// <summary>
/// The name of the third worm.
/// Gets or sets the number of games won.
/// </summary>
public string Worm3Name;
public int GamesWon { get; set; }
public int Unknown26 { get; set; }
public int Unknown27 { get; set; }
/// <summary>
/// The name the fourth worm.
/// Gets or sets the number of opponent worms killed by this team.
/// </summary>
public string Worm4Name;
public int Kills { get; set; }
/// <summary>
/// The name the fifth worm.
/// Gets or sets the number of worms which got killed in this team.
/// </summary>
public string Worm5Name;
public int Deaths { get; set; }
/// <summary>
/// The name the second worm.
/// Gets or sets the AI intelligence difficulty level, from 0-100, where 0 is human-controlled.
/// </summary>
public string Worm6Name;
public int CpuLevel { get; set; }
public int Unknown28 { get; set; }
public int Unknown29 { get; set; }
public int Unknown30 { get; set; }
/// <summary>
/// The name the seventh worm.
/// Gets or sets the "difference" statistics value.
/// </summary>
public string Worm7Name;
public int Difference { get; set; }
/// <summary>
/// The name the eighth worm.
/// Gets or sets the number of games played, always being 0 for AI controlled teams.
/// </summary>
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 GamesPlayed { get; set; }
/// <summary>
/// The number of games lost.
/// Gets or sets the points gained by this team.
/// </summary>
public int GamesLost;
public int Points { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// The number of games won.
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
public int GamesWon;
public int Unknown26;
public int Unknown27;
/// <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))
{
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();
}
}
/// <summary>
/// The number of opponent worms killed by this team.
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
public int WormsKilled;
/// <summary>
/// The number of worms which got killed in this team.
/// </summary>
public int WormsLost;
/// <summary>
/// The AI intelligence difficulty level, from 0-100, where 0 is human-controlled.
/// </summary>
public int CpuLevel;
public int Unknown28;
public int Unknown29;
public int Unknown30;
/// <summary>
/// The "difference" statistics value.
/// </summary>
public int Difference;
/// <summary>
/// The number of games played, always being 0 for AI controlled teams.
/// </summary>
public int GamesPlayed;
/// <summary>
/// The points gained by this team.
/// </summary>
public int Points;
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
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);
}
}
}
}

View File

@ -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
/// </summary>
public class TeamContainer : ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private static readonly char[] _trimChars = new char[] { (char)0x00 };
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
@ -67,57 +61,9 @@ namespace Syroot.Worms.Gen2.Worms2
Teams = new List<Team>();
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]);
}
}
}

View File

@ -21,6 +21,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ImageSharp" Version="1.0.0-alpha7-00006" />
<PackageReference Include="Syroot.IO.BinaryData" Version="1.2.2" />
<PackageReference Include="Syroot.Maths" Version="1.3.1" />
</ItemGroup>