mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-03-04 01:15:21 +03:00
Overhaul implementations and documentation.
This commit is contained in:
parent
8b92e6a8be
commit
5321dfb49a
7
.gitattributes
vendored
7
.gitattributes
vendored
@ -1 +1,8 @@
|
||||
*.dat filter=lfs diff=lfs merge=lfs -text
|
||||
*.img filter=lfs diff=lfs merge=lfs -text
|
||||
*.pxl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pxs filter=lfs diff=lfs merge=lfs -text
|
||||
*.wgt filter=lfs diff=lfs merge=lfs -text
|
||||
*.wsc filter=lfs diff=lfs merge=lfs -text
|
||||
*.wwp filter=lfs diff=lfs merge=lfs -text
|
||||
src/test/Syroot.Worms.Armageddon.Test/Files/Schemes/WA/Wsdb/dump.csv filter=lfs diff=lfs merge=lfs -text
|
||||
|
8
src/010editor/Common.bt
Normal file
8
src/010editor/Common.bt
Normal file
@ -0,0 +1,8 @@
|
||||
void FAlign(byte alignment)
|
||||
{
|
||||
local int bytesToSkip <hidden=true> = (-FTell() % alignment + alignment) % alignment;
|
||||
while (bytesToSkip--)
|
||||
{
|
||||
byte padding <fgcolor=0x808080, hidden=true>;
|
||||
}
|
||||
}
|
18
src/010editor/IMG.bt
Normal file
18
src/010editor/IMG.bt
Normal file
@ -0,0 +1,18 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: IMG.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms Armageddon and Worms World Party image files.
|
||||
// Category: Worms
|
||||
// File Mask: *.img
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-29 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
Image image <open=true>;
|
74
src/010editor/Image.bt
Normal file
74
src/010editor/Image.bt
Normal file
@ -0,0 +1,74 @@
|
||||
#include "Common.bt"
|
||||
|
||||
typedef struct(char description, char align)
|
||||
{
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1A474D49) // "IMG\x1A"
|
||||
{
|
||||
Warning("Invalid IMG signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
uint fileSize;
|
||||
|
||||
if (description)
|
||||
string description;
|
||||
|
||||
ubyte bpp;
|
||||
enum <ubyte> Flags
|
||||
{
|
||||
IMG_COMPRESSED = 1 << 6,
|
||||
IMG_PALETTIZED = 1 << 7
|
||||
} flags;
|
||||
|
||||
if (flags & IMG_PALETTIZED)
|
||||
{
|
||||
ushort colorCount;
|
||||
struct Color
|
||||
{
|
||||
ubyte r;
|
||||
ubyte g;
|
||||
ubyte b;
|
||||
} colors[colorCount];
|
||||
}
|
||||
|
||||
ushort width;
|
||||
ushort height;
|
||||
|
||||
if (align)
|
||||
FAlign(4);
|
||||
|
||||
if (flags & IMG_COMPRESSED)
|
||||
char data[GetCompressedImgSize()];
|
||||
else
|
||||
char data[bpp / 8.0 * width * height];
|
||||
} Image;
|
||||
|
||||
int GetCompressedImgSize()
|
||||
{
|
||||
local int pos = FTell();
|
||||
local int start = pos;
|
||||
local int cmd;
|
||||
while ((cmd = ReadByte(pos++)) != -1)
|
||||
{
|
||||
// Read a byte.
|
||||
if ((cmd & 0x80) != 0)
|
||||
{
|
||||
local int arg1 = cmd >> 3 & 0b1111; // bits 2-5
|
||||
local int arg2 = ReadByte(pos++);
|
||||
if (arg2 == -1)
|
||||
break;
|
||||
// Arg2 = bits 6-16
|
||||
arg2 = ((cmd << 8) | arg2) & 0x7FF;
|
||||
if (arg1 == 0)
|
||||
{
|
||||
// Command: 0x80 0x00
|
||||
if (arg2 == 0)
|
||||
break;
|
||||
if (ReadByte(pos++) == -1)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pos - start;
|
||||
}
|
20
src/010editor/OW_PAL.bt
Normal file
20
src/010editor/OW_PAL.bt
Normal file
@ -0,0 +1,20 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: OW_PAL.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Online Worms PAL color palettes.
|
||||
// Category: Worms
|
||||
// File Mask: *.pal
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
LittleEndian();
|
||||
|
||||
struct Color
|
||||
{
|
||||
ubyte r, g, b;
|
||||
} colors[256];
|
44
src/010editor/W2_LandDAT.bt
Normal file
44
src/010editor/W2_LandDAT.bt
Normal file
@ -0,0 +1,44 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: W2_LandDAT.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms 2 land generator data files.
|
||||
// Category: Worms
|
||||
// File Mask: land.dat
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1A444E4C) // "LND\x1A"
|
||||
{
|
||||
Warning("Invalid LND signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
int mapWidth;
|
||||
int mapHeight;
|
||||
int hasCavernBorder;
|
||||
int numObjectLocations;
|
||||
struct ObjectLocation
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} objectLocations[numObjectLocations];
|
||||
int unknown;
|
||||
Image foregroundImage(true, false);
|
||||
Image collisionImage(true, false);
|
||||
Image backgroundImage(true, false);
|
||||
Image unknownImage(true, false);
|
||||
ubyte landTexPathLength;
|
||||
char landTexPath[landTexPathLength];
|
||||
ubyte waterDirPathLength;
|
||||
char waterDirPath[waterDirPathLength];
|
43
src/010editor/WA3.0_LandDAT.bt
Normal file
43
src/010editor/WA3.0_LandDAT.bt
Normal file
@ -0,0 +1,43 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: WA3.0_LandDAT.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms Armageddon (older than 3.6.28.0) land generator data files.
|
||||
// Category: Worms
|
||||
// File Mask: land.dat
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1A444E4C) // "LND\x1A"
|
||||
{
|
||||
Warning("Invalid LND signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
int mapWidth;
|
||||
int mapHeight;
|
||||
int hasCavernBorder;
|
||||
int waterHeight;
|
||||
int numObjectLocations;
|
||||
struct ObjectLocation
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} objectLocations[numObjectLocations];
|
||||
Image foregroundImage(false, false);
|
||||
Image collisionImage(false, false);
|
||||
Image backgroundImage(false, false);
|
||||
ubyte landTexPathLength;
|
||||
char landTexPath[landTexPathLength];
|
||||
ubyte waterDirPathLength;
|
||||
char waterDirPath[waterDirPathLength];
|
44
src/010editor/WA3.6_LandDAT.bt
Normal file
44
src/010editor/WA3.6_LandDAT.bt
Normal file
@ -0,0 +1,44 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: WA3.6_LandDAT.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms Armageddon (3.6.28.0 and newer) land generator data files.
|
||||
// Category: Worms
|
||||
// File Mask: land.dat
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1A444E4C) // "LND\x1A"
|
||||
{
|
||||
Warning("Invalid LND signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
int mapWidth;
|
||||
int mapHeight;
|
||||
int hasCavernBorder;
|
||||
int waterHeight;
|
||||
int holeCount;
|
||||
int numObjectLocations;
|
||||
struct ObjectLocation
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} objectLocations[numObjectLocations];
|
||||
Image foregroundImage(false, false);
|
||||
Image collisionImage(false, false);
|
||||
Image backgroundImage(false, false);
|
||||
ubyte landTexPathLength;
|
||||
char landTexPath[landTexPathLength];
|
||||
ubyte waterDirPathLength;
|
||||
char waterDirPath[waterDirPathLength];
|
44
src/010editor/WWPA_LandDAT.bt
Normal file
44
src/010editor/WWPA_LandDAT.bt
Normal file
@ -0,0 +1,44 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: WWPA_LandDAT.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms World Party Aqua land generator data files.
|
||||
// Category: Worms
|
||||
// File Mask: land.dat
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1B444E4C) // "LND\x1B"
|
||||
{
|
||||
Warning("Invalid LND signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
int mapWidth;
|
||||
int mapHeight;
|
||||
int hasCavernBorder;
|
||||
int waterHeight;
|
||||
int holeCount;
|
||||
int numObjectLocations;
|
||||
struct ObjectLocation
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} objectLocations[numObjectLocations];
|
||||
Image foregroundImage(false, true);
|
||||
Image collisionImage(false, true);
|
||||
Image backgroundImage(false, true);
|
||||
ubyte landTexPathLength;
|
||||
char landTexPath[landTexPathLength];
|
||||
ubyte waterDirPathLength;
|
||||
char waterDirPath[waterDirPathLength];
|
43
src/010editor/WWP_LandDAT.bt
Normal file
43
src/010editor/WWP_LandDAT.bt
Normal file
@ -0,0 +1,43 @@
|
||||
//------------------------------------------------
|
||||
//--- 010 Editor v10.0.2 Binary Template
|
||||
//
|
||||
// File: WWP_LandDAT.bt
|
||||
// Authors: Syroot
|
||||
// Version: 0.1.0
|
||||
// Purpose: Parse Worms World Party land generator data files.
|
||||
// Category: Worms
|
||||
// File Mask: land.dat
|
||||
// ID Bytes:
|
||||
// History:
|
||||
// 0.1.0 2020-06-30 Initial version.
|
||||
//------------------------------------------------
|
||||
|
||||
#include "Image.bt"
|
||||
|
||||
LittleEndian();
|
||||
|
||||
uint signature <format=hex>;
|
||||
if (signature != 0x1A444E4C) // "LND\x1A"
|
||||
{
|
||||
Warning("Invalid LND signature.");
|
||||
Exit(-1);
|
||||
}
|
||||
|
||||
int fileSize;
|
||||
int mapWidth;
|
||||
int mapHeight;
|
||||
int hasCavernBorder;
|
||||
int waterHeight;
|
||||
int numObjectLocations;
|
||||
struct ObjectLocation
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} objectLocations[numObjectLocations];
|
||||
Image foregroundImage(false, true);
|
||||
Image collisionImage(false, true);
|
||||
Image backgroundImage(false, true);
|
||||
ubyte landTexPathLength;
|
||||
char landTexPath[landTexPathLength];
|
||||
ubyte waterDirPathLength;
|
||||
char waterDirPath[waterDirPathLength];
|
@ -44,8 +44,11 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = " Solution Items", " Solution Items", "{8A49F314-1011-4819-A8F6-0EDDA94A9C3D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
build.xml = build.xml
|
||||
test.xml = test.xml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.SchemeEditor", "tool\Syroot.Worms.SchemeEditor\Syroot.Worms.SchemeEditor.csproj", "{4ACE4589-4478-4B4D-8179-87A491B79DAE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -116,6 +119,10 @@ Global
|
||||
{1FAB6B9F-2585-46DC-81C0-579DC808C389}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FAB6B9F-2585-46DC-81C0-579DC808C389}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FAB6B9F-2585-46DC-81C0-579DC808C389}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4ACE4589-4478-4B4D-8179-87A491B79DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4ACE4589-4478-4B4D-8179-87A491B79DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4ACE4589-4478-4B4D-8179-87A491B79DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4ACE4589-4478-4B4D-8179-87A491B79DAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -137,6 +144,7 @@ Global
|
||||
{392E4CA2-61D9-4BE1-B065-8801A9F102B8} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{212F8090-9775-4098-BD44-9ABC01FBE553} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
|
||||
{1FAB6B9F-2585-46DC-81C0-579DC808C389} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{4ACE4589-4478-4B4D-8179-87A491B79DAE} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1CD4EDE2-A5FB-4A58-A850-3506AB7E7B69}
|
||||
|
@ -18,7 +18,8 @@
|
||||
<!-- Compilation -->
|
||||
<PropertyGroup>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
|
||||
</PropertyGroup>
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
public object Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
|
||||
public object? Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
|
||||
ByteConverter byteConverter)
|
||||
{
|
||||
ExplosionAction explosionAction = instance switch
|
||||
@ -19,11 +19,12 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
};
|
||||
return explosionAction switch
|
||||
{
|
||||
ExplosionAction.None => null,
|
||||
ExplosionAction.Bounce => stream.ReadObject<BounceAction>(),
|
||||
ExplosionAction.Dig => stream.ReadObject<DigAction>(),
|
||||
ExplosionAction.Home => stream.ReadObject<HomeAction>(),
|
||||
ExplosionAction.Roam => stream.ReadObject<RoamAction>(),
|
||||
_ => null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
@ -177,7 +177,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private object _value;
|
||||
private object _value = null!;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -198,7 +198,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
/// <summary>
|
||||
/// Gets or sets the name under which this item is stored.
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
public string Key { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of the item.
|
||||
|
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
@ -44,17 +45,17 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
|
||||
public SchemeFlags Flags { get; set; }
|
||||
|
||||
public List<Weapon[]> WeaponTables { get; set; }
|
||||
public IList<Weapon[]> WeaponTables { get; set; } = new List<Weapon[]>();
|
||||
|
||||
public Dictionary<string, byte[]> Files { get; set; }
|
||||
public IDictionary<string, byte[]> Files { get; set; } = new Dictionary<string, byte[]>();
|
||||
|
||||
public Dictionary<string, string> Scripts { get; set; }
|
||||
public IDictionary<string, string> Scripts { get; set; } = new Dictionary<string, string>();
|
||||
|
||||
public List<string> Libraries { get; set; }
|
||||
public IList<string> Libraries { get; set; } = new List<string>();
|
||||
|
||||
public string GameSchemeName { get; set; }
|
||||
public string GameSchemeName { get; set; } = String.Empty;
|
||||
|
||||
public Armageddon.Scheme GameScheme { get; set; }
|
||||
public Armageddon.Scheme? GameScheme { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -75,7 +76,12 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
int weaponTableCount = reader.ReadInt32();
|
||||
WeaponTables = new List<Weapon[]>(weaponTableCount);
|
||||
for (int i = 0; i < weaponTableCount; i++)
|
||||
WeaponTables.Add(reader.Load<Weapon>(_weaponsPerTable));
|
||||
{
|
||||
Weapon[] weaponTable = new Weapon[_weaponsPerTable];
|
||||
for (int j = 0; j < _weaponsPerTable; j++)
|
||||
weaponTable[j] = reader.Load<Weapon>();
|
||||
WeaponTables.Add(weaponTable);
|
||||
}
|
||||
|
||||
// Read a placeholder array.
|
||||
reader.Seek(sizeof(int));
|
||||
@ -132,7 +138,8 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
// Write the weapon tables.
|
||||
writer.Write(WeaponTables.Count);
|
||||
foreach (Weapon[] weaponTable in WeaponTables)
|
||||
writer.Save(weaponTable);
|
||||
for (int i = 0; i < _weaponsPerTable; i++)
|
||||
writer.Save(weaponTable[i]);
|
||||
|
||||
// Write a placeholder array.
|
||||
writer.Write(0);
|
||||
|
@ -19,7 +19,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
public WeaponAirstrikeSubstyle AirstrikeSubstyle;
|
||||
|
||||
[BinaryMember(Converter = typeof(AirstrikeSubstyleConverter))]
|
||||
public IStyle Style;
|
||||
public IStyle? Style;
|
||||
}
|
||||
|
||||
public enum WeaponAirstrikeSubstyle : int
|
||||
|
@ -20,7 +20,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
WeaponAirstrikeSubstyle.Launcher => stream.ReadObject<LauncherStyle>(),
|
||||
WeaponAirstrikeSubstyle.Mines => stream.ReadObject<MineStyle>(),
|
||||
_ => null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,13 +47,13 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
public ExplosionAction ExplosionAction { get; set; }
|
||||
|
||||
[BinaryMember(Converter = typeof(ActionConverter))]
|
||||
public IAction Action { get; set; }
|
||||
public IAction? Action { get; set; }
|
||||
|
||||
[BinaryMember(OffsetOrigin = OffsetOrigin.Begin, Offset = 180)]
|
||||
public ExplosionTarget ExplosionTarget { get; set; }
|
||||
|
||||
[BinaryMember(Offset = sizeof(int), Converter = typeof(TargetConverter))]
|
||||
public ITarget Target { get; set; }
|
||||
public ITarget? Target { get; set; }
|
||||
}
|
||||
|
||||
public enum ExplosionAction : int
|
||||
|
@ -3,9 +3,9 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Syroot.Worms.Armageddon.ProjectX</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Worms Armageddon ProjectX.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation.</PackageReleaseNotes>
|
||||
<PackageTags>$(PackageTags);project x;worms armageddon</PackageTags>
|
||||
<Version>3.2.0</Version>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms.Armageddon\Syroot.Worms.Armageddon.csproj" />
|
||||
|
@ -50,6 +50,6 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
public ExplosionAction ExplosionAction { get; set; }
|
||||
|
||||
[BinaryMember(Converter = typeof(ActionConverter))]
|
||||
public IAction Action { get; set; }
|
||||
public IAction? Action { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
public object Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
|
||||
public object? Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
|
||||
ByteConverter byteConverter)
|
||||
{
|
||||
ExplosionTarget explosionTarget = instance switch
|
||||
@ -18,9 +18,10 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
};
|
||||
return explosionTarget switch
|
||||
{
|
||||
ExplosionTarget.None => null,
|
||||
ExplosionTarget.Clusters => stream.ReadObject<ClusterTarget>(),
|
||||
ExplosionTarget.Fire => stream.ReadObject<FireTarget>(),
|
||||
_ => null,
|
||||
_ => throw new NotImplementedException(),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
@ -49,7 +50,7 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
|
||||
public WeaponThrowAction ThrowAction { get; set; }
|
||||
|
||||
public IStyle Style { get; set; }
|
||||
public IStyle? Style { get; set; }
|
||||
|
||||
public bool AmmunitionOverride { get; set; }
|
||||
|
||||
@ -59,15 +60,15 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
|
||||
public int WeaponSprite { get; set; }
|
||||
|
||||
public string NameLong { get; set; }
|
||||
public string NameLong { get; set; } = String.Empty;
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
public string GridImageFile { get; set; }
|
||||
public string GridImageFile { get; set; } = String.Empty;
|
||||
|
||||
public string GfxDirectoryFile { get; set; }
|
||||
public string GfxDirectoryFile { get; set; } = String.Empty;
|
||||
|
||||
public string[] SpriteNames { get; set; }
|
||||
public string[] SpriteNames { get; } = new string[5];
|
||||
|
||||
public bool DelayOverride { get; set; }
|
||||
|
||||
@ -75,27 +76,27 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
|
||||
public bool UseLibrary { get; set; }
|
||||
|
||||
public string LibraryName { get; set; }
|
||||
public string LibraryName { get; set; } = String.Empty;
|
||||
|
||||
public string LibraryWeaponName { get; set; }
|
||||
public string LibraryWeaponName { get; set; } = String.Empty;
|
||||
|
||||
public string AimSpriteEven { get; set; }
|
||||
public string AimSpriteEven { get; set; } = String.Empty;
|
||||
|
||||
public string AimSpriteUphill { get; set; }
|
||||
public string AimSpriteUphill { get; set; } = String.Empty;
|
||||
|
||||
public string AimSpriteDownhill { get; set; }
|
||||
public string AimSpriteDownhill { get; set; } = String.Empty;
|
||||
|
||||
public string PickSpriteEven { get; set; }
|
||||
public string PickSpriteEven { get; set; } = String.Empty;
|
||||
|
||||
public string PickSpriteUphill { get; set; }
|
||||
public string PickSpriteUphill { get; set; } = String.Empty;
|
||||
|
||||
public string PickSpriteDownhill { get; set; }
|
||||
public string PickSpriteDownhill { get; set; } = String.Empty;
|
||||
|
||||
public string FireSpriteEven { get; set; }
|
||||
public string FireSpriteEven { get; set; } = String.Empty;
|
||||
|
||||
public string FireSpriteUphill { get; set; }
|
||||
public string FireSpriteUphill { get; set; } = String.Empty;
|
||||
|
||||
public string FireSpriteDownhill { get; set; }
|
||||
public string FireSpriteDownhill { get; set; } = String.Empty;
|
||||
|
||||
public bool AimSpriteOverride { get; set; }
|
||||
|
||||
@ -244,7 +245,8 @@ namespace Syroot.Worms.Armageddon.ProjectX
|
||||
Name = reader.ReadString(StringCoding.Int32CharCount);
|
||||
GridImageFile = reader.ReadString(StringCoding.Int32CharCount);
|
||||
GfxDirectoryFile = reader.ReadString(StringCoding.Int32CharCount);
|
||||
SpriteNames = reader.ReadStrings(5, StringCoding.Int32CharCount);
|
||||
for (int i = 0; i < SpriteNames.Length; i++)
|
||||
SpriteNames[i] = reader.ReadString(StringCoding.Int32CharCount);
|
||||
DelayOverride = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
Delay = reader.ReadInt32();
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents <see cref="MapGeneratorSettings"/> stored in a LEV file.
|
||||
/// Represents <see cref="MapGenSettings"/> stored in a LEV file.
|
||||
/// Used by WA and WWP. S. https://worms2d.info/Monochrome_map_(.bit,_.lev).
|
||||
/// </summary>
|
||||
public class GeneratedMap : ILoadableFile, ISaveableFile
|
||||
@ -34,9 +35,9 @@ namespace Syroot.Worms.Armageddon
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="MapGeneratorSettings"/>.
|
||||
/// Gets or sets the <see cref="MapGenSettings"/>.
|
||||
/// </summary>
|
||||
public MapGeneratorSettings Settings { get; set; }
|
||||
public MapGenSettings Settings { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -44,7 +45,7 @@ namespace Syroot.Worms.Armageddon
|
||||
public void Load(Stream stream)
|
||||
{
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
Settings = reader.ReadStruct<MapGeneratorSettings>();
|
||||
Settings = reader.ReadStruct<MapGenSettings>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>>
|
||||
@ -68,4 +69,107 @@ namespace Syroot.Worms.Armageddon
|
||||
Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the required configuration for the land generator to create a map. This structure appears in LEV
|
||||
/// files (being their only content), in BIT files (being the header) and in PNG maps stored by WA (being the data
|
||||
/// of the w2lv or waLV chunks).
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MapGenSettings
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Random seed to generate the land shape (no effect in BIT files).</summary>
|
||||
public int LandSeed;
|
||||
/// <summary>Random seed to generate object placements.</summary>
|
||||
public int ObjectSeed;
|
||||
/// <summary><see langword="true"/> treats the generated map as a cavern, otherwise as an island, depending on
|
||||
/// <see cref="Style"/>.</summary>
|
||||
public bool Cavern;
|
||||
/// <summary>Style of the land generated, dependending on <see cref="Cavern"/>.</summary>
|
||||
public MapGenStyle Style;
|
||||
/// <summary><see langword="true"/> to disable an indestructible border being placed around the map.</summary>
|
||||
public bool NoIndiBorders;
|
||||
/// <summary>Probability percentage of map objects to appear on the land, from 0-100.</summary>
|
||||
public int ObjectPercentage;
|
||||
/// <summary>Probability percentage of bridges to appear on the land, from 0-100.</summary>
|
||||
public int BridgePercentage;
|
||||
/// <summary>Height of the water in percent, from 0-99.</summary>
|
||||
public int WaterLevel;
|
||||
/// <summary>Version of the structure, determining the available <see cref="SoilTextureIndex"/> values in Worms
|
||||
/// Armageddon.</summary>
|
||||
public MapGenVersion Version;
|
||||
/// <summary>Texture index determining the style of the generated map.</summary>
|
||||
public MapGenSoil SoilTextureIndex;
|
||||
/// <summary>Water color used for the map (deprecated, used only in Worms Armageddon 1.0).</summary>
|
||||
public int WaterColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible land styles.
|
||||
/// </summary>
|
||||
public enum MapGenStyle : int
|
||||
{
|
||||
/// <summary>A single island or a cavern.</summary>
|
||||
OneIslandOrCavern,
|
||||
/// <summary>Two islands or a double-layer cavern.</summary>
|
||||
TwoIslandsOrCaverns,
|
||||
/// <summary>One flat island or a cavern open at the bottom.</summary>
|
||||
OneFlatIslandOrCavernOpenBottom,
|
||||
/// <summary>Two flat islands or a cavern open at the left or right.</summary>
|
||||
TwoFlatIslandsOrCavernOpenLeftRight
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible versions which can be stored in the <see cref="MapGenSettings.Version"/> field.
|
||||
/// </summary>
|
||||
public enum MapGenVersion : short
|
||||
{
|
||||
/// <summary>Game version 3.0. Last soil texture indices are 26 = Tribal, 27 = Tribal, 28 = Urban. Additionally,
|
||||
/// floor and ceiling trimming is more severe.</summary>
|
||||
Version_3_0_0_0 = -1,
|
||||
/// <summary>Game version 3.5. Last soil texture indices are 26 = Tribal, 27 = Urban, 28 = undefined.</summary>
|
||||
Version_3_5_0_0 = 0,
|
||||
/// <summary>Game version 3.6.26.4. Last soil texture indices are 26 = Tools, 27 = Tribal, Urban = 28 (same as
|
||||
/// in WWP).</summary>
|
||||
Version_3_6_26_4 = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible soil styles. In case of Worms Armageddon, this list matches
|
||||
/// <see cref="MapGenVersion.Version_3_6_26_4"/>.
|
||||
/// </summary>
|
||||
public enum MapGenSoil : short
|
||||
{
|
||||
ClassicBeach,
|
||||
ClassicDesert,
|
||||
ClassicFarm,
|
||||
ClassicForest,
|
||||
ClassicHell,
|
||||
Art,
|
||||
Cheese,
|
||||
Construction,
|
||||
Desert,
|
||||
Dungeon,
|
||||
Easter,
|
||||
Forest,
|
||||
Fruit,
|
||||
Gulf,
|
||||
Hell,
|
||||
Hospital,
|
||||
Jungle,
|
||||
Manhattan,
|
||||
Medieval,
|
||||
Music,
|
||||
Pirate,
|
||||
Snow,
|
||||
Space,
|
||||
Sports,
|
||||
Tentacle,
|
||||
Time,
|
||||
Tools,
|
||||
Tribal,
|
||||
Urban
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents map configuration stored by the land generator in LAND.DAT files.
|
||||
/// Used by WA. S. https://worms2d.info/Land_Data_file.
|
||||
/// Used by WA and WWP. S. https://worms2d.info/Land_Data_file.
|
||||
/// </summary>
|
||||
public class LandData : ILoadableFile, ISaveableFile
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private const int _signature = 0x1A444E4C; // "LND", 0x1A
|
||||
private bool _alignImgData;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -38,6 +41,20 @@ namespace Syroot.Worms.Armageddon
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the format version of the file.
|
||||
/// </summary>
|
||||
public LandDataVersion Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether image data is aligned by 4-bytes. This is the case only for WWP.
|
||||
/// </summary>
|
||||
public bool AlignImgData
|
||||
{
|
||||
get => _alignImgData;
|
||||
set => _alignImgData = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the landscape in pixels.
|
||||
/// </summary>
|
||||
@ -54,39 +71,39 @@ namespace Syroot.Worms.Armageddon
|
||||
public int WaterHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value.
|
||||
/// Gets or sets an unknown value only available in newer W:A versions (apparently since 3.6.28.0).
|
||||
/// </summary>
|
||||
public int Unknown { get; set; }
|
||||
public int? Unknown { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an array of coordinates at which objects can be placed.
|
||||
/// </summary>
|
||||
public Point[] ObjectLocations { get; set; }
|
||||
public IList<Point> ObjectLocations { get; set; } = new List<Point>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual foreground image.
|
||||
/// </summary>
|
||||
public Img Foreground { get; set; }
|
||||
public Img Foreground { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the collision mask of the landscape.
|
||||
/// </summary>
|
||||
public Img CollisionMask { get; set; }
|
||||
public Img CollisionMask { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual background image.
|
||||
/// </summary>
|
||||
public Img Background { get; set; }
|
||||
public Img Background { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the land image file.
|
||||
/// </summary>
|
||||
public string LandTexturePath { get; set; }
|
||||
public string LandTexturePath { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Water.dir file.
|
||||
/// </summary>
|
||||
public string WaterDirPath { get; set; }
|
||||
public string WaterDirPath { get; set; } = String.Empty;
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -95,24 +112,71 @@ namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
int readLocationCount()
|
||||
{
|
||||
int oldLocationCount = reader.ReadInt32();
|
||||
int oldImgStart = oldLocationCount * Unsafe.SizeOf<Point>();
|
||||
|
||||
// Check whether the old IMG start would be invalid.
|
||||
bool isNew = false;
|
||||
using (reader.TemporarySeek(oldImgStart))
|
||||
isNew = reader.EndOfStream || reader.ReadUInt32() != Img.Signature;
|
||||
if (isNew)
|
||||
{
|
||||
Unknown = oldLocationCount;
|
||||
return reader.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
Unknown = null;
|
||||
return oldLocationCount;
|
||||
}
|
||||
}
|
||||
|
||||
Img readImage(ref bool aligned)
|
||||
{
|
||||
long imgStart = reader.Position;
|
||||
Img img = new Img(reader.BaseStream, aligned);
|
||||
|
||||
// If reading the next image fails, the previous data was aligned and must be reread.
|
||||
if (!aligned)
|
||||
{
|
||||
if (reader.ReadUInt32() == Img.Signature)
|
||||
{
|
||||
reader.Position -= sizeof(uint);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Position = imgStart;
|
||||
img = new Img(reader.BaseStream, true);
|
||||
aligned = true;
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// Read the header.
|
||||
if (reader.ReadInt32() != _signature)
|
||||
throw new InvalidDataException("Invalid LND file signature.");
|
||||
Version = reader.ReadEnum<LandDataVersion>(true);
|
||||
int fileSize = reader.ReadInt32();
|
||||
|
||||
// Read the data.
|
||||
Size = reader.ReadStruct<Size>();
|
||||
TopBorder = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
WaterHeight = reader.ReadInt32();
|
||||
Unknown = reader.ReadInt32();
|
||||
|
||||
// Read the possible object coordinate array.
|
||||
ObjectLocations = reader.ReadStructs<Point>(reader.ReadInt32());
|
||||
// Read the object locations.
|
||||
int locationCount = readLocationCount();
|
||||
ObjectLocations = new List<Point>(locationCount);
|
||||
for (int i = 0; i < locationCount; i++)
|
||||
ObjectLocations.Add(reader.ReadStruct<Point>());
|
||||
|
||||
// Read the image data.
|
||||
Foreground = reader.Load<Img>();
|
||||
CollisionMask = reader.Load<Img>();
|
||||
Background = reader.Load<Img>();
|
||||
// Read the image data, which alignment must be detected by trial-and-error.
|
||||
_alignImgData = Version == LandDataVersion.WormsWorldPartyAqua;
|
||||
long foreImgLocation = reader.Position;
|
||||
Foreground = readImage(ref _alignImgData);
|
||||
CollisionMask = readImage(ref _alignImgData);
|
||||
Background = new Img(reader.BaseStream, _alignImgData);
|
||||
|
||||
// Read the file paths.
|
||||
LandTexturePath = reader.ReadString(StringCoding.ByteCharCount);
|
||||
@ -132,29 +196,31 @@ namespace Syroot.Worms.Armageddon
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Write the header.
|
||||
writer.Write(_signature);
|
||||
writer.WriteEnum(Version, true);
|
||||
uint fileSizeOffset = writer.ReserveOffset();
|
||||
|
||||
// Write the data.
|
||||
writer.WriteStruct(Size);
|
||||
writer.Write(TopBorder, BooleanCoding.Dword);
|
||||
writer.Write(WaterHeight);
|
||||
writer.Write(Unknown);
|
||||
if (Unknown.HasValue)
|
||||
writer.Write(Unknown.Value);
|
||||
|
||||
// Write the possible object coordinate array.
|
||||
writer.Write(ObjectLocations.Length);
|
||||
writer.WriteStructs(ObjectLocations);
|
||||
writer.Write(ObjectLocations.Count);
|
||||
for (int i = 0; i < ObjectLocations.Count; i++)
|
||||
writer.WriteStruct(ObjectLocations[i]);
|
||||
|
||||
// Write the image data.
|
||||
Foreground.Save(writer.BaseStream);
|
||||
CollisionMask.Save(writer.BaseStream);
|
||||
Background.Save(writer.BaseStream);
|
||||
Foreground.Save(writer.BaseStream, _alignImgData);
|
||||
CollisionMask.Save(writer.BaseStream, _alignImgData);
|
||||
Background.Save(writer.BaseStream, _alignImgData);
|
||||
|
||||
// Write the file paths.
|
||||
writer.Write(LandTexturePath, StringCoding.ByteCharCount);
|
||||
writer.Write(WaterDirPath, StringCoding.ByteCharCount);
|
||||
|
||||
writer.SatisfyOffset(fileSizeOffset, (int)writer.Position);
|
||||
writer.SatisfyOffset(fileSizeOffset, (uint)writer.Position);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -164,4 +230,17 @@ namespace Syroot.Worms.Armageddon
|
||||
Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Represents the version of <see cref="LandData"/> files, encoded as the signature.
|
||||
/// </summary>
|
||||
public enum LandDataVersion : uint
|
||||
{
|
||||
/// <summary>Found in W2, WA, WWP, and OW.</summary>
|
||||
Team17 = 0x1A444E4C, // "LND\x1A"
|
||||
/// <summary>Found only in WWPA.</summary>
|
||||
WormsWorldPartyAqua = 0x1B444E4C // "LND\x1B"
|
||||
}
|
||||
}
|
||||
|
@ -1,158 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the required configuration for the land generator to create a map. This structure appears in LEV
|
||||
/// files (being their only content), in BIT files (being the header) and in PNG maps stored by WA (being the data
|
||||
/// of the w2lv or waLV chunks).
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MapGeneratorSettings
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The random seed to generate the land shape (no effect in BIT files).
|
||||
/// </summary>
|
||||
public int LandSeed;
|
||||
|
||||
/// <summary>
|
||||
/// The random seed to generate object placements.
|
||||
/// </summary>
|
||||
public int ObjectSeed;
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> treats the generated map as a cavern, otherwise as an island, depending on <see cref="Style"/>.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool Cavern;
|
||||
|
||||
/// <summary>
|
||||
/// The style of the land generated, dependending on <see cref="Cavern"/>
|
||||
/// </summary>
|
||||
public MapGeneratorStyle Style;
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> to disable an indestructible border being placed around the map.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool NoIndestructibleBorders;
|
||||
|
||||
/// <summary>
|
||||
/// The probability percentage of map objects to appear on the land, from 0-100.
|
||||
/// </summary>
|
||||
public int ObjectPercentage;
|
||||
|
||||
/// <summary>
|
||||
/// The probability percentage of bridges to appear on the land, from 0-100.
|
||||
/// </summary>
|
||||
public int BridgePercentage;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the water in percent, from 0-99.
|
||||
/// </summary>
|
||||
public int WaterLevel;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the structure, determining the available <see cref="SoilTextureIndex"/> values in Worms
|
||||
/// Armageddon.
|
||||
/// </summary>
|
||||
public MapGeneratorVersion Version;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the texture index determining the style of the generated map.
|
||||
/// </summary>
|
||||
public MapGeneratorSoil SoilTextureIndex;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the water color used for the map (deprecated, used only in Worms Armageddon 1.0).
|
||||
/// </summary>
|
||||
public int WaterColor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible land styles.
|
||||
/// </summary>
|
||||
public enum MapGeneratorStyle : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single island or a cavern.
|
||||
/// </summary>
|
||||
OneIslandOrCavern,
|
||||
|
||||
/// <summary>
|
||||
/// Represents two islands or a double-layer cavern.
|
||||
/// </summary>
|
||||
TwoIslandsOrCaverns,
|
||||
|
||||
/// <summary>
|
||||
/// Represents one flat island or a cavern open at the bottom.
|
||||
/// </summary>
|
||||
OneFlatIslandOrCavernOpenBottom,
|
||||
|
||||
/// <summary>
|
||||
/// Represents two flat islands or a cavern open at the left or right.
|
||||
/// </summary>
|
||||
TwoFlatIslandsOrCavernOpenLeftRight
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible versions which can be stored in the <see cref="MapGeneratorSettings.Version"/> field.
|
||||
/// </summary>
|
||||
public enum MapGeneratorVersion : short
|
||||
{
|
||||
/// <summary>
|
||||
/// Game version 3.0. Last soil texture indices are 26 = Tribal, 27 = Tribal, 28 = Urban. Additionally, floor
|
||||
/// and ceiling trimming is more severe.
|
||||
/// </summary>
|
||||
Version_3_0_0_0 = -1,
|
||||
|
||||
/// <summary>
|
||||
/// Game version 3.5. Last soil texture indices are 26 = Tribal, 27 = Urban, 28 = undefined.
|
||||
/// </summary>
|
||||
Version_3_5_0_0 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Game version 3.6.26.4. Last soil texture indices are 26 = Tools, 27 = Tribal, Urban = 28 (same as in WWP).
|
||||
/// </summary>
|
||||
Version_3_6_26_4 = 1
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the possible soil styles. In case of Worms Armageddon, this list matches
|
||||
/// <see cref="MapGeneratorVersion.Version_3_6_26_4"/>.
|
||||
/// </summary>
|
||||
public enum MapGeneratorSoil : short
|
||||
{
|
||||
ClassicBeach,
|
||||
ClassicDesert,
|
||||
ClassicFarm,
|
||||
ClassicForest,
|
||||
ClassicHell,
|
||||
Art,
|
||||
Cheese,
|
||||
Construction,
|
||||
Desert,
|
||||
Dungeon,
|
||||
Easter,
|
||||
Forest,
|
||||
Fruit,
|
||||
Gulf,
|
||||
Hell,
|
||||
Hospital,
|
||||
Jungle,
|
||||
Manhattan,
|
||||
Medieval,
|
||||
Music,
|
||||
Pirate,
|
||||
Snow,
|
||||
Space,
|
||||
Sports,
|
||||
Tentacle,
|
||||
Time,
|
||||
Tools,
|
||||
Tribal,
|
||||
Urban
|
||||
}
|
||||
}
|
@ -145,7 +145,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Represents the stockpiling mode of weapon armory between rounds.
|
||||
/// </summary>
|
||||
public enum StockpilingMode : byte
|
||||
public enum Stockpiling : byte
|
||||
{
|
||||
/// <summary>Each round starts with the exact amount of weapons set in the scheme.</summary>
|
||||
Off,
|
1136
src/library/Syroot.Worms.Armageddon/Scheme.ExtendedOptions.cs
Normal file
1136
src/library/Syroot.Worms.Armageddon/Scheme.ExtendedOptions.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,5 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
@ -14,30 +15,32 @@ namespace Syroot.Worms.Armageddon
|
||||
public class WeaponList : IReadOnlyCollection<SchemeWeapon>
|
||||
{
|
||||
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
|
||||
private readonly SchemeWeapon[] _list = new SchemeWeapon[64];
|
||||
private readonly SchemeWeapon[] _array = new SchemeWeapon[64];
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the weapon with the given <paramref name="index"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The index of the weapon to access.</param>
|
||||
/// <returns>A reference to the <see cref="SchemeWeapon"/>.</returns>
|
||||
public ref SchemeWeapon this[int index] => ref _list[index];
|
||||
public ref SchemeWeapon this[int index] => ref _array[index];
|
||||
|
||||
/// <summary>
|
||||
/// Gets a reference to the weapon with the given <paramref name="name"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The <see cref="Weapon"/> of the weapon to access.</param>
|
||||
/// <returns>A reference to the <see cref="SchemeWeapon"/>.</returns>
|
||||
public ref SchemeWeapon this[Weapon name] => ref _list[(int)name];
|
||||
public ref SchemeWeapon this[Weapon name] => ref _array[(int)name];
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => _list.Length;
|
||||
public int Count => _array.Length;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<SchemeWeapon> GetEnumerator() => ((IEnumerable<SchemeWeapon>)_list).GetEnumerator();
|
||||
public IEnumerator<SchemeWeapon> GetEnumerator() => ((IEnumerable<SchemeWeapon>)_array).GetEnumerator();
|
||||
|
||||
internal Span<SchemeWeapon> AsSpan(int length) => _array.AsSpan(0, length);
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => _list.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => _array.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
@ -38,8 +38,8 @@ namespace Syroot.Worms.Armageddon
|
||||
private byte _roundTimeMinutes;
|
||||
private byte _roundTimeSeconds;
|
||||
|
||||
private SchemeExtendedOptions _extended = SchemeExtendedOptions.Default;
|
||||
private ushort _rwVersionOverride;
|
||||
private ExtendedOptions _extended = ExtendedOptions.Default;
|
||||
private ushort _rwVersion;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -116,7 +116,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets the delay in seconds between each team's turn to allow relaxed switching of seats.
|
||||
/// </summary>
|
||||
public byte HotSeatDelay { get; set; }
|
||||
public byte HotSeatTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the time in seconds available for a worm to retreat after using a weapon which ends the turn
|
||||
@ -139,7 +139,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether significant turns will be replayed in offline games.
|
||||
/// </summary>
|
||||
public bool AutomaticReplays { get; set; }
|
||||
public bool Replays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the percentual amount of fall damage applied, relative to normal fall damage being 100%. Valid
|
||||
@ -155,7 +155,6 @@ namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
if (value < 0 || value > 508)
|
||||
throw new ArgumentOutOfRangeException(nameof(value), "Fall damage must be between 0-508.");
|
||||
|
||||
_fallDamage = value >> 2 << 2;
|
||||
}
|
||||
}
|
||||
@ -175,12 +174,12 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the stockpiling of armory between game rounds.
|
||||
/// </summary>
|
||||
public StockpilingMode StockpilingMode { get; set; }
|
||||
public Stockpiling Stockpiling { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the worm selection order determining the next worm to be played.
|
||||
/// </summary>
|
||||
public WormSelect WormSelectMode { get; set; }
|
||||
public WormSelect WormSelect { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the action triggered when Sudden Death starts.
|
||||
@ -218,7 +217,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// Gets or sets the percentual probability of a weapon crate to drop between turns. Negative values might crash
|
||||
/// the game.
|
||||
/// </summary>
|
||||
public sbyte WeaponCrateProbability { get; set; }
|
||||
public sbyte WeaponCrateProb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether donor cards can spawn upon a worm's death.
|
||||
@ -229,7 +228,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// Gets or sets the percentual probability of a health crate to drop between turns. Negative values might crash
|
||||
/// the game.
|
||||
/// </summary>
|
||||
public sbyte HealthCrateProbability { get; set; }
|
||||
public sbyte HealthCrateProb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of health included in a health crate added to the collecting worm's energy.
|
||||
@ -240,7 +239,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// Gets or sets the percentual probability of a utility crate to drop between turns. Negative values might
|
||||
/// crash the game.
|
||||
/// </summary>
|
||||
public sbyte UtilityCrateProbability { get; set; }
|
||||
public sbyte UtilityCrateProb { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of objects which can be placed on the map.
|
||||
@ -273,7 +272,7 @@ namespace Syroot.Worms.Armageddon
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number of seconds a mine requires to explode. Can be 1-3 and 5-127 seconds.
|
||||
/// Gets or sets the number of seconds a mine requires to explode. Can be 0-3 and 5-127 seconds.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Value is not between 0-127 or 4.</exception>
|
||||
public byte MineDelay
|
||||
@ -289,7 +288,7 @@ namespace Syroot.Worms.Armageddon
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the mine fuse will be randomly chosen between fractions of 1 to 3
|
||||
/// seconds. If <c>true</c>, the <see cref="MineDelay"/> setting will be ignored.
|
||||
/// seconds. If <see langword="true"/>, the <see cref="MineDelay"/> setting will be ignored.
|
||||
/// </summary>
|
||||
public bool MineDelayRandom { get; set; }
|
||||
|
||||
@ -325,7 +324,7 @@ namespace Syroot.Worms.Armageddon
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the turn time is unlimited. If <c>true</c>, the
|
||||
/// Gets or sets a value indicating whether the turn time is unlimited. If <see langword="true"/>, the
|
||||
/// <see cref="TurnTime"/> setting will be ignored.
|
||||
/// </summary>
|
||||
public bool TurnTimeInfinite { get; set; }
|
||||
@ -393,40 +392,40 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether terrain cannot be destroyed by explosions.
|
||||
/// </summary>
|
||||
public bool IndestructibleLand { get; set; }
|
||||
public bool IndiLand { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the Grenade weapon is more powerful.
|
||||
/// </summary>
|
||||
public bool UpgradedGrenade { get; set; }
|
||||
public bool UpgradeGrenade { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the Shotgun weapon shoots twice for each of the two shots.
|
||||
/// </summary>
|
||||
public bool UpgradedShotgun { get; set; }
|
||||
public bool UpgradeShotgun { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether cluster weapon explode into more clusters.
|
||||
/// </summary>
|
||||
public bool UpgradedCluster { get; set; }
|
||||
public bool UpgradeCluster { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the Longbow weapon is more powerful.
|
||||
/// </summary>
|
||||
public bool UpgradedLongbow { get; set; }
|
||||
public bool UpgradeLongbow { get; set; }
|
||||
|
||||
// ---- Weapons ----
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether team weapons will be given to the teams, overriding the default
|
||||
/// weapon settings for them.
|
||||
/// </summary>
|
||||
public bool EnableTeamWeapons { get; set; }
|
||||
public bool TeamWeapons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether super weapons can be collected from crates.
|
||||
/// </summary>
|
||||
public bool EnableSuperWeapons { get; set; }
|
||||
|
||||
// ---- Weapons ----
|
||||
public bool SuperWeapons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="SchemeWeapon"/> instances, of which each weapon can be accessed by index or
|
||||
@ -440,7 +439,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets <see cref="SchemeVersion.Version3"/> or RubberWorm settings.
|
||||
/// </summary>
|
||||
public ref SchemeExtendedOptions Extended => ref _extended;
|
||||
public ref ExtendedOptions Extended => ref _extended;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets trailing bytes which could not be parsed and will be attached when saving the scheme anew.
|
||||
@ -454,12 +453,12 @@ namespace Syroot.Worms.Armageddon
|
||||
/// </summary>
|
||||
/// <remarks>Configurable with the /version command in RubberWorm.
|
||||
/// S. http://worms2d.info/List_of_Worms_Armageddon_logic_versions.</remarks>
|
||||
public ushort RwVersionOverride
|
||||
public ushort RwVersion
|
||||
{
|
||||
get => _rwVersionOverride;
|
||||
get => _rwVersion;
|
||||
set
|
||||
{
|
||||
_rwVersionOverride = value;
|
||||
_rwVersion = value;
|
||||
|
||||
// Configure V3 settings according to selected version.
|
||||
void setBattyRope1To2() => Extended.BattyRope = true;
|
||||
@ -535,7 +534,7 @@ namespace Syroot.Worms.Armageddon
|
||||
Extended.WormSelectKeepHotSeat = true;
|
||||
}
|
||||
|
||||
switch (_rwVersionOverride)
|
||||
switch (_rwVersion)
|
||||
{
|
||||
case 11: // 3.5 Beta 3pre15[BattyRope1]
|
||||
case 12: // 3.5 Beta 3pre15[BattyRope2]
|
||||
@ -845,30 +844,29 @@ namespace Syroot.Worms.Armageddon
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => Equals(obj as Scheme);
|
||||
public override bool Equals(object? obj) => Equals(obj as Scheme);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(Scheme other)
|
||||
=> other == this
|
||||
|| other != null
|
||||
public bool Equals(Scheme? other)
|
||||
=> other != null
|
||||
&& Version == other.Version
|
||||
&& HotSeatDelay == other.HotSeatDelay
|
||||
&& HotSeatTime == other.HotSeatTime
|
||||
&& RetreatTime == other.RetreatTime
|
||||
&& RetreatTimeRope == other.RetreatTimeRope
|
||||
&& ShowRoundTime == other.ShowRoundTime
|
||||
&& AutomaticReplays == other.AutomaticReplays
|
||||
&& Replays == other.Replays
|
||||
&& FallDamage == other.FallDamage
|
||||
&& ArtilleryMode == other.ArtilleryMode
|
||||
&& SchemeEditor == other.SchemeEditor
|
||||
&& StockpilingMode == other.StockpilingMode
|
||||
&& WormSelectMode == other.WormSelectMode
|
||||
&& Stockpiling == other.Stockpiling
|
||||
&& WormSelect == other.WormSelect
|
||||
&& SuddenDeathEvent == other.SuddenDeathEvent
|
||||
&& WaterRiseRate == other.WaterRiseRate
|
||||
&& WeaponCrateProbability == other.WeaponCrateProbability
|
||||
&& WeaponCrateProb == other.WeaponCrateProb
|
||||
&& DonorCards == other.DonorCards
|
||||
&& HealthCrateProbability == other.HealthCrateProbability
|
||||
&& HealthCrateProb == other.HealthCrateProb
|
||||
&& HealthCrateEnergy == other.HealthCrateEnergy
|
||||
&& UtilityCrateProbability == other.UtilityCrateProbability
|
||||
&& UtilityCrateProb == other.UtilityCrateProb
|
||||
&& ObjectTypes == other.ObjectTypes
|
||||
&& ObjectCount == other.ObjectCount
|
||||
&& MineDelay == other.MineDelay
|
||||
@ -885,40 +883,40 @@ namespace Syroot.Worms.Armageddon
|
||||
&& AquaSheep == other.AquaSheep
|
||||
&& SheepHeaven == other.SheepHeaven
|
||||
&& GodWorms == other.GodWorms
|
||||
&& IndestructibleLand == other.IndestructibleLand
|
||||
&& UpgradedGrenade == other.UpgradedGrenade
|
||||
&& UpgradedShotgun == other.UpgradedShotgun
|
||||
&& UpgradedCluster == other.UpgradedCluster
|
||||
&& UpgradedLongbow == other.UpgradedLongbow
|
||||
&& EnableTeamWeapons == other.EnableTeamWeapons
|
||||
&& EnableSuperWeapons == other.EnableSuperWeapons
|
||||
&& IndiLand == other.IndiLand
|
||||
&& UpgradeGrenade == other.UpgradeGrenade
|
||||
&& UpgradeShotgun == other.UpgradeShotgun
|
||||
&& UpgradeCluster == other.UpgradeCluster
|
||||
&& UpgradeLongbow == other.UpgradeLongbow
|
||||
&& TeamWeapons == other.TeamWeapons
|
||||
&& SuperWeapons == other.SuperWeapons
|
||||
&& Weapons.SequenceEqual(other.Weapons)
|
||||
&& Extended.Equals(ref other.Extended)
|
||||
&& Extended.Equals(other.Extended)
|
||||
&& Attachment.SequenceEqual(other.Attachment)
|
||||
&& RwVersionOverride == other.RwVersionOverride;
|
||||
&& RwVersion == other.RwVersion;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new HashCode();
|
||||
hash.Add(Version);
|
||||
hash.Add(HotSeatDelay);
|
||||
hash.Add(HotSeatTime);
|
||||
hash.Add(RetreatTime);
|
||||
hash.Add(RetreatTimeRope);
|
||||
hash.Add(ShowRoundTime);
|
||||
hash.Add(AutomaticReplays);
|
||||
hash.Add(Replays);
|
||||
hash.Add(FallDamage);
|
||||
hash.Add(ArtilleryMode);
|
||||
hash.Add(SchemeEditor);
|
||||
hash.Add(StockpilingMode);
|
||||
hash.Add(WormSelectMode);
|
||||
hash.Add(Stockpiling);
|
||||
hash.Add(WormSelect);
|
||||
hash.Add(SuddenDeathEvent);
|
||||
hash.Add(WaterRiseRate);
|
||||
hash.Add(WeaponCrateProbability);
|
||||
hash.Add(WeaponCrateProb);
|
||||
hash.Add(DonorCards);
|
||||
hash.Add(HealthCrateProbability);
|
||||
hash.Add(HealthCrateProb);
|
||||
hash.Add(HealthCrateEnergy);
|
||||
hash.Add(UtilityCrateProbability);
|
||||
hash.Add(UtilityCrateProb);
|
||||
hash.Add(ObjectTypes);
|
||||
hash.Add(ObjectCount);
|
||||
hash.Add(MineDelay);
|
||||
@ -935,19 +933,19 @@ namespace Syroot.Worms.Armageddon
|
||||
hash.Add(AquaSheep);
|
||||
hash.Add(SheepHeaven);
|
||||
hash.Add(GodWorms);
|
||||
hash.Add(IndestructibleLand);
|
||||
hash.Add(UpgradedGrenade);
|
||||
hash.Add(UpgradedShotgun);
|
||||
hash.Add(UpgradedCluster);
|
||||
hash.Add(UpgradedLongbow);
|
||||
hash.Add(EnableTeamWeapons);
|
||||
hash.Add(EnableSuperWeapons);
|
||||
hash.Add(IndiLand);
|
||||
hash.Add(UpgradeGrenade);
|
||||
hash.Add(UpgradeShotgun);
|
||||
hash.Add(UpgradeCluster);
|
||||
hash.Add(UpgradeLongbow);
|
||||
hash.Add(TeamWeapons);
|
||||
hash.Add(SuperWeapons);
|
||||
foreach (SchemeWeapon weapon in Weapons)
|
||||
hash.Add(weapon);
|
||||
hash.Add(Extended);
|
||||
foreach (byte attachmentByte in Attachment)
|
||||
hash.Add(attachmentByte);
|
||||
hash.Add(RwVersionOverride);
|
||||
hash.Add(RwVersion);
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
|
||||
@ -1030,23 +1028,23 @@ namespace Syroot.Worms.Armageddon
|
||||
Version = reader.ReadEnum<SchemeVersion>(true);
|
||||
|
||||
// Read the options.
|
||||
HotSeatDelay = reader.Read1Byte();
|
||||
HotSeatTime = reader.Read1Byte();
|
||||
RetreatTime = reader.Read1Byte();
|
||||
RetreatTimeRope = reader.Read1Byte();
|
||||
ShowRoundTime = reader.ReadBoolean();
|
||||
AutomaticReplays = reader.ReadBoolean();
|
||||
Replays = reader.ReadBoolean();
|
||||
FallDamage = reader.ReadByte() * 50 % 256 * 2;
|
||||
ArtilleryMode = reader.ReadBoolean();
|
||||
SchemeEditor = reader.ReadEnum<SchemeEditor>(false);
|
||||
StockpilingMode = reader.ReadEnum<StockpilingMode>(true);
|
||||
WormSelectMode = reader.ReadEnum<WormSelect>(true);
|
||||
Stockpiling = reader.ReadEnum<Stockpiling>(true);
|
||||
WormSelect = reader.ReadEnum<WormSelect>(true);
|
||||
SuddenDeathEvent = reader.ReadEnum<SuddenDeathEvent>(true);
|
||||
_waterRiseIndex = reader.Read1Byte();
|
||||
WeaponCrateProbability = reader.ReadSByte();
|
||||
WeaponCrateProb = reader.ReadSByte();
|
||||
DonorCards = reader.ReadBoolean();
|
||||
HealthCrateProbability = reader.ReadSByte();
|
||||
HealthCrateProb = reader.ReadSByte();
|
||||
HealthCrateEnergy = reader.Read1Byte();
|
||||
UtilityCrateProbability = reader.ReadSByte();
|
||||
UtilityCrateProb = reader.ReadSByte();
|
||||
readObjectCombo();
|
||||
readMineDelay();
|
||||
DudMines = reader.ReadBoolean();
|
||||
@ -1059,19 +1057,17 @@ namespace Syroot.Worms.Armageddon
|
||||
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();
|
||||
IndiLand = reader.ReadBoolean();
|
||||
UpgradeGrenade = reader.ReadBoolean();
|
||||
UpgradeShotgun = reader.ReadBoolean();
|
||||
UpgradeCluster = reader.ReadBoolean();
|
||||
UpgradeLongbow = reader.ReadBoolean();
|
||||
TeamWeapons = reader.ReadBoolean();
|
||||
SuperWeapons = reader.ReadBoolean();
|
||||
|
||||
// Read the weapons.
|
||||
Weapons = new WeaponList();
|
||||
int weaponCount = GetWeaponCount(Version);
|
||||
for (int i = 0; i < weaponCount; i++)
|
||||
Weapons[i] = reader.ReadStruct<SchemeWeapon>();
|
||||
reader.ReadStructs(Weapons.AsSpan(GetWeaponCount(Version)));
|
||||
|
||||
// Read available extended settings or deserialize them from RubberWorm settings encoded in probabilities.
|
||||
switch (Version)
|
||||
@ -1163,23 +1159,23 @@ namespace Syroot.Worms.Armageddon
|
||||
writer.WriteEnum(version);
|
||||
|
||||
// Write the options.
|
||||
writer.Write(HotSeatDelay);
|
||||
writer.Write(HotSeatTime);
|
||||
writer.Write(RetreatTime);
|
||||
writer.Write(RetreatTimeRope);
|
||||
writer.Write(ShowRoundTime);
|
||||
writer.Write(AutomaticReplays);
|
||||
writer.Write(Replays);
|
||||
writer.Write((byte)(FallDamage / 4 * 41 % 128));
|
||||
writer.Write(ArtilleryMode);
|
||||
writer.WriteEnum(SchemeEditor, false);
|
||||
writer.WriteEnum(StockpilingMode, true);
|
||||
writer.WriteEnum(WormSelectMode, true);
|
||||
writer.WriteEnum(Stockpiling, true);
|
||||
writer.WriteEnum(WormSelect, true);
|
||||
writer.WriteEnum(SuddenDeathEvent, true);
|
||||
writer.Write(_waterRiseIndex);
|
||||
writer.Write(WeaponCrateProbability);
|
||||
writer.Write(WeaponCrateProb);
|
||||
writer.Write(DonorCards);
|
||||
writer.Write(HealthCrateProbability);
|
||||
writer.Write(HealthCrateProb);
|
||||
writer.Write(HealthCrateEnergy);
|
||||
writer.Write(UtilityCrateProbability);
|
||||
writer.Write(UtilityCrateProb);
|
||||
saveObjectTypesAndCount();
|
||||
saveMineDelayConfig();
|
||||
writer.Write(DudMines);
|
||||
@ -1192,22 +1188,20 @@ namespace Syroot.Worms.Armageddon
|
||||
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);
|
||||
writer.Write(IndiLand);
|
||||
writer.Write(UpgradeGrenade);
|
||||
writer.Write(UpgradeShotgun);
|
||||
writer.Write(UpgradeCluster);
|
||||
writer.Write(UpgradeLongbow);
|
||||
writer.Write(TeamWeapons);
|
||||
writer.Write(SuperWeapons);
|
||||
|
||||
// Serialize RubberWorm settings encoded in weapon probabilities.
|
||||
if (version == SchemeVersion.Version2)
|
||||
SaveRubberWorm();
|
||||
|
||||
// Write the weapons.
|
||||
int weaponCount = GetWeaponCount(version);
|
||||
for (int i = 0; i < weaponCount; i++)
|
||||
writer.WriteStruct(Weapons[i]);
|
||||
writer.WriteStructs<SchemeWeapon>(Weapons.AsSpan(GetWeaponCount(version)));
|
||||
|
||||
// Clear RubberWorm probabilities again or write available extended settings.
|
||||
switch (version)
|
||||
@ -1228,10 +1222,10 @@ namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
// Reset all super weapon probabilities to remove any settings made by RubberWorm.
|
||||
for (Weapon superWeapon = Weapon.Freeze; superWeapon <= Weapon.Armageddon; superWeapon++)
|
||||
Weapons[superWeapon].Crates = 0;
|
||||
Weapons[superWeapon].Prob = 0;
|
||||
}
|
||||
|
||||
private void ClearExtendedOptions() => Extended = SchemeExtendedOptions.Default;
|
||||
private void ClearExtendedOptions() => Extended = ExtendedOptions.Default;
|
||||
|
||||
private unsafe void LoadExtendedOptions(BinaryStream reader)
|
||||
{
|
||||
@ -1242,7 +1236,7 @@ namespace Syroot.Worms.Armageddon
|
||||
else
|
||||
{
|
||||
Span<byte> bytes = new Span<byte>(
|
||||
Unsafe.AsPointer(ref _extended), Unsafe.SizeOf<SchemeExtendedOptions>());
|
||||
Unsafe.AsPointer(ref _extended), Unsafe.SizeOf<ExtendedOptions>());
|
||||
#if NETSTANDARD2_0
|
||||
// Cannot prevent copy in .NET Standard 2.0.
|
||||
byte[] buffer = new byte[(int)Math.Min(bytes.Length, reader.Length - reader.Position)];
|
||||
@ -1259,7 +1253,7 @@ namespace Syroot.Worms.Armageddon
|
||||
unchecked
|
||||
{
|
||||
// Earthquake flags.
|
||||
byte prob = (byte)Weapons[Weapon.Earthquake].Crates;
|
||||
byte prob = (byte)Weapons[Weapon.Earthquake].Prob;
|
||||
Extended.AutoReaim = prob.GetBit(0);
|
||||
Extended.CircularAim = prob.GetBit(1);
|
||||
Extended.AntiLockPower = prob.GetBit(2);
|
||||
@ -1267,19 +1261,19 @@ namespace Syroot.Worms.Armageddon
|
||||
Extended.KaosMod = prob.DecodeByte(4, 4);
|
||||
|
||||
// Antisink.
|
||||
Extended.AntiSink = Weapons[Weapon.SheepStrike].Crates != 0;
|
||||
Extended.AntiSink = Weapons[Weapon.SheepStrike].Prob != 0;
|
||||
|
||||
// Crate limit and rate.
|
||||
prob = (byte)Weapons[Weapon.MagicBullet].Crates;
|
||||
prob = (byte)Weapons[Weapon.MagicBullet].Prob;
|
||||
Extended.CrateLimit = prob switch
|
||||
{
|
||||
0 => SchemeExtendedOptions.Default.CrateLimit,
|
||||
0 => ExtendedOptions.Default.CrateLimit,
|
||||
_ => prob
|
||||
};
|
||||
Extended.CrateRate = (byte)Weapons[Weapon.NuclearTest].Crates;
|
||||
Extended.CrateRate = (byte)Weapons[Weapon.NuclearTest].Prob;
|
||||
|
||||
// Mole squadron flags.
|
||||
prob = (byte)Weapons[Weapon.MoleSquadron].Crates;
|
||||
prob = (byte)Weapons[Weapon.MoleSquadron].Prob;
|
||||
Extended.ShotDoesntEndTurn = prob.GetBit(0);
|
||||
Extended.LoseControlDoesntEndTurn = prob.GetBit(1);
|
||||
Extended.FiringPausesTimer = !prob.GetBit(2);
|
||||
@ -1290,21 +1284,21 @@ namespace Syroot.Worms.Armageddon
|
||||
Extended.ExtendedFuse = prob.GetBit(7);
|
||||
|
||||
// Flame limit.
|
||||
prob = (byte)Weapons[Weapon.ScalesOfJustice].Crates;
|
||||
prob = (byte)Weapons[Weapon.ScalesOfJustice].Prob;
|
||||
if (prob > 0)
|
||||
Extended.FlameLimit = (ushort)(prob * 100);
|
||||
|
||||
// Friction.
|
||||
prob = (byte)Weapons[Weapon.SalvationArmy].Crates;
|
||||
prob = (byte)Weapons[Weapon.SalvationArmy].Prob;
|
||||
if (prob > 0)
|
||||
Extended.Friction = prob / 100f;
|
||||
|
||||
// Gravity - 8th and 7th bit control constant / proportional black hole, otherwise normal gravity.
|
||||
prob = (byte)Weapons[Weapon.MailStrike].Crates;
|
||||
prob = (byte)Weapons[Weapon.MailStrike].Prob;
|
||||
if (prob == 0)
|
||||
{
|
||||
Extended.RwGravityType = RwGravityType.None;
|
||||
Extended.RwGravity = SchemeExtendedOptions.Default.RwGravity;
|
||||
Extended.RwGravity = ExtendedOptions.Default.RwGravity;
|
||||
}
|
||||
else if (prob.GetBit(7) && prob.GetBit(6))
|
||||
{
|
||||
@ -1323,7 +1317,7 @@ namespace Syroot.Worms.Armageddon
|
||||
}
|
||||
|
||||
// Rope-knocking force.
|
||||
prob = (byte)Weapons[Weapon.SuperBananaBomb].Crates;
|
||||
prob = (byte)Weapons[Weapon.SuperBananaBomb].Prob;
|
||||
Extended.RopeKnockForce = prob switch
|
||||
{
|
||||
0 => null,
|
||||
@ -1332,35 +1326,35 @@ namespace Syroot.Worms.Armageddon
|
||||
};
|
||||
|
||||
// Maximum rope speed.
|
||||
prob = (byte)Weapons[Weapon.MineStrike].Crates;
|
||||
prob = (byte)Weapons[Weapon.MineStrike].Prob;
|
||||
Extended.RopeMaxSpeed = prob switch
|
||||
{
|
||||
0 => SchemeExtendedOptions.Default.RopeMaxSpeed,
|
||||
0 => ExtendedOptions.Default.RopeMaxSpeed,
|
||||
Byte.MaxValue => 0,
|
||||
_ => prob
|
||||
};
|
||||
|
||||
// Select worm any time.
|
||||
Extended.WormSelectAnytime = ((byte)Weapons[Weapon.MBBomb].Crates).GetBit(0);
|
||||
Extended.WormSelectAnytime = ((byte)Weapons[Weapon.MBBomb].Prob).GetBit(0);
|
||||
|
||||
// Viscosity.
|
||||
prob = (byte)Weapons[Weapon.ConcreteDonkey].Crates;
|
||||
prob = (byte)Weapons[Weapon.ConcreteDonkey].Prob;
|
||||
Extended.Viscosity = prob / 255f;
|
||||
Extended.ViscosityWorms = (prob & 1) == 1;
|
||||
|
||||
// Wind.
|
||||
prob = (byte)Weapons[Weapon.SuicideBomber].Crates;
|
||||
Extended.RwWind = (byte)Weapons[Weapon.SuicideBomber].Crates / 255f;
|
||||
prob = (byte)Weapons[Weapon.SuicideBomber].Prob;
|
||||
Extended.RwWind = (byte)Weapons[Weapon.SuicideBomber].Prob / 255f;
|
||||
Extended.RwWindWorms = (prob & 1) == 1;
|
||||
|
||||
// Worm bounce.
|
||||
Extended.WormBounce = (byte)Weapons[Weapon.Armageddon].Crates / 255f;
|
||||
Extended.WormBounce = (byte)Weapons[Weapon.Armageddon].Prob / 255f;
|
||||
|
||||
// Version override.
|
||||
RwVersionOverride = BinaryPrimitives.ReadUInt16BigEndian(stackalloc[]
|
||||
RwVersion = BinaryPrimitives.ReadUInt16BigEndian(stackalloc[]
|
||||
{
|
||||
(byte)Weapons[Weapon.SelectWorm].Crates,
|
||||
(byte)Weapons[Weapon.Freeze].Crates
|
||||
(byte)Weapons[Weapon.SelectWorm].Prob,
|
||||
(byte)Weapons[Weapon.Freeze].Prob
|
||||
});
|
||||
}
|
||||
|
||||
@ -1371,7 +1365,7 @@ namespace Syroot.Worms.Armageddon
|
||||
private unsafe void SaveExtendedOptions(BinaryStream writer)
|
||||
{
|
||||
ReadOnlySpan<byte> bytes = new ReadOnlySpan<byte>(
|
||||
Unsafe.AsPointer(ref _extended), Unsafe.SizeOf<SchemeExtendedOptions>());
|
||||
Unsafe.AsPointer(ref _extended), Unsafe.SizeOf<ExtendedOptions>());
|
||||
#if NETSTANDARD2_0
|
||||
// Cannot prevent copy in .NET Standard 2.0.
|
||||
writer.Write(bytes.ToArray());
|
||||
@ -1391,15 +1385,15 @@ namespace Syroot.Worms.Armageddon
|
||||
prob = prob.SetBit(2, Extended.AntiLockPower);
|
||||
prob = prob.SetBit(3, Extended.ShotDoesntEndTurnAll);
|
||||
prob = prob.Encode(Extended.KaosMod, 4, 4);
|
||||
Weapons[Weapon.Earthquake].Crates = (sbyte)prob;
|
||||
Weapons[Weapon.Earthquake].Prob = (sbyte)prob;
|
||||
|
||||
// Antisink
|
||||
Weapons[Weapon.SheepStrike].Crates = (sbyte)(Extended.AntiSink ? 1 : 0);
|
||||
Weapons[Weapon.SheepStrike].Prob = (sbyte)(Extended.AntiSink ? 1 : 0);
|
||||
|
||||
// Crate limit and rate.
|
||||
if (Extended.CrateLimit != SchemeExtendedOptions.Default.CrateLimit)
|
||||
Weapons[Weapon.MagicBullet].Crates = (sbyte)Math.Min(Byte.MaxValue, Extended.CrateLimit);
|
||||
Weapons[Weapon.NuclearTest].Crates = (sbyte)Extended.CrateRate;
|
||||
if (Extended.CrateLimit != ExtendedOptions.Default.CrateLimit)
|
||||
Weapons[Weapon.MagicBullet].Prob = (sbyte)Math.Min(Byte.MaxValue, Extended.CrateLimit);
|
||||
Weapons[Weapon.NuclearTest].Prob = (sbyte)Extended.CrateRate;
|
||||
|
||||
// Mole squadron flags.
|
||||
prob = 0;
|
||||
@ -1411,15 +1405,15 @@ namespace Syroot.Worms.Armageddon
|
||||
prob = prob.SetBit(5, Extended.ObjectPushByExplosion == true);
|
||||
prob = prob.SetBit(6, Extended.WeaponsDontChange);
|
||||
prob = prob.SetBit(7, Extended.ExtendedFuse);
|
||||
Weapons[Weapon.MoleSquadron].Crates = (sbyte)prob;
|
||||
Weapons[Weapon.MoleSquadron].Prob = (sbyte)prob;
|
||||
|
||||
// Flame limit.
|
||||
if (Extended.FlameLimit != SchemeExtendedOptions.Default.FlameLimit)
|
||||
Weapons[Weapon.ScalesOfJustice].Crates = (sbyte)(Extended.FlameLimit / 100);
|
||||
if (Extended.FlameLimit != ExtendedOptions.Default.FlameLimit)
|
||||
Weapons[Weapon.ScalesOfJustice].Prob = (sbyte)(Extended.FlameLimit / 100);
|
||||
|
||||
// Friction.
|
||||
if (Extended.Friction != SchemeExtendedOptions.Default.Friction)
|
||||
Weapons[Weapon.SalvationArmy].Crates = (sbyte)Math.Round(Extended.Friction * 100, 0);
|
||||
if (Extended.Friction != ExtendedOptions.Default.Friction)
|
||||
Weapons[Weapon.SalvationArmy].Prob = (sbyte)Math.Round(Extended.Friction * 100, 0);
|
||||
|
||||
// Gravity - 8th and 7th bit control constant / proportional black hole, otherwise normal gravity.
|
||||
prob = 0;
|
||||
@ -1438,10 +1432,10 @@ namespace Syroot.Worms.Armageddon
|
||||
prob = prob.Encode((sbyte)(Extended.RwGravity / 512), 6);
|
||||
break;
|
||||
}
|
||||
Weapons[Weapon.MailStrike].Crates = (sbyte)prob;
|
||||
Weapons[Weapon.MailStrike].Prob = (sbyte)prob;
|
||||
|
||||
// Rope-knocking force.
|
||||
Weapons[Weapon.SuperBananaBomb].Crates = (sbyte)(Extended.RopeKnockForce switch
|
||||
Weapons[Weapon.SuperBananaBomb].Prob = (sbyte)(Extended.RopeKnockForce switch
|
||||
{
|
||||
null => 0,
|
||||
0 => Byte.MaxValue,
|
||||
@ -1449,7 +1443,7 @@ namespace Syroot.Worms.Armageddon
|
||||
});
|
||||
|
||||
// Maximum rope speed.
|
||||
Weapons[Weapon.MineStrike].Crates = (sbyte)(Extended.RopeMaxSpeed switch
|
||||
Weapons[Weapon.MineStrike].Prob = (sbyte)(Extended.RopeMaxSpeed switch
|
||||
{
|
||||
16/*SchemeExtendedOptions.Default.RopeMaxSpeed*/ => 0,
|
||||
0 => Byte.MaxValue,
|
||||
@ -1457,27 +1451,27 @@ namespace Syroot.Worms.Armageddon
|
||||
});
|
||||
|
||||
// Select worm any time.
|
||||
prob = ((byte)Weapons[Weapon.MBBomb].Crates).SetBit(0, Extended.WormSelectAnytime);
|
||||
Weapons[Weapon.MBBomb].Crates = (sbyte)prob;
|
||||
prob = ((byte)Weapons[Weapon.MBBomb].Prob).SetBit(0, Extended.WormSelectAnytime);
|
||||
Weapons[Weapon.MBBomb].Prob = (sbyte)prob;
|
||||
|
||||
// Viscosity.
|
||||
prob = (byte)Math.Round(Extended.Viscosity * 255, 0);
|
||||
prob.SetBit(0, Extended.ViscosityWorms);
|
||||
Weapons[Weapon.ConcreteDonkey].Crates = (sbyte)prob;
|
||||
Weapons[Weapon.ConcreteDonkey].Prob = (sbyte)prob;
|
||||
|
||||
// Wind.
|
||||
prob = (byte)Math.Round(Extended.RwWind * 255, 0);
|
||||
prob.SetBit(0, Extended.RwWindWorms);
|
||||
Weapons[Weapon.SuicideBomber].Crates = (sbyte)prob;
|
||||
Weapons[Weapon.SuicideBomber].Prob = (sbyte)prob;
|
||||
|
||||
// Worm bounce.
|
||||
Weapons[Weapon.Armageddon].Crates = (sbyte)Math.Round(Extended.WormBounce * 255, 0);
|
||||
Weapons[Weapon.Armageddon].Prob = (sbyte)Math.Round(Extended.WormBounce * 255, 0);
|
||||
|
||||
// Version override.
|
||||
Span<byte> versionBytes = stackalloc byte[sizeof(ushort)];
|
||||
BinaryPrimitives.WriteUInt16BigEndian(versionBytes, RwVersionOverride);
|
||||
Weapons[Weapon.SelectWorm].Crates = (sbyte)versionBytes[0];
|
||||
Weapons[Weapon.Freeze].Crates = (sbyte)versionBytes[1];
|
||||
BinaryPrimitives.WriteUInt16BigEndian(versionBytes, RwVersion);
|
||||
Weapons[Weapon.SelectWorm].Prob = (sbyte)versionBytes[0];
|
||||
Weapons[Weapon.Freeze].Prob = (sbyte)versionBytes[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// values represent infinity.</summary>
|
||||
public sbyte Delay;
|
||||
/// <summary>Probability of this weapon to appear in crates. Has no effect on super weapons.</summary>
|
||||
public sbyte Crates;
|
||||
public sbyte Prob;
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
@ -39,9 +39,9 @@ namespace Syroot.Worms.Armageddon
|
||||
=> Ammo == other.Ammo
|
||||
&& Power == other.Power
|
||||
&& Delay == other.Delay
|
||||
&& Crates == other.Crates;
|
||||
&& Prob == other.Prob;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => HashCode.Combine(Ammo, Power, Delay, Crates);
|
||||
public override int GetHashCode() => HashCode.Combine(Ammo, Power, Delay, Prob);
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,9 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Syroot.Worms.Armageddon</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Team17's Worms Armageddon.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats. Simplify Scheme usage.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation. Implement W:A V3 scheme format.</PackageReleaseNotes>
|
||||
<PackageTags>$(PackageTags);worms armageddon</PackageTags>
|
||||
<Version>3.3.0-beta001</Version>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
@ -17,33 +18,17 @@ namespace Syroot.Worms.Armageddon
|
||||
private const int _missionCount = 33;
|
||||
private const int _trainingMissionCount = 6;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Team"/> class.
|
||||
/// </summary>
|
||||
public Team()
|
||||
{
|
||||
WormNames = new string[8];
|
||||
MissionStatuses = new TeamMissionStatus[_missionCount];
|
||||
TrainingMissionTimes = new int[_trainingMissionCount];
|
||||
Unknown1 = new int[10];
|
||||
TrainingMissionMedals = new byte[_trainingMissionCount];
|
||||
Unknown2 = new byte[10];
|
||||
Unknown3 = new int[7];
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the team.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the 8 worm names.
|
||||
/// Gets the 8 worm names.
|
||||
/// </summary>
|
||||
public string[] WormNames { get; set; }
|
||||
public string[] WormNames { get; } = new string[8];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the AI intelligence difficulty level, from 0-5, where 0 is human-controlled.
|
||||
@ -53,18 +38,18 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets the name of soundbank for the voice of team worms.
|
||||
/// </summary>
|
||||
public string SoundBankName { get; set; }
|
||||
public string SoundBankName { get; set; } = String.Empty;
|
||||
|
||||
public byte SoundBankLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the team fanfare.
|
||||
/// </summary>
|
||||
public string FanfareName { get; set; }
|
||||
public string FanfareName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the fanfare with the name stored in <see cref="FanfareName"/>
|
||||
/// (<c>true</c>) or the player's countries' fanfare should be played (<c>false</c>).
|
||||
/// (<see langword="true"/>) or the player's countries' fanfare should be played (<see langword="false"/>).
|
||||
/// </summary>
|
||||
public byte UseCustomFanfare { get; set; }
|
||||
|
||||
@ -76,12 +61,12 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets the file name of the team grave bitmap if it uses a custom one.
|
||||
/// </summary>
|
||||
public string GraveFileName { get; set; }
|
||||
public string GraveFileName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the team grave bitmap if it uses a custom one.
|
||||
/// </summary>
|
||||
public RawBitmap Grave { get; set; }
|
||||
public RawBitmap Grave { get; set; } = new RawBitmap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the team's special weapon.
|
||||
@ -139,19 +124,19 @@ namespace Syroot.Worms.Armageddon
|
||||
public int DeathmatchDeaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the array of 33 mission statuses.
|
||||
/// Gets the array of 33 mission statuses.
|
||||
/// </summary>
|
||||
public TeamMissionStatus[] MissionStatuses { get; set; }
|
||||
public TeamMissionStatus[] MissionStatuses { get; } = new TeamMissionStatus[_missionCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file name of the team flag.
|
||||
/// </summary>
|
||||
public string FlagFileName { get; set; }
|
||||
public string FlagFileName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bitmap of the team flag.
|
||||
/// </summary>
|
||||
public RawBitmap Flag { get; set; }
|
||||
public RawBitmap Flag { get; set; } = new RawBitmap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the deathmatch rank this team reached.
|
||||
@ -161,31 +146,19 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets the seconds the team required to finish all 6 training missions.
|
||||
/// </summary>
|
||||
public int[] TrainingMissionTimes { get; set; }
|
||||
public int[] TrainingMissionTimes { get; set; } = new int[_trainingMissionCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 10 unknown integer values.
|
||||
/// </summary>
|
||||
public int[] Unknown1 { get; set; }
|
||||
public int[] Unknown1 { get; set; } = new int[10];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the medals the team achieved in all 6 training missions.
|
||||
/// </summary>
|
||||
public byte[] TrainingMissionMedals { get; set; }
|
||||
public byte[] TrainingMissionMedals { get; set; } = new byte[_trainingMissionCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 10 unknown bytes.
|
||||
/// </summary>
|
||||
public byte[] Unknown2 { get; set; }
|
||||
public byte[] Unknown2 { get; set; } = new byte[10];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 7 unknown integer values.
|
||||
/// </summary>
|
||||
public int[] Unknown3 { get; set; }
|
||||
public int[] Unknown3 { get; set; } = new int[7];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown byte.
|
||||
/// </summary>
|
||||
public byte Unknown4 { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
@ -196,7 +169,8 @@ namespace Syroot.Worms.Armageddon
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
Name = reader.ReadString(17);
|
||||
WormNames = reader.ReadStrings(8, 17);
|
||||
for (int i = 0; i < WormNames.Length; i++)
|
||||
WormNames[i] = reader.ReadString(17);
|
||||
CpuLevel = reader.Read1Byte();
|
||||
SoundBankName = reader.ReadString(0x20);
|
||||
SoundBankLocation = reader.Read1Byte();
|
||||
@ -227,7 +201,8 @@ namespace Syroot.Worms.Armageddon
|
||||
DeathmatchKills = reader.ReadInt32();
|
||||
Deaths = reader.ReadInt32();
|
||||
DeathmatchDeaths = reader.ReadInt32();
|
||||
MissionStatuses = reader.ReadStructs<TeamMissionStatus>(_missionCount);
|
||||
for (int i = 0; i < _missionCount; i++)
|
||||
MissionStatuses[i] = reader.ReadStruct<TeamMissionStatus>();
|
||||
|
||||
FlagFileName = reader.ReadString(0x20);
|
||||
Flag = new RawBitmap()
|
||||
@ -252,19 +227,20 @@ namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
writer.WriteString(Name, 17);
|
||||
writer.WriteStrings(WormNames, 17);
|
||||
writer.WriteFixedString(Name, 17);
|
||||
for (int i = 0; i < WormNames.Length; i++)
|
||||
writer.WriteFixedString(WormNames[i], 17);
|
||||
writer.Write(CpuLevel);
|
||||
writer.WriteString(SoundBankName, 0x20);
|
||||
writer.WriteFixedString(SoundBankName, 0x20);
|
||||
writer.Write(SoundBankLocation);
|
||||
writer.WriteString(FanfareName, 0x20);
|
||||
writer.WriteFixedString(FanfareName, 0x20);
|
||||
writer.Write(UseCustomFanfare);
|
||||
|
||||
writer.Write(GraveSprite);
|
||||
if (GraveSprite < 0)
|
||||
{
|
||||
writer.WriteString(GraveFileName, 0x20);
|
||||
writer.WriteColors(Grave.Palette);
|
||||
writer.WriteFixedString(GraveFileName, 0x20);
|
||||
writer.WriteColors(Grave.Palette!);
|
||||
writer.Write(Grave.Data);
|
||||
}
|
||||
|
||||
@ -279,10 +255,11 @@ namespace Syroot.Worms.Armageddon
|
||||
writer.Write(DeathmatchKills);
|
||||
writer.Write(Deaths);
|
||||
writer.Write(DeathmatchDeaths);
|
||||
writer.WriteStructs(MissionStatuses);
|
||||
for (int i = 0; i < MissionStatuses.Length; i++)
|
||||
writer.WriteStruct(ref MissionStatuses[i]);
|
||||
|
||||
writer.WriteString(FlagFileName, 0x20);
|
||||
writer.WriteColors(Flag.Palette);
|
||||
writer.WriteFixedString(FlagFileName, 0x20);
|
||||
writer.WriteColors(Flag.Palette!);
|
||||
writer.Write(Flag.Data);
|
||||
|
||||
writer.Write(DeathmatchRank);
|
||||
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Armageddon
|
||||
{
|
||||
@ -22,7 +22,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class.
|
||||
/// </summary>
|
||||
public TeamContainer() => Teams = new List<Team>();
|
||||
public TeamContainer() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class, loading the data from the given
|
||||
@ -57,7 +57,7 @@ namespace Syroot.Worms.Armageddon
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="Team"/> instances stored.
|
||||
/// </summary>
|
||||
public IList<Team> Teams { get; set; }
|
||||
public IList<Team> Teams { get; set; } = new List<Team>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -77,7 +77,9 @@ namespace Syroot.Worms.Armageddon
|
||||
Unknown = reader.Read1Byte();
|
||||
|
||||
// Read the teams.
|
||||
Teams = new List<Team>(reader.Load<Team>(teamCount));
|
||||
Teams = new List<Team>();
|
||||
while (teamCount-- > 0)
|
||||
Teams.Add(reader.Load<Team>());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -3,7 +3,7 @@ using System.Drawing;
|
||||
using System.IO;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Mgame
|
||||
{
|
||||
@ -32,10 +32,10 @@ namespace Syroot.Worms.Mgame
|
||||
|
||||
public int UnknownA { get; set; }
|
||||
public int UnknownB { get; set; }
|
||||
public byte[] UnknownC { get; set; }
|
||||
public byte[] UnknownC { get; set; } = new byte[8];
|
||||
public Point Center { get; set; }
|
||||
public Size Size { get; set; }
|
||||
public IList<IgdImage> Images { get; set; }
|
||||
public IList<IgdImage> Images { get; set; } = new List<IgdImage>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -82,12 +82,9 @@ namespace Syroot.Worms.Mgame
|
||||
// Decompress the data.
|
||||
int dataSize = stream.ReadInt32();
|
||||
int dataSizeCompressed = stream.ReadInt32();
|
||||
image.RawBitmap = new RawBitmap
|
||||
{
|
||||
Size = new Size(Algebra.NextMultiple(image.Size.Width, 4), image.Size.Height),
|
||||
Palette = palette,
|
||||
Data = Decompress(stream, dataSizeCompressed, dataSize)
|
||||
};
|
||||
image.RawBitmap.Size = new Size(Algebra.NextMultiple(image.Size.Width, 4), image.Size.Height);
|
||||
image.RawBitmap.Palette = palette;
|
||||
image.RawBitmap.Data = Decompress(stream, dataSizeCompressed, dataSize);
|
||||
Images.Add(image);
|
||||
}
|
||||
}
|
||||
|
@ -14,6 +14,6 @@ namespace Syroot.Worms.Mgame
|
||||
public int UnknownC { get; set; }
|
||||
public Size Size { get; set; }
|
||||
public Point Center { get; set; }
|
||||
public RawBitmap RawBitmap { get; set; }
|
||||
public RawBitmap RawBitmap { get; } = new RawBitmap { BitsPerPixel = 8 };
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace Syroot.Worms.Mgame
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
/// <param name="palette">The color palette which is indexed by the image data.</param>
|
||||
public Ksf(string fileName, Palette palette) => Load(fileName, palette);
|
||||
public Ksf(string fileName, KsfPalette palette) => Load(fileName, palette);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Ksf"/> class, loading data from the given
|
||||
@ -31,7 +31,7 @@ namespace Syroot.Worms.Mgame
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
/// <param name="palette">The color palette which is indexed by the image data.</param>
|
||||
public Ksf(Stream stream, Palette palette) => Load(stream, palette);
|
||||
public Ksf(Stream stream, KsfPalette palette) => Load(stream, palette);
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
@ -48,7 +48,7 @@ namespace Syroot.Worms.Mgame
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
/// <param name="palette">The color palette which is indexed by the image data.</param>
|
||||
public void Load(string fileName, Palette palette)
|
||||
public void Load(string fileName, KsfPalette palette)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
Load(stream, palette);
|
||||
@ -60,7 +60,7 @@ namespace Syroot.Worms.Mgame
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
/// <param name="palette">The color palette which is indexed by the image data.</param>
|
||||
public void Load(Stream stream, Palette palette)
|
||||
public void Load(Stream stream, KsfPalette palette)
|
||||
{
|
||||
int imageCount = stream.ReadInt32(); // Includes terminator.
|
||||
_ = stream.ReadInt32(); // data size
|
||||
@ -91,6 +91,7 @@ namespace Syroot.Worms.Mgame
|
||||
{
|
||||
images[i].RawBitmap = new RawBitmap
|
||||
{
|
||||
BitsPerPixel = 8,
|
||||
Size = size,
|
||||
Palette = palette.Colors,
|
||||
Data = stream.ReadBytes(dataLength)
|
||||
|
@ -10,6 +10,6 @@ namespace Syroot.Worms.Mgame
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
public Point Center { get; set; }
|
||||
public RawBitmap RawBitmap { get; set; }
|
||||
public RawBitmap? RawBitmap { get; set; } = null;
|
||||
}
|
||||
}
|
@ -1,50 +1,49 @@
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.Graphics;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.Graphics;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Mgame
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a PAL color palette.
|
||||
/// Represents a color palette referenced by <see cref="KsfImage"/> data.
|
||||
/// </summary>
|
||||
public class Palette : ILoadableFile, IPalette
|
||||
public class KsfPalette : ILoadableFile, IPalette
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The number of colors stored in a palette.
|
||||
/// </summary>
|
||||
/// <summary>Number of colors stored in a palette.</summary>
|
||||
internal const int ColorCount = 256;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Palette"/> class.
|
||||
/// Initializes a new instance of the <see cref="KsfPalette"/> class.
|
||||
/// </summary>
|
||||
public Palette() { }
|
||||
public KsfPalette() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Palette"/> class, loading data from the file with the given
|
||||
/// Initializes a new instance of the <see cref="KsfPalette"/> class, loading data from the file with the given
|
||||
/// <paramref name="fileName"/>.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
public Palette(string fileName) => Load(fileName);
|
||||
public KsfPalette(string fileName) => Load(fileName);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Palette"/> class, loading data from the given
|
||||
/// Initializes a new instance of the <see cref="KsfPalette"/> class, loading data from the given
|
||||
/// <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
public Palette(Stream stream) => Load(stream);
|
||||
public KsfPalette(Stream stream) => Load(stream);
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array of 256 colors stored in this palette.
|
||||
/// </summary>
|
||||
public Color[] Colors { get; set; } = new Color[ColorCount];
|
||||
public IList<Color> Colors { get; set; } = new Color[ColorCount];
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
@ -3,7 +3,7 @@ using System.IO;
|
||||
using System.IO.MemoryMappedFiles;
|
||||
using System.Net;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Mgame
|
||||
{
|
||||
@ -14,7 +14,7 @@ namespace Syroot.Worms.Mgame
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private string _passwordString;
|
||||
private string _passwordString = String.Empty;
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
@ -26,17 +26,17 @@ namespace Syroot.Worms.Mgame
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value. Must not exceed 19 characters.
|
||||
/// </summary>
|
||||
public string Unknown { get; set; }
|
||||
public string Unknown { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the address of the game server.
|
||||
/// </summary>
|
||||
public IPEndPoint ServerEndPoint { get; set; }
|
||||
public IPEndPoint ServerEndPoint { get; set; } = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the initially entered user name. Must not exceed 250 characters.
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
public string UserName { get; set; } = String.Empty;
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -52,12 +52,12 @@ namespace Syroot.Worms.Mgame
|
||||
using (BinaryStream stream = new BinaryStream(mappedFile.CreateViewStream(),
|
||||
encoding: Encodings.Korean, stringCoding: StringCoding.ZeroTerminated))
|
||||
{
|
||||
stream.WriteString(Publisher, 16);
|
||||
stream.WriteString(Unknown, 20);
|
||||
stream.WriteString(_passwordString, 30);
|
||||
stream.WriteString($"UID={UserName}", 256);
|
||||
stream.WriteString(ServerEndPoint.Address.ToString(), 30);
|
||||
stream.WriteString(ServerEndPoint.Port.ToString(), 914);
|
||||
stream.WriteFixedString(Publisher, 16);
|
||||
stream.WriteFixedString(Unknown, 20);
|
||||
stream.WriteFixedString(_passwordString, 30);
|
||||
stream.WriteFixedString($"UID={UserName}", 256);
|
||||
stream.WriteFixedString(ServerEndPoint.Address.ToString(), 30);
|
||||
stream.WriteFixedString(ServerEndPoint.Port.ToString(), 914);
|
||||
}
|
||||
return mappedFile;
|
||||
}
|
||||
@ -68,8 +68,8 @@ namespace Syroot.Worms.Mgame
|
||||
/// </summary>
|
||||
public string GetPassword()
|
||||
{
|
||||
if (_passwordString == null)
|
||||
return null;
|
||||
if (String.IsNullOrEmpty(_passwordString))
|
||||
return String.Empty;
|
||||
string[] parts = _passwordString.Split(';');
|
||||
return PasswordCrypto.Decrypt(parts[1], UInt32.Parse(parts[2]));
|
||||
}
|
||||
@ -81,8 +81,6 @@ namespace Syroot.Worms.Mgame
|
||||
/// <param name="password">The password to store encrypted.</param>
|
||||
/// <param name="key">The key to encrypt with.</param>
|
||||
public void SetPassword(string password, int key = 1000)
|
||||
{
|
||||
_passwordString = $";{PasswordCrypto.Encrypt(password, (uint)key)};{key}";
|
||||
}
|
||||
=> _passwordString = $";{PasswordCrypto.Encrypt(password, (uint)key)};{key}";
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Mgame
|
||||
{
|
||||
@ -32,7 +32,7 @@ namespace Syroot.Worms.Mgame
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="LpdElement"/> instances stored by this class.
|
||||
/// </summary>
|
||||
public IList<LpdElement> Elements { get; set; }
|
||||
public IList<LpdElement> Elements { get; set; } = new List<LpdElement>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Syroot.Worms.Mgame
|
||||
{
|
||||
@ -10,18 +11,15 @@ namespace Syroot.Worms.Mgame
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a the relative path to the IGD storing the image of this element.
|
||||
/// Gets or sets a the relative path to the IGD storing the images of this element.
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
public string FileName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a the area at which the UI element appears.
|
||||
/// </summary>
|
||||
public Rectangle Rectangle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value.
|
||||
/// </summary>
|
||||
public int Properties { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
@ -3,9 +3,9 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Syroot.Worms.Mgame</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Mgame Worms clients.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation.</PackageReleaseNotes>
|
||||
<PackageTags>$(PackageTags);online worms;worms world party aqua</PackageTags>
|
||||
<Version>3.2.0</Version>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
|
@ -1,160 +0,0 @@
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
|
||||
namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents map configuration stored by the land generator in LAND.DAT files.
|
||||
/// Used by WWP. S. https://worms2d.info/Land_Data_file.
|
||||
/// </summary>
|
||||
public class LandData : ILoadableFile, ISaveableFile
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private const int _signature = 0x1A444E4C; // "LND", 0x1A
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LandData"/> class.
|
||||
/// </summary>
|
||||
public LandData() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given
|
||||
/// <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
public LandData(Stream stream) => Load(stream);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
public LandData(string fileName) => Load(fileName);
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the landscape in pixels.
|
||||
/// </summary>
|
||||
public Size Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether an indestructible top border will be enabled.
|
||||
/// </summary>
|
||||
public bool TopBorder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the water in pixels.
|
||||
/// </summary>
|
||||
public int WaterHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an array of coordinates at which objects can be placed.
|
||||
/// </summary>
|
||||
public Point[] ObjectLocations { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual foreground image.
|
||||
/// </summary>
|
||||
public Img Foreground { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the collision mask of the landscape.
|
||||
/// </summary>
|
||||
public Img CollisionMask { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual background image.
|
||||
/// </summary>
|
||||
public Img Background { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the land image file.
|
||||
/// </summary>
|
||||
public string LandTexturePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Water.dir file.
|
||||
/// </summary>
|
||||
public string WaterDirPath { get; set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Load(Stream stream)
|
||||
{
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Read the header.
|
||||
if (reader.ReadInt32() != _signature)
|
||||
throw new InvalidDataException("Invalid LND file signature.");
|
||||
int fileSize = reader.ReadInt32();
|
||||
|
||||
// Read the data.
|
||||
Size = reader.ReadStruct<Size>();
|
||||
TopBorder = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
WaterHeight = reader.ReadInt32();
|
||||
|
||||
// Read the possible object coordinate array.
|
||||
ObjectLocations = reader.ReadStructs<Point>(reader.ReadInt32());
|
||||
|
||||
// Read the image data.
|
||||
Foreground = new Img(stream, true);
|
||||
CollisionMask = new Img(stream, true);
|
||||
Background = new Img(stream, true);
|
||||
|
||||
// Read the file paths.
|
||||
LandTexturePath = reader.ReadString(StringCoding.ByteCharCount);
|
||||
WaterDirPath = reader.ReadString(StringCoding.ByteCharCount);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Load(string fileName)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Save(Stream stream)
|
||||
{
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Write the header.
|
||||
writer.Write(_signature);
|
||||
uint fileSizeOffset = writer.ReserveOffset();
|
||||
|
||||
// Write the data.
|
||||
writer.WriteStruct(Size);
|
||||
writer.Write(TopBorder, BooleanCoding.Dword);
|
||||
writer.Write(WaterHeight);
|
||||
|
||||
// Write the possible object coordinate array.
|
||||
writer.Write(ObjectLocations.Length);
|
||||
writer.WriteStructs(ObjectLocations);
|
||||
|
||||
// Write the image data.
|
||||
Foreground.Save(writer.BaseStream, false, true);
|
||||
CollisionMask.Save(writer.BaseStream, false, true);
|
||||
Background.Save(writer.BaseStream, false, true);
|
||||
|
||||
// Write the file paths.
|
||||
writer.Write(LandTexturePath, StringCoding.ByteCharCount);
|
||||
writer.Write(WaterDirPath, StringCoding.ByteCharCount);
|
||||
|
||||
writer.SatisfyOffset(fileSizeOffset, (int)writer.Position);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Save(string fileName)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
Save(stream);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,9 +3,9 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Syroot.Worms.WorldParty</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Team17's Worms World Party.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation.</PackageReleaseNotes>
|
||||
<PackageTags>$(PackageTags);worms world party</PackageTags>
|
||||
<Version>3.2.0</Version>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
@ -17,31 +18,17 @@ namespace Syroot.Worms.WorldParty
|
||||
private const int _missionCount = 45;
|
||||
private const int _trainingMissionCount = 35;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Team"/> class.
|
||||
/// </summary>
|
||||
public Team()
|
||||
{
|
||||
WormNames = new string[8];
|
||||
MissionStatuses = new TeamMissionStatus[_missionCount];
|
||||
TrainingMissionTimes = new int[_trainingMissionCount];
|
||||
WeaponPoints = new byte[46];
|
||||
Unknown2 = new int[7];
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the team.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the 8 worm names.
|
||||
/// Gets the 8 worm names.
|
||||
/// </summary>
|
||||
public string[] WormNames { get; set; }
|
||||
public string[] WormNames { get; } = new string[8];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the AI intelligence difficulty level, from 0-5, where 0 is human-controlled.
|
||||
@ -51,18 +38,18 @@ namespace Syroot.Worms.WorldParty
|
||||
/// <summary>
|
||||
/// Gets or sets the name of soundbank for the voice of team worms.
|
||||
/// </summary>
|
||||
public string SoundBankName { get; set; }
|
||||
public string SoundBankName { get; set; } = String.Empty;
|
||||
|
||||
public byte SoundBankLocation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the team fanfare.
|
||||
/// </summary>
|
||||
public string FanfareName { get; set; }
|
||||
public string FanfareName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the fanfare with the name stored in <see cref="FanfareName"/>
|
||||
/// (<c>true</c>) or the player's countries' fanfare should be played (<c>false</c>).
|
||||
/// (<see langword="true"/>) or the player's countries' fanfare should be played (<see langword="false"/>).
|
||||
/// </summary>
|
||||
public byte UseCustomFanfare { get; set; }
|
||||
|
||||
@ -74,12 +61,12 @@ namespace Syroot.Worms.WorldParty
|
||||
/// <summary>
|
||||
/// Gets or sets the file name of the team grave bitmap if it uses a custom one.
|
||||
/// </summary>
|
||||
public string GraveFileName { get; set; }
|
||||
public string GraveFileName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the team grave bitmap if it uses a custom one.
|
||||
/// </summary>
|
||||
public RawBitmap Grave { get; set; }
|
||||
public RawBitmap Grave { get; set; } = new RawBitmap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the team's special weapon.
|
||||
@ -137,23 +124,20 @@ namespace Syroot.Worms.WorldParty
|
||||
public int DeathmatchDeaths { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the array of 33 mission statuses.
|
||||
/// Gets the array of 33 mission statuses.
|
||||
/// </summary>
|
||||
public TeamMissionStatus[] MissionStatuses { get; set; }
|
||||
public TeamMissionStatus[] MissionStatuses { get; } = new TeamMissionStatus[_missionCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the file name of the team flag.
|
||||
/// </summary>
|
||||
public string FlagFileName { get; set; }
|
||||
public string FlagFileName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bitmap of the team flag.
|
||||
/// </summary>
|
||||
public RawBitmap Flag { get; set; }
|
||||
public RawBitmap Flag { get; set; } = new RawBitmap();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value.
|
||||
/// </summary>
|
||||
public byte Unknown1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -164,28 +148,20 @@ namespace Syroot.Worms.WorldParty
|
||||
/// <summary>
|
||||
/// Gets or sets the seconds the team required to finish all 35 training missions. The last one is unused.
|
||||
/// </summary>
|
||||
public int[] TrainingMissionTimes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a possibly unused training mission time for a 35th mission.
|
||||
/// </summary>
|
||||
public int UnknownTrainingMissionTime { get; set; }
|
||||
public int[] TrainingMissionTimes { get; set; } = new int[_trainingMissionCount];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the 46 weapons which were bought for points. Specific weapons can be accessed with the
|
||||
/// <see cref="TeamWeaponPoints"/> enumeration.
|
||||
/// <see cref="TeamPointWeapon"/> enumeration.
|
||||
/// </summary>
|
||||
public byte[] WeaponPoints { get; set; }
|
||||
public byte[] WeaponPoints { get; set; } = new byte[46];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the fort of the team.
|
||||
/// </summary>
|
||||
public byte Fort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 7 unknown integer values.
|
||||
/// </summary>
|
||||
public int[] Unknown2 { get; set; }
|
||||
public int[] Unknown2 { get; set; } = new int[7];
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -194,18 +170,19 @@ namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
Name = reader.ReadString(17);
|
||||
WormNames = reader.ReadStrings(8, 17);
|
||||
Name = reader.ReadFixedString(17);
|
||||
for (int i = 0; i < WormNames.Length; i++)
|
||||
WormNames[i] = reader.ReadFixedString(17);
|
||||
CpuLevel = reader.Read1Byte();
|
||||
SoundBankName = reader.ReadString(0x20);
|
||||
SoundBankName = reader.ReadFixedString(0x20);
|
||||
SoundBankLocation = reader.Read1Byte();
|
||||
FanfareName = reader.ReadString(0x20);
|
||||
FanfareName = reader.ReadFixedString(0x20);
|
||||
UseCustomFanfare = reader.Read1Byte();
|
||||
|
||||
GraveSprite = reader.ReadSByte();
|
||||
if (GraveSprite < 0)
|
||||
{
|
||||
GraveFileName = reader.ReadString(0x20);
|
||||
GraveFileName = reader.ReadFixedString(0x20);
|
||||
Grave = new RawBitmap()
|
||||
{
|
||||
BitsPerPixel = 8,
|
||||
@ -226,9 +203,10 @@ namespace Syroot.Worms.WorldParty
|
||||
DeathmatchKills = reader.ReadInt32();
|
||||
Deaths = reader.ReadInt32();
|
||||
DeathmatchDeaths = reader.ReadInt32();
|
||||
MissionStatuses = reader.ReadStructs<TeamMissionStatus>(_missionCount);
|
||||
for (int i = 0; i < _missionCount; i++)
|
||||
MissionStatuses[i] = reader.ReadStruct<TeamMissionStatus>();
|
||||
|
||||
FlagFileName = reader.ReadString(0x20);
|
||||
FlagFileName = reader.ReadFixedString(0x20);
|
||||
Flag = new RawBitmap()
|
||||
{
|
||||
BitsPerPixel = 8,
|
||||
@ -250,19 +228,20 @@ namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
writer.WriteString(Name, 17);
|
||||
writer.WriteStrings(WormNames, 17);
|
||||
writer.WriteFixedString(Name, 17);
|
||||
for (int i = 0; i < 8; i++)
|
||||
writer.WriteFixedString(WormNames[i], 17);
|
||||
writer.Write(CpuLevel);
|
||||
writer.WriteString(SoundBankName, 0x20);
|
||||
writer.WriteFixedString(SoundBankName, 0x20);
|
||||
writer.Write(SoundBankLocation);
|
||||
writer.WriteString(FanfareName, 0x20);
|
||||
writer.WriteFixedString(FanfareName, 0x20);
|
||||
writer.Write(UseCustomFanfare);
|
||||
|
||||
writer.Write(GraveSprite);
|
||||
if (GraveSprite < 0)
|
||||
{
|
||||
writer.WriteString(GraveFileName, 0x20);
|
||||
writer.WriteColors(Grave.Palette);
|
||||
writer.WriteFixedString(GraveFileName, 0x20);
|
||||
writer.WriteColors(Grave.Palette!);
|
||||
writer.Write(Grave.Data);
|
||||
}
|
||||
|
||||
@ -277,16 +256,16 @@ namespace Syroot.Worms.WorldParty
|
||||
writer.Write(DeathmatchKills);
|
||||
writer.Write(Deaths);
|
||||
writer.Write(DeathmatchDeaths);
|
||||
writer.WriteStructs(MissionStatuses);
|
||||
for (int i = 0; i < MissionStatuses.Length; i++)
|
||||
writer.WriteStruct(MissionStatuses[i]);
|
||||
|
||||
writer.WriteString(FlagFileName, 0x20);
|
||||
writer.WriteColors(Flag.Palette);
|
||||
writer.WriteFixedString(FlagFileName, 0x20);
|
||||
writer.WriteColors(Flag.Palette!);
|
||||
writer.Write(Flag.Data);
|
||||
|
||||
writer.Write(Unknown1);
|
||||
writer.Write(DeathmatchRank);
|
||||
writer.Write(TrainingMissionTimes);
|
||||
writer.Write(UnknownTrainingMissionTime);
|
||||
writer.Write(WeaponPoints);
|
||||
writer.Write(Fort);
|
||||
writer.Write(Unknown2);
|
||||
@ -299,14 +278,11 @@ namespace Syroot.Worms.WorldParty
|
||||
[DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")]
|
||||
public struct TeamMissionStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The number of attempts the team required to solve the mission.
|
||||
/// </summary>
|
||||
public int Attempts;
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// The medal the team got to solve the mission.
|
||||
/// </summary>
|
||||
/// <summary>Number of attempts the team required to solve the mission.</summary>
|
||||
public int Attempts;
|
||||
/// <summary>Medal the team got to solve the mission.</summary>
|
||||
public int Medal;
|
||||
}
|
||||
|
||||
@ -315,44 +291,21 @@ namespace Syroot.Worms.WorldParty
|
||||
/// </summary>
|
||||
public enum TeamWeapon : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// The Flame Thrower weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Flame Thrower weapon.</summary>
|
||||
Flamethrower,
|
||||
|
||||
/// <summary>
|
||||
/// The Mole Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mole Bomb weapon.</summary>
|
||||
MoleBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Old Woman weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Old Woman weapon.</summary>
|
||||
OldWoman,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Pigeon weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Pigeon weapon.</summary>
|
||||
HomingPigeon,
|
||||
|
||||
/// <summary>
|
||||
/// The Sheep Launcher weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Sheep Launcher weapon.</summary>
|
||||
SheepLauncher,
|
||||
|
||||
/// <summary>
|
||||
/// The Mad Cow weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mad Cow weapon.</summary>
|
||||
MadCow,
|
||||
|
||||
/// <summary>
|
||||
/// The Holy Hand Grenade weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Holy Hand Grenade weapon.</summary>
|
||||
HolyHandGrenade,
|
||||
|
||||
/// <summary>
|
||||
/// The Super Sheep or Aqua Sheep weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Super Sheep or Aqua Sheep weapon.</summary>
|
||||
SuperSheep
|
||||
}
|
||||
|
||||
@ -360,236 +313,99 @@ namespace Syroot.Worms.WorldParty
|
||||
/// Represents the weapons and utilities being an index into the <see cref="Team.WeaponPoints"/> array to store the
|
||||
/// amount the team bought.
|
||||
/// </summary>
|
||||
public enum TeamWeaponPoints
|
||||
public enum TeamPointWeapon
|
||||
{
|
||||
/// <summary>
|
||||
/// The Bazooka weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Bazooka weapon.</summary>
|
||||
Bazooka,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Missile weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Missile weapon.</summary>
|
||||
HomingMissile,
|
||||
|
||||
/// <summary>
|
||||
/// The Mortar weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mortar weapon.</summary>
|
||||
Mortar,
|
||||
|
||||
/// <summary>
|
||||
/// The Grenade weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Grenade weapon.</summary>
|
||||
Grenade,
|
||||
|
||||
/// <summary>
|
||||
/// The Cluster Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Cluster Bomb weapon.</summary>
|
||||
ClusterBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Skunk weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Skunk weapon.</summary>
|
||||
Skunk,
|
||||
|
||||
/// <summary>
|
||||
/// The Petrol Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Petrol Bomb weapon.</summary>
|
||||
PetrolBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Banana Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Banana Bomb weapon.</summary>
|
||||
BananaBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Handgun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Handgun weapon.</summary>
|
||||
Handgun,
|
||||
|
||||
/// <summary>
|
||||
/// The Shotgun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Shotgun weapon.</summary>
|
||||
Shotgun,
|
||||
|
||||
/// <summary>
|
||||
/// The Uzi weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Uzi weapon.</summary>
|
||||
Uzi,
|
||||
|
||||
/// <summary>
|
||||
/// The Minigun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Minigun weapon.</summary>
|
||||
Minigun,
|
||||
|
||||
/// <summary>
|
||||
/// The Longbow weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Longbow weapon.</summary>
|
||||
Longbow,
|
||||
|
||||
/// <summary>
|
||||
/// The Airstrike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Airstrike weapon.</summary>
|
||||
Airstrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Napalm Strike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Napalm Strike weapon.</summary>
|
||||
NapalmStrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Mine weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mine weapon.</summary>
|
||||
Mine,
|
||||
|
||||
/// <summary>
|
||||
/// The Firepunch weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Firepunch weapon.</summary>
|
||||
Firepunch,
|
||||
|
||||
/// <summary>
|
||||
/// The Dragonball weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Dragonball weapon.</summary>
|
||||
Dragonball,
|
||||
|
||||
/// <summary>
|
||||
/// The Kamikaze weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Kamikaze weapon.</summary>
|
||||
Kamikaze,
|
||||
|
||||
/// <summary>
|
||||
/// The Prod weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Prod weapon.</summary>
|
||||
Prod,
|
||||
|
||||
/// <summary>
|
||||
/// The Battle Axe weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Battle Axe weapon.</summary>
|
||||
BattleAxe,
|
||||
|
||||
/// <summary>
|
||||
/// The Blowtorch weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Blowtorch weapon.</summary>
|
||||
Blowtorch,
|
||||
|
||||
/// <summary>
|
||||
/// The Pneumatic Drill weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Pneumatic Drill weapon.</summary>
|
||||
PneumaticDrill,
|
||||
|
||||
/// <summary>
|
||||
/// The Girder weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Girder weapon.</summary>
|
||||
Girder,
|
||||
|
||||
/// <summary>
|
||||
/// The Ninja Rope weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Ninja Rope weapon.</summary>
|
||||
NinjaRope,
|
||||
|
||||
/// <summary>
|
||||
/// The Parachute weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Parachute weapon.</summary>
|
||||
Parachute,
|
||||
|
||||
/// <summary>
|
||||
/// The Bungee weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Bungee weapon.</summary>
|
||||
Bungee,
|
||||
|
||||
/// <summary>
|
||||
/// The Teleport weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Teleport weapon.</summary>
|
||||
Teleport,
|
||||
|
||||
/// <summary>
|
||||
/// The Dynamite weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Dynamite weapon.</summary>
|
||||
Dynamite,
|
||||
|
||||
/// <summary>
|
||||
/// The Sheep weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Sheep weapon.</summary>
|
||||
Sheep,
|
||||
|
||||
/// <summary>
|
||||
/// The Baseball Bat weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Baseball Bat weapon.</summary>
|
||||
BaseballBat,
|
||||
|
||||
/// <summary>
|
||||
/// The Flame Thrower weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Flame Thrower weapon.</summary>
|
||||
Flamethrower,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Pigeon weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Pigeon weapon.</summary>
|
||||
HomingPigeon,
|
||||
|
||||
/// <summary>
|
||||
/// The Mad Cow weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mad Cow weapon.</summary>
|
||||
MadCow,
|
||||
|
||||
/// <summary>
|
||||
/// The Holy Hand Grenade weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Holy Hand Grenade weapon.</summary>
|
||||
HolyHandGrenade,
|
||||
|
||||
/// <summary>
|
||||
/// The Old Woman weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Old Woman weapon.</summary>
|
||||
OldWoman,
|
||||
|
||||
/// <summary>
|
||||
/// The Sheep Launcher weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Sheep Launcher weapon.</summary>
|
||||
SheepLauncher,
|
||||
|
||||
/// <summary>
|
||||
/// The Super Sheep or Aqua Sheep weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Super Sheep or Aqua Sheep weapon.</summary>
|
||||
SuperSheep,
|
||||
|
||||
/// <summary>
|
||||
/// The Mole Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mole Bomb weapon.</summary>
|
||||
MoleBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Jetpack utility.
|
||||
/// </summary>
|
||||
/// <summary>The Jetpack utility.</summary>
|
||||
Jetpack,
|
||||
|
||||
/// <summary>
|
||||
/// The Low Gravity utility.
|
||||
/// </summary>
|
||||
/// <summary>The Low Gravity utility.</summary>
|
||||
LowGravity,
|
||||
|
||||
/// <summary>
|
||||
/// The Laser Sight utility.
|
||||
/// </summary>
|
||||
/// <summary>The Laser Sight utility.</summary>
|
||||
LaserSight,
|
||||
|
||||
/// <summary>
|
||||
/// The Fast Walk utility.
|
||||
/// </summary>
|
||||
/// <summary>The Fast Walk utility.</summary>
|
||||
FastWalk,
|
||||
|
||||
/// <summary>
|
||||
/// The Invisibility utility.
|
||||
/// </summary>
|
||||
/// <summary>The Invisibility utility.</summary>
|
||||
Invisibility,
|
||||
|
||||
/// <summary>
|
||||
/// The Suicide Bomber weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Suicide Bomber weapon.</summary>
|
||||
SuicideBomber,
|
||||
|
||||
/// <summary>
|
||||
/// The Worm Select utility.
|
||||
/// </summary>
|
||||
/// <summary>The Worm Select utility.</summary>
|
||||
WormSelect
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
@ -14,14 +14,14 @@ namespace Syroot.Worms.WorldParty
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private const string _signature = "WWP"; // 0-terminated.
|
||||
private const uint _signature = 0x00505757; // "WWP\0"
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class.
|
||||
/// </summary>
|
||||
public TeamContainer() => Teams = new List<Team>();
|
||||
public TeamContainer() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class, loading the data from the given
|
||||
@ -43,25 +43,19 @@ namespace Syroot.Worms.WorldParty
|
||||
/// </summary>
|
||||
public byte Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value.
|
||||
/// </summary>
|
||||
public byte Unknown1 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value.
|
||||
/// </summary>
|
||||
public byte Unknown2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets 840 unknown bytes, all possibly 0.
|
||||
/// </summary>
|
||||
public byte[] Unknown3 { get; set; }
|
||||
public byte[] Unknown3 { get; set; } = new byte[840];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="Team"/> instances stored.
|
||||
/// </summary>
|
||||
public List<Team> Teams { get; set; }
|
||||
public IList<Team> Teams { get; set; } = new List<Team>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -71,7 +65,7 @@ namespace Syroot.Worms.WorldParty
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Read the header.
|
||||
if (reader.ReadString(StringCoding.ZeroTerminated) != _signature)
|
||||
if (reader.ReadUInt32() != _signature)
|
||||
throw new InvalidDataException("Invalid WWP file signature.");
|
||||
Version = reader.Read1Byte(); // Really version?
|
||||
|
||||
@ -82,7 +76,9 @@ namespace Syroot.Worms.WorldParty
|
||||
Unknown3 = reader.ReadBytes(840);
|
||||
|
||||
// Read the teams.
|
||||
Teams = new List<Team>(reader.Load<Team>(teamCount));
|
||||
Teams = new List<Team>(teamCount);
|
||||
while (teamCount-- > 0)
|
||||
Teams.Add(reader.Load<Team>());
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -98,7 +94,7 @@ namespace Syroot.Worms.WorldParty
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Write the header.
|
||||
writer.Write(_signature, StringCoding.ZeroTerminated);
|
||||
writer.Write(_signature);
|
||||
writer.Write(Version);
|
||||
|
||||
// Write global settings.
|
||||
|
@ -1,20 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents map configuration stored by the land generator in LAND.DAT files.
|
||||
/// Used by W2. S. https://worms2d.info/Land_Data_file.
|
||||
/// Used by W2 and OW. S. https://worms2d.info/Land_Data_file.
|
||||
/// </summary>
|
||||
public class LandData : ILoadableFile, ISaveableFile
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private const int _signature = 0x1A444E4C; // "LND", 0x1A
|
||||
private const int _signature = 0x1A444E4C; // "LND\x1A"
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -51,7 +53,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Gets or sets an array of coordinates at which objects can be placed.
|
||||
/// </summary>
|
||||
public Point[] ObjectLocations { get; set; }
|
||||
public IList<Point> ObjectLocations { get; set; } = new List<Point>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an unknown value, seeming to be 0 most of the time.
|
||||
@ -61,32 +63,32 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Gets or sets the visual foreground image.
|
||||
/// </summary>
|
||||
public Img Foreground { get; set; }
|
||||
public Img Foreground { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the collision mask of the landscape.
|
||||
/// </summary>
|
||||
public Img CollisionMask { get; set; }
|
||||
public Img CollisionMask { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual background image.
|
||||
/// </summary>
|
||||
public Img Background { get; set; }
|
||||
public Img Background { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an image of unknown use.
|
||||
/// </summary>
|
||||
public Img UnknownImage { get; set; }
|
||||
public Img UnknownImage { get; set; } = new Img();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the land image file.
|
||||
/// </summary>
|
||||
public string LandTexturePath { get; set; }
|
||||
public string LandTexturePath { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Water.dir file.
|
||||
/// </summary>
|
||||
public string WaterDirPath { get; set; }
|
||||
public string WaterDirPath { get; set; } = String.Empty;
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -105,7 +107,10 @@ namespace Syroot.Worms.Worms2
|
||||
TopBorder = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
|
||||
// Read the possible object coordinate array.
|
||||
ObjectLocations = reader.ReadStructs<Point>(reader.ReadInt32());
|
||||
ObjectLocations = new List<Point>();
|
||||
int locationCount = reader.ReadInt32();
|
||||
for (int i = 0; i < locationCount; i++)
|
||||
ObjectLocations.Add(reader.ReadStruct<Point>());
|
||||
Unknown = reader.ReadInt32();
|
||||
|
||||
// Read the image data.
|
||||
@ -140,8 +145,9 @@ namespace Syroot.Worms.Worms2
|
||||
writer.Write(TopBorder, BooleanCoding.Dword);
|
||||
|
||||
// Write the possible object coordinate array.
|
||||
writer.Write(ObjectLocations.Length);
|
||||
writer.WriteStructs(ObjectLocations);
|
||||
writer.Write(ObjectLocations.Count);
|
||||
for (int i = 0; i < ObjectLocations.Count; i++)
|
||||
writer.WriteStruct(ObjectLocations[i]);
|
||||
writer.Write(Unknown);
|
||||
|
||||
// Write the image data.
|
||||
@ -154,7 +160,7 @@ namespace Syroot.Worms.Worms2
|
||||
writer.Write(LandTexturePath, StringCoding.ByteCharCount);
|
||||
writer.Write(WaterDirPath, StringCoding.ByteCharCount);
|
||||
|
||||
writer.SatisfyOffset(fileSizeOffset, (int)writer.Position);
|
||||
writer.SatisfyOffset(fileSizeOffset, (uint)writer.Position);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -3,222 +3,98 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Represents the method to determine the next turn's worm.
|
||||
/// </summary>
|
||||
public enum SchemeWormSelect : int
|
||||
public enum WormSelect : int
|
||||
{
|
||||
/// <summary>
|
||||
/// Worms are selected in the order in which they appear in the team.
|
||||
/// </summary>
|
||||
Sequential = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Worms are selected randomly.
|
||||
/// </summary>
|
||||
Random = 1,
|
||||
|
||||
/// <summary>
|
||||
/// Worms are selected by a computed rating system.
|
||||
/// </summary>
|
||||
Intelligent = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Worms are selected by the player.
|
||||
/// </summary>
|
||||
Manual = 3
|
||||
/// <summary>Worms are selected in the order in which they appear in the team.</summary>
|
||||
Sequential,
|
||||
/// <summary>Worms are selected randomly.</summary>
|
||||
Random,
|
||||
/// <summary>Worms are selected by a computed rating system.</summary>
|
||||
Intelligent,
|
||||
/// <summary>Worms are selected by the player.</summary>
|
||||
Manual
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents the weapons in the game.
|
||||
/// </summary>
|
||||
public enum SchemeWeapon
|
||||
public enum Weapon
|
||||
{
|
||||
/// <summary>
|
||||
/// The Bazooka weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Bazooka weapon.</summary>
|
||||
Bazooka,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Missile weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Missile weapon.</summary>
|
||||
HomingMissile,
|
||||
|
||||
/// <summary>
|
||||
/// The Grenade weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Grenade weapon.</summary>
|
||||
Grenade,
|
||||
|
||||
/// <summary>
|
||||
/// The Cluster Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Cluster Bomb weapon.</summary>
|
||||
ClusterBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Banana Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Banana Bomb weapon.</summary>
|
||||
BananaBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Holy Hand Grenade weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Holy Hand Grenade weapon.</summary>
|
||||
HolyHandGrenade,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Cluster Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Cluster Bomb weapon.</summary>
|
||||
HomingClusterBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Petrol Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Petrol Bomb weapon.</summary>
|
||||
PetrolBomb,
|
||||
|
||||
/// <summary>
|
||||
/// The Shotgun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Shotgun weapon.</summary>
|
||||
Shotgun,
|
||||
|
||||
/// <summary>
|
||||
/// The Handgun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Handgun weapon.</summary>
|
||||
Handgun,
|
||||
|
||||
/// <summary>
|
||||
/// The Uzi weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Uzi weapon.</summary>
|
||||
Uzi,
|
||||
|
||||
/// <summary>
|
||||
/// The Minigun weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Minigun weapon.</summary>
|
||||
Minigun,
|
||||
|
||||
/// <summary>
|
||||
/// The Firepunch weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Firepunch weapon.</summary>
|
||||
Firepunch,
|
||||
|
||||
/// <summary>
|
||||
/// The Dragonball weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Dragonball weapon.</summary>
|
||||
Dragonball,
|
||||
|
||||
/// <summary>
|
||||
/// The Kamikaze weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Kamikaze weapon.</summary>
|
||||
Kamikaze,
|
||||
|
||||
/// <summary>
|
||||
/// The Dynamite weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Dynamite weapon.</summary>
|
||||
Dynamite,
|
||||
|
||||
/// <summary>
|
||||
/// The Mine weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mine weapon.</summary>
|
||||
Mine,
|
||||
|
||||
/// <summary>
|
||||
/// The Ming Vase weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Ming Vase weapon.</summary>
|
||||
MingVase,
|
||||
|
||||
/// <summary>
|
||||
/// The Airstrike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Airstrike weapon.</summary>
|
||||
Airstrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Airstrike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Airstrike weapon.</summary>
|
||||
HomingAirstrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Napalm Strike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Napalm Strike weapon.</summary>
|
||||
NapalmStrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Mail Strike weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mail Strike weapon.</summary>
|
||||
MailStrike,
|
||||
|
||||
/// <summary>
|
||||
/// The Girder weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Girder weapon.</summary>
|
||||
Girder,
|
||||
|
||||
/// <summary>
|
||||
/// The Pneumatic Drill weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Pneumatic Drill weapon.</summary>
|
||||
PneumaticDrill,
|
||||
|
||||
/// <summary>
|
||||
/// The Baseball Bat weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Baseball Bat weapon.</summary>
|
||||
BaseballBat,
|
||||
|
||||
/// <summary>
|
||||
/// The Prod weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Prod weapon.</summary>
|
||||
Prod,
|
||||
|
||||
/// <summary>
|
||||
/// The Teleport weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Teleport weapon.</summary>
|
||||
Teleport,
|
||||
|
||||
/// <summary>
|
||||
/// The Ninja Rope weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Ninja Rope weapon.</summary>
|
||||
NinjaRope,
|
||||
|
||||
/// <summary>
|
||||
/// The Bungee weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Bungee weapon.</summary>
|
||||
Bungee,
|
||||
|
||||
/// <summary>
|
||||
/// The Parachute weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Parachute weapon.</summary>
|
||||
Parachute,
|
||||
|
||||
/// <summary>
|
||||
/// The Sheep weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Sheep weapon.</summary>
|
||||
Sheep,
|
||||
|
||||
/// <summary>
|
||||
/// The Mad Cow weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mad Cow weapon.</summary>
|
||||
MadCow,
|
||||
|
||||
/// <summary>
|
||||
/// The Old Woman weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Old Woman weapon.</summary>
|
||||
OldWoman,
|
||||
|
||||
/// <summary>
|
||||
/// The Mortar weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Mortar weapon.</summary>
|
||||
Mortar,
|
||||
|
||||
/// <summary>
|
||||
/// The Blowtorch weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Blowtorch weapon.</summary>
|
||||
Blowtorch,
|
||||
|
||||
/// <summary>
|
||||
/// The Homing Pigeon weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Homing Pigeon weapon.</summary>
|
||||
HomingPigeon,
|
||||
|
||||
/// <summary>
|
||||
/// The Super Sheep weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Super Sheep weapon.</summary>
|
||||
SuperSheep,
|
||||
|
||||
/// <summary>
|
||||
/// The Super Banana Bomb weapon.
|
||||
/// </summary>
|
||||
/// <summary>The Super Banana Bomb weapon.</summary>
|
||||
SuperBananaBomb
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
@ -140,7 +140,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the worm selection order determining the next worm to be played.
|
||||
/// </summary>
|
||||
public SchemeWormSelect WormSelectMode { get; set; }
|
||||
public WormSelect WormSelectMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the chat box will be closed upon starting to move a worm or stays
|
||||
@ -236,7 +236,7 @@ namespace Syroot.Worms.Worms2
|
||||
SuddenDeathHealthDrop = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
IndestructibleBorder = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
RestrictGirders = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
WormSelectMode = reader.ReadEnum<SchemeWormSelect>(true);
|
||||
WormSelectMode = reader.ReadEnum<WormSelect>(true);
|
||||
ExtendedChatControls = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
HotSeatDelay = reader.ReadInt32();
|
||||
EnableStockpiling = reader.ReadBoolean(BooleanCoding.Dword);
|
||||
|
171
src/library/Syroot.Worms.Worms2/SchemeWeapon.cs
Normal file
171
src/library/Syroot.Worms.Worms2/SchemeWeapon.cs
Normal file
@ -0,0 +1,171 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the configuration of a weapon.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SchemeWeapon : IEquatable<SchemeWeapon>
|
||||
{
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>Amount of this weapon with which a team is equipped at game start. 10 and negative values represent
|
||||
/// infinity.</summary>
|
||||
public int Ammo;
|
||||
/// <summary>Number of turns required to be taken by each team before this weapon becomes available.</summary>
|
||||
public int Delay;
|
||||
/// <summary>Retreat time after using this weapon. 0 uses the setting from the game options.</summary>
|
||||
public int RetreatTime;
|
||||
/// <summary><see langword="true"/> to preselect this weapon in the next turn; otherwise <see langword="false"/>.</summary>
|
||||
public bool Remember;
|
||||
public int Unused1;
|
||||
/// <summary>Amount of this weapon added to the team armory when collected from a crate.</summary>
|
||||
public int CrateAmmo;
|
||||
/// <summary>Amount of bullets shot at once.</summary>
|
||||
public int BulletCount;
|
||||
/// <summary>Percentual chance of this weapon to appear in crates.</summary>
|
||||
public int Probability;
|
||||
/// <summary>Damage measured in health points which also determines the blast radius.</summary>
|
||||
public int Damage;
|
||||
/// <summary>Pushing power measured in percent.</summary>
|
||||
public int ExplosionPower;
|
||||
/// <summary>Offset to the bottom of an explosion, measured in percent.</summary>
|
||||
public int ExplosionBias;
|
||||
/// <summary>Milliseconds required before this weapon starts flying towards its target.</summary>
|
||||
public int HomingDelay;
|
||||
/// <summary>Length in milliseconds this weapon flies towards its target before giving up.</summary>
|
||||
public int HomingTime;
|
||||
/// <summary>Percentual amount this weaopn is affected by wind.</summary>
|
||||
public int WindResponse;
|
||||
public int Unused2;
|
||||
/// <summary>Number of clusters into which this weapon explodes.</summary>
|
||||
public int ClusterCount;
|
||||
/// <summary>Speed in which clusters are dispersed in percent.</summary>
|
||||
public int ClusterLaunchPower;
|
||||
/// <summary>Angle in which clusters are dispersed in degrees.</summary>
|
||||
public int ClusterLaunchAngle;
|
||||
/// <summary>Damage of clusters measured in health points which also determines the blast radius.</summary>
|
||||
public int ClusterDamage;
|
||||
/// <summary>Overrides the fuse of this weapon, 0 for default.</summary>
|
||||
public int Fuse;
|
||||
/// <summary>Amount of fire created.</summary>
|
||||
public int FireAmount;
|
||||
/// <summary>Speed in which fire spreads, measured in percent.</summary>
|
||||
public int FireSpreadSpeed;
|
||||
/// <summary>Period in which fire burns, measured in percent.</summary>
|
||||
public int FireTime;
|
||||
/// <summary>Melee impact force in percent.</summary>
|
||||
public int MeleeForce;
|
||||
/// <summary>Melee impact angle in degrees.</summary>
|
||||
public int MeleeAngle;
|
||||
/// <summary>Melee damage in health points.</summary>
|
||||
public int MeleeDamage;
|
||||
/// <summary>Height of the fire punch jump, measured in percent.</summary>
|
||||
public int FirepunchHeight;
|
||||
/// <summary>Damage a dragon ball causes, measured in health points.</summary>
|
||||
public int DragonballDamage;
|
||||
/// <summary>Power in which a dragon ball launches hit worms, measured in percent.</summary>
|
||||
public int DragonballPower;
|
||||
/// <summary>Angle in which a dragon ball launches hit worms, measured in degrees.</summary>
|
||||
public int DragonballAngle;
|
||||
/// <summary>Lifetime of a launched dragon ball measured in milliseconds.</summary>
|
||||
public int DragonballTime;
|
||||
/// <summary>Length of digging measured in milliseconds. Applies to Kamikaze and digging tools.</summary>
|
||||
public int DiggingTime;
|
||||
/// <summary>Amount of airstrike clusters thrown.</summary>
|
||||
public int StrikeClusterCount;
|
||||
/// <summary>Angle in which bullets are dispersed, measured in degrees.</summary>
|
||||
public int BulletSpreadAngle;
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
public static bool operator ==(SchemeWeapon left, SchemeWeapon right) => left.Equals(right);
|
||||
|
||||
public static bool operator !=(SchemeWeapon left, SchemeWeapon right) => !(left == right);
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj) => obj is SchemeWeapon weapon && Equals(weapon);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(SchemeWeapon other)
|
||||
=> Ammo == other.Ammo
|
||||
&& Delay == other.Delay
|
||||
&& RetreatTime == other.RetreatTime
|
||||
&& Remember == other.Remember
|
||||
&& Unused1 == other.Unused1
|
||||
&& CrateAmmo == other.CrateAmmo
|
||||
&& BulletCount == other.BulletCount
|
||||
&& Probability == other.Probability
|
||||
&& Damage == other.Damage
|
||||
&& ExplosionPower == other.ExplosionPower
|
||||
&& ExplosionBias == other.ExplosionBias
|
||||
&& HomingDelay == other.HomingDelay
|
||||
&& HomingTime == other.HomingTime
|
||||
&& WindResponse == other.WindResponse
|
||||
&& Unused2 == other.Unused2
|
||||
&& ClusterCount == other.ClusterCount
|
||||
&& ClusterLaunchPower == other.ClusterLaunchPower
|
||||
&& ClusterLaunchAngle == other.ClusterLaunchAngle
|
||||
&& ClusterDamage == other.ClusterDamage
|
||||
&& Fuse == other.Fuse
|
||||
&& FireAmount == other.FireAmount
|
||||
&& FireSpreadSpeed == other.FireSpreadSpeed
|
||||
&& FireTime == other.FireTime
|
||||
&& MeleeForce == other.MeleeForce
|
||||
&& MeleeAngle == other.MeleeAngle
|
||||
&& MeleeDamage == other.MeleeDamage
|
||||
&& FirepunchHeight == other.FirepunchHeight
|
||||
&& DragonballDamage == other.DragonballDamage
|
||||
&& DragonballPower == other.DragonballPower
|
||||
&& DragonballAngle == other.DragonballAngle
|
||||
&& DragonballTime == other.DragonballTime
|
||||
&& DiggingTime == other.DiggingTime
|
||||
&& StrikeClusterCount == other.StrikeClusterCount
|
||||
&& BulletSpreadAngle == other.BulletSpreadAngle;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
HashCode hash = new HashCode();
|
||||
hash.Add(Ammo);
|
||||
hash.Add(Delay);
|
||||
hash.Add(RetreatTime);
|
||||
hash.Add(Remember);
|
||||
hash.Add(Unused1);
|
||||
hash.Add(CrateAmmo);
|
||||
hash.Add(BulletCount);
|
||||
hash.Add(Probability);
|
||||
hash.Add(Damage);
|
||||
hash.Add(ExplosionPower);
|
||||
hash.Add(ExplosionBias);
|
||||
hash.Add(HomingDelay);
|
||||
hash.Add(HomingTime);
|
||||
hash.Add(WindResponse);
|
||||
hash.Add(Unused2);
|
||||
hash.Add(ClusterCount);
|
||||
hash.Add(ClusterLaunchPower);
|
||||
hash.Add(ClusterLaunchAngle);
|
||||
hash.Add(ClusterDamage);
|
||||
hash.Add(Fuse);
|
||||
hash.Add(FireAmount);
|
||||
hash.Add(FireSpreadSpeed);
|
||||
hash.Add(FireTime);
|
||||
hash.Add(MeleeForce);
|
||||
hash.Add(MeleeAngle);
|
||||
hash.Add(MeleeDamage);
|
||||
hash.Add(FirepunchHeight);
|
||||
hash.Add(DragonballDamage);
|
||||
hash.Add(DragonballPower);
|
||||
hash.Add(DragonballAngle);
|
||||
hash.Add(DragonballTime);
|
||||
hash.Add(DiggingTime);
|
||||
hash.Add(StrikeClusterCount);
|
||||
hash.Add(BulletSpreadAngle);
|
||||
return hash.ToHashCode();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,182 +0,0 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the configuration of a weapon.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct SchemeWeaponSetting
|
||||
{
|
||||
/// <summary>
|
||||
/// The amount of this weapon with which a team is equipped at game start. 10 and negative values represent
|
||||
/// infinity.
|
||||
/// </summary>
|
||||
public int Ammunition;
|
||||
|
||||
/// <summary>
|
||||
/// The number of turns required to be taken by each team before this weapon becomes available.
|
||||
/// </summary>
|
||||
public int Delay;
|
||||
|
||||
/// <summary>
|
||||
/// Retreat time after using this weapon. 0 uses the setting from the game options.
|
||||
/// </summary>
|
||||
public int RetreatTime;
|
||||
|
||||
/// <summary>
|
||||
/// <c>true</c> to preselect this weapon in the next turn; otherwise <c>false</c>.
|
||||
/// </summary>
|
||||
public bool Remember;
|
||||
|
||||
/// <summary>
|
||||
/// An unused field with unknown value.
|
||||
/// </summary>
|
||||
public int Unused1;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of this weapon added to the team armory when collected from a crate.
|
||||
/// </summary>
|
||||
public int CrateAmmunition;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of bullets shot at once.
|
||||
/// </summary>
|
||||
public int BulletCount;
|
||||
|
||||
/// <summary>
|
||||
/// The percentual chance of this weapon to appear in crates.
|
||||
/// </summary>
|
||||
public int Probability;
|
||||
|
||||
/// <summary>
|
||||
/// The damage measured in health points which also determines the blast radius.
|
||||
/// </summary>
|
||||
public int Damage;
|
||||
|
||||
/// <summary>
|
||||
/// The pushing power measured in percent.
|
||||
/// </summary>
|
||||
public int ExplosionPower;
|
||||
|
||||
/// <summary>
|
||||
/// The offset to the bottom of an explosion, measured in percent.
|
||||
/// </summary>
|
||||
public int ExplosionBias;
|
||||
|
||||
/// <summary>
|
||||
/// The milliseconds required before this weapon starts flying towards its target.
|
||||
/// </summary>
|
||||
public int HomingDelay;
|
||||
|
||||
/// <summary>
|
||||
/// The length in milliseconds this weapon flies towards its target before giving up.
|
||||
/// </summary>
|
||||
public int HomingTime;
|
||||
|
||||
/// <summary>
|
||||
/// The percentual amount this weaopn is affected by wind.
|
||||
/// </summary>
|
||||
public int WindResponse;
|
||||
|
||||
/// <summary>
|
||||
/// An unused field with unknown value.
|
||||
/// </summary>
|
||||
public int Unused2;
|
||||
|
||||
/// <summary>
|
||||
/// The number of clusters into which this weapon explodes.
|
||||
/// </summary>
|
||||
public int ClusterCount;
|
||||
|
||||
/// <summary>
|
||||
/// The speed in which clusters are dispersed in percent.
|
||||
/// </summary>
|
||||
public int ClusterLaunchPower;
|
||||
|
||||
/// <summary>
|
||||
/// The angle in which clusters are dispersed in degrees.
|
||||
/// </summary>
|
||||
public int ClusterLaunchAngle;
|
||||
|
||||
/// <summary>
|
||||
/// The damage of clusters measured in health points which also determines the blast radius.
|
||||
/// </summary>
|
||||
public int ClusterDamage;
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the fuse of this weapon, 0 for default.
|
||||
/// </summary>
|
||||
public int Fuse;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of fire created.
|
||||
/// </summary>
|
||||
public int FireAmount;
|
||||
|
||||
/// <summary>
|
||||
/// The speed in which fire spreads, measured in percent.
|
||||
/// </summary>
|
||||
public int FireSpreadSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// The period in which fire burns, measured in percent.
|
||||
/// </summary>
|
||||
public int FireTime;
|
||||
|
||||
/// <summary>
|
||||
/// The melee impact force in percent.
|
||||
/// </summary>
|
||||
public int MeleeForce;
|
||||
|
||||
/// <summary>
|
||||
/// The melee impact angle in degrees.
|
||||
/// </summary>
|
||||
public int MeleeAngle;
|
||||
|
||||
/// <summary>
|
||||
/// The melee damage in health points.
|
||||
/// </summary>
|
||||
public int MeleeDamage;
|
||||
|
||||
/// <summary>
|
||||
/// The height of the fire punch jump, measured in percent.
|
||||
/// </summary>
|
||||
public int FirepunchHeight;
|
||||
|
||||
/// <summary>
|
||||
/// The damage a dragon ball causes, measured in health points.
|
||||
/// </summary>
|
||||
public int DragonballDamage;
|
||||
|
||||
/// <summary>
|
||||
/// The power in which a dragon ball launches hit worms, measured in percent.
|
||||
/// </summary>
|
||||
public int DragonballPower;
|
||||
|
||||
/// <summary>
|
||||
/// The angle in which a dragon ball launches hit worms, measured in degrees.
|
||||
/// </summary>
|
||||
public int DragonballAngle;
|
||||
|
||||
/// <summary>
|
||||
/// The life time of a launched dragon ball measured in milliseconds.
|
||||
/// </summary>
|
||||
public int DragonballTime;
|
||||
|
||||
/// <summary>
|
||||
/// The length of digging measured in milliseconds. Applies to Kamikaze and digging tools.
|
||||
/// </summary>
|
||||
public int DiggingTime;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of airstrike clusters thrown.
|
||||
/// </summary>
|
||||
public int StrikeClusterCount;
|
||||
|
||||
/// <summary>
|
||||
/// The angle in which bullets are dispersed, measured in degrees.
|
||||
/// </summary>
|
||||
public int BulletSpreadAngle;
|
||||
}
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
@ -9,7 +11,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// Represents scheme weapons stored in an WEP file which contains armory configuration.
|
||||
/// Used by W2. S. https://worms2d.info/Weapons_file.
|
||||
/// </summary>
|
||||
public class SchemeWeapons : ILoadableFile, ISaveableFile
|
||||
public class SchemeWeapons : ILoadableFile, ISaveableFile, IEquatable<SchemeWeapons?>
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
@ -22,7 +24,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SchemeWeapons"/> class.
|
||||
/// </summary>
|
||||
public SchemeWeapons() => Weapons = new SchemeWeaponSetting[_weaponCount];
|
||||
public SchemeWeapons() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SchemeWeapons"/> class, loading the data from the given
|
||||
@ -40,13 +42,24 @@ namespace Syroot.Worms.Worms2
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets the array of <see cref="SchemeWeaponSetting"/> instances, each mapping to one weapon at the index of
|
||||
/// the <see cref="SchemeWeapon"/> enumeration.
|
||||
/// Gets the array of <see cref="SchemeWeapon"/> instances, each mapping to one weapon at the index of
|
||||
/// the <see cref="Weapon"/> enumeration.
|
||||
/// </summary>
|
||||
public SchemeWeaponSetting[] Weapons { get; set; }
|
||||
public SchemeWeapon[] Weapons { get; set; } = new SchemeWeapon[_weaponCount];
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object? obj) => Equals(obj as SchemeWeapons);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Equals(SchemeWeapons? other)
|
||||
=> other != null
|
||||
&& Weapons.SequenceEqual(other.Weapons);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override int GetHashCode() => HashCode.Combine(Weapons);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Load(Stream stream)
|
||||
{
|
||||
@ -58,9 +71,9 @@ namespace Syroot.Worms.Worms2
|
||||
throw new InvalidDataException("Invalid WEP file signature.");
|
||||
|
||||
// Read the weapon settings.
|
||||
Weapons = new SchemeWeaponSetting[_weaponCount];
|
||||
Weapons = new SchemeWeapon[_weaponCount];
|
||||
for (int i = 0; i < _weaponCount; i++)
|
||||
Weapons[i] = reader.ReadStruct<SchemeWeaponSetting>();
|
||||
Weapons[i] = reader.ReadStruct<SchemeWeapon>();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
@ -80,7 +93,7 @@ namespace Syroot.Worms.Worms2
|
||||
writer.Write(_signature, StringCoding.ZeroTerminated);
|
||||
|
||||
// Write the weapon settings.
|
||||
foreach (SchemeWeaponSetting weapon in Weapons)
|
||||
foreach (SchemeWeapon weapon in Weapons)
|
||||
writer.WriteStruct(weapon);
|
||||
}
|
||||
|
||||
|
@ -3,9 +3,9 @@
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Syroot.Worms.Worms2</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Team17's Worms 2.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats.</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation.</PackageReleaseNotes>
|
||||
<PackageTags>$(PackageTags);worms 2</PackageTags>
|
||||
<Version>3.2.0</Version>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
|
||||
|
@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
@ -17,17 +18,17 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the team.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of soundbank for the voice of team worms.
|
||||
/// </summary>
|
||||
public string SoundBankName { get; set; }
|
||||
public string SoundBankName { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the 8 worm names.
|
||||
/// Gets the 8 worm names.
|
||||
/// </summary>
|
||||
public string[] WormNames { get; set; }
|
||||
public string[] WormNames { get; } = new string[8];
|
||||
|
||||
public int Unknown2 { get; set; }
|
||||
public int Unknown3 { get; set; }
|
||||
@ -110,7 +111,8 @@ namespace Syroot.Worms.Worms2
|
||||
Unknown1 = reader.ReadInt16();
|
||||
Name = reader.ReadString(66);
|
||||
SoundBankName = reader.ReadString(36);
|
||||
WormNames = reader.ReadStrings(8, 20);
|
||||
for (int i = 0; i < WormNames.Length; i++)
|
||||
WormNames[i] = reader.ReadString(20);
|
||||
Unknown2 = reader.ReadInt32();
|
||||
Unknown3 = reader.ReadInt32();
|
||||
Unknown4 = reader.ReadInt32();
|
||||
@ -155,9 +157,10 @@ namespace Syroot.Worms.Worms2
|
||||
{
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
writer.Write(Unknown1);
|
||||
writer.WriteString(Name, 66);
|
||||
writer.WriteString(SoundBankName, 36);
|
||||
writer.WriteStrings(WormNames, 20);
|
||||
writer.WriteFixedString(Name, 66);
|
||||
writer.WriteFixedString(SoundBankName, 36);
|
||||
for (int i = 0; i < 8; i++)
|
||||
writer.WriteFixedString(WormNames[i], 20);
|
||||
writer.Write(Unknown2);
|
||||
writer.Write(Unknown3);
|
||||
writer.Write(Unknown4);
|
||||
|
@ -2,7 +2,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Worms2
|
||||
{
|
||||
@ -17,7 +17,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class.
|
||||
/// </summary>
|
||||
public TeamContainer() => Teams = new List<Team>();
|
||||
public TeamContainer() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TeamContainer"/> class, loading the data from the given
|
||||
@ -37,7 +37,7 @@ namespace Syroot.Worms.Worms2
|
||||
/// <summary>
|
||||
/// Gets or sets the list of <see cref="Team"/> instances stored.
|
||||
/// </summary>
|
||||
public List<Team> Teams { get; set; }
|
||||
public IList<Team> Teams { get; set; } = new List<Team>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms
|
||||
{
|
||||
@ -13,7 +14,7 @@ namespace Syroot.Worms
|
||||
/// optimal performance when accessing and manipulating the directory.
|
||||
/// Used by W2, WA and WWP. S. https://worms2d.info/Graphics_directory.
|
||||
/// </summary>
|
||||
public class Archive : Dictionary<string, byte[]>, ILoadableFile, ISaveableFile
|
||||
public class Archive : IDictionary<string, byte[]>, ILoadableFile, ISaveableFile
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
@ -23,6 +24,10 @@ namespace Syroot.Worms
|
||||
private const int _hashBits = 10;
|
||||
private const int _hashSize = 1 << _hashBits;
|
||||
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
private readonly IDictionary<string, byte[]> _entries = new Dictionary<string, byte[]>();
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
@ -43,8 +48,42 @@ namespace Syroot.Worms
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
public Archive(string fileName) => Load(fileName);
|
||||
|
||||
// ---- OPERATORS ----------------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public byte[] this[string key]
|
||||
{
|
||||
get => _entries[key];
|
||||
set => _entries[key] = value;
|
||||
}
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICollection<string> Keys => _entries.Keys;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ICollection<byte[]> Values => _entries.Values;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int Count => _entries.Count;
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICollection<KeyValuePair<string, byte[]>>.IsReadOnly => false;
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Add(string key, byte[] value) => _entries.Add(key, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Clear() => _entries.Clear();
|
||||
/// <inheritdoc/>
|
||||
public bool ContainsKey(string key) => _entries.ContainsKey(key);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IEnumerator<KeyValuePair<string, byte[]>> GetEnumerator() => _entries.GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the data from the given <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
@ -100,6 +139,9 @@ namespace Syroot.Worms
|
||||
Load(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Remove(string key) => _entries.Remove(key);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data into the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
@ -132,8 +174,8 @@ namespace Syroot.Worms
|
||||
}
|
||||
|
||||
// Write the hash table and file entries.
|
||||
int tocStart = (int)writer.Position;
|
||||
int fileEntryOffset = sizeof(int) + _hashSize * sizeof(int);
|
||||
uint tocStart = (uint)writer.Position;
|
||||
uint fileEntryOffset = sizeof(int) + _hashSize * sizeof(int);
|
||||
writer.SatisfyOffset(tocOffset, tocStart);
|
||||
writer.Write(_tocSignature);
|
||||
for (int i = 0; i < _hashSize; i++)
|
||||
@ -158,9 +200,9 @@ namespace Syroot.Worms
|
||||
writer.Write(entry.Name, StringCoding.ZeroTerminated);
|
||||
writer.Align(4);
|
||||
if (j < entries.Count - 1)
|
||||
writer.SatisfyOffset(nextEntryOffset, (int)writer.Position - tocStart);
|
||||
writer.SatisfyOffset(nextEntryOffset, (uint)writer.Position - tocStart);
|
||||
}
|
||||
fileEntryOffset = (int)writer.Position - tocStart;
|
||||
fileEntryOffset = (uint)writer.Position - tocStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -178,6 +220,9 @@ namespace Syroot.Worms
|
||||
Save(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool TryGetValue(string key, out byte[] value) => _entries.TryGetValue(key, out value);
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private int CalculateHash(string name)
|
||||
@ -192,7 +237,24 @@ namespace Syroot.Worms
|
||||
return hash;
|
||||
}
|
||||
|
||||
// ---- STRUCTURES ---------------------------------------------------------------------------------------------
|
||||
// ---- METHODS ------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <inheritdoc/>
|
||||
void ICollection<KeyValuePair<string, byte[]>>.Add(KeyValuePair<string, byte[]> item) => _entries.Add(item);
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICollection<KeyValuePair<string, byte[]>>.Contains(KeyValuePair<string, byte[]> item) => _entries.Contains(item);
|
||||
|
||||
/// <inheritdoc/>
|
||||
void ICollection<KeyValuePair<string, byte[]>>.CopyTo(KeyValuePair<string, byte[]>[] array, int arrayIndex) => _entries.CopyTo(array, arrayIndex);
|
||||
|
||||
/// <inheritdoc/>
|
||||
IEnumerator IEnumerable.GetEnumerator() => _entries.GetEnumerator();
|
||||
|
||||
/// <inheritdoc/>
|
||||
bool ICollection<KeyValuePair<string, byte[]>>.Remove(KeyValuePair<string, byte[]> item) => _entries.Remove(item);
|
||||
|
||||
// ---- CLASSES, STRUCTS & ENUMS -------------------------------------------------------------------------------
|
||||
|
||||
private struct HashTableEntry
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ namespace Syroot.Worms.Core
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
|
||||
/// <param name="index">The 0-based index of the bit to check.</param>
|
||||
/// <returns><c>true</c> when the bit is set; otherwise <c>false</c>.</returns>
|
||||
/// <returns><see langword="true"/> when the bit is set; otherwise <see langword="false"/>.</returns>
|
||||
public static bool GetBit(this byte self, int index) => (self & (1 << index)) != 0;
|
||||
|
||||
/// <summary>
|
||||
@ -62,7 +62,7 @@ namespace Syroot.Worms.Core
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
|
||||
/// <param name="index">The 0-based index of the bit to enable or disable.</param>
|
||||
/// <param name="enable"><c>true</c> to enable the bit; otherwise <c>false</c>.</param>
|
||||
/// <param name="enable"><see langword="true"/> to enable the bit; otherwise <see langword="false"/>.</param>
|
||||
/// <returns>The current byte with the bit enabled or disabled.</returns>
|
||||
public static byte SetBit(this byte self, int index, bool enable)
|
||||
=> enable ? EnableBit(self, index) : DisableBit(self, index);
|
||||
|
@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
namespace Syroot.Worms.Core.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a collection of methods helping with palettized images.
|
||||
/// </summary>
|
||||
public static class BitmapTools
|
||||
{
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Creates an indexed <see cref="Bitmap"/> with the given <paramref name="size"/> and
|
||||
/// <paramref name="palette"/> from the provided raw <paramref name="data"/> array.
|
||||
/// </summary>
|
||||
/// <param name="size">The dimensions of the image.</param>
|
||||
/// <param name="palette">The palette as a <see cref="Color"/> array.</param>
|
||||
/// <param name="data">The data array storing bytes indexing the palette color array.</param>
|
||||
/// <returns>The <see cref="Bitmap"/> instance.</returns>
|
||||
public static unsafe Bitmap CreateIndexed(Size size, IList<Color> palette, byte[] data)
|
||||
{
|
||||
// Transfer the pixel data, respecting power-of-2 strides.
|
||||
Bitmap bitmap = new Bitmap(size.Width, size.Height, PixelFormat.Format8bppIndexed);
|
||||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, size.Width, size.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
Span<byte> bitmapSpan = new Span<byte>(bitmapData.Scan0.ToPointer(), bitmapData.Stride * bitmapData.Height);
|
||||
for (int y = 0; y < size.Height; y++)
|
||||
data.AsSpan(y * size.Width, size.Width).CopyTo(bitmapSpan.Slice(y * bitmapData.Stride));
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
|
||||
// Transfer the palette.
|
||||
ColorPalette bitmapPalette = bitmap.Palette;
|
||||
for (int i = 0; i < palette.Count; i++)
|
||||
bitmapPalette.Entries[i] = palette[i];
|
||||
bitmap.Palette = bitmapPalette;
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,265 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Syroot.BinaryData;
|
||||
|
||||
namespace Syroot.Worms.Core.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents extension methods for <see cref="BinaryStream"/> instances.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static partial class BinaryStreamExtensions
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
// ---- Reading ----
|
||||
|
||||
/// <summary>
|
||||
/// Reads an <see cref="ILoadable"/> instance from the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ILoadable"/> class to instantiate.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The <see cref="ILoadable"/> instance.</returns>
|
||||
public static T Load<T>(this BinaryStream self) where T : ILoadable, new()
|
||||
{
|
||||
T instance = new T();
|
||||
instance.Load(self.BaseStream);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads <see cref="ILoadable"/> instances from the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ILoadable"/> class to instantiate.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="count">The number of instances to read.</param>
|
||||
/// <returns>The <see cref="ILoadable"/> instances.</returns>
|
||||
public static T[] Load<T>(this BinaryStream self, int count) where T : ILoadable, new()
|
||||
{
|
||||
T[] instances = new T[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
instances[i] = Load<T>(self);
|
||||
return instances;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an RGBA 32-bit color.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The read color.</returns>
|
||||
public static Color ReadColor(this BinaryStream self) => Color.FromArgb(self.ReadInt32());
|
||||
|
||||
/// <summary>
|
||||
/// Reads <paramref name="count"/> RGBA 32-bit colors.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="count">The number of values to read.</param>
|
||||
/// <returns>The read colors.</returns>
|
||||
public static Color[] ReadColors(this BinaryStream self, int count)
|
||||
{
|
||||
Color[] values = new Color[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
values[i] = Color.FromArgb(self.ReadInt32());
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 0-terminated string which is stored in a fixed-size block of <paramref name="length"/> bytes.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
||||
/// <returns>The read string.</returns>
|
||||
public static string ReadString(this BinaryStream self, int length)
|
||||
{
|
||||
// TODO: This may not work with multi-byte encodings.
|
||||
// Ensure to not try to decode any bytes after the 0 termination.
|
||||
byte[] bytes = self.ReadBytes(length);
|
||||
while (bytes[--length] == 0 && length > 0) { }
|
||||
return self.Encoding.GetString(bytes, 0, length + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads <paramref name="count"/> 0-terminated strings which are stored in a fixed-size block of
|
||||
/// <paramref name="length"/> bytes.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="count">The number of values to read.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
||||
/// <returns>The read strings.</returns>
|
||||
public static string[] ReadStrings(this BinaryStream self, int count, int length)
|
||||
{
|
||||
string[] strings = new string[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
strings[i] = ReadString(self, length);
|
||||
return strings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a raw byte structure from the current stream and returns it.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The structure of type <typeparamref name="T"/>.</returns>
|
||||
public static T ReadStruct<T>(this BinaryStream self) where T : unmanaged
|
||||
{
|
||||
// Read the raw bytes of the structure.
|
||||
#if NETSTANDARD2_0
|
||||
byte[] bytes = new byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes, 0, bytes.Length);
|
||||
#else
|
||||
Span<byte> bytes = stackalloc byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes);
|
||||
#endif
|
||||
|
||||
// Convert them to a structure instance and return it.
|
||||
ReadOnlySpan<T> span = MemoryMarshal.Cast<byte, T>(bytes);
|
||||
return span[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads raw byte structures from the current stream and returns them.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="count">The number of values to read.</param>
|
||||
/// <returns>The structures of type <typeparamref name="T"/>.</returns>
|
||||
public static T[] ReadStructs<T>(this BinaryStream self, int count) where T : unmanaged
|
||||
{
|
||||
// Read the raw bytes of the structures.
|
||||
#if NETSTANDARD2_0
|
||||
byte[] bytes = new byte[Unsafe.SizeOf<T>()];
|
||||
self.Read(bytes, 0, bytes.Length);
|
||||
#else
|
||||
Span<byte> bytes = stackalloc byte[Unsafe.SizeOf<T>() * count];
|
||||
self.Read(bytes);
|
||||
#endif
|
||||
|
||||
// Convert them to a structure array and return it.
|
||||
ReadOnlySpan<T> span = MemoryMarshal.Cast<byte, T>(bytes);
|
||||
return span.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current address of the stream to which a 4-byte placeholder has been written which can be filled
|
||||
/// later.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The address at which a 4-byte placeholder has been written to.</returns>
|
||||
public static uint ReserveOffset(this BinaryStream self)
|
||||
{
|
||||
uint offset = (uint)self.Position;
|
||||
self.WriteUInt32(0);
|
||||
return offset;
|
||||
}
|
||||
|
||||
// ---- Writing ----
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given <see cref="ISaveable"/> instance into the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ISaveable"/> class to write.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The instance to write into the current stream.</param>
|
||||
public static void Save<T>(this BinaryStream self, T value) where T : ISaveable
|
||||
{
|
||||
value.Save(self.BaseStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given <see cref="ISaveable"/> instances into the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ISaveable"/> class to write.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="values">The instances to write into the current stream.</param>
|
||||
public static void Save<T>(this BinaryStream self, IList<T> values) where T : ISaveable
|
||||
{
|
||||
foreach (T value in values)
|
||||
Save(self, value);
|
||||
}
|
||||
|
||||
public static void SatisfyOffset(this BinaryStream self, uint offset, int value)
|
||||
{
|
||||
using (self.TemporarySeek(offset, SeekOrigin.Begin))
|
||||
self.WriteInt32(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given color.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The color to write.</param>
|
||||
public static void WriteColor(this BinaryStream self, Color color)
|
||||
=> self.Write(color.R << 24 | color.G << 16 | color.B << 8 | color.A);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given colors.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The colors to write.</param>
|
||||
public static void WriteColors(this BinaryStream self, IEnumerable<Color> colors)
|
||||
{
|
||||
foreach (Color color in colors)
|
||||
WriteColor(self, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given string into a fixed-size block of <paramref name="length"/> bytes and 0-terminates it.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The string to write.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size block takes.</param>
|
||||
public static void WriteString(this BinaryStream self, string value, int length)
|
||||
{
|
||||
// TODO: This may not work with multi-byte encodings.
|
||||
byte[] bytes = new byte[length];
|
||||
if (value != null)
|
||||
self.Encoding.GetBytes(value, 0, value.Length, bytes, 0);
|
||||
self.WriteBytes(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given strings into fixed-size blocks of <paramref name="length"/> bytes and 0-terminates them.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="values">The strings to write.</param>
|
||||
/// <param name="length">The number of bytes a fixed-size block takes.</param>
|
||||
public static void WriteStrings(this BinaryStream self, IEnumerable<string> values, int length)
|
||||
{
|
||||
foreach (string value in values)
|
||||
WriteString(self, value, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the bytes of a structure into the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The structure to write.</param>
|
||||
public static unsafe void WriteStruct<T>(this BinaryStream self, T value) where T : unmanaged
|
||||
{
|
||||
ReadOnlySpan<byte> bytes = new ReadOnlySpan<byte>(Unsafe.AsPointer(ref value), Unsafe.SizeOf<T>());
|
||||
#if NETSTANDARD2_0
|
||||
self.Write(bytes.ToArray()); // cannot prevent copy in .NET Standard 2.0
|
||||
#else
|
||||
self.Write(bytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the bytes of structures into the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the structure to read.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="values">The structures to write.</param>
|
||||
public static void WriteStructs<T>(this BinaryStream self, IEnumerable<T> values) where T : unmanaged
|
||||
{
|
||||
foreach (T value in values)
|
||||
WriteStruct(self, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
using System.Drawing;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Syroot.Worms.Core.Graphics
|
||||
namespace Syroot.Worms.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an interface for any class storing indexed image palette colors.
|
||||
@ -12,6 +13,6 @@ namespace Syroot.Worms.Core.Graphics
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="Color"/> values stored by this palette.
|
||||
/// </summary>
|
||||
Color[] Colors { get; set; }
|
||||
IList<Color> Colors { get; set; }
|
||||
}
|
||||
}
|
@ -20,7 +20,7 @@ namespace Syroot.Worms
|
||||
/// <summary>
|
||||
/// Gets or sets the colors in the palette of the bitmap, if it has one.
|
||||
/// </summary>
|
||||
public IList<Color> Palette { get; set; }
|
||||
public IList<Color>? Palette { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the image in pixels.
|
||||
@ -30,7 +30,7 @@ namespace Syroot.Worms
|
||||
/// <summary>
|
||||
/// Gets or sets the data of the image pixels.
|
||||
/// </summary>
|
||||
public byte[] Data { get; set; }
|
||||
public byte[] Data { get; set; } = Array.Empty<byte>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -40,20 +40,44 @@ namespace Syroot.Worms
|
||||
/// <returns>The <see cref="Bitmap"/> created from the raw data.</returns>
|
||||
public unsafe Bitmap ToBitmap()
|
||||
{
|
||||
// Create bitmap with appropriate pixel format.
|
||||
PixelFormat pixelFormat = BitsPerPixel switch
|
||||
{
|
||||
1 => PixelFormat.Format1bppIndexed,
|
||||
8 => PixelFormat.Format8bppIndexed,
|
||||
32 => PixelFormat.Format32bppRgb,
|
||||
_ => throw new NotSupportedException($"Cannot convert to {BitsPerPixel}bpp bitmap.")
|
||||
};
|
||||
Bitmap bitmap = new Bitmap(Size.Width, Size.Height, pixelFormat);
|
||||
|
||||
// Transfer the pixel data, respecting power-of-2 strides.
|
||||
Bitmap bitmap = new Bitmap(Size.Width, Size.Height, PixelFormat.Format8bppIndexed);
|
||||
BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, Size.Width, Size.Height),
|
||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||
ImageLockMode.WriteOnly, pixelFormat);
|
||||
float bytesPerPixel = BitsPerPixel / 8f;
|
||||
Span<byte> bitmapSpan = new Span<byte>(bitmapData.Scan0.ToPointer(), bitmapData.Stride * bitmapData.Height);
|
||||
for (int y = 0; y < Size.Height; y++)
|
||||
Data.AsSpan(y * Size.Width, Size.Width).CopyTo(bitmapSpan.Slice(y * bitmapData.Stride));
|
||||
{
|
||||
Data.AsSpan((int)(y * Size.Width * bytesPerPixel), (int)(Size.Width * bytesPerPixel))
|
||||
.CopyTo(bitmapSpan.Slice((int)(y * bitmapData.Stride * bytesPerPixel)));
|
||||
}
|
||||
bitmap.UnlockBits(bitmapData);
|
||||
|
||||
// Transfer the palette.
|
||||
ColorPalette bitmapPalette = bitmap.Palette;
|
||||
for (int i = 0; i < Palette.Count; i++)
|
||||
bitmapPalette.Entries[i] = Palette[i];
|
||||
bitmap.Palette = bitmapPalette;
|
||||
// Transfer any palette.
|
||||
switch (pixelFormat)
|
||||
{
|
||||
case PixelFormat.Format1bppIndexed:
|
||||
ColorPalette palette1bpp = bitmap.Palette;
|
||||
palette1bpp.Entries[0] = Color.Black;
|
||||
palette1bpp.Entries[1] = Color.White;
|
||||
bitmap.Palette = palette1bpp;
|
||||
break;
|
||||
case PixelFormat.Format8bppIndexed:
|
||||
ColorPalette palette8bpp = bitmap.Palette;
|
||||
for (int i = 0; i < Palette!.Count; i++)
|
||||
palette8bpp.Entries[i] = Palette[i];
|
||||
bitmap.Palette = palette8bpp;
|
||||
break;
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Syroot.Worms.Core
|
||||
namespace Syroot.Worms.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
|
||||
@ -17,7 +17,7 @@ namespace Syroot.Worms.Core
|
||||
/// </summary>
|
||||
/// <param name="bytes">The data to compress.</param>
|
||||
/// <returns>The compressed data.</returns>
|
||||
internal static byte[] Compress(byte[] bytes)
|
||||
internal static byte[] Compress(ReadOnlySpan<byte> bytes)
|
||||
=> throw new NotImplementedException("Compressing data has not been implemented yet.");
|
||||
|
||||
/// <summary>
|
||||
@ -25,10 +25,9 @@ namespace Syroot.Worms.Core
|
||||
/// <paramref name="buffer"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to read the data from.</param>
|
||||
/// <param name="buffer">The byte array buffer to write the decompressed data to.</param>
|
||||
internal static void Decompress(Stream stream, byte[] buffer)
|
||||
/// <param name="buffer">The byte buffer to write the decompressed data to.</param>
|
||||
internal static void Decompress(Stream stream, Span<byte> buffer)
|
||||
{
|
||||
// TODO: This fails for compressed data in CD:\Data\Mission\Training0-9.img.
|
||||
int output = 0; // Offset of next write.
|
||||
int cmd;
|
||||
while ((cmd = stream.ReadByte()) != -1)
|
||||
@ -41,8 +40,7 @@ namespace Syroot.Worms.Core
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arg1 = bits 2-5
|
||||
int arg1 = (cmd >> 3) & 0xF;
|
||||
int arg1 = cmd >> 3 & 0b1111; // bits 2-5
|
||||
int arg2 = stream.ReadByte();
|
||||
if (arg2 == -1)
|
||||
return;
|
||||
@ -68,9 +66,46 @@ namespace Syroot.Worms.Core
|
||||
}
|
||||
}
|
||||
|
||||
// Own Span reimplementation, has the same issues with some out-of-bounds-access maps. Supports color remap.
|
||||
//internal static int Decompress(ReadOnlySpan<byte> src, Span<byte> dst, ReadOnlySpan<byte> colorMap)
|
||||
//{
|
||||
// int srcPos = 0;
|
||||
// int dstPos = 0;
|
||||
// int count, seek;
|
||||
//
|
||||
// while (true)
|
||||
// {
|
||||
// while (true)
|
||||
// {
|
||||
// while ((src[srcPos] & 0b1000_0000) == 0)
|
||||
// dst[dstPos++] = colorMap[src[srcPos++]];
|
||||
//
|
||||
// if ((src[srcPos] & 0b0111_1000) == 0)
|
||||
// break;
|
||||
//
|
||||
// count = (src[srcPos] >> 3 & 0b0000_1111) + 2;
|
||||
// seek = (src[srcPos + 1] | ((src[srcPos] & 0b0000_0111) << 8)) + 1;
|
||||
// while (count-- > 0)
|
||||
// dst[dstPos] = dst[dstPos++ - seek];
|
||||
// srcPos += 2;
|
||||
// }
|
||||
//
|
||||
// seek = src[srcPos + 1] | (src[srcPos] & 0b0000_0111) << 8;
|
||||
// if (seek == 0)
|
||||
// break;
|
||||
// count = src[srcPos + 2] + 18;
|
||||
// while (count-- > 0)
|
||||
// dst[dstPos] = dst[dstPos++ - seek];
|
||||
//
|
||||
// srcPos += 3;
|
||||
// }
|
||||
//
|
||||
// return dstPos;
|
||||
//}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private static int CopyData(int offset, int compressedOffset, int count, byte[] buffer)
|
||||
private static int CopyData(int offset, int compressedOffset, int count, Span<byte> buffer)
|
||||
{
|
||||
for (; count > 0; count--)
|
||||
buffer[offset] = buffer[offset++ - compressedOffset];
|
140
src/library/Syroot.Worms/IO/BinaryStreamExtensions.cs
Normal file
140
src/library/Syroot.Worms/IO/BinaryStreamExtensions.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Syroot.BinaryData;
|
||||
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents extension methods for <see cref="BinaryStream"/> instances.
|
||||
/// </summary>
|
||||
public static partial class BinaryStreamExtensions
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
// ---- Reading ----
|
||||
|
||||
/// <summary>
|
||||
/// Reads an <see cref="ILoadable"/> instance from the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ILoadable"/> class to instantiate.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The <see cref="ILoadable"/> instance.</returns>
|
||||
public static T Load<T>(this BinaryStream self) where T : ILoadable, new()
|
||||
{
|
||||
T instance = new T();
|
||||
instance.Load(self.BaseStream);
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an RGBA 32-bit color.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The read color.</returns>
|
||||
public static Color ReadColor(this BinaryStream self) => Color.FromArgb(self.ReadInt32());
|
||||
|
||||
/// <summary>
|
||||
/// Reads <paramref name="count"/> RGBA 32-bit colors.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="count">The number of values to read.</param>
|
||||
/// <returns>The read colors.</returns>
|
||||
public static Color[] ReadColors(this BinaryStream self, int count)
|
||||
{
|
||||
Color[] values = new Color[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
values[i] = Color.FromArgb(self.ReadInt32());
|
||||
return values;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a 0-terminated string which is stored in a fixed-size block of <paramref name="length"/> bytes.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size blocks takes.</param>
|
||||
/// <returns>The read string.</returns>
|
||||
public static string ReadFixedString(this BinaryStream self, int length)
|
||||
{
|
||||
// TODO: This may not work with multi-byte encodings.
|
||||
// Ensure to not try to decode any bytes after the 0 termination.
|
||||
byte[] bytes = self.ReadBytes(length);
|
||||
for (length = 0; length < bytes.Length && bytes[length] != 0; length++) ;
|
||||
return self.Encoding.GetString(bytes, 0, length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current position of the stream at which a 4-byte placeholder has been written which can be
|
||||
/// filled later with <see cref="SatisfyOffset"/>.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <returns>The position at which a 4-byte placeholder has been written to.</returns>
|
||||
public static uint ReserveOffset(this BinaryStream self)
|
||||
{
|
||||
uint offset = (uint)self.Position;
|
||||
self.WriteUInt32(0);
|
||||
return offset;
|
||||
}
|
||||
|
||||
// ---- Writing ----
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given <see cref="ISaveable"/> instance into the current stream.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the <see cref="ISaveable"/> class to write.</typeparam>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The instance to write into the current stream.</param>
|
||||
public static void Save<T>(this BinaryStream self, T value) where T : ISaveable
|
||||
{
|
||||
value.Save(self.BaseStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given <paramref name="value"/> to the given <paramref name="offset"/>. This is meant to be used
|
||||
/// in combination with <see cref="ReserveOffset"/>.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="offset">The position at which to write the value.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static void SatisfyOffset(this BinaryStream self, uint offset, uint value)
|
||||
{
|
||||
using var _ = self.TemporarySeek(offset, SeekOrigin.Begin);
|
||||
self.WriteUInt32(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given color.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The color to write.</param>
|
||||
public static void WriteColor(this BinaryStream self, Color color)
|
||||
=> self.Write(color.A << 24 | color.R << 16 | color.G << 8 | color.B);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given colors.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The colors to write.</param>
|
||||
public static void WriteColors(this BinaryStream self, IEnumerable<Color> colors)
|
||||
{
|
||||
foreach (Color color in colors)
|
||||
WriteColor(self, color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given string into a fixed-size block of <paramref name="length"/> bytes and 0-terminates it.
|
||||
/// </summary>
|
||||
/// <param name="self">The extended <see cref="BinaryStream"/> instance.</param>
|
||||
/// <param name="value">The string to write.</param>
|
||||
/// <param name="length">The number of bytes the fixed-size block takes.</param>
|
||||
public static void WriteFixedString(this BinaryStream self, string value, int length)
|
||||
{
|
||||
// TODO: This may not work with multi-byte encodings.
|
||||
byte[] bytes = new byte[length];
|
||||
if (value != null)
|
||||
self.Encoding.GetBytes(value, 0, value.Length, bytes, 0);
|
||||
self.WriteBytes(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Syroot.Worms.Core.IO
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents data which can be loaded by providing a <see cref="Stream"/> to read from.
|
@ -1,4 +1,4 @@
|
||||
namespace Syroot.Worms.Core.IO
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a file which can be loaded by providing a file name.
|
@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Syroot.Worms.Core.IO
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents data which can be saved by providing a <see cref="Stream "/>to write to.
|
@ -1,4 +1,4 @@
|
||||
namespace Syroot.Worms.Core.IO
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a file which can be saved by providing a file name.
|
@ -4,7 +4,7 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms.Core.Riff
|
||||
{
|
||||
@ -82,10 +82,10 @@ namespace Syroot.Worms.Core.Riff
|
||||
|
||||
chunkSaver.Value.Invoke(this, new object[] { writer });
|
||||
|
||||
writer.SatisfyOffset(chunkSizeOffset, (int)(writer.Position - chunkSizeOffset - 4));
|
||||
writer.SatisfyOffset(chunkSizeOffset, (uint)(writer.Position - chunkSizeOffset - 4));
|
||||
}
|
||||
|
||||
writer.SatisfyOffset(fileSizeOffset, (int)(writer.Position - 8));
|
||||
writer.SatisfyOffset(fileSizeOffset, (uint)(writer.Position - 8));
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
@ -102,8 +102,6 @@ namespace Syroot.Worms.Core.Riff
|
||||
typeData.FileIdentifier = typeInfo.GetCustomAttribute<RiffFileAttribute>().Identifier;
|
||||
|
||||
// Get the chunk loading and saving handlers.
|
||||
typeData.ChunkLoaders = new Dictionary<string, MethodInfo>();
|
||||
typeData.ChunkSavers = new Dictionary<string, MethodInfo>();
|
||||
foreach (MethodInfo method in typeInfo.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance))
|
||||
{
|
||||
RiffChunkLoadAttribute loadAttribute = method.GetCustomAttribute<RiffChunkLoadAttribute>();
|
||||
@ -137,9 +135,9 @@ namespace Syroot.Worms.Core.Riff
|
||||
|
||||
private class TypeData
|
||||
{
|
||||
internal string FileIdentifier;
|
||||
internal Dictionary<string, MethodInfo> ChunkLoaders;
|
||||
internal Dictionary<string, MethodInfo> ChunkSavers;
|
||||
internal string FileIdentifier = String.Empty;
|
||||
internal IDictionary<string, MethodInfo> ChunkLoaders = new Dictionary<string, MethodInfo>();
|
||||
internal IDictionary<string, MethodInfo> ChunkSavers = new Dictionary<string, MethodInfo>();
|
||||
}
|
||||
}
|
||||
}
|
101
src/library/Syroot.Worms/IO/StreamExtensions.cs
Normal file
101
src/library/Syroot.Worms/IO/StreamExtensions.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Syroot.Worms.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents extension methods for <see cref="Stream"/> instances.
|
||||
/// </summary>
|
||||
public static class StreamExtensions
|
||||
{
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Reads the unmanaged representation of a struct of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the struct to read.</typeparam>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to read with.</param>
|
||||
/// <returns>The read value.</returns>
|
||||
public static T ReadStruct<T>(this Stream stream) where T : unmanaged
|
||||
{
|
||||
Span<T> span = stackalloc T[1];
|
||||
stream.Read(MemoryMarshal.Cast<T, byte>(span));
|
||||
return span[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the unmanaged representations of structs of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the structs to read.</typeparam>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to read with.</param>
|
||||
/// <param name="span">A span receiving the read instances.</param>
|
||||
public static void ReadStructs<T>(this Stream stream, Span<T> span) where T : unmanaged
|
||||
=> stream.Read(MemoryMarshal.Cast<T, byte>(span));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the unmanaged representation of a struct of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the struct to write.</typeparam>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static unsafe void WriteStruct<T>(this Stream stream, T value) where T : unmanaged
|
||||
=> stream.Write(new ReadOnlySpan<byte>(Unsafe.AsPointer(ref value), Unsafe.SizeOf<T>()));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the unmanaged representation of a struct of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the struct to write.</typeparam>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
public static unsafe void WriteStruct<T>(this Stream stream, ref T value) where T : unmanaged
|
||||
=> stream.Write(new ReadOnlySpan<byte>(Unsafe.AsPointer(ref value), Unsafe.SizeOf<T>()));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the unmanaged representations of structs of type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the struct to write.</typeparam>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="span">The values to write.</param>
|
||||
public static unsafe void WriteStructs<T>(this Stream stream, ReadOnlySpan<T> span) where T : unmanaged
|
||||
=> stream.Write(MemoryMarshal.Cast<T, byte>(span));
|
||||
|
||||
// ---- Backports ----
|
||||
#if NETSTANDARD2_0
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the
|
||||
/// position within the stream by the number of bytes read.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance to write with.</param>
|
||||
/// <param name="buffer">A region of memory. When this method returns, the contents of this region are replaced
|
||||
/// by the bytes read from the current source.</param>
|
||||
/// <returns>The total number of bytes read into the buffer. This can be less than the number of bytes allocated
|
||||
/// in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream has been
|
||||
/// reached.</returns>
|
||||
/// <remarks>
|
||||
/// This .NET Standard 2.0 backport requires a temporary copy.
|
||||
/// </remarks>
|
||||
public static int Read(this Stream stream, Span<byte> buffer)
|
||||
{
|
||||
byte[] bytes = new byte[buffer.Length];
|
||||
int bytesRead = stream.Read(bytes);
|
||||
bytes.AsSpan(0, bytesRead).CopyTo(buffer);
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When overridden in a derived class, writes a sequence of bytes to the current stream and advances the
|
||||
/// current position within this stream by the number of bytes written.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> instance.</param>
|
||||
/// <param name="value">A region of memory. This method copies the contents of this region to the current
|
||||
/// stream.</param>
|
||||
/// <remarks>
|
||||
/// This .NET Standard 2.0 backport requires a temporary copy.
|
||||
/// </remarks>
|
||||
public static void Write(this Stream stream, ReadOnlySpan<byte> value) => stream.Write(value.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
@ -1,22 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.Graphics;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
|
||||
/// Represents a (palletized) graphical image stored in an IMG file, possibly compressed.
|
||||
/// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
|
||||
/// </summary>
|
||||
public class Img : RawBitmap, ILoadableFile, ISaveableFile
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private const int _signature = 0x1A474D49; // "IMG", 0x1A
|
||||
/// <summary>Magic value identifying the start of IMG data.</summary>
|
||||
public const uint Signature = 0x1A474D49; // "IMG\x1A"
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
@ -43,15 +45,20 @@ namespace Syroot.Worms
|
||||
/// <see cref="Stream"/>. The data block can be aligned to a 4-bte boundary.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
/// <param name="alignData"><c>true</c> to align the data array by 4 bytes.</param>
|
||||
/// <param name="alignData"><see langword="true"/> to align the data array by 4 bytes.</param>
|
||||
public Img(Stream stream, bool alignData) => Load(stream, alignData);
|
||||
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating data was compressed or should be compressed when saving.
|
||||
/// </summary>
|
||||
public bool Compressed { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an optional description of the image contents.
|
||||
/// </summary>
|
||||
public string Description { get; private set; }
|
||||
public string? Description { get; private set; }
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -59,12 +66,16 @@ namespace Syroot.Worms
|
||||
/// Loads the data from the given <see cref="Stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
/// <exception cref="IndexOutOfRangeException">Compressed images required more bytes than usually to decompress.
|
||||
/// This error can be ignored, the image has been completely read, and is only caused by a few files.</exception>
|
||||
public void Load(Stream stream) => Load(stream, false);
|
||||
|
||||
/// <summary>
|
||||
/// Loads the data from the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
/// <exception cref="IndexOutOfRangeException">Compressed images required more bytes than usually to decompress.
|
||||
/// This error can be ignored, the image has been completely read, and is only caused by a few files.</exception>
|
||||
public void Load(string fileName)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
@ -75,13 +86,15 @@ namespace Syroot.Worms
|
||||
/// Loads the data from the given <see cref="Stream"/>. The data block can be aligned to a 4-bte boundary.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||
/// <param name="alignData"><c>true</c> to align the data array by 4 bytes.</param>
|
||||
/// <param name="alignData"><see langword="true"/> to align the data array by 4 bytes.</param>
|
||||
/// <exception cref="IndexOutOfRangeException">Compressed images required more bytes than usually to decompress.
|
||||
/// This error can be ignored, the image has been completely read, and is only caused by a few files.</exception>
|
||||
public void Load(Stream stream, bool alignData)
|
||||
{
|
||||
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Read the header.
|
||||
if (reader.ReadInt32() != _signature)
|
||||
if (reader.ReadUInt32() != Signature)
|
||||
throw new InvalidDataException("Invalid IMG file signature.");
|
||||
int fileSize = reader.ReadInt32();
|
||||
|
||||
@ -109,10 +122,10 @@ namespace Syroot.Worms
|
||||
if (flags.HasFlag(Flags.Palettized))
|
||||
{
|
||||
int colorCount = reader.ReadInt16();
|
||||
Palette = new Color[colorCount + 1];
|
||||
Palette[0] = Color.Black;
|
||||
for (int i = 1; i <= colorCount; i++)
|
||||
Palette[i] = Color.FromArgb(reader.Read1Byte(), reader.Read1Byte(), reader.Read1Byte());
|
||||
Palette = new List<Color>(colorCount + 1);
|
||||
Palette.Add(Color.Black);
|
||||
while (colorCount-- > 0)
|
||||
Palette.Add(Color.FromArgb(reader.Read1Byte(), reader.Read1Byte(), reader.Read1Byte()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -125,20 +138,26 @@ namespace Syroot.Worms
|
||||
// Read the data byte array, which might be compressed or aligned.
|
||||
if (alignData)
|
||||
reader.Align(4);
|
||||
byte[] data = new byte[Size.Width * Size.Height * BitsPerPixel / 8];
|
||||
int dataSize = (int)(BitsPerPixel / 8f * Size.Width * Size.Height);
|
||||
if (flags.HasFlag(Flags.Compressed))
|
||||
Team17Compression.Decompress(reader.BaseStream, data);
|
||||
{
|
||||
// Some shipped images require up to 3 bytes to not fail when decompressing with out-of-bounds access.
|
||||
Data = new byte[dataSize];
|
||||
Team17Compression.Decompress(reader.BaseStream, Data);
|
||||
}
|
||||
else
|
||||
data = reader.ReadBytes(data.Length);
|
||||
|
||||
Data = data;
|
||||
{
|
||||
Data = reader.ReadBytes(dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the data from the given file. The data block can be aligned to a 4-bte boundary.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||
/// <param name="alignData"><c>true</c> to align the data array by 4 bytes.</param>
|
||||
/// <param name="alignData"><see langword="true"/> to align the data array by 4 bytes.</param>
|
||||
/// <exception cref="IndexOutOfRangeException">Compressed images required more bytes than usually to decompress.
|
||||
/// This error can be ignored, the image has been completely read, and is only caused by a few files.</exception>
|
||||
public void Load(string fileName, bool alignData)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
@ -149,41 +168,25 @@ namespace Syroot.Worms
|
||||
/// Saves the data into the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
|
||||
public void Save(Stream stream) => Save(stream, false, false);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the optionally compressed data into the given <paramref name="stream"/>.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
|
||||
/// <param name="compress"><c>true</c> to compress image data.</param>
|
||||
public void Save(Stream stream, bool compress) => Save(stream, compress, false);
|
||||
public void Save(Stream stream) => Save(stream, false);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the data in the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to save the data in.</param>
|
||||
public void Save(string fileName) => Save(fileName, false, false);
|
||||
public void Save(string fileName) => Save(fileName, false);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the optionally compressed data in the given file.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to save the data in.</param>
|
||||
/// <param name="compress"><c>true</c> to compress image data.</param>
|
||||
public void Save(string fileName, bool compress) => Save(fileName, compress, false);
|
||||
|
||||
/// <summary>
|
||||
/// Saves the optionally compressed data into the given <paramref name="stream"/>. The data block can be aligned
|
||||
/// to a 4-bte boundary.
|
||||
/// Saves the data into the given <paramref name="stream"/>. The data block can be aligned to a 4-byte boundary.
|
||||
/// </summary>
|
||||
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
|
||||
/// <param name="compress"><c>true</c> to compress image data.</param>
|
||||
/// <param name="alignData"><c>true</c> to align the data array by 4 bytes.</param>
|
||||
public void Save(Stream stream, bool compress, bool alignData)
|
||||
/// <param name="alignData"><see langword="true"/> to align the data array by 4 bytes.</param>
|
||||
public void Save(Stream stream, bool alignData)
|
||||
{
|
||||
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
|
||||
|
||||
// Write the header.
|
||||
writer.Write(_signature);
|
||||
writer.Write(Signature);
|
||||
uint fileSizeOffset = writer.ReserveOffset();
|
||||
|
||||
// Write an optional string describing the image contents and the bits per pixel.
|
||||
@ -195,7 +198,7 @@ namespace Syroot.Worms
|
||||
Flags flags = Flags.None;
|
||||
if (Palette != null)
|
||||
flags |= Flags.Palettized;
|
||||
if (compress)
|
||||
if (Compressed)
|
||||
flags |= Flags.Compressed;
|
||||
writer.WriteEnum(flags, true);
|
||||
|
||||
@ -220,23 +223,22 @@ namespace Syroot.Worms
|
||||
if (alignData)
|
||||
writer.Align(4);
|
||||
byte[] data = Data;
|
||||
if (compress)
|
||||
if (Compressed)
|
||||
data = Team17Compression.Compress(data);
|
||||
writer.Write(data);
|
||||
|
||||
writer.SatisfyOffset(fileSizeOffset, (int)writer.Position);
|
||||
writer.SatisfyOffset(fileSizeOffset, (uint)writer.Position);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the optionally compressed data in the given file. The data block can be aligned to a 4-byte boundary.
|
||||
/// Saves the data in the given file. The data block can be aligned to a 4-byte boundary.
|
||||
/// </summary>
|
||||
/// <param name="fileName">The name of the file to save the data in.</param>
|
||||
/// <param name="compress"><c>true</c> to compress image data.</param>
|
||||
/// <param name="alignData"><c>true</c> to align the data array by 4 bytes.</param>
|
||||
public void Save(string fileName, bool compress, bool alignData)
|
||||
/// <param name="alignData"><see langword="true"/> to align the data array by 4 bytes.</param>
|
||||
public void Save(string fileName, bool alignData)
|
||||
{
|
||||
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
Save(stream, compress, alignData);
|
||||
Save(stream, alignData);
|
||||
}
|
||||
|
||||
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
|
||||
@ -244,7 +246,7 @@ namespace Syroot.Worms
|
||||
[Flags]
|
||||
private enum Flags : byte
|
||||
{
|
||||
None = 0,
|
||||
None,
|
||||
Compressed = 1 << 6,
|
||||
Palettized = 1 << 7
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
namespace Syroot.Worms
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the map terrain configuration found in LEV and BIT files.
|
||||
/// </summary>
|
||||
public class LevelInfo
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
public uint LandSeed { get; set; }
|
||||
|
||||
public uint ObjectSeed { get; set; }
|
||||
|
||||
public bool Cavern { get; set; }
|
||||
|
||||
public LandStyle Style { get; set; }
|
||||
|
||||
public bool NoBorder { get; set; }
|
||||
|
||||
public int ObjectPercent { get; set; }
|
||||
|
||||
public int BridgePercent { get; set; }
|
||||
|
||||
public int WaterLevel { get; set; }
|
||||
|
||||
public int SoilIndex { get; set; }
|
||||
|
||||
public int WaterColor { get; set; }
|
||||
}
|
||||
|
||||
public enum LandStyle : int
|
||||
{
|
||||
SingleIsland,
|
||||
DoubleIsland,
|
||||
SingleSmallIsland,
|
||||
DoubleSmallIsland,
|
||||
Cavern,
|
||||
SingleTunnel,
|
||||
CavernWater,
|
||||
DoubleTunnel
|
||||
}
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using Syroot.BinaryData;
|
||||
using Syroot.Worms.Core.Graphics;
|
||||
using Syroot.Worms.Core.IO;
|
||||
using Syroot.Worms.Core.Riff;
|
||||
using Syroot.Worms.Graphics;
|
||||
using Syroot.Worms.IO;
|
||||
|
||||
namespace Syroot.Worms
|
||||
{
|
||||
@ -23,7 +25,7 @@ namespace Syroot.Worms
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RiffPalette"/> class.
|
||||
/// </summary>
|
||||
public RiffPalette() => Version = _version;
|
||||
public RiffPalette() { }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RiffPalette"/> class, loading the data from the given
|
||||
@ -43,27 +45,27 @@ namespace Syroot.Worms
|
||||
/// <summary>
|
||||
/// Gets the version of the palette data.
|
||||
/// </summary>
|
||||
public int Version { get; set; }
|
||||
public int Version { get; set; } = _version;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Color"/> instances stored in this palette.
|
||||
/// Gets or sets the <see cref="Color"/> instances stored in this palette.
|
||||
/// </summary>
|
||||
public Color[] Colors { get; set; }
|
||||
public IList<Color> Colors { get; set; } = new List<Color>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unknown data in the offl chunk.
|
||||
/// </summary>
|
||||
public byte[] OfflData { get; set; }
|
||||
public byte[] OfflData { get; set; } = Array.Empty<byte>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unknown data in the tran chunk.
|
||||
/// </summary>
|
||||
public byte[] TranData { get; set; }
|
||||
public byte[] TranData { get; set; } = Array.Empty<byte>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unknown data in the unde chunk.
|
||||
/// </summary>
|
||||
public byte[] UndeData { get; set; }
|
||||
public byte[] UndeData { get; set; } = Array.Empty<byte>();
|
||||
|
||||
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||
|
||||
@ -103,7 +105,7 @@ namespace Syroot.Worms
|
||||
|
||||
#pragma warning disable IDE0051 // Remove unused private members
|
||||
[RiffChunkLoad("data")]
|
||||
private void LoadDataChunk(BinaryStream reader, int length)
|
||||
private void LoadDataChunk(BinaryStream reader, int _)
|
||||
{
|
||||
// Read the PAL version.
|
||||
Version = reader.ReadInt16();
|
||||
@ -111,10 +113,11 @@ namespace Syroot.Worms
|
||||
throw new InvalidDataException("Unknown PAL version.");
|
||||
|
||||
// Read the colors.
|
||||
Colors = new Color[reader.ReadInt16()];
|
||||
for (int i = 0; i < Colors.Length; i++)
|
||||
short colorCount = reader.ReadInt16();
|
||||
Colors = new List<Color>();
|
||||
while (colorCount-- > 0)
|
||||
{
|
||||
Colors[i] = Color.FromArgb(reader.Read1Byte(), reader.Read1Byte(), reader.Read1Byte());
|
||||
Colors.Add(Color.FromArgb(reader.Read1Byte(), reader.Read1Byte(), reader.Read1Byte()));
|
||||
_ = reader.ReadByte(); // Dismiss alpha, as it is not used in WA.
|
||||
}
|
||||
}
|
||||
@ -135,10 +138,9 @@ namespace Syroot.Worms
|
||||
writer.Write(_version);
|
||||
|
||||
// Write the colors.
|
||||
writer.Write((short)Colors.Length);
|
||||
for (int i = 0; i < Colors.Length; i++)
|
||||
writer.Write((short)Colors.Count);
|
||||
foreach (Color color in Colors)
|
||||
{
|
||||
Color color = Colors[i];
|
||||
writer.Write(color.R);
|
||||
writer.Write(color.G);
|
||||
writer.Write(color.B);
|
||||
|
@ -4,8 +4,8 @@
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<AssemblyName>Syroot.Worms</AssemblyName>
|
||||
<Description>.NET library for loading and modifying files of Team17 Worms games.</Description>
|
||||
<PackageReleaseNotes>Fix issues when loading and saving some formats.</PackageReleaseNotes>
|
||||
<Version>3.2.0</Version>
|
||||
<PackageReleaseNotes>Overhaul implementation and documentation.</PackageReleaseNotes>
|
||||
<Version>4.0.0</Version>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Syroot.BinaryData.Serialization" Version="5.2.0" />
|
||||
|
26
src/test.xml
Normal file
26
src/test.xml
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<!-- Compilation -->
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<TargetFramework>netcoreapp3</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- References -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
|
||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.2" />
|
||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Files Linking -->
|
||||
<Target Name="FilesRemove" AfterTargets="Build;Clean">
|
||||
<Message Text="Removing Files" Importance="high" />
|
||||
<Exec Command="RD "$(OutputPath)Files" /S/Q" />
|
||||
</Target>
|
||||
<Target Name="FilesCreate" AfterTargets="Build">
|
||||
<Message Text="Linking Files" Importance="high" />
|
||||
<Exec Command="MKLINK /D "$(OutputPath)Files" "$(ProjectDir)Files"" />
|
||||
</Target>
|
||||
</Project>
|
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/(_twicken_weapons_).pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/(_twicken_weapons_).pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/0h so high 2.0.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/0h so high 2.0.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_102917.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_102917.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1180343.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1180343.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1281323.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1281323.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1341540.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1341540.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1360588.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1360588.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1423955.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1423955.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1432545.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1432545.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1497131.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1497131.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1518228.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1518228.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1608557.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1608557.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1675572.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1675572.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1696867.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1696867.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1764764.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1764764.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_194940.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_194940.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1967721.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1967721.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1974050.pxl
(Stored with Git LFS)
Normal file
BIN
src/test/Syroot.Worms.Armageddon.ProjectX.Test/Files/Libraries/Cache/cached_1974050.pxl
(Stored with Git LFS)
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user