diff --git a/README.md b/README.md
index 7ed6da7..3b052b5 100644
--- a/README.md
+++ b/README.md
@@ -32,7 +32,7 @@ Formats of the second generation 2D games are mostly focused right now.
| Replay | WAGAME | WA | No | No |
| Scheme | WSC | WA, WWP | Yes | Yes |
| Scheme Options | OPT | W2 | Yes | Yes |
-| Scheme Weapons | WEP | W2 | No | No |
+| Scheme Weapons | WEP | W2 | Yes | Yes |
| Team Container | ST1 | W2 | No | No |
| Team Container | WGT | WA, WWP | No | No |
diff --git a/src/Syroot.Worms.Test/Program.cs b/src/Syroot.Worms.Test/Program.cs
index 742710e..c4a4809 100644
--- a/src/Syroot.Worms.Test/Program.cs
+++ b/src/Syroot.Worms.Test/Program.cs
@@ -2,7 +2,6 @@ using System;
using System.IO;
using System.Collections.Generic;
using Syroot.Worms.Gen2.Armageddon;
-using Syroot.Worms.Core;
namespace Syroot.Worms.Test
{
@@ -34,9 +33,11 @@ namespace Syroot.Worms.Test
// Console.WriteLine("Loading {imgFile}...");
// Image image = new Image(imgFile);
//}
- Scheme scheme = new Scheme(@"D:\Pictures\Test.wsc");
+ Scheme scheme = new Scheme(@"D:\Archive\Games\Worms\Worms Armageddon\Common\User\Schemes\{{13}} The Full Wormage.wsc");
scheme.Save(@"D:\Pictures\Test2.wsc");
+ scheme.Load(@"D:\Pictures\Test2.wsc");
+ Console.WriteLine("Done.");
Console.ReadLine();
}
diff --git a/src/Syroot.Worms/Core/BinaryReaderExtensions.cs b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs
new file mode 100644
index 0000000..0aae743
--- /dev/null
+++ b/src/Syroot.Worms/Core/BinaryReaderExtensions.cs
@@ -0,0 +1,33 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Syroot.Worms.Core
+{
+ ///
+ /// Represents extension methods for instances.
+ ///
+ internal static class BinaryReaderExtensions
+ {
+ // ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
+
+ ///
+ /// Reads a raw byte structure from the current stream and returns it.
+ ///
+ /// The type of the structure to read.
+ /// The extended instance.
+ /// The structure of type .
+ internal static T ReadStruct(this BinaryReader self) where T : struct
+ {
+ // Read the raw bytes of the structure.
+ byte[] bytes = self.ReadBytes(Marshal.SizeOf());
+
+ // Convert them to a structure instance and return it.
+ GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
+ T instance = Marshal.PtrToStructure(handle.AddrOfPinnedObject());
+ handle.Free();
+
+ return instance;
+ }
+ }
+}
diff --git a/src/Syroot.Worms/Core/BinaryWriterExtensions.cs b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs
new file mode 100644
index 0000000..b60e203
--- /dev/null
+++ b/src/Syroot.Worms/Core/BinaryWriterExtensions.cs
@@ -0,0 +1,32 @@
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace Syroot.Worms.Core
+{
+ ///
+ /// Represents extension methods for instances.
+ ///
+ internal static class BinaryWriterExtensions
+ {
+ // ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
+
+ ///
+ /// 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
+ {
+ // 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);
+ handle.Free();
+
+ // Write the bytes to the stream.
+ self.Write(bytes);
+ }
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs b/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs
index 6c266ec..6f298ed 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs
@@ -355,9 +355,9 @@ namespace Syroot.Worms.Gen2.Armageddon
public bool EnableSuperWeapons { get; set; }
///
- /// Gets the array of instances, each mapping to one weapon at the index of the
- /// enumeration. Depending on the scheme , super weapons might not
- /// be stored in this array.
+ /// Gets the array of instances, each mapping to one weapon at the index of
+ /// the enumeration. Depending on the scheme , super weapons
+ /// might not be stored in this array.
///
public SchemeWeaponSetting[] Weapons { get; set; }
@@ -651,10 +651,7 @@ namespace Syroot.Worms.Gen2.Armageddon
int weaponCount = GetWeaponCount();
for (int i = 0; i < weaponCount; i++)
{
- Weapons[i].Ammunition = reader.ReadSByte();
- Weapons[i].Power = reader.ReadByte();
- Weapons[i].Delay = reader.ReadSByte();
- Weapons[i].Probability = reader.ReadSByte();
+ Weapons[i] = reader.ReadStruct();
}
// Ignore possible unknown WWP trash at the end of the file.
@@ -741,12 +738,9 @@ namespace Syroot.Worms.Gen2.Armageddon
// Write the weapon settings. Old versions do not store super weapon settings.
int weaponCount = GetWeaponCount();
- for (int i = 0; i < weaponCount; i++)
+ foreach (SchemeWeaponSetting weapon in Weapons)
{
- writer.Write(Weapons[i].Ammunition);
- writer.Write(Weapons[i].Power);
- writer.Write(Weapons[i].Delay);
- writer.Write(Weapons[i].Probability);
+ writer.Write(weapon);
}
// Ignore possible unknown WWP trash at the end of the file.
diff --git a/src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs b/src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs
index 2b24343..77fc147 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs
@@ -1362,9 +1362,9 @@ namespace Syroot.Worms.Gen2.Armageddon
Longbow,
///
- /// The Airstrike weapon.
+ /// The Air Strike weapon.
///
- Airstrike,
+ AirStrike,
///
/// The Napalm Strike weapon.
@@ -1402,9 +1402,9 @@ namespace Syroot.Worms.Gen2.Armageddon
BattleAxe,
///
- /// The Blowtorch weapon.
+ /// The Blow Torch weapon.
///
- Blowtorch,
+ BlowTorch,
///
/// The Pneumatic Drill weapon.
diff --git a/src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs b/src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs
index 9712127..f758810 100644
--- a/src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs
+++ b/src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs
@@ -1,4 +1,5 @@
using System.Diagnostics;
+using System.Runtime.InteropServices;
namespace Syroot.Worms.Gen2.Armageddon
{
@@ -6,6 +7,7 @@ namespace Syroot.Worms.Gen2.Armageddon
/// Represents the configuration of a weapon.
///
[DebuggerDisplay("Ammo={Ammunition} Power={Power} Delay={Delay} Prob={Probability}")]
+ [StructLayout(LayoutKind.Sequential)]
public struct SchemeWeaponSetting
{
///
@@ -21,7 +23,7 @@ namespace Syroot.Worms.Gen2.Armageddon
///
/// The number of turns required to be taken by each team before this weapon becomes available. Negative values
- /// represenet infinity.
+ /// represent infinity.
///
public sbyte Delay;
diff --git a/src/Syroot.Worms/Gen2/Worms2/SchemeEnums.cs b/src/Syroot.Worms/Gen2/Worms2/SchemeEnums.cs
new file mode 100644
index 0000000..78e3e30
--- /dev/null
+++ b/src/Syroot.Worms/Gen2/Worms2/SchemeEnums.cs
@@ -0,0 +1,225 @@
+namespace Syroot.Worms.Gen2.Worms2
+{
+ ///
+ /// Represents the method to determine the next turn's worm.
+ ///
+ public enum SchemeWormSelect : int
+ {
+ ///
+ /// Worms are selected in the order in which they appear in the team.
+ ///
+ Sequential = 0,
+
+ ///
+ /// Worms are selected randomly.
+ ///
+ Random = 1,
+
+ ///
+ /// Worms are selected by a computed rating system.
+ ///
+ Intelligent = 2,
+
+ ///
+ /// Worms are selected by the player.
+ ///
+ Manual = 3
+ }
+
+
+ ///
+ /// Represents the weapons in the game.
+ ///
+ public enum SchemeWeapon
+ {
+ ///
+ /// The Bazooka weapon.
+ ///
+ Bazooka,
+
+ ///
+ /// The Homing Missile weapon.
+ ///
+ HomingMissile,
+
+ ///
+ /// The Grenade weapon.
+ ///
+ Grenade,
+
+ ///
+ /// The Cluster Bomb weapon.
+ ///
+ ClusterBomb,
+
+ ///
+ /// The Banana Bomb weapon.
+ ///
+ BananaBomb,
+
+ ///
+ /// The Holy Hand Grenade weapon.
+ ///
+ HolyHandGrenade,
+
+ ///
+ /// The Homing Cluster Bomb weapon.
+ ///
+ HomingClusterBomb,
+
+ ///
+ /// The Petrol Bomb weapon.
+ ///
+ PetrolBomb,
+
+ ///
+ /// The Shotgun weapon.
+ ///
+ Shotgun,
+
+ ///
+ /// The Handgun weapon.
+ ///
+ Handgun,
+
+ ///
+ /// The Uzi weapon.
+ ///
+ Uzi,
+
+ ///
+ /// The Minigun weapon.
+ ///
+ Minigun,
+
+ ///
+ /// The Fire Punch weapon.
+ ///
+ FirePunch,
+
+ ///
+ /// The Dragon Ball weapon.
+ ///
+ DragonBall,
+
+ ///
+ /// The Kamikaze weapon.
+ ///
+ Kamikaze,
+
+ ///
+ /// The Dynamite weapon.
+ ///
+ Dynamite,
+
+ ///
+ /// The Mine weapon.
+ ///
+ Mine,
+
+ ///
+ /// The Ming Vase weapon.
+ ///
+ MingVase,
+
+ ///
+ /// The Air Strike weapon.
+ ///
+ AirStrike,
+
+ ///
+ /// The Homing Air Strike weapon.
+ ///
+ HomingAirStrike,
+
+ ///
+ /// The Napalm Strike weapon.
+ ///
+ NapalmStrike,
+
+ ///
+ /// The Mail Strike weapon.
+ ///
+ MailStrike,
+
+ ///
+ /// The Girder weapon.
+ ///
+ Girder,
+
+ ///
+ /// The Pneumatic Drill weapon.
+ ///
+ PneumaticDrill,
+
+ ///
+ /// The Baseball Bat weapon.
+ ///
+ BaseballBat,
+
+ ///
+ /// The Prod weapon.
+ ///
+ Prod,
+
+ ///
+ /// The Teleport weapon.
+ ///
+ Teleport,
+
+ ///
+ /// The Ninja Rope weapon.
+ ///
+ NinjaRope,
+
+ ///
+ /// The Bungee weapon.
+ ///
+ Bungee,
+
+ ///
+ /// The Parachute weapon.
+ ///
+ Parachute,
+
+ ///
+ /// The Sheep weapon.
+ ///
+ Sheep,
+
+ ///
+ /// The Mad Cow weapon.
+ ///
+ MadCow,
+
+ ///
+ /// The Old Woman weapon.
+ ///
+ OldWoman,
+
+ ///
+ /// The Mortar weapon.
+ ///
+ Mortar,
+
+ ///
+ /// The Blow Torch weapon.
+ ///
+ BlowTorch,
+
+ ///
+ /// The Homing Pigeon weapon.
+ ///
+ HomingPigeon,
+
+ ///
+ /// The Super Sheep weapon.
+ ///
+ SuperSheep,
+
+ ///
+ /// The Super Banana Bomb weapon.
+ ///
+ SuperBananaBomb
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/Worms2/SchemeOptions.cs b/src/Syroot.Worms/Gen2/Worms2/SchemeOptions.cs
index 8d288f8..3ee266d 100644
--- a/src/Syroot.Worms/Gen2/Worms2/SchemeOptions.cs
+++ b/src/Syroot.Worms/Gen2/Worms2/SchemeOptions.cs
@@ -30,7 +30,7 @@ namespace Syroot.Worms.Gen2.Worms2
}
///
- /// Initializes a new instance of the class, loading the data from the given file.
+ /// 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 SchemeOptions(string fileName)
@@ -335,30 +335,4 @@ namespace Syroot.Worms.Gen2.Worms2
}
}
}
-
- ///
- /// Represents the method to determine the next turn's worm.
- ///
- public enum SchemeWormSelect : int
- {
- ///
- /// Worms are selected in the order in which they appear in the team.
- ///
- Sequential = 0,
-
- ///
- /// Worms are selected randomly.
- ///
- Random = 1,
-
- ///
- /// Worms are selected by a computed rating system.
- ///
- Intelligent = 2,
-
- ///
- /// Worms are selected by the player.
- ///
- Manual = 3
- }
}
diff --git a/src/Syroot.Worms/Gen2/Worms2/SchemeWeaponSetting.cs b/src/Syroot.Worms/Gen2/Worms2/SchemeWeaponSetting.cs
new file mode 100644
index 0000000..9da1c7f
--- /dev/null
+++ b/src/Syroot.Worms/Gen2/Worms2/SchemeWeaponSetting.cs
@@ -0,0 +1,182 @@
+using System.Runtime.InteropServices;
+
+namespace Syroot.Worms.Gen2.Worms2
+{
+ ///
+ /// Represents the configuration of a weapon.
+ ///
+ [StructLayout(LayoutKind.Sequential)]
+ public struct SchemeWeaponSetting
+ {
+ ///
+ /// The amount of this weapon with which a team is equipped at game start. 10 and negative values represent
+ /// infinity.
+ ///
+ public int Ammunition;
+
+ ///
+ /// The number of turns required to be taken by each team before this weapon becomes available.
+ ///
+ public int Delay;
+
+ ///
+ /// Retreat time after using this weapon. 0 uses the setting from the game options.
+ ///
+ public int RetreatTime;
+
+ ///
+ /// true to preselect this weapon in the next turn; otherwise false.
+ ///
+ public bool Remember;
+
+ ///
+ /// An unused field with unknown value.
+ ///
+ public int Unused1;
+
+ ///
+ /// The amount of this weapon added to the team armory when collected from a crate.
+ ///
+ public int CrateAmmunition;
+
+ ///
+ /// The amount of bullets shot at once.
+ ///
+ public int BulletCount;
+
+ ///
+ /// The percentual chance of this weapon to appear in crates.
+ ///
+ public int Probability;
+
+ ///
+ /// The damage measured in health points which also determines the blast radius.
+ ///
+ public int Damage;
+
+ ///
+ /// The pushing power measured in percent.
+ ///
+ public int BlastPower;
+
+ ///
+ /// The offset to the bottom of an explosion, measured in percent.
+ ///
+ public int BlastBias;
+
+ ///
+ /// The milliseconds required before this weapon starts flying towards its target.
+ ///
+ public int HomingDelay;
+
+ ///
+ /// The length in milliseconds this weapon flies towards its target before giving up.
+ ///
+ public int HomingTime;
+
+ ///
+ /// The percentual amount this weaopn is affected by wind.
+ ///
+ public int WindResponse;
+
+ ///
+ /// An unused field with unknown value.
+ ///
+ public int Unused2;
+
+ ///
+ /// The number of clusters into which this weapon explodes.
+ ///
+ public int ClusterCount;
+
+ ///
+ /// The speed in which clusters are dispersed in percent.
+ ///
+ public int ClusterLaunchPower;
+
+ ///
+ /// The angle in which clusters are dispersed in degrees.
+ ///
+ public int ClusterLaunchAngle;
+
+ ///
+ /// The damage of clusters measured in health points which also determines the blast radius.
+ ///
+ public int ClusterDamage;
+
+ ///
+ /// Overrides the fuse of this weapon, 0 for default.
+ ///
+ public int Fuse;
+
+ ///
+ /// The amount of fire created.
+ ///
+ public int FireAmount;
+
+ ///
+ /// The speed in which fire spreads, measured in percent.
+ ///
+ public int FireSpreadSpeed;
+
+ ///
+ /// The period in which fire burns, measured in percent.
+ ///
+ public int FireTime;
+
+ ///
+ /// The melee impact force in percent.
+ ///
+ public int MeleeForce;
+
+ ///
+ /// The melee impact angle in degrees.
+ ///
+ public int MeleeAngle;
+
+ ///
+ /// The melee damage in health points.
+ ///
+ public int MeleeDamage;
+
+ ///
+ /// The height of the fire punch jump, measured in percent.
+ ///
+ public int FirePunchHeight;
+
+ ///
+ /// The damage a dragon ball causes, measured in health points.
+ ///
+ public int DragonBallDamage;
+
+ ///
+ /// The power in which a dragon ball launches hit worms, measured in percent.
+ ///
+ public int DragonBallPower;
+
+ ///
+ /// The angle in which a dragon ball launches hit worms, measured in degrees.
+ ///
+ public int DragonBallAngle;
+
+ ///
+ /// The life time of a launched dragon ball measured in milliseconds.
+ ///
+ public int DragonBallTime;
+
+ ///
+ /// The length of digging measured in milliseconds. Applies to Kamikaze and digging tools.
+ ///
+ public int DiggingTime;
+
+ ///
+ /// The amount of airstrike clusters thrown.
+ ///
+ public int StrikeClusterCount;
+
+ ///
+ /// The angle in which bullets are dispersed, measured in degrees.
+ ///
+ public int BulletSpreadAngle;
+ }
+}
diff --git a/src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs b/src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs
index 9ed2258..aa4fed5 100644
--- a/src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs
+++ b/src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs
@@ -1,10 +1,122 @@
-using System;
+using System;
using System.Collections.Generic;
+using System.IO;
+using System.Runtime.InteropServices;
using System.Text;
+using Syroot.IO;
+using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
- class WeaponsScheme
+ ///
+ /// Represents scheme weapons stored in an WEP file which contains armory configuration.
+ /// S. https://worms2d.info/Weapons_file.
+ ///
+ public class SchemeWeapons : ILoadableFile, ISaveableFile
{
+ // ---- CONSTANTS ----------------------------------------------------------------------------------------------
+
+ private const int _trashLength = 16;
+ private const string _signature = "WEPFILE"; // Zero-terminated.
+ private const int _weaponCount = 38;
+
+ // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
+
+ ///
+ /// Initializes a new instance of the class, loading the data from the given
+ /// .
+ ///
+ /// The to load the data from.
+ public SchemeWeapons(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 SchemeWeapons(string fileName)
+ {
+ Load(fileName);
+ }
+
+ // ---- PROPERTIES ---------------------------------------------------------------------------------------------
+
+ ///
+ /// Gets the array of instances, each mapping to one weapon at the index of
+ /// the enumeration.
+ ///
+ public SchemeWeaponSetting[] Weapons { 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))
+ {
+ // Read the header.
+ reader.Seek(_trashLength);
+ if (reader.ReadString(BinaryStringFormat.ZeroTerminated) != _signature)
+ {
+ throw new InvalidDataException("Invalid WEP file signature.");
+ }
+
+ // Read the weapon settings.
+ Weapons = new SchemeWeaponSetting[_weaponCount];
+ for (int i = 0; i < _weaponCount; i++)
+ {
+ Weapons[i] = reader.ReadStruct();
+ }
+ }
+ }
+
+ ///
+ /// 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 with the specified .
+ ///
+ /// The to save the data to.
+ public void Save(Stream stream)
+ {
+ using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII))
+ {
+ // Write the header.
+ writer.Write(new byte[_trashLength]);
+ writer.Write(_signature, BinaryStringFormat.ZeroTerminated);
+
+ // Write the weapon settings.
+ foreach (SchemeWeaponSetting weapon in Weapons)
+ {
+ writer.Write(weapon);
+ }
+ }
+ }
+
+ ///
+ /// 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);
+ }
+ }
}
}
diff --git a/src/Syroot.Worms/Syroot.Worms.csproj b/src/Syroot.Worms/Syroot.Worms.csproj
index 90a2080..f2ea078 100644
--- a/src/Syroot.Worms/Syroot.Worms.csproj
+++ b/src/Syroot.Worms/Syroot.Worms.csproj
@@ -17,7 +17,7 @@
git
https://github.com/Syroot/Worms
- net45;netstandard1.6
+ net46;netstandard1.6