diff --git a/README.md b/README.md index 4a4145e..870540f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ Formats of the second generation 2D games are mostly focused right now. | Description | Extension | Games | Load | Save | |-------------------|:---------:|:-----------:|:----:|:----:| | Archive | DIR | W2, WA, WWP | Yes | Yes | -| Game Scheme | WSC | WA, WWP | No | No | | Image | IMG | W2, WA, WWP | Yes | No | | Mission | DAT | W2 | No | No | | Mission | WAM | WA, WWP | No | No | @@ -32,6 +31,7 @@ Formats of the second generation 2D games are mostly focused right now. | Project X Library | PXL | WA+PX | No | No | | Project X Scheme | PXS | WA+PX | No | No | | Replay | WAGAME | WA | No | No | +| Scheme | WSC | WA, WWP | Yes | Yes | | Team Container | ST1 | W2 | No | No | | Team Container | WGT | WA, WWP | No | No | | Weapon Scheme | WEP | W2 | No | No | diff --git a/src/Syroot.Worms.Test/Program.cs b/src/Syroot.Worms.Test/Program.cs index 2e7f6d7..742710e 100644 --- a/src/Syroot.Worms.Test/Program.cs +++ b/src/Syroot.Worms.Test/Program.cs @@ -1,7 +1,8 @@ using System; using System.IO; -using Syroot.Worms.Gen2; using System.Collections.Generic; +using Syroot.Worms.Gen2.Armageddon; +using Syroot.Worms.Core; namespace Syroot.Worms.Test { @@ -33,16 +34,8 @@ namespace Syroot.Worms.Test // Console.WriteLine("Loading {imgFile}..."); // Image image = new Image(imgFile); //} - - Palette pal = new Palette(@"C:\Games\Worms Armageddon 3.7.2.1\graphics\ServerLobby\flagsandwormnet.pal"); - pal.Save(@"D:\Pictures\test.pal"); - - foreach (string palFile in GetFiles(" *.pal")) - { - Console.WriteLine($"Loading {palFile}..."); - Palette palette = new Palette(palFile); - palette.Save(@"D:\Pictures\test.pal"); - } + Scheme scheme = new Scheme(@"D:\Pictures\Test.wsc"); + scheme.Save(@"D:\Pictures\Test2.wsc"); Console.ReadLine(); } diff --git a/src/Syroot.Worms/Core/ByteArrayExtensions.cs b/src/Syroot.Worms/Core/ByteArrayExtensions.cs index 7e5b142..a78348f 100644 --- a/src/Syroot.Worms/Core/ByteArrayExtensions.cs +++ b/src/Syroot.Worms/Core/ByteArrayExtensions.cs @@ -1,7 +1,7 @@ namespace Syroot.Worms.Core { /// - /// Represents extension methods for byte array instances. + /// Represents extension methods for array instances. /// internal static class ByteArrayExtensions { diff --git a/src/Syroot.Worms/Core/ByteExtensions.cs b/src/Syroot.Worms/Core/ByteExtensions.cs new file mode 100644 index 0000000..b57ef7c --- /dev/null +++ b/src/Syroot.Worms/Core/ByteExtensions.cs @@ -0,0 +1,226 @@ +namespace Syroot.Worms.Core +{ + /// + /// Represents extension methods for instances. + /// + internal static class ByteExtensions + { + // ---- METHODS (INTERNAL) ------------------------------------------------------------------------------------- + + /// + /// Returns the current byte with the bit at the set (being 1). + /// + /// The extended instance. + /// The 0-based index of the bit to enable. + /// The current byte with the bit enabled. + internal static byte EnableBit(this byte self, int index) + { + return (byte)(self | (1 << index)); + } + + /// + /// Returns the current byte with the bit at the cleared (being 0). + /// + /// The extended instance. + /// The 0-based index of the bit to disable. + /// The current byte with the bit disabled. + internal static byte DisableBit(this byte self, int index) + { + return (byte)(self & ~(1 << index)); + } + + /// + /// Returns a value indicating whether the bit at the in the current byte is enabled + /// or disabled. + /// + /// The extended instance. + /// The 0-based index of the bit to check. + /// true when the bit is set; otherwise false. + internal static bool GetBit(this byte self, int index) + { + return (self & (1 << index)) != 0; + } + + /// + /// Returns the current byte with all bits rotated in the given , where positive + /// directions rotate left and negative directions rotate right. + /// + /// The extended instance. + /// The direction in which to rotate, where positive directions rotate left. + /// The current byte with the bits rotated. + internal static byte RotateBits(this byte self, int direction) + { + int bits = sizeof(byte) * 8; + if (direction > 0) + { + return (byte)((self << direction) | (self >> (bits - direction))); + } + else if (direction < 0) + { + direction = -direction; + return (byte)((self >> direction) | (self << (bits - direction))); + } + return self; + } + + /// + /// Returns the current byte with the bit at the enabled or disabled, according to + /// . + /// + /// The extended instance. + /// The 0-based index of the bit to enable or disable. + /// true to enable the bit; otherwise false. + /// The current byte with the bit enabled or disabled. + internal static byte SetBit(this byte self, int index, bool enable) + { + if (enable) + { + return EnableBit(self, index); + } + else + { + return DisableBit(self, index); + } + } + + /// + /// Returns the current byte with the bit at the enabled when it is disabled or + /// disabled when it is enabled. + /// + /// The extended instance. + /// The 0-based index of the bit to toggle. + /// The current byte with the bit toggled. + internal static byte ToggleBit(this byte self, int index) + { + if (GetBit(self, index)) + { + return DisableBit(self, index); + } + else + { + return EnableBit(self, index); + } + } + + /// + /// Returns an instance represented by the given number of . + /// + /// The extended instance. + /// The number of least significant bits which are used to store the + /// value. + /// The decoded . + internal static byte DecodeByte(this byte self, int bits) + { + return DecodeByte(self, bits, 0); + } + + /// + /// Returns an instance represented by the given number of , starting + /// at the . + /// + /// The extended instance. + /// The number of least significant bits which are used to store the + /// value. + /// The first bit of the encoded value. + /// The decoded . + internal static byte DecodeByte(this byte self, int bits, int firstBit) + { + // Shift to the first bit and keep only the required bits. + return (byte)((self >> firstBit) & ((1 << bits) - 1)); + } + + /// + /// Returns an instance represented by the given number of . + /// + /// The extended instance. + /// The number of least significant bits which are used to store the + /// value. + /// The decoded . + internal static sbyte DecodeSByte(this byte self, int bits) + { + return DecodeSByte(self, bits, 0); + } + + /// + /// Returns an instance represented by the given number of , starting + /// at the . + /// + /// The extended instance. + /// The number of least significant bits which are used to store the + /// value. + /// The first bit of the encoded value. + /// The decoded . + internal static sbyte DecodeSByte(this byte self, int bits, int firstBit) + { + self >>= firstBit; + int absMask = 1 << bits; + byte abs = (byte)(self & (absMask - 1)); + if (abs.GetBit(bits - 1)) + { + return (sbyte)(abs - absMask); + } + else + { + return (sbyte)abs; + } + } + + /// + /// Returns the current byte with the given set into the given number of + /// . + /// + /// The extended instance. + /// The number of bits which are used to store the value. + /// The current byte with the value encoded into it. + internal static byte Encode(this byte self, byte value, int bits) + { + return Encode(self, value, bits, 0); + } + + /// + /// Returns the current byte with the given set into the given number of + /// starting at . + /// + /// The extended instance. + /// The number of bits which are used to store the value. + /// The first bit used for the encoded value. + /// The current byte with the value encoded into it. + internal static byte Encode(this byte self, byte value, int bits, int firstBit) + { + // Clear the bits required for the value and fit it into them by truncating. + int mask = ((1 << bits) - 1) << firstBit; + self &= (byte)~mask; + value = (byte)((value << firstBit) & mask); + + // Set the value. + return (byte)(self | value); + } + + /// + /// Returns the current byte with the given set into the given number of + /// . + /// + /// The extended instance. + /// The number of bits which are used to store the value. + /// The current byte with the value encoded into it. + internal static byte Encode(this byte self, sbyte value, int bits) + { + return Encode(self, value, bits, 0); + } + + /// + /// Returns the current byte with the given set into the given number of + /// starting at . + /// + /// The extended instance. + /// The number of bits which are used to store the value. + /// The first bit used for the encoded value. + /// The current byte with the value encoded into it. + internal static byte Encode(this byte self, sbyte value, int bits, int firstBit) + { + // Set the value as a normal byte, but then fix the sign. + self = Encode(self, (byte)value, bits, firstBit); + return self.SetBit(bits + firstBit - 1, value < 0); + } + } +} diff --git a/src/Syroot.Worms/Gen2/Armageddon/GameScheme.cs b/src/Syroot.Worms/Gen2/Armageddon/GameScheme.cs deleted file mode 100644 index f71d920..0000000 --- a/src/Syroot.Worms/Gen2/Armageddon/GameScheme.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Syroot.Worms.Gen2.Armageddon -{ - class GameScheme - { - } -} diff --git a/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs b/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs new file mode 100644 index 0000000..4b39f44 --- /dev/null +++ b/src/Syroot.Worms/Gen2/Armageddon/Scheme.cs @@ -0,0 +1,2772 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; +using Syroot.IO; +using Syroot.Maths; +using Syroot.Worms.Core; + +namespace Syroot.Worms.Gen2.Armageddon +{ + /// + /// Represents a high level view on a scheme stored in a WSC file which contains game settings and armory + /// configuration. + /// Used by WA and WWP. S. https://worms2d.info/Game_scheme_file. + /// + public class Scheme : ILoadableFile, ISaveableFile + { + // ---- CONSTANTS ---------------------------------------------------------------------------------------------- + + private const int _signature = 0x4D484353; // "SCHM" + + #region Lookup Tables + + private static readonly Dictionary _mapWaterRiseToRaw = new Dictionary() + { + [0] = 0, + [5] = 1, + [13] = 19, + [20] = 2, + [21] = 55, + [29] = 43, + [37] = 47, + [45] = 3, + [52] = 26, + [53] = 25, + [61] = 27, + [64] = 8, + [69] = 33, + [77] = 13, + [80] = 4, + [84] = 18, + [85] = 23, + [93] = 11, + [101] = 15, + [109] = 29, + [116] = 22, + [117] = 57, + [125] = 5, + [133] = 63, + [141] = 45, + [148] = 30, + [149] = 9, + [157] = 21, + [165] = 17, + [173] = 61, + [180] = 6, + [181] = 39, + [189] = 37, + [197] = 31, + [205] = 51, + [208] = 12, + [212] = 14, + [213] = 41, + [221] = 53, + [229] = 49, + [237] = 35, + [244] = 10, + [245] = 7, + [253] = 59 + }; + private static readonly byte[] _objectCounts = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, + 90, 95, 100, 110, 120, 130, 140, 150, 160, 170, 180, 190, 200, 210, 220, 230, 240, 250 }; + + #endregion + + // ---- MEMBERS ------------------------------------------------------------------------------------------------ + + private byte _mineDelay; + private byte _turnTime; + private byte _roundTimeMinutes; + private byte _roundTimeSeconds; + private byte _numberOfWins; + private sbyte _rwGravity; + private sbyte _rwGravityConstBlackHole; + private sbyte _rwGravityPropBlackHole; + private byte _rwKaosMod; + + // ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------ + + /// + /// Initializes a new instance of the class, loading the data from the given + /// . + /// + /// The to load the data from. + public Scheme(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 Scheme(string fileName) + { + Load(fileName); + } + + // ---- PROPERTIES --------------------------------------------------------------------------------------------- + + /// + /// Gets or sets the of this scheme, controlling whether super weapon settings + /// are stored or not. + /// + public SchemeVersion Version { get; set; } + + /// + /// Gets or sets the delay in seconds between each team's turn to allow relaxed switching of seats. + /// + public byte HotSeatDelay { get; set; } + + /// + /// Gets or sets the time in seconds available for a worm to retreat after using a weapon which ends the turn + /// while standing on land. + /// + public byte RetreatTime { get; set; } + + /// + /// Gets or sets the time in seconds available for a worm to retreat after using a weapon which ends the turn + /// while on a rope. + /// + public byte RetreatTimeRope { get; set; } + + /// + /// Gets or sets a value indicating whether the total round time until sudden death will be displayed in the + /// turn timer. + /// + public bool ShowRoundTime { get; set; } + + /// + /// Gets or sets a value indicating whether significant turns will be replayed in offline games. + /// + public bool AutomaticReplays { get; set; } + + /// + /// Gets or sets the percentual amount of fall damage applied, relative to normal fall damage being 100%. + /// + public SchemeFallDamage FallDamage { get; set; } + + /// + /// Gets or sets a value indicating whether worms cannot walk and are mostly stuck at their current position + /// without using any utilities. + /// + public bool ArtilleryMode { get; set; } + + /// + /// Gets or sets a value indicating the scheme editor used to modify this scheme. Originally used to indicate + /// the unimplemented Bounty Mode. + /// + public SchemeEditor SchemeEditor { get; set; } + + /// + /// Gets or sets a value indicating the stockpiling of armory between game rounds. + /// + public SchemeStockpiling StockpilingMode { get; set; } + + /// + /// Gets or sets a value indicating the worm selection order determining the next worm to be played. + /// + public SchemeWormSelect WormSelectMode { get; set; } + + /// + /// Gets or sets a value indicating the action triggered when Sudden Death starts. + /// + public SchemeSuddenDeathEvent SuddenDeathEvent { get; set; } + + /// + /// Gets or sets the amount in pixels which the water will rise between turns after Sudden Death was triggered. + /// + public SchemeWaterRise WaterRiseRate { get; set; } + + /// + /// Gets or sets the percentual probability of a weapon crate to drop between turns. Negative values might crash + /// the game. + /// + public sbyte WeaponCrateProbability { get; set; } + + /// + /// Gets or sets a value indicating whether donor cards can spawn upon a worm's death. + /// + public bool DonorCards { get; set; } + + /// + /// Gets or sets the percentual probability of a health crate to drop between turns. Negative values might crash + /// the game. + /// + public sbyte HealthCrateProbability { get; set; } + + /// + /// Gets or sets the amount of health included in a health crate added to the collecting worm's energy. + /// + public byte HealthCrateEnergy { get; set; } + + /// + /// Gets or sets the percentual probability of a utility crate to drop between turns. Negative values might + /// crash the game. + /// + public sbyte UtilityCrateProbability { get; set; } + + /// + /// Gets or sets the type of objects which can be placed on the map. + /// + public SchemeObjectType ObjectTypes { get; set; } + + /// + /// Gets or sets the maximum number of objects (mines or oil drums) on the map. + /// + public SchemeObjectCount ObjectCount { get; set; } + + /// + /// Gets or sets the number of seconds a mine requires to explode. Can be 1-3 and 5-127 seconds. + /// + public byte MineDelay + { + get + { + return _mineDelay; + } + set + { + if (value == 4 || value > 0x7F) + { + throw new ArgumentException("Mine delay must be between 0-127 and not be 4.", nameof(value)); + } + _mineDelay = value; + } + } + + /// + /// Gets or sets a value indicating whether the mine fuse will be randomly chosen between fractions of 1 to 3 + /// seconds. If true, the setting will be ignored. + /// + public bool MineDelayRandom { get; set; } + + /// + /// Gets or sets a value indicating whether mines can refuse to explode after their count down. + /// + public bool DudMines { get; set; } + + /// + /// Gets or sets a value indicating whether worms are placed manually by the players for their initial position + /// at round start. + /// + public bool ManualWormPlacement { get; set; } + + /// + /// Gets or sets the initial worm energy at round start. + /// + public byte WormEnergy { get; set; } + + /// + /// Gets or sets the turn time in seconds available for the player to move. Must be in the range of 0-127. + /// + public byte TurnTime + { + get + { + return _turnTime; + } + set + { + if (value > 0x7F) + { + throw new ArgumentException("Turn time must be between 0-127.", nameof(value)); + } + _turnTime = value; + } + } + + /// + /// Gets or sets a value indicating whether the turn time is unlimited. If true, the + /// setting will be ignored. + /// + public bool TurnTimeInfinite { get; set; } + + /// + /// Gets or sets the round time before sudden death is triggered between 0-127 minutes. + /// + public byte RoundTimeMinutes + { + get + { + return _roundTimeMinutes; + } + set + { + if (value > 0x7F) + { + throw new ArgumentException("Round time must be between 0-127 minutes.", nameof(value)); + } + _roundTimeMinutes = value; + } + } + + /// + /// Gets or sets the round time before sudden death is triggered in between 0-128 seconds. When 0, + /// is used instead. + /// + public byte RoundTimeSeconds + { + get + { + return _roundTimeSeconds; + } + set + { + if (value > 0x80) + { + throw new ArgumentException("Round time must be between 0-128 seconds.", nameof(value)); + } + _roundTimeSeconds = value; + } + } + + /// + /// Gets or sets the number of round wins required to win the game. Must not be 0. + /// + public byte NumberOfWins + { + get + { + return _numberOfWins; + } + set + { + if (value == 0) + { + throw new ArgumentException("Number of wins must not be 0.", nameof(value)); + } + _numberOfWins = value; + } + } + + /// + /// Gets or sets a value indicating whether blood effects are enabled. + /// + public bool Blood { get; set; } + + /// + /// Gets or sets a value indicating whether the Super Sheep weapon gets upgraded to the Aqua Sheep, which can + /// fly underwater. + /// + public bool AquaSheep { get; set; } + + /// + /// Gets or sets a value indicating whether sheeps will jump out of exploding crates. + /// + public bool SheepHeaven { get; set; } + + /// + /// Gets or sets a value indicating whether worms have infinity energy, killable only by drowning them. + /// + public bool GodWorms { get; set; } + + /// + /// Gets or sets a value indicating whether terrain cannot be destroyed by explosions. + /// + public bool IndestructibleLand { get; set; } + + /// + /// Gets or sets a value indicating whether the Grenade weapon is more powerful. + /// + public bool UpgradedGrenade { get; set; } + + /// + /// Gets or sets a value indicating whether the Shotgun weapon shoots twice for each of the two shots. + /// + public bool UpgradedShotgun { get; set; } + + /// + /// Gets or sets a value indicating whether cluster weapon explode into more clusters. + /// + public bool UpgradedCluster { get; set; } + + /// + /// Gets or sets a value indicating whether the Longbow weapon is more powerful. + /// + public bool UpgradedLongbow { get; set; } + + /// + /// Gets or sets a value indicating whether team weapons will be given to the teams, overriding the default + /// weapon settings for them. + /// + public bool EnableTeamWeapons { get; set; } + + /// + /// Gets or sets a value indicating whether super weapons can be collected from crates. + /// + 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. + /// + public SchemeWeaponSetting[] Weapons { get; set; } + + // ---- RubberWorm Settings ---- + + /// + /// Gets or sets a value whether power is unlocked like in TestStuff. Configurable with the /alp command. + /// + public bool RwAntiLockPower { get; set; } + + /// + /// Gets or sets a value indicating whether worms falling into water will be reset to the last solid location + /// they stood on. Configurable with the /antisink command. + /// + public bool RwAntiSink { get; set; } + + /// + /// Gets or sets a value indicating whether the aim direction of a weapon will be reset at turn start. + /// Configurable with the /reaim command. + /// + public bool RwAutoReaim { get; set; } + + /// + /// Gets or sets a value whether the aim of a weapon loops in full rather than half circles. Configurable with + /// the /cira command. + /// + public bool RwCircularAim { get; set; } + + /// + /// Gets or sets the maximum number of crates existing on the map at the same time. 0 disables this feature, + /// default limit is 5. Configurable with the /cratelimit command. + /// + public byte RwCrateLimit { get; set; } + + /// + /// Gets or sets the maximum number of crates spawning per turn and enables the crate counter. Configurable with + /// the /craterate command. + /// + public byte RwCrateRate { get; set; } + + /// + /// Gets or sets a value indicating whether crate shower is enabled throughout a turn. Configurable with the + /// /crateshower command. + /// + public bool RwCrateShower { get; set; } + + /// + /// Gets or sets a value indicating whether weapon fuses can be selected between 0-9 seconds and herd counts + /// between 1-10 animals. Configurable with the /fuseex command. + /// + public bool RwExtendedFuse { get; set; } + + /// + /// Gets or sets a value indicating whether the turn timer is paused while launching a weapon. Configurable with + /// the /fdpt or /nopause commands. + /// + public bool RwFireDoesntPauseTimer { get; set; } + + /// + /// Gets or sets the maximum number of flame particles active at the same time in the scale of 100x. + /// Configurable with the /flames command. + /// + public byte RwFlameLimit { get; set; } + + /// + /// Gets or sets the friction deaccelerating objects touching solid ground. 96 is default, 100 is no friction, + /// higher values accelerate objects. Configurable with the /friction command. + /// + public byte RwFriction { get; set; } + + /// + /// Gets or sets the amount of gravity. Ranges from -64-63 where 0 and 12 are default gravity and negative + /// values pull objects upwards. Configurable with the /gravity command. When set, + /// and are reset. + /// + public sbyte RwGravity + { + get + { + return _rwGravity; + } + set + { + if (value != 0) + { + RwGravityConstBlackHole = 0; + RwGravityPropBlackHole = 0; + } + _rwGravity = value; + } + } + + /// + /// gets or sets the amount of gravity acting as a constant black hole. Ranges from -32 to 31. Configurable with + /// the /cbh command. When set, and are reset. + /// + public sbyte RwGravityConstBlackHole + { + get + { + return _rwGravityConstBlackHole; + } + set + { + if (value != 0) + { + RwGravity = 0; + RwGravityPropBlackHole = 0; + } + _rwGravityConstBlackHole = value; + } + } + + /// + /// Gets or sets the amount of gravity acting as a proportional black hole. Ranges from -32 to 31. Configurable + /// with the /pbh command. When set, and are + /// reset. + /// + public sbyte RwGravityPropBlackHole + { + get + { + return _rwGravityPropBlackHole; + } + set + { + if (value != 0) + { + RwGravity = 0; + RwGravityConstBlackHole = 0; + } + _rwGravityPropBlackHole = value; + } + } + + /// + /// Gets or sets the Kaos game scheme mod. 0 for none, 1-5 for the corresponding mod. Configurable with the + /// /kaosmod command. + /// + public byte RwKaosMod + { + get + { + return _rwKaosMod; + } + set + { + if (value > 0xF) + { + throw new ArgumentException("Kaos mod must not be greater than 15."); + } + _rwKaosMod = value; + } + } + + /// + /// Gets or sets the rope knocking power in percent, where 100 is the default power. Configurable with the + /// /knock command. + /// + public byte RwKnockForce { get; set; } + + /// + /// Gets or sets a value indicating whether the loss of control while moving a worm ends does no longer end the + /// turn and allows the player to continue moving. Configurable with the /ldet or /stoicworm commands. + /// + public bool RwLoseControlDoesntEndTurn { get; set; } + + /// + /// Gets or sets the maximum speed a player can reach while roping. 16 is default, 32 is like in TestStuff, 255 + /// is unlimited. Configurable with the /speed command. + /// + public byte RwMaxRopeSpeed { get; set; } + + /// + /// Gets or sets a value indicating whether using a weapon does no longer end the turn and allows to shoot + /// multiple weapons in one turn. Configurable with the /sdet or /multishot commands. + /// + public bool RwShotDoesntEndTurn { get; set; } + + /// + /// Gets or sets a value indicating whether the weapons Armageddon, Earthquake and Indian Nuke Test are affected + /// by aswell. Configurable with the /usw command. + /// + public bool RwShotDoesntEndTurnAll { get; set; } + + /// + /// Gets or sets a value indicating whether all objects are pushed by explosions near them. Configurable with + /// the /ope command. + /// + public bool RwObjectPushByExplosion { get; set; } + + /// + /// Gets or sets a value indicating whether worms can be selected at any time during the turn, as long as worm + /// selection is activated. Configurable with the /swat command. + /// + public bool RwSelectWormAnytime { get; set; } + + /// + /// Gets or sets a value indicating whether the Ninja Rope is more powerful. Configurable with the /ir or /rope+ + /// commands. + /// + public bool RwUpgradedRope { get; set; } + + /// + /// Gets or sets the (special) game version to be forced. Configurable with the /version command. + /// S. http://worms2d.info/List_of_Worms_Armageddon_logic_versions. + /// + public ushort RwVersionOverride { get; set; } + + /// + /// Gets or sets the amount of air viscosity affecting objects. Odd numbers affect worms too. Configurable with + /// the /visc command. + /// + public byte RwViscosity { get; set; } + + /// + /// Gets or sets a value indicating whether the selected weapon no longer resets to a remembered one upon + /// shooting it. Configurable with the /wdca command. + /// + public bool RwWeaponsDontChange { get; set; } + + /// + /// Gets or sets the influence power of the wind affecting all weapons. 255 is the same influence as the + /// Bazooka. Odd numbers affect worms too. Configurable with the /wind command. + /// + public byte RwWindPower { get; set; } + + /// + /// Gets or sets the power with which worms bounce off terrain, where 0 disables this feature and 255 fully + /// bounces worms back without speed loss. Configurable with the /rubber command. + /// + public byte RwWormBouncyness { 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. + int signature = reader.ReadInt32(); + if (signature != _signature) + { + throw new InvalidDataException("Invalid WSC file signature."); + } + Version = reader.ReadEnum(true); + + // Read the options. + HotSeatDelay = reader.ReadByte(); + RetreatTime = reader.ReadByte(); + RetreatTimeRope = reader.ReadByte(); + ShowRoundTime = reader.ReadBoolean(); + AutomaticReplays = reader.ReadBoolean(); + FallDamage = (SchemeFallDamage)(reader.ReadByte() * 50 % 0x100 * 2); + ArtilleryMode = reader.ReadBoolean(); + SchemeEditor = reader.ReadEnum(false); + StockpilingMode = reader.ReadEnum(true); + WormSelectMode = reader.ReadEnum(true); + SuddenDeathEvent = reader.ReadEnum(true); + WaterRiseRate = (SchemeWaterRise)(Math.Pow(reader.ReadByte(), 2) * 5 % 0x100); + WeaponCrateProbability = reader.ReadSByte(); + DonorCards = reader.ReadBoolean(); + HealthCrateProbability = reader.ReadSByte(); + HealthCrateEnergy = reader.ReadByte(); + UtilityCrateProbability = reader.ReadSByte(); + LoadObjectTypesAndCount(reader); + LoadMineDelayConfig(reader); + DudMines = reader.ReadBoolean(); + ManualWormPlacement = reader.ReadBoolean(); + WormEnergy = reader.ReadByte(); + LoadTurnTimeConfig(reader); + LoadRoundTimeConfig(reader); + NumberOfWins = (byte)Math.Max(1, (int)reader.ReadByte()); + Blood = reader.ReadBoolean(); + AquaSheep = reader.ReadBoolean(); + SheepHeaven = reader.ReadBoolean(); + GodWorms = reader.ReadBoolean(); + IndestructibleLand = reader.ReadBoolean(); + UpgradedGrenade = reader.ReadBoolean(); + UpgradedShotgun = reader.ReadBoolean(); + UpgradedCluster = reader.ReadBoolean(); + UpgradedLongbow = reader.ReadBoolean(); + EnableTeamWeapons = reader.ReadBoolean(); + EnableSuperWeapons = reader.ReadBoolean(); + + // Read the weapon settings. Old versions do not store super weapon settings. + Weapons = new SchemeWeaponSetting[64]; + 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(); + } + + // Ignore possible unknown WWP trash at the end of the file. + + // Parse the RubberWorm settings. + LoadRubberWormSettings(); + } + } + + /// + /// 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) + { + Save(stream, SchemeSaveFormat.ExtendedWithObjectCount); + } + + /// + /// Saves the data into the given with the specified . + /// + /// The to save the data to. + /// The to respect when storing the settings. + public void Save(Stream stream, SchemeSaveFormat format) + { + using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII)) + { + // Write the header. + writer.Write(_signature); + writer.Write((byte)Version); + + // Write the options. + writer.Write(HotSeatDelay); + writer.Write(RetreatTime); + writer.Write(RetreatTimeRope); + writer.Write(ShowRoundTime); + writer.Write(AutomaticReplays); + writer.Write((byte)((int)FallDamage / 4 * 41 % 0x80)); + writer.Write(ArtilleryMode); + writer.Write(SchemeEditor, false); + writer.Write(StockpilingMode, true); + writer.Write(WormSelectMode, true); + writer.Write(SuddenDeathEvent, true); + writer.Write(_mapWaterRiseToRaw[(byte)WaterRiseRate]); + writer.Write(WeaponCrateProbability); + writer.Write(DonorCards); + writer.Write(HealthCrateProbability); + writer.Write(HealthCrateEnergy); + writer.Write(UtilityCrateProbability); + SaveObjectTypesAndCount(writer, format); + SaveMineDelayConfig(writer); + writer.Write(DudMines); + writer.Write(ManualWormPlacement); + writer.Write(WormEnergy); + SaveTurnTimeConfig(writer); + SaveRoundTimeConfig(writer); + writer.Write(NumberOfWins); + writer.Write(Blood); + writer.Write(AquaSheep); + writer.Write(SheepHeaven); + writer.Write(GodWorms); + writer.Write(IndestructibleLand); + writer.Write(UpgradedGrenade); + writer.Write(UpgradedShotgun); + writer.Write(UpgradedCluster); + writer.Write(UpgradedLongbow); + writer.Write(EnableTeamWeapons); + writer.Write(EnableSuperWeapons); + + // Transfer the RubberWorm settings to unused weapon configuration. + SaveRubberWormSettings(); + + // Write the weapon settings. Old versions do not store super weapon settings. + int weaponCount = GetWeaponCount(); + for (int i = 0; i < weaponCount; i++) + { + writer.Write(Weapons[i].Ammunition); + writer.Write(Weapons[i].Power); + writer.Write(Weapons[i].Delay); + writer.Write(Weapons[i].Probability); + } + + // Ignore possible unknown WWP trash at the end of the file. + } + } + + /// + /// Saves the data in the given file. + /// + /// The name of the file to save the data in. + public void Save(string fileName) + { + Save(fileName, SchemeSaveFormat.ExtendedWithObjectCount); + } + + /// + /// Saves the data in the given file with the specified . + /// + /// The name of the file to save the data in. + /// The to respect when storing the settings. + public void Save(string fileName, SchemeSaveFormat format) + { + using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None)) + { + Save(stream, format); + } + } + + // ---- METHODS (PRIVATE) -------------------------------------------------------------------------------------- + + private void LoadObjectTypesAndCount(BinaryDataReader reader) + { + // Invalid values default to 8 mines. + ObjectTypes = SchemeObjectType.Mines; + ObjectCount = SchemeObjectCount.Count8; + + byte raw = reader.ReadByte(); + if (raw < 12) + { + // WA before 3.6.28.0 and WWP only store object type. + switch (raw) + { + case 0x00: + ObjectTypes = SchemeObjectType.None; + break; + case 0x02: + ObjectTypes = SchemeObjectType.OilDrums; + break; + case 0x05: + ObjectTypes = SchemeObjectType.Mines | SchemeObjectType.OilDrums; + break; + } + } + else + { + // WA since 3.6.28.0 encodes object type and count in one byte. + int modulo = raw % 4; + switch (modulo) + { + case 0x00: + ObjectTypes = SchemeObjectType.None; + break; + case 0x02: + ObjectTypes = SchemeObjectType.OilDrums; + break; + case 0x03: + ObjectTypes = SchemeObjectType.Mines | SchemeObjectType.OilDrums; + break; + } + ObjectCount = (SchemeObjectCount)_objectCounts[(raw - (8 + modulo)) / 4]; + } + } + + private void LoadMineDelayConfig(BinaryDataReader reader) + { + byte raw = reader.ReadByte(); + if (raw == 4 || raw > 0x7F) + { + MineDelay = 0; + MineDelayRandom = true; + } + else + { + MineDelay = raw; + MineDelayRandom = false; + } + } + + private void LoadTurnTimeConfig(BinaryDataReader reader) + { + byte raw = reader.ReadByte(); + if (raw > 0x7F) + { + TurnTime = 0; + TurnTimeInfinite = true; + } + else + { + TurnTime = raw; + TurnTimeInfinite = false; + } + } + + private void LoadRoundTimeConfig(BinaryDataReader reader) + { + byte raw = reader.ReadByte(); + if (raw > 0x7F) + { + RoundTimeMinutes = 0; + RoundTimeSeconds = (byte)(raw - 0x7F); + } + else + { + RoundTimeMinutes = raw; + RoundTimeSeconds = 0; + } + } + + private void LoadRubberWormSettings() + { + var earthquakeProb = (RwEarthquakeProb)Weapons[(int)SchemeWeapon.Earthquake].Probability; + RwAntiLockPower = earthquakeProb.HasFlag(RwEarthquakeProb.AntiLockPower); + RwAutoReaim = earthquakeProb.HasFlag(RwEarthquakeProb.AutoReaim); + RwCircularAim = earthquakeProb.HasFlag(RwEarthquakeProb.CircularAim); + RwShotDoesntEndTurnAll = earthquakeProb.HasFlag(RwEarthquakeProb.ShotDoesntEndTurnAll); + RwKaosMod = ((byte)earthquakeProb).DecodeByte(4, 4); + + RwAntiSink = Weapons[(int)SchemeWeapon.SheepStrike].Probability != 0; + RwCrateLimit = (byte)Weapons[(int)SchemeWeapon.MagicBullet].Probability; + RwCrateRate = (byte)Weapons[(int)SchemeWeapon.NuclearTest].Probability; + + var moleSquadronProb = (RwMoleSquadronProb)Weapons[(int)SchemeWeapon.MoleSquadron].Probability; + RwCrateShower = moleSquadronProb.HasFlag(RwMoleSquadronProb.CrateShower); + RwExtendedFuse = moleSquadronProb.HasFlag(RwMoleSquadronProb.ExtendedFuse); + RwFireDoesntPauseTimer = moleSquadronProb.HasFlag(RwMoleSquadronProb.FireDoesntPauseTimer); + RwLoseControlDoesntEndTurn = moleSquadronProb.HasFlag(RwMoleSquadronProb.LoseControlDoesntEndTurn); + RwObjectPushByExplosion = moleSquadronProb.HasFlag(RwMoleSquadronProb.ObjectPushByExplosion); + RwShotDoesntEndTurn = moleSquadronProb.HasFlag(RwMoleSquadronProb.ShotDoesntEndTurn); + RwUpgradedRope = moleSquadronProb.HasFlag(RwMoleSquadronProb.UpgradedRope); + RwWeaponsDontChange = moleSquadronProb.HasFlag(RwMoleSquadronProb.WeaponsDontChange); + + RwFlameLimit = (byte)Weapons[(int)SchemeWeapon.ScalesOfJustice].Probability; + RwFriction = (byte)Weapons[(int)SchemeWeapon.SalvationArmy].Probability; + + // 8th and 7th bit control constant / proportional black hole gravity, otherwise normal gravity. + var mailStrikeProb = (byte)Weapons[(int)SchemeWeapon.MailStrike].Probability; + if (mailStrikeProb.GetBit(7)) + { + if (mailStrikeProb.GetBit(6)) + { + RwGravityPropBlackHole = mailStrikeProb.DecodeSByte(6); + } + else + { + RwGravityConstBlackHole = mailStrikeProb.DecodeSByte(6); + } + } + else + { + RwGravity = mailStrikeProb.DecodeSByte(7); + } + + RwKnockForce = (byte)Weapons[(int)SchemeWeapon.SuperBananaBomb].Probability; + RwMaxRopeSpeed = (byte)Weapons[(int)SchemeWeapon.MineStrike].Probability; + RwSelectWormAnytime = ((byte)Weapons[(int)SchemeWeapon.MBBomb].Probability).GetBit(1); + + byte[] versionBytes = new byte[2]; + versionBytes[0] = (byte)Weapons[(int)SchemeWeapon.SelectWorm].Probability; + versionBytes[1] = (byte)Weapons[(int)SchemeWeapon.Freeze].Probability; + RwVersionOverride = BitConverter.ToUInt16(versionBytes, 0); + + RwViscosity = (byte)Weapons[(int)SchemeWeapon.ConcreteDonkey].Probability; + RwWindPower = (byte)Weapons[(int)SchemeWeapon.SuicideBomber].Probability; + RwWormBouncyness = (byte)Weapons[(int)SchemeWeapon.Armageddon].Probability; + } + + private int GetWeaponCount() + { + // Old versions do not store super weapon settings. + return Version == SchemeVersion.Extended ? 64 : 45; + } + + private void SaveObjectTypesAndCount(BinaryDataWriter writer, SchemeSaveFormat format) + { + byte raw = 0; + if (format == SchemeSaveFormat.ExtendedWithObjectCount) + { + // WA since 3.6.28.0 encodes object type and count in one byte. + switch (ObjectTypes) + { + case SchemeObjectType.Mines: + raw = 0x01; + break; + case SchemeObjectType.OilDrums: + raw = 0x02; + break; + case SchemeObjectType.Mines | SchemeObjectType.OilDrums: + raw = 0x03; + break; + } + // Get the index of the object count and compute the raw value from that. + int index = Array.IndexOf(_objectCounts, (byte)ObjectCount); + raw = (byte)(index * 4 + (8 + raw)); + } + else + { + // WA before 3.6.28.0 and WWP only store object type. + switch (ObjectTypes) + { + case SchemeObjectType.Mines: + raw = 0x01; + break; + case SchemeObjectType.OilDrums: + raw = 0x02; + break; + case SchemeObjectType.Mines | SchemeObjectType.OilDrums: + raw = 0x05; + break; + } + } + writer.Write(raw); + } + + private void SaveMineDelayConfig(BinaryDataWriter writer) + { + if (MineDelayRandom) + { + writer.Write((byte)4); + } + else + { + writer.Write(MineDelay); + } + } + + private void SaveTurnTimeConfig(BinaryDataWriter writer) + { + if (TurnTimeInfinite) + { + writer.Write((byte)0xFF); + } + else + { + writer.Write(TurnTime); + } + } + + private void SaveRoundTimeConfig(BinaryDataWriter writer) + { + if (RoundTimeSeconds > 0) + { + writer.Write((byte)(0xFF - (RoundTimeSeconds - 1))); + } + else + { + writer.Write(RoundTimeMinutes); + } + } + + private void SaveRubberWormSettings() + { + byte earthquakeProb = 0; + if (RwAntiLockPower) earthquakeProb |= (byte)RwEarthquakeProb.AntiLockPower; + if (RwAutoReaim) earthquakeProb |= (byte)RwEarthquakeProb.AutoReaim; + if (RwCircularAim) earthquakeProb |= (byte)RwEarthquakeProb.CircularAim; + if (RwShotDoesntEndTurnAll) earthquakeProb |= (byte)RwEarthquakeProb.ShotDoesntEndTurnAll; + earthquakeProb = earthquakeProb.Encode(RwKaosMod, 4); + Weapons[(int)SchemeWeapon.Earthquake].Probability = (sbyte)earthquakeProb; + + Weapons[(int)SchemeWeapon.SheepStrike].Probability = (sbyte)(RwAntiSink ? 1 : 0); + Weapons[(int)SchemeWeapon.MagicBullet].Probability = (sbyte)RwCrateLimit; + Weapons[(int)SchemeWeapon.NuclearTest].Probability = (sbyte)RwCrateRate; + + RwMoleSquadronProb moleSquadronProb = RwMoleSquadronProb.None; + if (RwCrateShower) moleSquadronProb |= RwMoleSquadronProb.CrateShower; + if (RwExtendedFuse) moleSquadronProb |= RwMoleSquadronProb.ExtendedFuse; + if (RwFireDoesntPauseTimer) moleSquadronProb |= RwMoleSquadronProb.FireDoesntPauseTimer; + if (RwLoseControlDoesntEndTurn) moleSquadronProb |= RwMoleSquadronProb.LoseControlDoesntEndTurn; + if (RwObjectPushByExplosion) moleSquadronProb |= RwMoleSquadronProb.ObjectPushByExplosion; + if (RwShotDoesntEndTurn) moleSquadronProb |= RwMoleSquadronProb.ShotDoesntEndTurn; + if (RwUpgradedRope) moleSquadronProb |= RwMoleSquadronProb.UpgradedRope; + if (RwWeaponsDontChange) moleSquadronProb |= RwMoleSquadronProb.WeaponsDontChange; + Weapons[(int)SchemeWeapon.MoleSquadron].Probability = (sbyte)moleSquadronProb; + + Weapons[(int)SchemeWeapon.ScalesOfJustice].Probability = (sbyte)RwFlameLimit; + Weapons[(int)SchemeWeapon.SalvationArmy].Probability = (sbyte)RwFriction; + + // 8th and 7th bit control constant / proportional black hole gravity, otherwise normal gravity. + byte mailStrikeProb = 0; + if (RwGravity != 0) + { + mailStrikeProb = mailStrikeProb.Encode(RwGravity, 7); + } + else if (RwGravityConstBlackHole != 0) + { + mailStrikeProb = mailStrikeProb.EnableBit(7); + mailStrikeProb = mailStrikeProb.Encode(RwGravityConstBlackHole, 6); + } + else if (RwGravityPropBlackHole != 0) + { + mailStrikeProb = mailStrikeProb.EnableBit(7); + mailStrikeProb = mailStrikeProb.EnableBit(6); + mailStrikeProb = mailStrikeProb.Encode(RwGravityPropBlackHole, 6); + } + Weapons[(int)SchemeWeapon.MailStrike].Probability = (sbyte)mailStrikeProb; + + Weapons[(int)SchemeWeapon.SuperBananaBomb].Probability = (sbyte)RwKnockForce; + Weapons[(int)SchemeWeapon.MineStrike].Probability = (sbyte)RwMaxRopeSpeed; + byte mbBombProb = ((byte)Weapons[(int)SchemeWeapon.MBBomb].Probability).SetBit(0, RwSelectWormAnytime); + Weapons[(int)SchemeWeapon.MBBomb].Probability = (sbyte)mbBombProb; + + byte[] versionBytes = BitConverter.GetBytes(RwVersionOverride); + Weapons[(int)SchemeWeapon.SelectWorm].Probability = (sbyte)versionBytes[0]; + Weapons[(int)SchemeWeapon.Freeze].Probability = (sbyte)versionBytes[1]; + + Weapons[(int)SchemeWeapon.ConcreteDonkey].Probability = (sbyte)RwViscosity; + Weapons[(int)SchemeWeapon.SuicideBomber].Probability = (sbyte)RwWindPower; + Weapons[(int)SchemeWeapon.Armageddon].Probability = (sbyte)RwWormBouncyness; + } + + // ---- ENUMERATIONS ------------------------------------------------------------------------------------------- + + [Flags] + private enum RwEarthquakeProb : byte + { + None = 0, + AutoReaim = 1 << 0, + CircularAim = 1 << 1, + AntiLockPower = 1 << 2, + ShotDoesntEndTurnAll = 1 << 3 + // Remaining bits represent kaosmod version. + } + + [Flags] + private enum RwMoleSquadronProb : byte + { + None = 0, + ShotDoesntEndTurn = 1 << 0, + LoseControlDoesntEndTurn = 1 << 1, + FireDoesntPauseTimer = 1 << 2, + UpgradedRope = 1 << 3, + CrateShower = 1 << 4, + ObjectPushByExplosion = 1 << 5, + WeaponsDontChange = 1 << 6, + ExtendedFuse = 1 << 7 + } + } + + /// + /// Represents the configuration of a weapon. + /// + [DebuggerDisplay("Ammo={Ammunition} Power={Power} Delay={Delay} Prob={Probability}")] + public struct SchemeWeaponSetting + { + /// + /// The amount of this weapon with which a team is equipped at game start. 10 and negative values represent + /// infinity. + /// + public sbyte Ammunition; + + /// + /// The power of this weapon. + /// + public byte Power; + + /// + /// The number of turns required to be taken by each team before this weapon becomes available. Negative values + /// represenet infinity. + /// + public sbyte Delay; + + /// + /// The percentual chance of this weapon to appear in crates. Has no effect for super weapons. + /// + public sbyte Probability; + } + + #region Enumerations + + /// + /// Represents the known versions of scheme file formats. + /// + public enum SchemeVersion : byte + { + /// + /// The standard format used by WA before version 3.6.28.0 and WWP. It does not store super weapon settings. + /// + Standard = 1, + + /// + /// The extended format used by WA since version 3.6.28.0. + /// + Extended = 2 + } + + /// + /// Represents the possible variations of the options stored in a scheme file. + /// + public enum SchemeSaveFormat + { + /// + /// Represents the format. + /// + Standard, + + /// + /// Represents the format, and does not store object counts. + /// + Extended, + + /// + /// Represents the format, and stores object counts (supported since WA + /// 3.6.28.0). + /// + ExtendedWithObjectCount + } + + /// + /// Represents the fall damage in percent, relative to the normal fall damage being 100%. + /// + public enum SchemeFallDamage + { + /// + /// No fall damage. + /// + None = 0, + + /// + /// 4% fall damage. + /// + Percent4 = 4, + + /// + /// 8% fall damage. + /// + Percent8 = 8, + + /// + /// 12% fall damage. + /// + Percent12 = 12, + + /// + /// 16% fall damage. + /// + Percent16 = 16, + + /// + /// 20% fall damage. + /// + Percent20 = 20, + + /// + /// 24% fall damage. + /// + Percent24 = 24, + + /// + /// 28% fall damage. + /// + Percent28 = 28, + + /// + /// 32% fall damage. + /// + Percent32 = 32, + + /// + /// 36% fall damage. + /// + Percent36 = 36, + + /// + /// 40% fall damage. + /// + Percent40 = 40, + + /// + /// 44% fall damage. + /// + Percent44 = 44, + + /// + /// 48% fall damage. + /// + Percent48 = 48, + + /// + /// 52% fall damage. + /// + Percent52 = 52, + + /// + /// 56% fall damage. + /// + Percent56 = 56, + + /// + /// 60% fall damage. + /// + Percent60 = 60, + + /// + /// 64% fall damage. + /// + Percent64 = 64, + + /// + /// 68% fall damage. + /// + Percent68 = 68, + + /// + /// 72% fall damage. + /// + Percent72 = 72, + + /// + /// 76% fall damage. + /// + Percent76 = 76, + + /// + /// 80% fall damage. + /// + Percent80 = 80, + + /// + /// 84% fall damage. + /// + Percent84 = 84, + + /// + /// 88% fall damage. + /// + Percent88 = 88, + + /// + /// 92% fall damage. + /// + Percent92 = 92, + + /// + /// 96% fall damage. + /// + Percent96 = 96, + + /// + /// 100% fall damage. + /// + Percent100 = 100, + + /// + /// 104% fall damage. + /// + Percent104 = 104, + + /// + /// 108% fall damage. + /// + Percent108 = 108, + + /// + /// 112% fall damage. + /// + Percent112 = 112, + + /// + /// 116% fall damage. + /// + Percent116 = 116, + + /// + /// 120% fall damage. + /// + Percent120 = 120, + + /// + /// 124% fall damage. + /// + Percent124 = 124, + + /// + /// 128% fall damage. + /// + Percent128 = 128, + + /// + /// 132% fall damage. + /// + Percent132 = 132, + + /// + /// 136% fall damage. + /// + Percent136 = 136, + + /// + /// 140% fall damage. + /// + Percent140 = 140, + + /// + /// 144% fall damage. + /// + Percent144 = 144, + + /// + /// 148% fall damage. + /// + Percent148 = 148, + + /// + /// 152% fall damage. + /// + Percent152 = 152, + + /// + /// 156% fall damage. + /// + Percent156 = 156, + + /// + /// 160% fall damage. + /// + Percent160 = 160, + + /// + /// 164% fall damage. + /// + Percent164 = 164, + + /// + /// 168% fall damage. + /// + Percent168 = 168, + + /// + /// 172% fall damage. + /// + Percent172 = 172, + + /// + /// 176% fall damage. + /// + Percent176 = 176, + + /// + /// 180% fall damage. + /// + Percent180 = 180, + + /// + /// 184% fall damage. + /// + Percent184 = 184, + + /// + /// 188% fall damage. + /// + Percent188 = 188, + + /// + /// 192% fall damage. + /// + Percent192 = 192, + + /// + /// 196% fall damage. + /// + Percent196 = 196, + + /// + /// 200% fall damage. + /// + Percent200 = 200, + + /// + /// 204% fall damage. + /// + Percent204 = 204, + + /// + /// 208% fall damage. + /// + Percent208 = 208, + + /// + /// 212% fall damage. + /// + Percent212 = 212, + + /// + /// 216% fall damage. + /// + Percent216 = 216, + + /// + /// 220% fall damage. + /// + Percent220 = 220, + + /// + /// 224% fall damage. + /// + Percent224 = 224, + + /// + /// 228% fall damage. + /// + Percent228 = 228, + + /// + /// 232% fall damage. + /// + Percent232 = 232, + + /// + /// 236% fall damage. + /// + Percent236 = 236, + + /// + /// 240% fall damage. + /// + Percent240 = 240, + + /// + /// 244% fall damage. + /// + Percent244 = 244, + + /// + /// 248% fall damage. + /// + Percent248 = 248, + + /// + /// 252% fall damage. + /// + Percent252 = 252, + + /// + /// 256% fall damage. + /// + Percent256 = 256, + + /// + /// 260% fall damage. + /// + Percent260 = 260, + + /// + /// 264% fall damage. + /// + Percent264 = 264, + + /// + /// 268% fall damage. + /// + Percent268 = 268, + + /// + /// 272% fall damage. + /// + Percent272 = 272, + + /// + /// 276% fall damage. + /// + Percent276 = 276, + + /// + /// 280% fall damage. + /// + Percent280 = 280, + + /// + /// 284% fall damage. + /// + Percent284 = 284, + + /// + /// 288% fall damage. + /// + Percent288 = 288, + + /// + /// 292% fall damage. + /// + Percent292 = 292, + + /// + /// 296% fall damage. + /// + Percent296 = 296, + + /// + /// 300% fall damage. + /// + Percent300 = 300, + + /// + /// 304% fall damage. + /// + Percent304 = 304, + + /// + /// 308% fall damage. + /// + Percent308 = 308, + + /// + /// 312% fall damage. + /// + Percent312 = 312, + + /// + /// 316% fall damage. + /// + Percent316 = 316, + + /// + /// 320% fall damage. + /// + Percent320 = 320, + + /// + /// 324% fall damage. + /// + Percent324 = 324, + + /// + /// 328% fall damage. + /// + Percent328 = 328, + + /// + /// 332% fall damage. + /// + Percent332 = 332, + + /// + /// 336% fall damage. + /// + Percent336 = 336, + + /// + /// 340% fall damage. + /// + Percent340 = 340, + + /// + /// 344% fall damage. + /// + Percent344 = 344, + + /// + /// 348% fall damage. + /// + Percent348 = 348, + + /// + /// 352% fall damage. + /// + Percent352 = 352, + + /// + /// 356% fall damage. + /// + Percent356 = 356, + + /// + /// 360% fall damage. + /// + Percent360 = 360, + + /// + /// 364% fall damage. + /// + Percent364 = 364, + + /// + /// 368% fall damage. + /// + Percent368 = 368, + + /// + /// 372% fall damage. + /// + Percent372 = 372, + + /// + /// 376% fall damage. + /// + Percent376 = 376, + + /// + /// 380% fall damage. + /// + Percent380 = 380, + + /// + /// 384% fall damage. + /// + Percent384 = 384, + + /// + /// 388% fall damage. + /// + Percent388 = 388, + + /// + /// 392% fall damage. + /// + Percent392 = 392, + + /// + /// 396% fall damage. + /// + Percent396 = 396, + + /// + /// 400% fall damage. + /// + Percent400 = 400, + + /// + /// 404% fall damage. + /// + Percent404 = 404, + + /// + /// 408% fall damage. + /// + Percent408 = 408, + + /// + /// 412% fall damage. + /// + Percent412 = 412, + + /// + /// 416% fall damage. + /// + Percent416 = 416, + + /// + /// 420% fall damage. + /// + Percent420 = 420, + + /// + /// 424% fall damage. + /// + Percent424 = 424, + + /// + /// 428% fall damage. + /// + Percent428 = 428, + + /// + /// 432% fall damage. + /// + Percent432 = 432, + + /// + /// 436% fall damage. + /// + Percent436 = 436, + + /// + /// 440% fall damage. + /// + Percent440 = 440, + + /// + /// 444% fall damage. + /// + Percent444 = 444, + + /// + /// 448% fall damage. + /// + Percent448 = 448, + + /// + /// 452% fall damage. + /// + Percent452 = 452, + + /// + /// 456% fall damage. + /// + Percent456 = 456, + + /// + /// 460% fall damage. + /// + Percent460 = 460, + + /// + /// 464% fall damage. + /// + Percent464 = 464, + + /// + /// 468% fall damage. + /// + Percent468 = 468, + + /// + /// 472% fall damage. + /// + Percent472 = 472, + + /// + /// 476% fall damage. + /// + Percent476 = 476, + + /// + /// 480% fall damage. + /// + Percent480 = 480, + + /// + /// 484% fall damage. + /// + Percent484 = 484, + + /// + /// 488% fall damage. + /// + Percent488 = 488, + + /// + /// 492% fall damage. + /// + Percent492 = 492, + + /// + /// 496% fall damage. + /// + Percent496 = 496, + + /// + /// 500% fall damage. + /// + Percent500 = 500, + + /// + /// 504% fall damage. + /// + Percent504 = 504, + + /// + /// 508% fall damage. + /// + Percent508 = 508 + } + + /// + /// Represents the known identifiers of scheme editors stored in schemes modified by them. + /// + public enum SchemeEditor : byte + { + None = 0, + LeTotalKiller = 0x5F, + SchemeEddy = 0x89 + } + + /// + /// Represents the stockpiling mode of weapon armory between rounds. + /// + public enum SchemeStockpiling : byte + { + Off = 0, + On = 1, + Anti = 2 + } + + /// + /// Represents the method to determine the next turn's worm. + /// + public enum SchemeWormSelect : byte + { + Ordered = 0, + Manual = 1, + Random = 2 + } + + /// + /// Represents the event triggered when the round timer runs out. + /// + public enum SchemeSuddenDeathEvent : byte + { + RoundEnd = 0, + NuclearStrike = 1, + HealthDrop = 2 + } + + /// + /// Represents the water rise in pixels after sudden death was triggered. + /// + public enum SchemeWaterRise : byte + { + /// + /// No water rise. + /// + None = 0, + + /// + /// 5 pixels water rise. + /// + Pixels5 = 5, + + /// + /// 13 pixels water rise. + /// + Pixels13 = 13, + + /// + /// 20 pixels water rise. + /// + Pixels20 = 20, + + /// + /// 21 pixels water rise. + /// + Pixels21 = 21, + + /// + /// 29 pixels water rise. + /// + Pixels29 = 29, + + /// + /// 37 pixels water rise. + /// + Pixels37 = 37, + + /// + /// 45 pixels water rise. + /// + Pixels45 = 45, + + /// + /// 52 pixels water rise. + /// + Pixels52 = 52, + + /// + /// 53 pixels water rise. + /// + Pixels53 = 53, + + /// + /// 61 pixels water rise. + /// + Pixels61 = 61, + + /// + /// 64 pixels water rise. + /// + Pixels64 = 64, + + /// + /// 69 pixels water rise. + /// + Pixels69 = 69, + + /// + /// 77 pixels water rise. + /// + Pixels77 = 77, + + /// + /// 80 pixels water rise. + /// + Pixels80 = 80, + + /// + /// 84 pixels water rise. + /// + Pixels84 = 84, + + /// + /// 85 pixels water rise. + /// + Pixels85 = 85, + + /// + /// 93 pixels water rise. + /// + Pixels93 = 93, + + /// + /// 101 pixels water rise. + /// + Pixels101 = 101, + + /// + /// 109 pixels water rise. + /// + Pixels109 = 109, + + /// + /// 116 pixels water rise. + /// + Pixels116 = 116, + + /// + /// 117 pixels water rise. + /// + Pixels117 = 117, + + /// + /// 125 pixels water rise. + /// + Pixels125 = 125, + + /// + /// 133 pixels water rise. + /// + Pixels133 = 133, + + /// + /// 141 pixels water rise. + /// + Pixels141 = 141, + + /// + /// 148 pixels water rise. + /// + Pixels148 = 148, + + /// + /// 149 pixels water rise. + /// + Pixels149 = 149, + + /// + /// 157 pixels water rise. + /// + Pixels157 = 157, + + /// + /// 165 pixels water rise. + /// + Pixels165 = 165, + + /// + /// 173 pixels water rise. + /// + Pixels173 = 173, + + /// + /// 180 pixels water rise. + /// + Pixels180 = 180, + + /// + /// 181 pixels water rise. + /// + Pixels181 = 181, + + /// + /// 189 pixels water rise. + /// + Pixels189 = 189, + + /// + /// 197 pixels water rise. + /// + Pixels197 = 197, + + /// + /// 205 pixels water rise. + /// + Pixels205 = 205, + + /// + /// 208 pixels water rise. + /// + Pixels208 = 208, + + /// + /// 212 pixels water rise. + /// + Pixels212 = 212, + + /// + /// 213 pixels water rise. + /// + Pixels213 = 213, + + /// + /// 221 pixels water rise. + /// + Pixels221 = 221, + + /// + /// 229 pixels water rise. + /// + Pixels229 = 229, + + /// + /// 237 pixels water rise. + /// + Pixels237 = 237, + + /// + /// 244 pixels water rise. + /// + Pixels244 = 244, + + /// + /// 245 pixels water rise. + /// + Pixels245 = 245, + + /// + /// 253 pixels water rise. + /// + Pixels253 = 253 + } + + /// + /// Represents the types of objects which can appear on the map. + /// + [Flags] + public enum SchemeObjectType + { + None = 0, + Mines = 1 << 0, + OilDrums = 1 << 1 + } + + /// + /// Represents the possible maximum number of objects which can appear on the map. + /// + public enum SchemeObjectCount + { + /// + /// No objects. + /// + None = 0, + + /// + /// Up to 1 object. + /// + Count1 = 1, + + /// + /// Up to 2 objects. + /// + Count2 = 2, + + /// + /// Up to 3 objects. + /// + Count3 = 3, + + /// + /// Up to 4 objects. + /// + Count4 = 4, + + /// + /// Up to 5 objects. + /// + Count5 = 5, + + /// + /// Up to 6 objects. + /// + Count6 = 6, + + /// + /// Up to 7 objects. + /// + Count7 = 7, + + /// + /// Up to 8 objects. + /// + Count8 = 8, + + /// + /// Up to 9 objects. + /// + Count9 = 9, + + /// + /// Up to 10 objects. + /// + Count10 = 10, + + /// + /// Up to 11 objects. + /// + Count11 = 11, + + /// + /// Up to 12 objects. + /// + Count12 = 12, + + /// + /// Up to 13 objects. + /// + Count13 = 13, + + /// + /// Up to 14 objects. + /// + Count14 = 14, + + /// + /// Up to 15 objects. + /// + Count15 = 15, + + /// + /// Up to 16 objects. + /// + Count16 = 16, + + /// + /// Up to 17 objects. + /// + Count17 = 17, + + /// + /// Up to 18 objects. + /// + Count18 = 18, + + /// + /// Up to 19 objects. + /// + Count19 = 19, + + /// + /// Up to 20 objects. + /// + Count20 = 20, + + /// + /// Up to 21 objects. + /// + Count21 = 21, + + /// + /// Up to 22 objects. + /// + Count22 = 22, + + /// + /// Up to 23 objects. + /// + Count23 = 23, + + /// + /// Up to 24 objects. + /// + Count24 = 24, + + /// + /// Up to 25 objects. + /// + Count25 = 25, + + /// + /// Up to 26 objects. + /// + Count26 = 26, + + /// + /// Up to 27 objects. + /// + Count27 = 27, + + /// + /// Up to 28 objects. + /// + Count28 = 28, + + /// + /// Up to 29 objects. + /// + Count29 = 29, + + /// + /// Up to 30 objects. + /// + Count30 = 30, + + /// + /// Up to 35 objects. + /// + Count35 = 35, + + /// + /// Up to 40 objects. + /// + Count40 = 40, + + /// + /// Up to 45 objects. + /// + Count45 = 45, + + /// + /// Up to 50 objects. + /// + Count50 = 50, + + /// + /// Up to 55 objects. + /// + Count55 = 55, + + /// + /// Up to 60 objects. + /// + Count60 = 60, + + /// + /// Up to 65 objects. + /// + Count65 = 65, + + /// + /// Up to 70 objects. + /// + Count70 = 70, + + /// + /// Up to 75 objects. + /// + Count75 = 75, + + /// + /// Up to 80 objects. + /// + Count80 = 80, + + /// + /// Up to 85 objects. + /// + Count85 = 85, + + /// + /// Up to 90 objects. + /// + Count90 = 90, + + /// + /// Up to 95 objects. + /// + Count95 = 95, + + /// + /// Up to 100 objects. + /// + Count100 = 100, + + /// + /// Up to 110 objects. + /// + Count110 = 110, + + /// + /// Up to 120 objects. + /// + Count120 = 120, + + /// + /// Up to 130 objects. + /// + Count130 = 130, + + /// + /// Up to 140 objects. + /// + Count140 = 140, + + /// + /// Up to 150 objects. + /// + Count150 = 150, + + /// + /// Up to 160 objects. + /// + Count160 = 160, + + /// + /// Up to 170 objects. + /// + Count170 = 170, + + /// + /// Up to 180 objects. + /// + Count180 = 180, + + /// + /// Up to 190 objects. + /// + Count190 = 190, + + /// + /// Up to 200 objects. + /// + Count200 = 200, + + /// + /// Up to 210 objects. + /// + Count210 = 210, + + /// + /// Up to 220 objects. + /// + Count220 = 220, + + /// + /// Up to 230 objects. + /// + Count230 = 230, + + /// + /// Up to 240 objects. + /// + Count240 = 240, + + /// + /// Up to 250 objects. + /// + Count250 = 250 + } + + /// + /// Represents the weapons in the game. + /// + public enum SchemeWeapon + { + /// + /// The Bazooka weapon. + /// + Bazooka, + + /// + /// The Homing Missile weapon. + /// + HomingMissile, + + /// + /// The Mortar weapon. + /// + Mortar, + + /// + /// The Grenade weapon. + /// + Grenade, + + /// + /// The Cluster Bomb weapon. + /// + ClusterBomb, + + /// + /// The Skunk weapon. + /// + Skunk, + + /// + /// The Petrol Bomb weapon. + /// + PetrolBomb, + + /// + /// The Banana Bomb weapon. + /// + BananaBomb, + + /// + /// The Handgun weapon. + /// + Handgun, + + /// + /// The Shotgun weapon. + /// + Shotgun, + + /// + /// The Uzi weapon. + /// + Uzi, + + /// + /// The Minigun weapon. + /// + Minigun, + + /// + /// The Longbow weapon. + /// + Longbow, + + /// + /// The Airstrike weapon. + /// + Airstrike, + + /// + /// The Napalm Strike weapon. + /// + NapalmStrike, + + /// + /// The Mine weapon. + /// + Mine, + + /// + /// The Fire Punch weapon. + /// + FirePunch, + + /// + /// The Dragon Ball weapon. + /// + DragonBall, + + /// + /// The Kamikaze weapon. + /// + Kamikaze, + + /// + /// The Prod weapon. + /// + Prod, + + /// + /// The Battle Axe weapon. + /// + BattleAxe, + + /// + /// The Blowtorch weapon. + /// + Blowtorch, + + /// + /// The Pneumatic Drill weapon. + /// + PneumaticDrill, + + /// + /// The Girder weapon. + /// + Girder, + + /// + /// The Ninja Rope weapon. + /// + NinjaRope, + + /// + /// The Parachute weapon. + /// + Parachute, + + /// + /// The Bungee weapon. + /// + Bungee, + + /// + /// The Teleport weapon. + /// + Teleport, + + /// + /// The Dynamite weapon. + /// + Dynamite, + + /// + /// The Sheep weapon. + /// + Sheep, + + /// + /// The Baseball Bat weapon. + /// + BaseballBat, + + /// + /// The Flame Thrower weapon. + /// + FlameThrower, + + /// + /// The Homing Pigeon weapon. + /// + HomingPigeon, + + /// + /// The Mad Cow weapon. + /// + MadCow, + + /// + /// The Holy Hand Grenade weapon. + /// + HolyHandGrenade, + + /// + /// The Old Woman weapon. + /// + OldWoman, + + /// + /// The Sheep Launcher weapon. + /// + SheepLauncher, + + /// + /// The Super Sheep or Aqua Sheep weapon. + /// + SuperSheep, + + /// + /// The Mole Bomb weapon. + /// + MoleBomb, + + /// + /// The Jet Pack utility. + /// + JetPack, + + /// + /// The Low Gravity utility. + /// + LowGravity, + + /// + /// The Laser Sight utility. + /// + LaserSight, + + /// + /// The Fast Walk utility. + /// + FastWalk, + + /// + /// The Invisibility utility. + /// + Invisibility, + + /// + /// The Damage x2 utility. + /// + DamageX2, + + /// + /// The Freeze super weapon. + /// + Freeze, + + /// + /// The Super Banana Bomb super weapon. + /// + SuperBananaBomb, + + /// + /// The Mine Strike super weapon. + /// + MineStrike, + + /// + /// The Girder Starter Pack super weapon. + /// + GirderStarterPack, + + /// + /// The Earthquake super weapon. + /// + Earthquake, + + /// + /// The Scales Of Justice super weapon. + /// + ScalesOfJustice, + + /// + /// The Ming Vase super weapon. + /// + MingVase, + + /// + /// The Mike's Carpet Bomb super weapon. + /// + MikesCarpetBomb, + + /// + /// The Patsy's Magic Bullet super weapon. + /// + MagicBullet, + + /// + /// The Indian Nuclear Test super weapon. + /// + NuclearTest, + + /// + /// The Select Worm super weapon. + /// + SelectWorm, + + /// + /// The Salvation Army super weapon. + /// + SalvationArmy, + + /// + /// The Mole Squadron super weapon. + /// + MoleSquadron, + + /// + /// The MB Bomb super weapon. + /// + MBBomb, + + /// + /// The Concrete Donkey super weapon. + /// + ConcreteDonkey, + + /// + /// The Suicide Bomber super weapon. + /// + SuicideBomber, + + /// + /// The Sheep Strike super weapon. + /// + SheepStrike, + + /// + /// The Mail Strike super weapon. + /// + MailStrike, + + /// + /// The Armageddon super weapon. + /// + Armageddon + } + + #endregion +} diff --git a/src/Syroot.Worms/Syroot.Worms.csproj b/src/Syroot.Worms/Syroot.Worms.csproj index 8d2376b..90a2080 100644 --- a/src/Syroot.Worms/Syroot.Worms.csproj +++ b/src/Syroot.Worms/Syroot.Worms.csproj @@ -2,7 +2,7 @@ .NET library to load and modify file formats of Team17 Worms games. - MIT + (c) Syroot, licensed under MIT Syroot.Worms Worms Syroot @@ -17,19 +17,25 @@ git https://github.com/Syroot/Worms - netstandard1.6 - true + net45;netstandard1.6 - - - - - - - - + + + + + + + + portable + + + + none + true + + \ No newline at end of file