From 21b48ad76b32f01562038dfe39629aec9f75bf04 Mon Sep 17 00:00:00 2001 From: Ray Koopa Date: Sun, 23 Apr 2017 16:40:40 +0200 Subject: [PATCH] Added support for ST1 team files. --- README.md | 2 +- .../Gen2/Worms2/TeamContainerTests.cs | 25 ++ .../Core/BinaryReaderExtensions.cs | 2 +- .../Core/BinaryWriterExtensions.cs | 2 +- src/Syroot.Worms/Gen2/Worms2/Team.cs | 142 +++++++++++ src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs | 221 +++++++++++++++++- 6 files changed, 389 insertions(+), 5 deletions(-) create mode 100644 src/Syroot.Worms.UnitTest/Gen2/Worms2/TeamContainerTests.cs create mode 100644 src/Syroot.Worms/Gen2/Worms2/Team.cs diff --git a/README.md b/README.md index a8a6e73..57dfd4c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ Formats of the second generation 2D games are mostly focused right now. | Scheme | WSC | WA, WWP | Yes | Yes | | Scheme Options | OPT | W2 | Yes | Yes | | Scheme Weapons | WEP | W2 | Yes | Yes | -| Team Container | ST1 | W2 | No | No | +| Team Container | ST1 | W2 | Yes | Yes | | Team Container | WGT | WA, WWP | No | No | ## Third Generation (3D) diff --git a/src/Syroot.Worms.UnitTest/Gen2/Worms2/TeamContainerTests.cs b/src/Syroot.Worms.UnitTest/Gen2/Worms2/TeamContainerTests.cs new file mode 100644 index 0000000..84e1289 --- /dev/null +++ b/src/Syroot.Worms.UnitTest/Gen2/Worms2/TeamContainerTests.cs @@ -0,0 +1,25 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Syroot.Worms.Gen2.Worms2; +using Syroot.Worms.UnitTest.Common; + +namespace Syroot.Worms.UnitTest.Gen2.Worms2 +{ + /// + /// Represents a collection of tests for the class. + /// + [TestCategory("TeamContainer (Worms2)")] + [TestClass] + public class TeamContainerTests + { + // ---- METHODS (PUBLIC) --------------------------------------------------------------------------------------- + + /// + /// Loads all files found in any game directories. + /// + [TestMethod] + public void LoadTeamContainers() + { + TestHelpers.LoadFiles(Game.Worms2, "*.st1"); + } + } +} diff --git a/src/Syroot.Worms/Core/BinaryReaderExtensions.cs b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs index 0aae743..db2135a 100644 --- a/src/Syroot.Worms/Core/BinaryReaderExtensions.cs +++ b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs @@ -1,6 +1,6 @@ -using System; using System.IO; using System.Runtime.InteropServices; +using Syroot.IO; namespace Syroot.Worms.Core { diff --git a/src/Syroot.Worms/Core/BinaryWriterExtensions.cs b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs index b60e203..7ee352d 100644 --- a/src/Syroot.Worms/Core/BinaryWriterExtensions.cs +++ b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs @@ -9,7 +9,7 @@ namespace Syroot.Worms.Core internal static class BinaryWriterExtensions { // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- - + /// /// Writes the bytes of a structure into the current stream. /// diff --git a/src/Syroot.Worms/Gen2/Worms2/Team.cs b/src/Syroot.Worms/Gen2/Worms2/Team.cs new file mode 100644 index 0000000..530ed82 --- /dev/null +++ b/src/Syroot.Worms/Gen2/Worms2/Team.cs @@ -0,0 +1,142 @@ +using System; + +namespace Syroot.Worms.Gen2.Worms2 +{ + /// + /// Represents a team stored in a file. + /// + public struct Team + { + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + 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; + + /// + /// The number of games lost. + /// + public int GamesLost; + + /// + /// The number of games won. + /// + public int GamesWon; + + /// + /// The number of opponent worms killed by this team. + /// + public int WormsKilled; + + /// + /// The number of worms which got killed in this team. + /// + public int WormsLost; + + /// + /// The AI intelligence, from 0-64, where 0 is human-controlled. + /// + public int CpuLevel; + + public int KillsKilled; + + /// + /// The number of games played, always being 0 for AI controlled teams. + /// + public int GamesPlayed; + + 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; + + /// + /// The number of hits goaled by this team. + /// + public int Hits; + + /// + /// The number of hits by others on this team. + /// + public int HitsByOthers; + + public int Unknown23; + public int Unknown24; + public int Unknown25; + public int Unknown26; + + public int Difference; + + public int Unknown27; + + /// + /// The points gained by this team. + /// + public int Points; + } +} diff --git a/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs b/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs index 34410df..9d76faa 100644 --- a/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs +++ b/src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs @@ -1,10 +1,227 @@ -using System; 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 { - class TeamContainer + /// + /// Represents the list of teams stored in ST1 files. + /// Used by W2. S. https://worms2d.info/Worms_2_team_file. + /// + public class TeamContainer : ILoadableFile, ISaveableFile { + // ---- CONSTANTS ---------------------------------------------------------------------------------------------- + + private static readonly char[] _trimChars = new char[] { (char)0x00 }; + + // ---- 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 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)) + { + 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), + GamesLost = reader.ReadInt32(), + GamesWon = reader.ReadInt32(), + WormsKilled = reader.ReadInt32(), + WormsLost = reader.ReadInt32(), + CpuLevel = reader.ReadInt32(), + KillsKilled = reader.ReadInt32(), + GamesPlayed = reader.ReadInt32(), + 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(), + Hits = reader.ReadInt32(), + HitsByOthers = reader.ReadInt32(), + Unknown23 = reader.ReadInt32(), + Unknown24 = reader.ReadInt32(), + Unknown25 = reader.ReadInt32(), + Unknown26 = reader.ReadInt32(), + Difference = reader.ReadInt32(), + Unknown27 = reader.ReadInt32(), + Points = reader.ReadInt32() + }); + } + } + } + + /// + /// 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)) + { + 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.GamesLost); + writer.Write(team.GamesWon); + writer.Write(team.WormsKilled); + writer.Write(team.WormsLost); + writer.Write(team.CpuLevel); + writer.Write(team.KillsKilled); + writer.Write(team.GamesPlayed); + 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.Hits); + writer.Write(team.HitsByOthers); + writer.Write(team.Unknown23); + writer.Write(team.Unknown24); + writer.Write(team.Unknown25); + writer.Write(team.Unknown26); + writer.Write(team.Difference); + writer.Write(team.Unknown27); + writer.Write(team.Points); + } + } + } + + /// + /// 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); + } + } + + // ---- 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]); + } } }