Compare commits

..

No commits in common. "master" and "Worms.NET" have entirely different histories.

1164 changed files with 10941 additions and 23273 deletions

8
.gitattributes vendored
View File

@ -1,8 +0,0 @@
*.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

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017-2024 Syroot
Copyright (c) 2017 Syroot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,44 +1,41 @@
# Worms
The goal of this .NET library is to provide managed language access to game specific file formats of the Worms game series by Team17.
This repository hosts .NET libraries which can import, modify, and export the following file formats of second generation Worms games developed by Team17 or Mgame:
Right now, the following file formats are supported:
| Extension | Description | Games | Library | Load | Save |
|-----------|-------------------|-------------|------------------------------------|:----:|:----:|
| BIT | Monochrome Map | WA, WWP | `Syroot.Worms.Armageddon` | ❌ | ❌ |
| DAT | Mission | W2 | `Syroot.Worms.Worms2` | ❌ | ❌ |
| LAND.DAT | Land Data | W2, WA, WWP | `Syroot.Worms` | ✔ | ✔ |
| DIR | Archive | W2, WA, WWP | `Syroot.Worms` | ✔ | ✔ |
| IGD | Image Container | WWPA | `Syroot.Worms.Mgame` | ✔ | ❌ |
| IMG | Image | W2, WA, WWP | `Syroot.Worms` | ✔ | ✔ |
| KSF | Image Container | OW | `Syroot.Worms.Mgame` | ✔ | ❌ |
| LEV | Generated Map | WA, WWP | `Syroot.Worms.Armageddon` | ✔ | ✔ |
| LEV | Monochrome Map | W2 | `Syroot.Worms.Worms2` | ❌ | ❌ |
| LPD | Interface Layout | WWPA | `Syroot.Worms.Mgame` | ✔ | ❌ |
| OPT | Scheme Options | W2 | `Syroot.Worms.Worms2` | ✔ | ✔ |
| PAL | Palette | W2, WA, WWP | `Syroot.Worms` | ✔ | ✔ |
| PXL | Project X Library | WA+PX | `Syroot.Worms.Armageddon.ProjectX` | ✔ | ✔ |
| PXS | Project X Scheme | WA+PX | `Syroot.Worms.Armageddon.ProjectX` | ✔ | ✔ |
| ST1 | Team Container | W2 | `Syroot.Worms.Worms2` | ✔ | ✔ |
| WAGAME | Replay | WA | `Syroot.Worms.Armageddon` | ❌ | ❌ |
| WAM | Mission | WA, WWP | `Syroot.Worms.Worms2` | ❌ | ❌ |
| WEP | Scheme Weapons | W2 | `Syroot.Worms.Worms2` | ✔ | ✔ |
| WGT | Team Container | WA | `Syroot.Worms.Armageddon` | ✔ | ✔ |
| WSC | Scheme | WA, WWP | `Syroot.Worms.Armageddon` | ✔ | ✔ |
| WWP | Team Container | WWP | `Syroot.Worms.WorldParty` | ✔ | ✔ |
## First Generation (2D)
Support for first generation 2D games is planned at a later stage.
Implementation of formats listed above as unsupported is planned for a later date.
| Description | Extension | Games | Load | Save |
|----------------|:---------:|:-------:|:----:|:----:|
| Color Map | WRM | W1 | No | No |
| DIY Terrain | DIY | DC | No | No |
| Monochrome Map | GFT | DC | No | No |
| Mountain Set | MNT | DC | No | No |
| Option Scheme | OPT | DC | No | No |
| Team Container | - | DC | No | No |
The libraries are available on [NuGet](https://www.nuget.org/packages?q=Syroot.Worms).
## Second Generation (2D)
Formats of the second generation 2D games are mostly focused right now.
## Modules
| Description | Extension | Games | Load | Save |
|-------------------|:---------:|:-----------:|:----:|:----:|
| Archive | DIR | W2, WA, WWP | Yes | Yes |
| Image | IMG | W2, WA, WWP | Yes | No |
| Land Data | LAND.DAT | W2, WA, WWP | Yes | No |
| Mission | DAT | W2 | No | No |
| Mission | WAM | WA, WWP | No | No |
| Monochrome Map | LEV | W2 | No | No |
| Monochrome Map | LEV, BIT | WA, WWP | No | No |
| Palette | PAL | W2, WA, WWP | Yes | Yes |
| Project X Library | PXL | WA+PX | No | No |
| Project X Scheme | PXS | WA+PX | No | No |
| Replay | WAGAME | WA | No | No |
| Scheme | WSC | WA, WWP | Yes | Yes |
| Scheme Options | OPT | W2 | Yes | Yes |
| Scheme Weapons | WEP | W2 | Yes | Yes |
| Team Container | ST1 | W2 | No | No |
| Team Container | WGT | WA, WWP | No | No |
* `fkNetcode`: Patches Worms 2's outdated external IP detection and resolves it properly via a web service.
* `fkDesPatch`: Unfinished module meant to replace functionality found in Sn*tch patcher.
* `FrontendKitWS`: WormKit-like module loader for patching the Worms 2 Frontend.
* `WormKitLib`: Utilities like signature scanning or import replacement to help in patching Worms executables.
## Tools
* `Syroot.Worms.Mgame.Launcher`: Creates a fake launch configuration to start OW or WWPA clients with.
* `Syroot.Worms.Mgame.GameServer`: Simulates OW or WWPA networking to allow playing games.
* `Syroot.Worms.Worms2.GameServer`: Simulates a Worms 2 server.
## Third Generation (3D)
Third generation file formats used by the 3D games have not yet been looked into.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -1,113 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg3039"
version="1.1"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
width="64"
height="64"
sodipodi:docname="icon.svg"
inkscape:export-filename="icon.png"
inkscape:export-xdpi="192"
inkscape:export-ydpi="192">
<metadata
id="metadata3045">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3043" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview3041"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="19.203125"
inkscape:cx="32"
inkscape:cy="32"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g3889"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<g
id="g3889"
transform="translate(-7.8100759,-66.876826)">
<path
style="fill:#f0eff1;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 27.04262,126.71289 c -1.181776,-1.55006 -1.966744,-3.43909 -2.368435,-5.34643 -0.731962,-3.47556 0.09235,-5.94777 0.01998,-10.65539 -1.181472,-0.48787 -1.759686,-1.09396 -2.451634,-1.84793 -0.54815,-0.59728 -1.00234,-1.30327 -1.292215,-2.06037 -0.32661,-0.85304 -0.539845,-1.78974 -0.466734,-2.70023 0.06964,-0.86724 0.419788,-1.86425 0.849262,-2.46806 -2.222622,-2.315179 -5.867212,-9.13785 -7.388442,-14.27538 -0.627091,-2.117826 -1.043782,-4.421047 -0.649327,-6.594253 0.555377,-3.059784 1.963392,-6.129269 4.118816,-8.370897 2.426515,-2.523562 5.794227,-4.355239 9.234755,-5.002661 5.494996,-1.034023 11.734091,-0.591808 16.644562,2.082413 3.532402,1.923732 6.734565,5.354675 7.754134,9.245561 1.992433,7.603525 -2.025069,17.565155 -4.34531,23.176897 0.372134,1.17735 0.38457,2.09971 0.0082,3.21285 0.749005,-1.22124 4.617222,-1.26695 6.698763,-0.44528 2.151128,0.84914 3.662957,3.01905 4.741805,5.06463 1.345959,2.55205 1.452591,4.39726 1.87347,8.45051 3.361416,-0.18651 4.546466,0.75415 5.629108,2.49832 1.281217,2.06409 0.988026,5.22596 -0.30647,7.28174 -0.983854,1.56245 -3.082892,2.22379 -4.890208,2.6017 -2.756327,0.57634 -7.55332,-0.082 -8.422992,-0.64716 -1.45258,-0.87758 -2.109794,-2.9623 -2.521142,-4.48379 -1.402821,1.51154 -3.163799,3.01285 -5.10957,3.91927 -2.09583,0.97633 -4.460352,1.39763 -6.772715,1.49729 -2.215996,0.0955 -4.559406,0.009 -6.594511,-0.87097 -1.577588,-0.68223 -2.951008,-1.89553 -3.993098,-3.26238 z"
id="path3866"
inkscape:connector-curvature="0"
sodipodi:nodetypes="aacaaacaaaaaaccaacaaaccaaaa" />
<path
sodipodi:nodetypes="acacaaaaacaaaaacccacaaacaaaacaccaaaaa"
inkscape:connector-curvature="0"
id="path3863"
d="m 27.793976,121.07863 c -0.938536,-3.15558 -0.431941,-7.06522 -0.225814,-9.874 1.138774,0.22476 2.717839,0.0994 3.985541,-0.31129 1.841729,-0.5966 4.299757,-1.43626 4.955594,-3.02871 0.236765,-0.63702 0.345752,-1.15549 0.06504,-1.61557 -0.193357,-0.31691 -0.638827,-0.46544 -1.010038,-0.46919 -1.673779,-0.0169 -2.943507,1.75701 -4.596122,2.02285 -1.760095,0.28312 -3.745971,0.31928 -5.323725,-0.51064 -1.09879,-0.57799 -2.201799,-1.62705 -2.39356,-2.85368 -0.154663,-0.98932 0.23963,-2.16839 1.135926,-2.78097 -2.929955,-3.399706 -8.1456,-12.579671 -8.160525,-19.681834 -0.0044,-2.109158 1.048726,-4.234736 2.398876,-5.855128 1.71254,-2.055312 4.188437,-3.580424 6.755692,-4.332973 4.127116,-1.209799 8.848113,-1.435252 12.902341,0 3.39863,1.203161 7.071834,3.456088 8.406815,6.805122 2.936371,7.366413 -1.457276,15.631594 -3.123633,23.584293 0.515326,1.26768 0.641215,2.38898 0.539889,2.96776 -0.154313,3.04461 -3.141404,4.07388 -3.239326,5.47599 -0.02063,0.58726 0.341836,1.39745 0.91974,1.50395 1.775112,0.32715 3.061188,-2.30516 4.286317,-3.30904 1.117915,-0.89135 1.996385,-0.9664 3.077678,-1.08716 0.874694,-0.0977 1.799048,-0.002 2.622308,0.3085 0.865772,0.32731 1.72577,0.84177 2.282632,1.5811 2.403642,3.1912 3.475179,7.7645 3.839445,11.35383 0.4388,-0.041 1.184307,-0.25821 1.779541,-0.20907 0.737401,0.0608 1.50374,0.22656 2.132242,0.61701 0.629338,0.39097 1.226145,0.95186 1.499881,1.64033 0.325059,0.81755 0.486956,1.87965 0.04271,2.63906 -0.723244,1.23633 -1.896504,1.92514 -3.779208,2.04498 -2.093197,0.12713 -3.819496,0.14085 -5.585908,-0.46833 -0.51923,-0.17906 -1.046235,-0.49834 -1.377768,-0.90375 -0.690384,-0.61349 -1.704647,-5.64303 -2.331707,-7.49746 -0.844935,1.6212 -1.981417,3.77823 -3.430533,5.30695 -0.873833,0.92182 -1.927815,1.71307 -3.085071,2.23666 -1.825122,0.82576 -3.858872,1.28185 -5.861626,1.3259 -2.28516,0.0503 -4.857846,0.0676 -6.748215,-1.21733 -1.75457,-1.19259 -2.750631,-3.37468 -3.355429,-5.40816 z"
style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="aaaaaasa"
inkscape:connector-curvature="0"
id="path3852"
d="m 24.845061,101.57125 c -0.757785,-0.16767 -1.362649,-0.8291 -1.812441,-1.46158 -2.864311,-4.027717 -5.244139,-9.020989 -5.003042,-13.957446 0.05609,-1.148428 0.472152,-2.555423 1.474802,-3.118219 0.785949,-0.441159 1.946104,-0.224569 2.688711,0.28619 1.490827,1.025381 1.978028,3.093067 2.467387,4.835045 1.194569,4.252334 1.587326,10.668599 1.004252,13.2127 -0.07475,0.32614 -0.544814,0.26412 -0.819669,0.20331 z"
style="fill:#f0eff1;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="aaaaaaaaa"
inkscape:connector-curvature="0"
id="path3854"
d="m 30.698047,101.30525 c -0.696747,-0.19779 -1.080939,-0.99485 -1.450625,-1.617677 -1.7475,-2.944117 -2.997748,-6.285458 -3.428451,-9.681934 -0.219233,-1.728845 -0.303507,-3.641173 0.459783,-5.207813 0.653868,-1.342053 1.810141,-2.749695 3.270463,-3.059737 1.927361,-0.409199 4.220692,0.514482 5.58488,1.936158 1.292526,1.346999 1.657827,3.496363 1.614575,5.362684 -0.09581,4.134002 -1.123529,8.853546 -4.122816,11.700209 -0.48591,0.46118 -1.283351,0.75106 -1.927809,0.56811 z"
style="fill:#f0eff1;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="aaaaa"
inkscape:connector-curvature="0"
id="path3053"
d="m 23.111155,79.209874 c -0.01138,-1.138917 -1.930391,-1.44014 -3.067506,-1.505266 -1.227005,-0.07027 -3.445842,0.007 -3.473799,1.235725 -0.03231,1.419638 2.525944,1.671948 3.944553,1.608843 0.972968,-0.04328 2.606486,-0.365424 2.596752,-1.339302 z"
style="fill:#f0eff1;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="caaaac"
inkscape:connector-curvature="0"
id="path3049"
d="m 29.471776,95.528773 c -1.113382,-2.31393 -2.039835,-6.332128 -0.123439,-8.229053 0.525742,-0.5204 1.661753,-0.39519 2.179449,0.133771 1.713921,1.751223 1.246507,5.081874 0.515104,7.455946 -0.180015,0.584323 -0.54871,1.299349 -1.129933,1.42105 -0.531671,0.111328 -1.046805,-0.154223 -1.441181,-0.781714 z"
style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="saaas"
inkscape:connector-curvature="0"
id="path3055"
d="m 25.360823,78.864231 c -0.04026,-1.419992 4.606645,-2.402702 7.123563,-2.53499 1.588866,-0.08351 4.506608,-0.465415 4.639913,1.120045 0.145405,1.729321 -3.071775,1.778317 -4.78587,2.049595 -2.306761,0.365074 -6.940969,0.657497 -6.977606,-0.63465 z"
style="fill:#f0eff1;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:nodetypes="aaaasa"
inkscape:connector-curvature="0"
id="path3051"
d="m 19.499778,91.756829 c -0.336512,-1.403856 -0.725814,-3.395762 0.388636,-4.3134 0.595308,-0.490178 1.713417,-0.260854 2.301122,0.238413 1.282561,1.08956 1.273616,3.189522 1.325224,4.871612 0.04396,1.432965 -0.03199,4.135797 -0.872415,4.211507 -1.153711,0.103931 -2.683166,-3.091608 -3.142567,-5.008132 z"
style="fill:#424242;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -1,8 +0,0 @@
void FAlign(byte alignment)
{
local int bytesToSkip <hidden=true> = (-FTell() % alignment + alignment) % alignment;
while (bytesToSkip--)
{
byte padding <fgcolor=0x808080, hidden=true>;
}
}

View File

@ -1,18 +0,0 @@
//------------------------------------------------
//--- 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>;

View File

@ -1,74 +0,0 @@
#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;
}

View File

@ -1,32 +0,0 @@
//------------------------------------------------
//--- 010 Editor v9.0.1 Binary Template
//
// File: LEV.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms LEV map terrain files.
// Category: Worms
// File Mask: *.bit;*.lev
// ID Bytes:
// History:
// 0.1.0 2019-01-28 Initial version.
//------------------------------------------------
LittleEndian();
uint landSeed;
uint objectSeed;
int cavern;
enum LANDSTYLE
{
SingleIsland_Cavern,
DoubleIsland_DoubleTunnel,
SingleIslandSmall_CavernWater,
DoubleIslandSmall_SingleTunnel,
} style;
int noBorder;
int objectPercent;
int bridgePercent;
int waterLevel;
int soilIndex;
int waterColor;

View File

@ -1,29 +0,0 @@
//------------------------------------------------
//--- 010 Editor v9.0.1 Binary Template
//
// File: KSF.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Online Worms KSF bitmap files.
// Category: Online Worms
// File Mask: *.ksf
// ID Bytes:
// History:
// 0.1.0 2018-12-21 Initial version.
//------------------------------------------------
typedef struct
{
uint offset;
uint halfWidth;
uint halfHeight;
ushort width;
ushort height;
} Image;
LittleEndian();
int numImages;
int lenData;
Image images[numImages];
ubyte data[lenData];

View File

@ -1,20 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -1,44 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -1,43 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -1,44 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -1,51 +0,0 @@
//------------------------------------------------
//--- 010 Editor v9.0.1 Binary Template
//
// File: IGD.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms World Party Aqua IGD graphics containers.
// Category: Worms World Party Aqua
// File Mask: *.igd
// ID Bytes:
// History:
// 0.1.0 2019-01-05 Initial version.
//------------------------------------------------
typedef struct
{
int x;
int y;
} Vec2 <read=Vec2Read>;
string Vec2Read(Vec2& v)
{
string s;
SPrintf(s, "(%d, %d)", v.x, v.y);
return s;
}
typedef struct
{
uint unkA;
uint index;
uint unkB;
uint unkC;
Vec2 size;
Vec2 center;
uint lenData;
uint lenDataComp;
ubyte dataComp[lenDataComp];
} Image;
LittleEndian();
uint unkA;
uint unkB;
Vec2 negativeCenter;
Vec2 center;
Vec2 size;
uint numColors;
uint palette[numColors] <format=hex>;
uint numImages;
if (numImages <= 512)
Image images[numImages] <optimize=false>;

View File

@ -1,35 +0,0 @@
//------------------------------------------------
//--- 010 Editor v9.0.1 Binary Template
//
// File: LPD.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms World Party Aqua LPD layout files.
// Category: Worms World Party Aqua
// File Mask: *.lpd
// ID Bytes:
// History:
// 0.1.0 2019-01-05 Initial version.
//------------------------------------------------
typedef struct
{
uint lenFileName;
char fileName[lenFileName];
uint left;
uint top;
uint right;
uint bottom;
uint param5;
uint version;
} Element <read=ElementRead>;
wstring ElementRead(Element &var)
{
return StringToWString(var.fileName, CHARSET_KOREAN_J);
}
LittleEndian();
uint numElements;
if (numElements <= 512)
Element elements[numElements] <optimize=false>;

View File

@ -1,44 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -1,43 +0,0 @@
//------------------------------------------------
//--- 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];

View File

@ -0,0 +1,35 @@
using System;
using System.IO;
using System.Collections.Generic;
using Syroot.Worms.Gen2;
namespace Syroot.Worms.Test
{
/// <summary>
/// Represents the main class of the application containing the program entry point.
/// </summary>
internal class Program
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private static readonly string[] _testPaths = { @"C:\Games\Worms Armageddon 3.7.2.1" };
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static void Main(string[] args)
{
Console.WriteLine("Done.");
Console.ReadLine();
}
private static List<string> GetFiles(string wildcard)
{
List<string> files = new List<string>();
foreach (string testPath in _testPaths)
{
files.AddRange(Directory.GetFiles(testPath, wildcard, SearchOption.AllDirectories));
}
return files;
}
}
}

View File

@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Syroot.Worms.Core;
namespace Syroot.Worms.UnitTest.Common
{
/// <summary>
/// Represents a collection of methods helping in executing tests.
/// </summary>
internal static class TestHelpers
{
// ---- MEMBERS ------------------------------------------------------------------------------------------------
private static readonly string[] _gamePathsWorms2 = { @"C:\Games\Worms2" };
private static readonly string[] _gamePathsWormsArmageddon = { @"C:\Games\Worms Armageddon 3.7.2.1" };
private static readonly string[] _gamePathsWormsWorldParty = { @"C:\Games\Worms World Party" };
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Loads the files found with the given <paramref name="wildcard"/>. Excludes file names specified in the
/// optional array <paramref name="excludedFiles"/>.
/// </summary>
/// <typeparam name="T">The type of the files to load.</typeparam>
/// <param name="games">The games to test.</param>
/// <param name="wildcard">The wildcard to match.</param>
/// <param name="excludedFiles">Optionally, the files to exclude.</param>
internal static void LoadFiles<T>(Game games, string wildcard, string[] excludedFiles = null)
where T : ILoadableFile, new()
{
foreach (string fileName in FindFiles(games, wildcard))
{
if (excludedFiles?.Contains(Path.GetFileName(fileName), StringComparer.OrdinalIgnoreCase) == true)
{
Debug.WriteLine($"Skipping {fileName}");
continue;
}
Debug.Write($"Loading {fileName}...");
T instance = new T();
instance.Load(fileName);
Debug.WriteLine($" ok");
}
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static List<string> FindFiles(Game games, string wildcard)
{
List<string> gamePaths = GetGamePaths(games);
List<string> files = new List<string>();
foreach (string testPath in gamePaths)
{
files.AddRange(Directory.GetFiles(testPath, wildcard, SearchOption.AllDirectories));
}
return files;
}
private static List<string> GetGamePaths(Game game)
{
List<string> gamePaths = new List<string>();
if (game.HasFlag(Game.Worms2))
{
gamePaths.AddRange(_gamePathsWorms2);
}
if (game.HasFlag(Game.WormsArmageddon))
{
gamePaths.AddRange(_gamePathsWormsArmageddon);
}
if (game.HasFlag(Game.WormsWorldParty))
{
gamePaths.AddRange(_gamePathsWormsWorldParty);
}
return gamePaths;
}
}
[Flags]
internal enum Game
{
Worms2 = 1 << 0,
WormsArmageddon = 1 << 1,
WormsWorldParty = 1 << 2,
Gen2 = Worms2 | WormsArmageddon | WormsWorldParty,
Armageddon = WormsArmageddon | WormsWorldParty,
All = -1
}
}

View File

@ -1,19 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.Test
namespace Syroot.Worms.UnitTest.Gen2
{
/// <summary>
/// Represents a collection of tests for the <see cref="Archive"/> class.
/// </summary>
[TestCategory("Archive")]
[TestClass]
public class ArchiveTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void TestArchives() => Tools.TestFiles<Archive>("*.dir");
public void LoadArchives()
{
TestHelpers.LoadFiles<Archive>(Game.Gen2, "*.dir");
}
}
}

View File

@ -1,24 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Armageddon;
namespace Syroot.Worms.Test.Armageddon
{
/// <summary>
/// Represents a collection of tests for the <see cref="LandData"/> class.
/// </summary>
[TestClass]
public class LandDataTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// </summary>
[TestMethod]
public void TestLandData() => Tools.TestFiles<LandData>("*.dat", new[]
{
// Decompressing embedded IMG files fails with extreme IndexOutOfRangeExceptions.
"WWPA"
});
}
}
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2.Armageddon;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.UnitTest.Gen2.Armageddon
{
/// <summary>
/// Represents a collection of tests for the <see cref="LandData"/> class.
/// </summary>
[TestCategory("LandData (Armageddon)")]
[TestClass]
public class LandDataTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadLandData()
{
TestHelpers.LoadFiles<LandData>(Game.Armageddon, "land.dat");
}
}
}

View File

@ -1,20 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Armageddon.ProjectX;
using Syroot.Worms.Gen2.Armageddon;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.Test.Armageddon.ProjectX
namespace Syroot.Worms.UnitTest.Gen2.Armageddon
{
/// <summary>
/// Represents a collection of tests for the <see cref="Scheme"/> class.
/// </summary>
[TestCategory("Scheme")]
[TestClass]
public class SchemeTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void TestSchemes() => Tools.TestFiles<Scheme>("*.pxs");
public void LoadSchemes()
{
TestHelpers.LoadFiles<Scheme>(Game.Armageddon, "*.wsc");
}
}
}

View File

@ -0,0 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.UnitTest.Gen2
{
/// <summary>
/// Represents a collection of tests for the <see cref="Image"/> class.
/// </summary>
[TestCategory("Image")]
[TestClass]
public class ImageTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadImages()
{
TestHelpers.LoadFiles<Image>(Game.All, "*.img");
}
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Gen2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.UnitTest.Gen2
{
/// <summary>
/// Represents a collection of tests for the <see cref="Palette"/> class.
/// </summary>
[TestCategory("Palette")]
[TestClass]
public class PaletteTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void LoadPalettes()
{
TestHelpers.LoadFiles<Palette>(Game.Gen2, "*.pal", new string[]
{
"wwp.pal", // Contains 4 bytes of trash after the data chunk.
"wwpmaped.pal" // Contains 4 bytes of trash after the data chunk.
});
}
}
}

View File

@ -1,20 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Worms2;
using Syroot.Worms.Gen2.Worms2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.Test.Worms2
namespace Syroot.Worms.UnitTest.Gen2.Worms2
{
/// <summary>
/// Represents a collection of tests for the <see cref="LandData"/> class.
/// </summary>
[TestCategory("LandData (Worms2)")]
[TestClass]
public class LandDataTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void TestLandData() => Tools.TestFiles<LandData>("*.dat");
public void LoadLandData()
{
TestHelpers.LoadFiles<LandData>(Game.Worms2, "land.dat");
}
}
}

View File

@ -1,20 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Worms2;
using Syroot.Worms.Gen2.Worms2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.Test.Worms2
namespace Syroot.Worms.UnitTest.Gen2.Worms2
{
/// <summary>
/// Represents a collection of tests for the <see cref="SchemeOptions"/> class.
/// </summary>
[TestCategory("SchemeOptions")]
[TestClass]
public class SchemeOptionsTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void TestSchemeOptions() => Tools.TestFiles<SchemeOptions>("*.opt");
public void LoadSchemeOptions()
{
TestHelpers.LoadFiles<SchemeOptions>(Game.Worms2, "*.opt");
}
}
}

View File

@ -1,20 +1,25 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Syroot.Worms.Worms2;
using Syroot.Worms.Gen2.Worms2;
using Syroot.Worms.UnitTest.Common;
namespace Syroot.Worms.Test.Worms2
namespace Syroot.Worms.UnitTest.Gen2.Worms2
{
/// <summary>
/// Represents a collection of tests for the <see cref="SchemeWeapons"/> class.
/// </summary>
[TestCategory("SchemeWeapons")]
[TestClass]
public class SchemeWeaponsTests
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Tests all files found in the test directory.
/// Loads all files found in any game directories.
/// </summary>
[TestMethod]
public void TestSchemeWeapons() => Tools.TestFiles<SchemeWeapons>("*.wep");
public void LoadSchemeWeapons()
{
TestHelpers.LoadFiles<SchemeWeapons>(Game.Worms2, "*.wep");
}
}
}

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0" />
<PackageReference Include="MSTest.TestAdapter" Version="1.1.11" />
<PackageReference Include="MSTest.TestFramework" Version="1.1.11" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@ -1,189 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30204.135
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms", "library\Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Scratchpad", "tool\Syroot.Worms.Scratchpad\Syroot.Worms.Scratchpad.csproj", "{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Mgame.Launcher", "tool\Syroot.Worms.Mgame.Launcher\Syroot.Worms.Mgame.Launcher.csproj", "{510EE83E-9C52-40FD-AC7E-C4981EBF4182}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Armageddon", "library\Syroot.Worms.Armageddon\Syroot.Worms.Armageddon.csproj", "{D9694108-539C-4DEE-B5DD-284208D48B46}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Armageddon.ProjectX", "library\Syroot.Worms.Armageddon.ProjectX\Syroot.Worms.Armageddon.ProjectX.csproj", "{AC9F52FA-F552-49E0-83AE-79759BF44FED}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.WorldParty", "library\Syroot.Worms.WorldParty\Syroot.Worms.WorldParty.csproj", "{4E124BBA-15B5-422E-93D5-96EA7D4180F3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Worms2", "library\Syroot.Worms.Worms2\Syroot.Worms.Worms2.csproj", "{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Mgame", "library\Syroot.Worms.Mgame\Syroot.Worms.Mgame.csproj", "{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test Projects", "Test Projects", "{99E56312-A064-4AD3-8443-0B56A5F76E6B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library Projects", "Library Projects", "{9E964426-D744-405A-9EAA-D8D7A310B614}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tool Projects", "Tool Projects", "{0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.WorldParty.Test", "test\Syroot.Worms.WorldParty.Test\Syroot.Worms.WorldParty.Test.csproj", "{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Armageddon.Test", "test\Syroot.Worms.Armageddon.Test\Syroot.Worms.Armageddon.Test.csproj", "{748D16FF-35C6-4249-A1E8-04B2D239C954}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Worms2.Test", "test\Syroot.Worms.Worms2.Test\Syroot.Worms.Worms2.Test.csproj", "{3AAC4992-DDB9-4175-82B9-C57F22E12FF6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Armageddon.ProjectX.Test", "test\Syroot.Worms.Armageddon.ProjectX.Test\Syroot.Worms.Armageddon.ProjectX.Test.csproj", "{EF308D4E-26A0-471C-B764-9C4EB713BEAE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Test", "test\Syroot.Worms.Test\Syroot.Worms.Test.csproj", "{351B93B0-301F-42E1-82A0-7FA217154F5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Mgame.GameServer", "tool\Syroot.Worms.Mgame.GameServer\Syroot.Worms.Mgame.GameServer.csproj", "{392E4CA2-61D9-4BE1-B065-8801A9F102B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Mgame.Test", "test\Syroot.Worms.Mgame.Test\Syroot.Worms.Mgame.Test.csproj", "{212F8090-9775-4098-BD44-9ABC01FBE553}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Shell", "tool\Syroot.Worms.Shell\Syroot.Worms.Shell.csproj", "{1FAB6B9F-2585-46DC-81C0-579DC808C389}"
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.Worms2.GameServer", "tool\Syroot.Worms.Worms2.GameServer\Syroot.Worms.Worms2.GameServer.csproj", "{13ABF717-5809-441D-A5D8-66E1EE75A390}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Module Projects", "Module Projects", "{2A8C6AAA-BA1F-4FB6-A598-114930217B6C}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WormKitTools", "module\WormKitTools\WormKitTools.vcxproj", "{068A8647-0A66-4E39-983B-43ACEAC5C937}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FrontendKitWS", "module\FrontendKitWS\FrontendKitWS.vcxproj", "{E391EA12-B929-466C-932F-DEF72B8CEB5D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fkDesPatch", "module\fkDesPatch\fkDesPatch.vcxproj", "{6B4D57EA-4642-440A-AB62-2E011D7B64E1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fkNetcode", "module\fkNetcode\fkNetcode.vcxproj", "{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wkUnlimiter", "module\wkUnlimiter\wkUnlimiter.vcxproj", "{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.Build.0 = Release|Any CPU
{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}.Release|Any CPU.Build.0 = Release|Any CPU
{510EE83E-9C52-40FD-AC7E-C4981EBF4182}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{510EE83E-9C52-40FD-AC7E-C4981EBF4182}.Debug|Any CPU.Build.0 = Debug|Any CPU
{510EE83E-9C52-40FD-AC7E-C4981EBF4182}.Release|Any CPU.ActiveCfg = Release|Any CPU
{510EE83E-9C52-40FD-AC7E-C4981EBF4182}.Release|Any CPU.Build.0 = Release|Any CPU
{D9694108-539C-4DEE-B5DD-284208D48B46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9694108-539C-4DEE-B5DD-284208D48B46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9694108-539C-4DEE-B5DD-284208D48B46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9694108-539C-4DEE-B5DD-284208D48B46}.Release|Any CPU.Build.0 = Release|Any CPU
{AC9F52FA-F552-49E0-83AE-79759BF44FED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC9F52FA-F552-49E0-83AE-79759BF44FED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC9F52FA-F552-49E0-83AE-79759BF44FED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC9F52FA-F552-49E0-83AE-79759BF44FED}.Release|Any CPU.Build.0 = Release|Any CPU
{4E124BBA-15B5-422E-93D5-96EA7D4180F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4E124BBA-15B5-422E-93D5-96EA7D4180F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4E124BBA-15B5-422E-93D5-96EA7D4180F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4E124BBA-15B5-422E-93D5-96EA7D4180F3}.Release|Any CPU.Build.0 = Release|Any CPU
{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}.Release|Any CPU.Build.0 = Release|Any CPU
{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}.Release|Any CPU.Build.0 = Release|Any CPU
{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B}.Release|Any CPU.Build.0 = Release|Any CPU
{748D16FF-35C6-4249-A1E8-04B2D239C954}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{748D16FF-35C6-4249-A1E8-04B2D239C954}.Debug|Any CPU.Build.0 = Debug|Any CPU
{748D16FF-35C6-4249-A1E8-04B2D239C954}.Release|Any CPU.ActiveCfg = Release|Any CPU
{748D16FF-35C6-4249-A1E8-04B2D239C954}.Release|Any CPU.Build.0 = Release|Any CPU
{3AAC4992-DDB9-4175-82B9-C57F22E12FF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3AAC4992-DDB9-4175-82B9-C57F22E12FF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3AAC4992-DDB9-4175-82B9-C57F22E12FF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3AAC4992-DDB9-4175-82B9-C57F22E12FF6}.Release|Any CPU.Build.0 = Release|Any CPU
{EF308D4E-26A0-471C-B764-9C4EB713BEAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF308D4E-26A0-471C-B764-9C4EB713BEAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF308D4E-26A0-471C-B764-9C4EB713BEAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF308D4E-26A0-471C-B764-9C4EB713BEAE}.Release|Any CPU.Build.0 = Release|Any CPU
{351B93B0-301F-42E1-82A0-7FA217154F5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{351B93B0-301F-42E1-82A0-7FA217154F5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{351B93B0-301F-42E1-82A0-7FA217154F5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{351B93B0-301F-42E1-82A0-7FA217154F5D}.Release|Any CPU.Build.0 = Release|Any CPU
{392E4CA2-61D9-4BE1-B065-8801A9F102B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{392E4CA2-61D9-4BE1-B065-8801A9F102B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{392E4CA2-61D9-4BE1-B065-8801A9F102B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{392E4CA2-61D9-4BE1-B065-8801A9F102B8}.Release|Any CPU.Build.0 = Release|Any CPU
{212F8090-9775-4098-BD44-9ABC01FBE553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{212F8090-9775-4098-BD44-9ABC01FBE553}.Debug|Any CPU.Build.0 = Debug|Any CPU
{212F8090-9775-4098-BD44-9ABC01FBE553}.Release|Any CPU.ActiveCfg = Release|Any CPU
{212F8090-9775-4098-BD44-9ABC01FBE553}.Release|Any CPU.Build.0 = Release|Any CPU
{1FAB6B9F-2585-46DC-81C0-579DC808C389}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Release|Any CPU.Build.0 = Release|Any CPU
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Debug|Any CPU.ActiveCfg = Debug|Win32
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Debug|Any CPU.Build.0 = Debug|Win32
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Release|Any CPU.ActiveCfg = Release|Win32
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Release|Any CPU.Build.0 = Release|Win32
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.ActiveCfg = Debug|Win32
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.Build.0 = Debug|Win32
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.ActiveCfg = Release|Win32
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.Build.0 = Release|Win32
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Debug|Any CPU.ActiveCfg = Debug|Win32
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Debug|Any CPU.Build.0 = Debug|Win32
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Release|Any CPU.ActiveCfg = Release|Win32
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Release|Any CPU.Build.0 = Release|Win32
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.ActiveCfg = Debug|Win32
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.Build.0 = Debug|Win32
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.ActiveCfg = Release|Win32
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.Build.0 = Release|Win32
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.ActiveCfg = Debug|Win32
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.Build.0 = Debug|Win32
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.ActiveCfg = Release|Win32
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
{510EE83E-9C52-40FD-AC7E-C4981EBF4182} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
{D9694108-539C-4DEE-B5DD-284208D48B46} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{AC9F52FA-F552-49E0-83AE-79759BF44FED} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{4E124BBA-15B5-422E-93D5-96EA7D4180F3} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26} = {9E964426-D744-405A-9EAA-D8D7A310B614}
{239763CD-B7C9-4E8B-A84B-8F24DECF6D7B} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
{748D16FF-35C6-4249-A1E8-04B2D239C954} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
{3AAC4992-DDB9-4175-82B9-C57F22E12FF6} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
{EF308D4E-26A0-471C-B764-9C4EB713BEAE} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
{351B93B0-301F-42E1-82A0-7FA217154F5D} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
{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}
{13ABF717-5809-441D-A5D8-66E1EE75A390} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
{068A8647-0A66-4E39-983B-43ACEAC5C937} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
{E391EA12-B929-466C-932F-DEF72B8CEB5D} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
{6B4D57EA-4642-440A-AB62-2E011D7B64E1} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1CD4EDE2-A5FB-4A58-A850-3506AB7E7B69}
EndGlobalSection
EndGlobal

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms.UnitTest", "Syroot.Worms.UnitTest\Syroot.Worms.UnitTest.csproj", "{493816DB-A1A1-4981-9F5F-8044499937B6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Test", "Syroot.Worms.Test\Syroot.Worms.Test.csproj", "{2D796945-A523-4A22-BDEE-702D6BA36F69}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.Build.0 = Release|Any CPU
{493816DB-A1A1-4981-9F5F-8044499937B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{493816DB-A1A1-4981-9F5F-8044499937B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{493816DB-A1A1-4981-9F5F-8044499937B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{493816DB-A1A1-4981-9F5F-8044499937B6}.Release|Any CPU.Build.0 = Release|Any CPU
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,33 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents extension methods for <see cref="BinaryReader"/> instances.
/// </summary>
internal static class BinaryReaderExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <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="BinaryReader"/> instance.</param>
/// <returns>The structure of type <typeparamref name="T"/>.</returns>
internal static T ReadStruct<T>(this BinaryReader self) where T : struct
{
// Read the raw bytes of the structure.
byte[] bytes = self.ReadBytes(Marshal.SizeOf<T>());
// Convert them to a structure instance and return it.
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
T instance = Marshal.PtrToStructure<T>(handle.AddrOfPinnedObject());
handle.Free();
return instance;
}
}
}

View File

@ -0,0 +1,32 @@
using System.IO;
using System.Runtime.InteropServices;
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents extension methods for <see cref="BinaryWriter"/> instances.
/// </summary>
internal static class BinaryWriterExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Writes the bytes of a structure into the current stream.
/// </summary>
/// <typeparam name="T">The type of the structure to read.</typeparam>
/// <param name="self">The extended <see cref="BinaryWriter"/> instance.</param>
/// <param name="instance">The structure to write.</param>
internal static void Write<T>(this BinaryWriter self, T instance) where T : struct
{
// Get the raw bytes of the structure instance.
byte[] bytes = new byte[Marshal.SizeOf<T>()];
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
Marshal.StructureToPtr(instance, handle.AddrOfPinnedObject(), false);
handle.Free();
// Write the bytes to the stream.
self.Write(bytes);
}
}
}

View File

@ -0,0 +1,34 @@
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents extension methods for <see cref="Byte"/> array instances.
/// </summary>
internal static class ByteArrayExtensions
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Returns <c>true</c> if the current byte array instance holds the same values as the given one.
/// </summary>
/// <param name="self">The extended byte array instance.</param>
/// <param name="other">The byte array instance to compare with.</param>
/// <returns><c>true</c> if both instances hold the same values, otherwise <c>false</c>.</returns>
internal static bool Compare(this byte[] self, byte[] other)
{
if (self.Length != other.Length)
{
return false;
}
for (int i = 0; i < self.Length; i++)
{
if (self[i] != other[i])
{
return false;
}
}
return true;
}
}
}

View File

@ -1,13 +1,11 @@
using System;
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents extension methods for <see cref="Byte"/> instances.
/// </summary>
public static class ByteExtensions
internal static class ByteExtensions
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Returns the current byte with the bit at the <paramref name="index"/> set (being 1).
@ -15,7 +13,10 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="index">The 0-based index of the bit to enable.</param>
/// <returns>The current byte with the bit enabled.</returns>
public static byte EnableBit(this byte self, int index) => (byte)(self | (1 << index));
internal static byte EnableBit(this byte self, int index)
{
return (byte)(self | (1 << index));
}
/// <summary>
/// Returns the current byte with the bit at the <paramref name="index"/> cleared (being 0).
@ -23,7 +24,10 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="index">The 0-based index of the bit to disable.</param>
/// <returns>The current byte with the bit disabled.</returns>
public static byte DisableBit(this byte self, int index) => (byte)(self & ~(1 << index));
internal static byte DisableBit(this byte self, int index)
{
return (byte)(self & ~(1 << index));
}
/// <summary>
/// Returns a value indicating whether the bit at the <paramref name="index"/> in the current byte is enabled
@ -31,8 +35,11 @@ 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><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;
/// <returns><c>true</c> when the bit is set; otherwise <c>false</c>.</returns>
internal static bool GetBit(this byte self, int index)
{
return (self & (1 << index)) != 0;
}
/// <summary>
/// Returns the current byte with all bits rotated in the given <paramref name="direction"/>, where positive
@ -41,7 +48,7 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="direction">The direction in which to rotate, where positive directions rotate left.</param>
/// <returns>The current byte with the bits rotated.</returns>
public static byte RotateBits(this byte self, int direction)
internal static byte RotateBits(this byte self, int direction)
{
int bits = sizeof(byte) * 8;
if (direction > 0)
@ -62,10 +69,19 @@ 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"><see langword="true"/> to enable the bit; otherwise <see langword="false"/>.</param>
/// <param name="enable"><c>true</c> to enable the bit; otherwise <c>false</c>.</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);
internal static byte SetBit(this byte self, int index, bool enable)
{
if (enable)
{
return EnableBit(self, index);
}
else
{
return DisableBit(self, index);
}
}
/// <summary>
/// Returns the current byte with the bit at the <paramref name="index"/> enabled when it is disabled or
@ -74,8 +90,17 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="index">The 0-based index of the bit to toggle.</param>
/// <returns>The current byte with the bit toggled.</returns>
public static byte ToggleBit(this byte self, int index)
=> GetBit(self, index) ? DisableBit(self, index) : EnableBit(self, index);
internal static byte ToggleBit(this byte self, int index)
{
if (GetBit(self, index))
{
return DisableBit(self, index);
}
else
{
return EnableBit(self, index);
}
}
/// <summary>
/// Returns an <see cref="Byte"/> instance represented by the given number of <paramref name="bits"/>.
@ -84,7 +109,10 @@ namespace Syroot.Worms.Core
/// <param name="bits">The number of least significant bits which are used to store the <see cref="Byte"/>
/// value.</param>
/// <returns>The decoded <see cref="Byte"/>.</returns>
public static byte DecodeByte(this byte self, int bits) => DecodeByte(self, bits, 0);
internal static byte DecodeByte(this byte self, int bits)
{
return DecodeByte(self, bits, 0);
}
/// <summary>
/// Returns an <see cref="Byte"/> instance represented by the given number of <paramref name="bits"/>, starting
@ -93,10 +121,13 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="bits">The number of least significant bits which are used to store the <see cref="Byte"/>
/// value.</param>
/// <param name="firstBit">The first bit of the encoded value.</param>
/// <paramref name="firstBit"/>The first bit of the encoded value.</param>
/// <returns>The decoded <see cref="Byte"/>.</returns>
public static byte DecodeByte(this byte self, int bits, int firstBit)
=> (byte)((self >> firstBit) & ((1 << bits) - 1)); // shift to the first bit and keep only required bits
internal static byte DecodeByte(this byte self, int bits, int firstBit)
{
// Shift to the first bit and keep only the required bits.
return (byte)((self >> firstBit) & ((1 << bits) - 1));
}
/// <summary>
/// Returns an <see cref="SByte"/> instance represented by the given number of <paramref name="bits"/>.
@ -105,7 +136,10 @@ namespace Syroot.Worms.Core
/// <param name="bits">The number of least significant bits which are used to store the <see cref="SByte"/>
/// value.</param>
/// <returns>The decoded <see cref="SByte"/>.</returns>
public static sbyte DecodeSByte(this byte self, int bits) => DecodeSByte(self, bits, 0);
internal static sbyte DecodeSByte(this byte self, int bits)
{
return DecodeSByte(self, bits, 0);
}
/// <summary>
/// Returns an <see cref="SByte"/> instance represented by the given number of <paramref name="bits"/>, starting
@ -114,14 +148,21 @@ namespace Syroot.Worms.Core
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="bits">The number of least significant bits which are used to store the <see cref="SByte"/>
/// value.</param>
/// <param name="firstBit">The first bit of the encoded value.</param>
/// <paramref name="firstBit"/>The first bit of the encoded value.</param>
/// <returns>The decoded <see cref="SByte"/>.</returns>
public static sbyte DecodeSByte(this byte self, int bits, int firstBit)
internal static sbyte DecodeSByte(this byte self, int bits, int firstBit)
{
self >>= firstBit;
int absMask = 1 << bits;
byte abs = (byte)(self & (absMask - 1));
return abs.GetBit(bits - 1) ? (sbyte)(abs - absMask) : (sbyte)abs;
if (abs.GetBit(bits - 1))
{
return (sbyte)(abs - absMask);
}
else
{
return (sbyte)abs;
}
}
/// <summary>
@ -129,51 +170,53 @@ namespace Syroot.Worms.Core
/// <paramref name="bits"/>.
/// </summary>
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="value">The value to encode.</param>
/// <param name="bits">The number of bits which are used to store the <see cref="Byte"/> value.</param>
/// <returns>The current byte with the value encoded into it.</returns>
public static byte Encode(this byte self, byte value, int bits) => Encode(self, value, bits, 0);
internal static byte Encode(this byte self, byte value, int bits)
{
return Encode(self, value, bits, 0);
}
/// <summary>
/// Returns the current byte with the given <paramref name="value"/> set into the given number of
/// <paramref name="bits"/> starting at <paramref name="firstBit"/>.
/// </summary>
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="value">The value to encode.</param>
/// <param name="bits">The number of bits which are used to store the <see cref="Byte"/> value.</param>
/// <param name="firstBit">The first bit used for the encoded value.</param>
/// <param name="firstBit"/>The first bit used for the encoded value.</param>
/// <returns>The current byte with the value encoded into it.</returns>
public static byte Encode(this byte self, byte value, int bits, int firstBit)
internal static byte Encode(this byte self, byte value, int bits, int firstBit)
{
// Clear the bits required for the value and fit it into them by truncating.
int mask = ((1 << bits) - 1) << firstBit;
self &= (byte)~mask;
value = (byte)((value << firstBit) & mask);
// Set the value.
return (byte)(self | value);
}
/// <summary>
/// Returns the current byte with the given <paramref name="value"/> set into the given number of
/// <paramref name="bits"/>.
/// </summary>
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="value">The value to encode.</param>
/// <param name="bits">The number of bits which are used to store the <see cref="SByte"/> value.</param>
/// <returns>The current byte with the value encoded into it.</returns>
public static byte Encode(this byte self, sbyte value, int bits) => Encode(self, value, bits, 0);
internal static byte Encode(this byte self, sbyte value, int bits)
{
return Encode(self, value, bits, 0);
}
/// <summary>
/// Returns the current byte with the given <paramref name="value"/> set into the given number of
/// <paramref name="bits"/> starting at <paramref name="firstBit"/>.
/// </summary>
/// <param name="self">The extended <see cref="Byte"/> instance.</param>
/// <param name="value">The value to encode.</param>
/// <param name="bits">The number of bits which are used to store the <see cref="SByte"/> value.</param>
/// <param name="firstBit">The first bit used for the encoded value.</param>
/// <param name="firstBit"/>The first bit used for the encoded value.</param>
/// <returns>The current byte with the value encoded into it.</returns>
public static byte Encode(this byte self, sbyte value, int bits, int firstBit)
internal static byte Encode(this byte self, sbyte value, int bits, int firstBit)
{
// Set the value as a normal byte, but then fix the sign.
self = Encode(self, (byte)value, bits, firstBit);

View File

@ -1,6 +1,6 @@
using System.IO;
namespace Syroot.Worms.IO
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents data which can be loaded by providing a <see cref="Stream"/> to read from.
@ -8,7 +8,7 @@ namespace Syroot.Worms.IO
public interface ILoadable
{
// ---- METHODS ------------------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <paramref name="stream"/>.
/// </summary>

View File

@ -1,4 +1,4 @@
namespace Syroot.Worms.IO
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents a file which can be loaded by providing a file name.

View File

@ -1,6 +1,6 @@
using System.IO;
namespace Syroot.Worms.IO
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents data which can be saved by providing a <see cref="Stream "/>to write to.
@ -8,7 +8,7 @@ namespace Syroot.Worms.IO
public interface ISaveable
{
// ---- METHODS ------------------------------------------------------------------------------------------------
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>

View File

@ -1,4 +1,4 @@
namespace Syroot.Worms.IO
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents a file which can be saved by providing a file name.

View File

@ -1,6 +1,6 @@
using System;
namespace Syroot.Worms.Core.Riff
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents the attribute to decorate methods in <see cref="RiffFile"/> inheriting classes to provide methods
@ -16,7 +16,10 @@ namespace Syroot.Worms.Core.Riff
/// <paramref name="identifier"/>.
/// </summary>
/// <param name="identifier">The chunk identifier required to invoke this method for loading it.</param>
internal RiffChunkLoadAttribute(string identifier) => Identifier = identifier;
internal RiffChunkLoadAttribute(string identifier)
{
Identifier = identifier;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
using System;
namespace Syroot.Worms.Core.Riff
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents the attribute to decorate methods in <see cref="RiffFile"/> inheriting classes to provide methods
@ -16,7 +16,10 @@ namespace Syroot.Worms.Core.Riff
/// <paramref name="identifier"/>.
/// </summary>
/// <param name="identifier">The chunk identifier saved in the file.</param>
internal RiffChunkSaveAttribute(string identifier) => Identifier = identifier;
internal RiffChunkSaveAttribute(string identifier)
{
Identifier = identifier;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------

View File

@ -3,10 +3,9 @@ using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
using Syroot.IO;
namespace Syroot.Worms.Core.Riff
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents the format of RIFF files, which manage their data in chunks.
@ -17,18 +16,21 @@ namespace Syroot.Worms.Core.Riff
private const string _signature = "RIFF";
// ---- FIELDS -------------------------------------------------------------------------------------------------
// ---- MEMBERS ------------------------------------------------------------------------------------------------
private static readonly Dictionary<Type, TypeData> _typeDataCache = new Dictionary<Type, TypeData>();
private readonly TypeData _typeData;
private TypeData _typeData;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="RiffFile"/> class.
/// </summary>
protected RiffFile() => _typeData = GetTypeData();
protected RiffFile()
{
_typeData = GetTypeData();
}
// ---- METHODS (PROTECTED) ------------------------------------------------------------------------------------
@ -38,26 +40,35 @@ namespace Syroot.Worms.Core.Riff
/// <param name="stream">The <see cref="Stream"/> to load the RIFF data from.</param>
protected void LoadRiff(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Read the file header.
if (reader.ReadString(_signature.Length) != _signature)
throw new InvalidDataException("Invalid RIFF file signature.");
int fileSize = reader.ReadInt32();
string fileIdentifier = reader.ReadString(4);
if (fileIdentifier != _typeData.FileIdentifier)
throw new InvalidDataException("Invalid RIFF file identifier.");
// Read the chunks.
while (!reader.EndOfStream)
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
string chunkIdentifier = reader.ReadString(4);
int chunkLength = reader.ReadInt32();
// Invoke a loader method if matching the identifier or skip the chunk.
if (_typeData.ChunkLoaders.TryGetValue(chunkIdentifier, out MethodInfo loader))
loader.Invoke(this, new object[] { reader, chunkLength });
else
reader.Seek(chunkLength);
// Read the file header.
if (reader.ReadString(_signature.Length) != _signature)
{
throw new InvalidDataException("Invalid RIFF file signature.");
}
int fileSize = reader.ReadInt32();
string fileIdentifier = reader.ReadString(4);
if (fileIdentifier != _typeData.FileIdentifier)
{
throw new InvalidDataException("Invalid RIFF file identifier.");
}
// Read the chunks.
while (!reader.EndOfStream)
{
string chunkIdentifier = reader.ReadString(4);
int chunkLength = reader.ReadInt32();
// Invoke a loader method if matching the identifier or skip the chunk.
if (_typeData.ChunkLoaders.TryGetValue(chunkIdentifier, out MethodInfo loader))
{
loader.Invoke(this, new object[] { reader, chunkLength });
}
else
{
reader.Seek(chunkLength);
}
}
}
}
@ -67,25 +78,26 @@ namespace Syroot.Worms.Core.Riff
/// <param name="stream">The <see cref="Stream"/> to save the RIFF data in.</param>
protected void SaveRiff(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Write the header.
writer.Write(_signature, StringCoding.Raw);
uint fileSizeOffset = writer.ReserveOffset();
writer.Write(_typeData.FileIdentifier, StringCoding.Raw);
// Write the chunks.
foreach (KeyValuePair<string, MethodInfo> chunkSaver in _typeData.ChunkSavers)
using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII))
{
writer.Write(chunkSaver.Key, StringCoding.Raw);
uint chunkSizeOffset = writer.ReserveOffset();
// Write the header.
writer.Write(_signature, BinaryStringFormat.NoPrefixOrTermination);
Offset fileSizeOffset = writer.ReserveOffset();
writer.Write(_typeData.FileIdentifier, BinaryStringFormat.NoPrefixOrTermination);
chunkSaver.Value.Invoke(this, new object[] { writer });
// Write the chunks.
foreach (KeyValuePair<string, MethodInfo> chunkSaver in _typeData.ChunkSavers)
{
writer.Write(chunkSaver.Key, BinaryStringFormat.NoPrefixOrTermination);
Offset chunkSizeOffset = writer.ReserveOffset();
writer.SatisfyOffset(chunkSizeOffset, (uint)(writer.Position - chunkSizeOffset - 4));
chunkSaver.Value.Invoke(this, new object[] { writer });
chunkSizeOffset.Satisfy((int)(writer.Position - chunkSizeOffset.Position - 4));
}
fileSizeOffset.Satisfy((int)writer.Position - 8);
}
writer.SatisfyOffset(fileSizeOffset, (uint)(writer.Position - 8));
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
@ -102,6 +114,8 @@ 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>();
@ -109,7 +123,7 @@ namespace Syroot.Worms.Core.Riff
{
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == 2
&& parameters[0].ParameterType == typeof(BinaryStream)
&& parameters[0].ParameterType == typeof(BinaryDataReader)
&& parameters[1].ParameterType == typeof(int))
{
typeData.ChunkLoaders.Add(loadAttribute.Identifier, method);
@ -120,8 +134,11 @@ namespace Syroot.Worms.Core.Riff
if (saveAttribute != null)
{
ParameterInfo[] parameters = method.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(BinaryStream))
if (parameters.Length == 1
&& parameters[0].ParameterType == typeof(BinaryDataWriter))
{
typeData.ChunkSavers.Add(saveAttribute.Identifier, method);
}
continue;
}
}
@ -135,9 +152,9 @@ namespace Syroot.Worms.Core.Riff
private class TypeData
{
internal string FileIdentifier = String.Empty;
internal IDictionary<string, MethodInfo> ChunkLoaders = new Dictionary<string, MethodInfo>();
internal IDictionary<string, MethodInfo> ChunkSavers = new Dictionary<string, MethodInfo>();
internal string FileIdentifier;
internal Dictionary<string, MethodInfo> ChunkLoaders;
internal Dictionary<string, MethodInfo> ChunkSavers;
}
}
}

View File

@ -1,6 +1,6 @@
using System;
namespace Syroot.Worms.Core.Riff
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents the attribute to decorate <see cref="RiffFile"/> inheriting classes to provide their file identifier.
@ -15,7 +15,10 @@ namespace Syroot.Worms.Core.Riff
/// <paramref name="identifier"/>.
/// </summary>
/// <param name="identifier">The file identifier in the RIFF file header which will be validated.</param>
internal RiffFileAttribute(string identifier) => Identifier = identifier;
internal RiffFileAttribute(string identifier)
{
Identifier = identifier;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------

View File

@ -1,115 +1,79 @@
using System;
using System.IO;
namespace Syroot.Worms.Graphics
{
/// <summary>
/// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
/// graphic file formats.
/// S. http://worms2d.info/Team17_compression.
/// </summary>
internal static class Team17Compression
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Returns the data available in <paramref name="bytes"/> in compressed format.
/// </summary>
/// <param name="bytes">The data to compress.</param>
/// <returns>The compressed data.</returns>
internal static byte[] Compress(ReadOnlySpan<byte> bytes)
=> throw new NotImplementedException("Compressing data has not been implemented yet.");
/// <summary>
/// Decompresses the data available in the given <paramref name="stream"/> into the provided
/// <paramref name="buffer"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to read the data from.</param>
/// <param name="buffer">The byte buffer to write the decompressed data to.</param>
internal static void Decompress(Stream stream, Span<byte> buffer)
{
int output = 0; // Offset of next write.
int cmd;
while ((cmd = stream.ReadByte()) != -1)
{
// Read a byte.
if ((cmd & 0x80) == 0)
{
// Command: 1 byte (color)
buffer[output++] = (byte)cmd;
}
else
{
int arg1 = cmd >> 3 & 0b1111; // bits 2-5
int arg2 = stream.ReadByte();
if (arg2 == -1)
return;
// Arg2 = bits 6-16
arg2 = ((cmd << 8) | arg2) & 0x7FF;
if (arg1 == 0)
{
// Command: 0x80 0x00
if (arg2 == 0)
return;
int arg3 = stream.ReadByte();
if (arg3 == -1)
return;
// Command: 3 bytes
output = CopyData(output, arg2, arg3 + 18, buffer);
}
else
{
// Command: 2 bytes
output = CopyData(output, arg2 + 1, arg1 + 2, buffer);
}
}
}
}
// 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, Span<byte> buffer)
{
for (; count > 0; count--)
buffer[offset] = buffer[offset++ - compressedOffset];
return offset;
}
}
}
using System.IO;
namespace Syroot.Worms.Core
{
/// <summary>
/// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
/// graphic file formats.
/// S. http://worms2d.info/Team17_compression.
/// </summary>
internal static class Team17Compression
{
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
/// <summary>
/// Decompresses the data available in the given <paramref name="stream"/> into the provided
/// <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, ref 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)
{
// Read a byte.
if ((cmd & 0x80) == 0)
{
// Command: 1 byte (color)
buffer[output++] = (byte)cmd;
}
else
{
// Arg1 = bits 2-5
int arg1 = (cmd >> 3) & 0xF;
int arg2 = stream.ReadByte();
if (arg2 == -1)
{
return;
}
// Arg2 = bits 6-16
arg2 = ((cmd << 8) | arg2) & 0x7FF;
if (arg1 == 0)
{
// Command: 0x80 0x00
if (arg2 == 0)
{
return;
}
int arg3 = stream.ReadByte();
if (arg3 == -1)
{
return;
}
// Command: 3 bytes
output = CopyData(output, arg2, arg3 + 18, ref buffer);
}
else
{
// Command: 2 bytes
output = CopyData(output, arg2 + 1, arg1 + 2, ref buffer);
}
}
}
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private static int CopyData(int offset, int compressedOffset, int count, ref byte[] buffer)
{
for (; count > 0; count--)
{
buffer[offset] = buffer[offset++ - compressedOffset];
}
return offset;
}
}
}

View File

@ -0,0 +1,230 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2
{
/// <summary>
/// Represents a directory of files stored in a DIR file, mostly used to store graphics files. Due to the nowadays
/// small size of typical directories, the entries and data are loaded directly into a dictionary to profit from
/// 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
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1A524944; // "DIR", 0x1A
private const int _tocSignature = 0x0000000A;
private const int _hashBits = 10;
private const int _hashSize = 1 << _hashBits;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Archive"/> class.
/// </summary>
public Archive()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Archive"/> 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 Archive(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="Archive"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Archive(string fileName)
{
Load(fileName);
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
if (!stream.CanSeek)
{
throw new ArgumentException("Stream requires to be seekable.", nameof(stream));
}
Clear();
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid DIR file signature.");
}
int fileSize = reader.ReadInt32();
int tocOffset = reader.ReadInt32();
// Read the table of contents.
reader.Position = tocOffset;
int tocSignature = reader.ReadInt32();
if (tocSignature != _tocSignature)
{
throw new InvalidDataException("Invalid DIR table of contents signature.");
}
// Generate a data dictionary out of the hash table and file entries.
int[] hashTable = reader.ReadInt32s(_hashSize);
foreach (int entryOffset in hashTable)
{
// If the hash is not 0, it points to a list of files which have a hash being the hash table index.
if (entryOffset > 0)
{
int nextEntryOffset = entryOffset;
do
{
reader.Position = tocOffset + nextEntryOffset;
nextEntryOffset = reader.ReadInt32();
int offset = reader.ReadInt32();
int length = reader.ReadInt32();
string name = reader.ReadString(BinaryStringFormat.ZeroTerminated);
using (reader.TemporarySeek(offset, SeekOrigin.Begin))
{
Add(name, reader.ReadBytes(length));
}
} while (nextEntryOffset != 0);
}
}
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data in.</param>
public void Save(Stream stream)
{
using (BinaryDataWriter writer = new BinaryDataWriter(stream))
{
// Write the header.
writer.Write(_signature);
Offset fileSizeOffset = writer.ReserveOffset();
Offset tocOffset = writer.ReserveOffset();
// Write the data and build the hash table and file entries.
List<HashTableEntry>[] hashTable = new List<HashTableEntry>[_hashSize];
foreach (KeyValuePair<string, byte[]> item in this)
{
HashTableEntry entry = new HashTableEntry()
{
Name = item.Key,
Offset = (int)writer.Position,
Length = item.Value.Length
};
writer.Write(item.Value);
int hash = CalculateHash(item.Key);
if (hashTable[hash] == null)
{
hashTable[hash] = new List<HashTableEntry>();
}
hashTable[hash].Add(entry);
}
// Write the hash table and file entries.
int tocStart = (int)writer.Position;
int fileEntryOffset = sizeof(int) + _hashSize * sizeof(int);
tocOffset.Satisfy(tocStart);
writer.Write(_tocSignature);
for (int i = 0; i < _hashSize; i++)
{
List<HashTableEntry> entries = hashTable[i];
if (entries == null)
{
writer.Write(0);
}
else
{
// Write the entries resolving to the current hash.
writer.Write(fileEntryOffset);
using (writer.TemporarySeek(tocStart + fileEntryOffset, SeekOrigin.Begin))
{
for (int j = 0; j < entries.Count; j++)
{
HashTableEntry entry = entries[j];
Offset nextEntryOffset = writer.ReserveOffset();
writer.Write(entry.Offset);
writer.Write(entry.Length);
writer.Write(entry.Name, BinaryStringFormat.ZeroTerminated);
writer.Align(4);
if (j < entries.Count - 1)
{
nextEntryOffset.Satisfy((int)writer.Position - tocStart);
}
}
fileEntryOffset = (int)writer.Position - tocStart;
}
}
}
fileSizeOffset.Satisfy(tocStart + fileEntryOffset - 1);
}
}
/// <summary>
/// Saves the data in the file with the given <paramref name="fileName"/>.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
private int CalculateHash(string name)
{
int hash = 0;
for (int i = 0; i < name.Length; i++)
{
hash = ((hash << 1) % _hashSize) | (hash >> (_hashBits - 1) & 1);
hash += name[i];
hash %= _hashSize;
}
return hash;
}
// ---- STRUCTURES ---------------------------------------------------------------------------------------------
private struct HashTableEntry
{
internal string Name;
internal int Offset;
internal int Length;
}
}
}

View File

@ -0,0 +1,147 @@
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Armageddon
{
/// <summary>
/// Represents map configuration stored by the land generator in LAND.DAT files.
/// Used by WA and WWP. S. https://worms2d.info/Land_Data_file.
/// </summary>
public class LandData : ILoadableFile
{
// ---- 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 Vector2 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 Vector2[] ObjectLocations { get; set; }
/// <summary>
/// Gets or sets the visual foreground image.
/// </summary>
public Image Foreground { get; set; }
/// <summary>
/// Gets or sets the collision mask of the landscape.
/// </summary>
public Image CollisionMask { get; set; }
/// <summary>
/// Gets or sets the visual background image.
/// </summary>
public Image 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) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid LND file signature.");
}
int fileLength = reader.ReadInt32();
// Read the data.
Size = reader.ReadStruct<Vector2>();
TopBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WaterHeight = reader.ReadInt32();
// Read the possible object coordinate array.
int badObjectLocations = reader.ReadInt32(); // TODO: Check what this is used for.
ObjectLocations = new Vector2[reader.ReadInt32()];
for (int i = 0; i < ObjectLocations.Length; i++)
{
ObjectLocations[i] = reader.ReadStruct<Vector2>();
}
// Read the image data.
Foreground = new Image(stream);
CollisionMask = new Image(stream);
Background = new Image(stream);
// Read the file paths.
LandTexturePath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
WaterDirPath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Armageddon
{
class Mission
{
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Armageddon
{
class MonoMap
{
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Armageddon
{
class Replay
{
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Syroot.Worms.Gen2.Armageddon
{
/// <summary>
/// Represents the configuration of a weapon.
/// </summary>
[DebuggerDisplay("Ammo={Ammunition} Power={Power} Delay={Delay} Prob={Probability}")]
[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 sbyte Ammunition;
/// <summary>
/// The power of this weapon.
/// </summary>
public byte Power;
/// <summary>
/// The number of turns required to be taken by each team before this weapon becomes available. Negative values
/// represent infinity.
/// </summary>
public sbyte Delay;
/// <summary>
/// The percentual chance of this weapon to appear in crates. Has no effect for super weapons.
/// </summary>
public sbyte Probability;
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Armageddon
{
class TeamContainer
{
}
}

View File

@ -0,0 +1,158 @@
using System;
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2
{
/// <summary>
/// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
/// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
/// </summary>
public class Image : ILoadableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1A474D49; // "IMG", 0x1A
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class.
/// </summary>
public Image()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> 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 Image(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="Image"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Image(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets an optional description of the image contents.
/// </summary>
public string Description { get; private set; }
/// <summary>
/// Gets the number of bits required to describe a color per pixel.
/// </summary>
public int BitsPerPixel { get; private set; }
/// <summary>
/// Gets the color palette of the image. The first color must always be black.
/// </summary>
public Color[] Palette { get; private set; }
/// <summary>
/// Gets the size of the image in pixels.
/// </summary>
public Vector2 Size { get; private set; }
/// <summary>
/// Gets the data of the image pixels.
/// </summary>
public byte[] Data { get; private set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid IMG file signature.");
}
int fileSize = reader.ReadInt32();
// Read an optional string describing the image contents or the bits per pixel.
BitsPerPixel = reader.ReadByte();
if (BitsPerPixel == 0)
{
Description = String.Empty;
BitsPerPixel = reader.ReadByte();
}
else if (BitsPerPixel > 32)
{
Description = (char)BitsPerPixel + reader.ReadString(BinaryStringFormat.ZeroTerminated);
BitsPerPixel = reader.ReadByte();
}
// Read image flags describing the format and availability of the following contents.
Flags flags = (Flags)reader.ReadByte();
// Read the image palette if available. The first color of the palette is implicitly black.
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] = new Color(reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
}
}
Size = new Vector2(reader.ReadInt16(), reader.ReadInt16());
// Read the bytes, which might be compressed.
byte[] data = new byte[Size.X * Size.Y * BitsPerPixel / 8];
if (flags.HasFlag(Flags.Compressed))
{
Team17Compression.Decompress(reader.BaseStream, ref data);
}
else
{
data = reader.ReadBytes(data.Length);
}
Data = data;
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
[Flags]
private enum Flags
{
Compressed = 1 << 6,
Palettized = 1 << 7
}
}
}

View File

@ -1,161 +1,194 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using Syroot.BinaryData;
using Syroot.Worms.Core.Riff;
using Syroot.Worms.Graphics;
using Syroot.Worms.IO;
namespace Syroot.Worms
{
/// <summary>
/// Represents a color palette stored in PAL files, following the RIFF format. It is used to index colors in images.
/// Used by WA and WWP. S. http://worms2d.info/Palette_file.
/// </summary>
[RiffFile("PAL ")]
public class RiffPalette : RiffFile, ILoadableFile, ISaveableFile, IPalette
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const short _version = 0x0300;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="RiffPalette"/> class.
/// </summary>
public RiffPalette() { }
/// <summary>
/// Initializes a new instance of the <see cref="RiffPalette"/> 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 RiffPalette(Stream stream) => Load(stream);
/// <summary>
/// Initializes a new instance of the <see cref="RiffPalette"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public RiffPalette(string fileName) => Load(fileName);
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the version of the palette data.
/// </summary>
public int Version { get; set; } = _version;
/// <summary>
/// Gets or sets the <see cref="Color"/> instances stored in this palette.
/// </summary>
public IList<Color> Colors { get; set; } = new List<Color>();
/// <summary>
/// Gets the unknown data in the offl chunk.
/// </summary>
public byte[] OfflData { get; set; } = Array.Empty<byte>();
/// <summary>
/// Gets the unknown data in the tran chunk.
/// </summary>
public byte[] TranData { get; set; } = Array.Empty<byte>();
/// <summary>
/// Gets the unknown data in the unde chunk.
/// </summary>
public byte[] UndeData { get; set; } = Array.Empty<byte>();
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream) => LoadRiff(stream);
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Load(stream);
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
public void Save(Stream stream) => SaveRiff(stream);
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
#pragma warning disable IDE0051 // Remove unused private members
[RiffChunkLoad("data")]
private void LoadDataChunk(BinaryStream reader, int _)
{
// Read the PAL version.
Version = reader.ReadInt16();
if (Version != _version)
throw new InvalidDataException("Unknown PAL version.");
// Read the colors.
short colorCount = reader.ReadInt16();
Colors = new List<Color>();
while (colorCount-- > 0)
{
Colors.Add(Color.FromArgb(reader.Read1Byte(), reader.Read1Byte(), reader.Read1Byte()));
_ = reader.ReadByte(); // Dismiss alpha, as it is not used in WA.
}
}
[RiffChunkLoad("offl")]
private void LoadOfflChunk(BinaryStream reader, int length) => OfflData = reader.ReadBytes(length);
[RiffChunkLoad("tran")]
private void LoadTranChunk(BinaryStream reader, int length) => TranData = reader.ReadBytes(length);
[RiffChunkLoad("unde")]
private void LoadUndeChunk(BinaryStream reader, int length) => UndeData = reader.ReadBytes(length);
[RiffChunkSave("data")]
private void SaveDataChunk(BinaryStream writer)
{
// Write the PAL version.
writer.Write(_version);
// Write the colors.
writer.Write((short)Colors.Count);
foreach (Color color in Colors)
{
writer.Write(color.R);
writer.Write(color.G);
writer.Write(color.B);
writer.Write((byte)0); // Dismiss alpha, as it is not used in WA.
}
}
[RiffChunkSave("offl")]
private void SaveOfflChunk(BinaryStream writer) => writer.Write(OfflData);
[RiffChunkSave("tran")]
private void SaveTranChunk(BinaryStream writer) => writer.Write(TranData);
[RiffChunkSave("unde")]
private void SaveUndeChunk(BinaryStream writer) => writer.Write(UndeData);
#pragma warning restore IDE0051
}
}
using System.IO;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2
{
/// <summary>
/// Represents a color palette stored in PAL files, following the RIFF format. It is used to index colors in images.
/// Used by WA and WWP. S. http://worms2d.info/Palette_file.
/// </summary>
[RiffFile("PAL ")]
public class Palette : RiffFile, ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const short _version = 0x0300;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Palette"/> class.
/// </summary>
public Palette()
{
Version = _version;
}
/// <summary>
/// Initializes a new instance of the <see cref="Palette"/> 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 Palette(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="Palette"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Palette(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the version of the palette data.
/// </summary>
public int Version { get; set; }
/// <summary>
/// Gets the <see cref="Color"/> instances stored in this palette.
/// </summary>
public Color[] Colors { get; set; }
/// <summary>
/// Gets the unknown data in the offl chunk.
/// </summary>
public byte[] OfflData { get; set; }
/// <summary>
/// Gets the unknown data in the tran chunk.
/// </summary>
public byte[] TranData { get; set; }
/// <summary>
/// Gets the unknown data in the unde chunk.
/// </summary>
public byte[] UndeData { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
LoadRiff(stream);
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
public void Save(Stream stream)
{
SaveRiff(stream);
}
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
[RiffChunkLoad("data")]
private void LoadDataChunk(BinaryDataReader reader, int length)
{
// Read the PAL version.
Version = reader.ReadInt16();
if (Version != _version)
{
throw new InvalidDataException("Unknown PAL version.");
}
// Read the colors.
Colors = new Color[reader.ReadInt16()];
for (int i = 0; i < Colors.Length; i++)
{
Colors[i] = new Color(reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
int alpha = reader.ReadByte(); // Dismiss alpha, as it is not used in WA.
}
}
[RiffChunkLoad("offl")]
private void LoadOfflChunk(BinaryDataReader reader, int length)
{
OfflData = reader.ReadBytes(length);
}
[RiffChunkLoad("tran")]
private void LoadTranChunk(BinaryDataReader reader, int length)
{
TranData = reader.ReadBytes(length);
}
[RiffChunkLoad("unde")]
private void LoadUndeChunk(BinaryDataReader reader, int length)
{
UndeData = reader.ReadBytes(length);
}
[RiffChunkSave("data")]
private void SaveDataChunk(BinaryDataWriter writer)
{
// Write the PAL version.
writer.Write(_version);
// Write the colors.
writer.Write((short)Colors.Length);
for (int i = 0; i < Colors.Length; i++)
{
Color color = Colors[i];
writer.Write(color.R);
writer.Write(color.G);
writer.Write(color.B);
writer.Write((byte)0); // Dismiss alpha, as it is not used in WA.
}
}
[RiffChunkSave("offl")]
private void SaveOfflChunk(BinaryDataWriter writer)
{
writer.Write(OfflData);
}
[RiffChunkSave("tran")]
private void SaveTranChunk(BinaryDataWriter writer)
{
writer.Write(TranData);
}
[RiffChunkSave("unde")]
private void SaveUndeChunk(BinaryDataWriter writer)
{
writer.Write(UndeData);
}
}
}

View File

@ -0,0 +1,147 @@
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents map configuration stored by the land generator in LAND.DAT files.
/// Used by W2. S. https://worms2d.info/Land_Data_file.
/// </summary>
public class LandData : ILoadableFile
{
// ---- 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 Vector2 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 an array of coordinates at which objects can be placed.
/// </summary>
public Vector2[] ObjectLocations { get; set; }
/// <summary>
/// Gets or sets the visual foreground image.
/// </summary>
public Image Foreground { get; set; }
/// <summary>
/// Gets or sets the collision mask of the landscape.
/// </summary>
public Image CollisionMask { get; set; }
/// <summary>
/// Gets or sets the visual background image.
/// </summary>
public Image Background { get; set; }
/// <summary>
/// Gets or sets an image of unknown use.
/// </summary>
public Image UnknownImage { 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) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid LND file signature.");
}
int fileLength = reader.ReadInt32();
// Read the data.
Size = reader.ReadStruct<Vector2>();
TopBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
// Read the possible object coordinate array.
ObjectLocations = new Vector2[reader.ReadInt32()];
for (int i = 0; i < ObjectLocations.Length; i++)
{
ObjectLocations[i] = reader.ReadStruct<Vector2>();
}
int unknown = reader.ReadInt32(); // Seems 0.
// Read the image data.
Foreground = new Image(stream);
CollisionMask = new Image(stream);
Background = new Image(stream);
UnknownImage = new Image(stream);
// Read the file paths.
LandTexturePath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
WaterDirPath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Worms2
{
class Mission
{
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Worms2
{
class MonoMap
{
}
}

View File

@ -0,0 +1,225 @@
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents the method to determine the next turn's worm.
/// </summary>
public enum SchemeWormSelect : 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>
/// Represents the weapons in the game.
/// </summary>
public enum SchemeWeapon
{
/// <summary>
/// The Bazooka weapon.
/// </summary>
Bazooka,
/// <summary>
/// The Homing Missile weapon.
/// </summary>
HomingMissile,
/// <summary>
/// The Grenade weapon.
/// </summary>
Grenade,
/// <summary>
/// The Cluster Bomb weapon.
/// </summary>
ClusterBomb,
/// <summary>
/// The Banana Bomb weapon.
/// </summary>
BananaBomb,
/// <summary>
/// The Holy Hand Grenade weapon.
/// </summary>
HolyHandGrenade,
/// <summary>
/// The Homing Cluster Bomb weapon.
/// </summary>
HomingClusterBomb,
/// <summary>
/// The Petrol Bomb weapon.
/// </summary>
PetrolBomb,
/// <summary>
/// The Shotgun weapon.
/// </summary>
Shotgun,
/// <summary>
/// The Handgun weapon.
/// </summary>
Handgun,
/// <summary>
/// The Uzi weapon.
/// </summary>
Uzi,
/// <summary>
/// The Minigun weapon.
/// </summary>
Minigun,
/// <summary>
/// The Fire Punch weapon.
/// </summary>
FirePunch,
/// <summary>
/// The Dragon Ball weapon.
/// </summary>
DragonBall,
/// <summary>
/// The Kamikaze weapon.
/// </summary>
Kamikaze,
/// <summary>
/// The Dynamite weapon.
/// </summary>
Dynamite,
/// <summary>
/// The Mine weapon.
/// </summary>
Mine,
/// <summary>
/// The Ming Vase weapon.
/// </summary>
MingVase,
/// <summary>
/// The Air Strike weapon.
/// </summary>
AirStrike,
/// <summary>
/// The Homing Air Strike weapon.
/// </summary>
HomingAirStrike,
/// <summary>
/// The Napalm Strike weapon.
/// </summary>
NapalmStrike,
/// <summary>
/// The Mail Strike weapon.
/// </summary>
MailStrike,
/// <summary>
/// The Girder weapon.
/// </summary>
Girder,
/// <summary>
/// The Pneumatic Drill weapon.
/// </summary>
PneumaticDrill,
/// <summary>
/// The Baseball Bat weapon.
/// </summary>
BaseballBat,
/// <summary>
/// The Prod weapon.
/// </summary>
Prod,
/// <summary>
/// The Teleport weapon.
/// </summary>
Teleport,
/// <summary>
/// The Ninja Rope weapon.
/// </summary>
NinjaRope,
/// <summary>
/// The Bungee weapon.
/// </summary>
Bungee,
/// <summary>
/// The Parachute weapon.
/// </summary>
Parachute,
/// <summary>
/// The Sheep weapon.
/// </summary>
Sheep,
/// <summary>
/// The Mad Cow weapon.
/// </summary>
MadCow,
/// <summary>
/// The Old Woman weapon.
/// </summary>
OldWoman,
/// <summary>
/// The Mortar weapon.
/// </summary>
Mortar,
/// <summary>
/// The Blow Torch weapon.
/// </summary>
BlowTorch,
/// <summary>
/// The Homing Pigeon weapon.
/// </summary>
HomingPigeon,
/// <summary>
/// The Super Sheep weapon.
/// </summary>
SuperSheep,
/// <summary>
/// The Super Banana Bomb weapon.
/// </summary>
SuperBananaBomb
}
}

View File

@ -1,9 +1,9 @@
using System.IO;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
using Syroot.IO;
using Syroot.Worms.Core;
namespace Syroot.Worms.Worms2
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents scheme options stored in an OPT file which contains game settings.
@ -20,20 +20,28 @@ namespace Syroot.Worms.Worms2
/// <summary>
/// Initializs a new instance of the <see cref="SchemeOptions"/> class.
/// </summary>
public SchemeOptions() { }
public SchemeOptions()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SchemeOptions"/> 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 SchemeOptions(Stream stream) => Load(stream);
public SchemeOptions(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="SchemeOptions"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public SchemeOptions(string fileName) => Load(fileName);
public SchemeOptions(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
@ -52,13 +60,13 @@ namespace Syroot.Worms.Worms2
/// while standing on land.
/// </summary>
public int RetreatTime { get; set; }
/// <summary>
/// Gets or sets the time in seconds available for a worm to retreat after using a weapon which ends the turn
/// while on a rope.
/// </summary>
public int RetreatTimeRope { get; set; }
/// <summary>
/// Gets or sets the maximum number of objects (mines or oil drums) on the map.
/// </summary>
@ -68,7 +76,7 @@ namespace Syroot.Worms.Worms2
/// Gets or sets the number of seconds a mine requires to explode. -1 is random between 0-3 seconds.
/// </summary>
public int MineDelay { get; set; }
/// <summary>
/// Gets or sets a value indicating whether mines can refuse to explode after their count down.
/// </summary>
@ -78,7 +86,7 @@ namespace Syroot.Worms.Worms2
/// Gets or sets the influence power of the wind affecting weapons in percent.
/// </summary>
public int WindPower { get; set; }
/// <summary>
/// Gets or sets the friction deaccelerating objects touching solid ground between 0-5. 0 is default, 1 is low
/// friction, 5 is high friction.
@ -94,7 +102,7 @@ namespace Syroot.Worms.Worms2
/// Gets or sets the number of damage in health points which has to be done to replay the turn.
/// </summary>
public int ReplayRequiredDamage { get; set; }
/// <summary>
/// Gets or sets a value indicating whether significant turns will be replayed in offline games.
/// </summary>
@ -109,13 +117,13 @@ namespace Syroot.Worms.Worms2
/// Gets or sets the number of rope swings allowed with one Ninja Rope.
/// </summary>
public int RopeSwings { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the total round time until sudden death will be displayed in the
/// turn timer.
/// </summary>
public bool ShowRoundTime { get; set; }
/// <summary>
/// Gets or sets the amount in pixels which the water will rise between turns after Sudden Death was triggered.
/// </summary>
@ -140,14 +148,14 @@ namespace Syroot.Worms.Worms2
/// <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 SchemeWormSelect 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
/// open.
/// </summary>
public bool ExtendedChatControls { get; set; }
/// <summary>
/// Gets or sets the delay in seconds between each team's turn to allow relaxed switching of seats.
/// </summary>
@ -158,7 +166,7 @@ namespace Syroot.Worms.Worms2
/// round.
/// </summary>
public bool EnableStockpiling { get; set; }
/// <summary>
/// Gets or sets the percentual probability of a weapon or health crate to drop between turns.
/// </summary>
@ -168,7 +176,7 @@ namespace Syroot.Worms.Worms2
/// Gets or sets the percentual probability of a crate dropping closer to weak teams.
/// </summary>
public int CrateIntelligence { get; set; }
/// <summary>
/// Gets or sets the amount of health included in a health crate added to the collecting worm's energy.
/// </summary>
@ -204,110 +212,132 @@ namespace Syroot.Worms.Worms2
/// Gets or sets a value indicating whether oil drums will be placed instead of mines.
/// </summary>
public bool UseOilDrums { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadString(_signature.Length) != _signature)
{
throw new InvalidDataException("Invalid OPT file signature.");
}
// Read the header.
if (reader.ReadString(_signature.Length) != _signature)
throw new InvalidDataException("Invalid OPT file signature.");
// Read the options.
RoundTime = reader.ReadInt32();
TurnTime = reader.ReadInt32();
RetreatTime = reader.ReadInt32();
RetreatTimeRope = reader.ReadInt32();
ObjectCount = reader.ReadInt32();
MineDelay = reader.ReadInt32();
DudMines = reader.ReadBoolean(BooleanCoding.Dword);
WindPower = reader.ReadInt32();
Friction = reader.ReadInt32();
ReplayRequiredKills = reader.ReadInt32();
ReplayRequiredDamage = reader.ReadInt32();
AutomaticReplays = reader.ReadBoolean(BooleanCoding.Dword);
FallDamage = reader.ReadInt32();
RopeSwings = reader.ReadInt32();
ShowRoundTime = reader.ReadBoolean(BooleanCoding.Dword);
WaterRiseRate = reader.ReadInt32();
SuddenDeathHealthDrop = reader.ReadBoolean(BooleanCoding.Dword);
IndestructibleBorder = reader.ReadBoolean(BooleanCoding.Dword);
RestrictGirders = reader.ReadBoolean(BooleanCoding.Dword);
WormSelectMode = reader.ReadEnum<WormSelect>(true);
ExtendedChatControls = reader.ReadBoolean(BooleanCoding.Dword);
HotSeatDelay = reader.ReadInt32();
EnableStockpiling = reader.ReadBoolean(BooleanCoding.Dword);
CrateProbability = reader.ReadInt32();
CrateIntelligence = reader.ReadInt32();
HealthCrateEnergy = reader.ReadInt32();
BoobyTraps = reader.ReadBoolean(BooleanCoding.Dword);
EnableSuperWeapons = reader.ReadBoolean(BooleanCoding.Dword);
WormEnergy = reader.ReadInt32();
ArtilleryMode = reader.ReadBoolean(BooleanCoding.Dword);
SuddenDeathDisableWormSelect = reader.ReadBoolean(BooleanCoding.Dword);
// The following option does not exist in all schemes.
if (!reader.EndOfStream)
UseOilDrums = reader.ReadBoolean(BooleanCoding.Dword);
// Read the options.
RoundTime = reader.ReadInt32();
TurnTime = reader.ReadInt32();
RetreatTime = reader.ReadInt32();
RetreatTimeRope = reader.ReadInt32();
ObjectCount = reader.ReadInt32();
MineDelay = reader.ReadInt32();
DudMines = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WindPower = reader.ReadInt32();
Friction = reader.ReadInt32();
ReplayRequiredKills = reader.ReadInt32();
ReplayRequiredDamage = reader.ReadInt32();
AutomaticReplays = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
FallDamage = reader.ReadInt32();
RopeSwings = reader.ReadInt32();
ShowRoundTime = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WaterRiseRate = reader.ReadInt32();
SuddenDeathHealthDrop = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
IndestructibleBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
RestrictGirders = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WormSelectMode = reader.ReadEnum<SchemeWormSelect>(true);
ExtendedChatControls = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
HotSeatDelay = reader.ReadInt32();
EnableStockpiling = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
CrateProbability = reader.ReadInt32();
CrateIntelligence = reader.ReadInt32();
HealthCrateEnergy = reader.ReadInt32();
BoobyTraps = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
EnableSuperWeapons = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WormEnergy = reader.ReadInt32();
ArtilleryMode = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
SuddenDeathDisableWormSelect = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
// The following option does not exist in all schemes.
if (!reader.EndOfStream)
{
UseOilDrums = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
}
}
}
/// <inheritdoc/>
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Load(stream);
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
/// <inheritdoc/>
/// <summary>
/// Saves the data into the given <paramref name="stream"/> with the specified <paramref name="format"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
public void Save(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII))
{
// Write the header.
writer.Write(_signature, BinaryStringFormat.NoPrefixOrTermination);
// Write the header.
writer.Write(_signature, StringCoding.Raw);
// Write the options.
writer.Write(RoundTime);
writer.Write(TurnTime);
writer.Write(RetreatTime);
writer.Write(RetreatTimeRope);
writer.Write(ObjectCount);
writer.Write(MineDelay);
writer.Write(DudMines, BooleanCoding.Dword);
writer.Write(WindPower);
writer.Write(Friction);
writer.Write(ReplayRequiredKills);
writer.Write(ReplayRequiredDamage);
writer.Write(AutomaticReplays, BooleanCoding.Dword);
writer.Write(FallDamage);
writer.Write(RopeSwings);
writer.Write(ShowRoundTime, BooleanCoding.Dword);
writer.Write(WaterRiseRate);
writer.Write(SuddenDeathHealthDrop, BooleanCoding.Dword);
writer.Write(IndestructibleBorder, BooleanCoding.Dword);
writer.Write(RestrictGirders, BooleanCoding.Dword);
writer.WriteEnum(WormSelectMode, true);
writer.Write(ExtendedChatControls, BooleanCoding.Dword);
writer.Write(HotSeatDelay);
writer.Write(EnableStockpiling, BooleanCoding.Dword);
writer.Write(CrateProbability);
writer.Write(CrateIntelligence);
writer.Write(HealthCrateEnergy);
writer.Write(BoobyTraps, BooleanCoding.Dword);
writer.Write(EnableSuperWeapons, BooleanCoding.Dword);
writer.Write(WormEnergy);
writer.Write(ArtilleryMode, BooleanCoding.Dword);
writer.Write(SuddenDeathDisableWormSelect, BooleanCoding.Dword);
writer.Write(UseOilDrums, BooleanCoding.Dword);
// Write the options.
writer.Write(RoundTime);
writer.Write(TurnTime);
writer.Write(RetreatTime);
writer.Write(RetreatTimeRope);
writer.Write(ObjectCount);
writer.Write(MineDelay);
writer.Write(DudMines, BinaryBooleanFormat.NonZeroDword);
writer.Write(WindPower);
writer.Write(Friction);
writer.Write(ReplayRequiredKills);
writer.Write(ReplayRequiredDamage);
writer.Write(AutomaticReplays, BinaryBooleanFormat.NonZeroDword);
writer.Write(FallDamage);
writer.Write(RopeSwings);
writer.Write(ShowRoundTime, BinaryBooleanFormat.NonZeroDword);
writer.Write(WaterRiseRate);
writer.Write(SuddenDeathHealthDrop, BinaryBooleanFormat.NonZeroDword);
writer.Write(IndestructibleBorder, BinaryBooleanFormat.NonZeroDword);
writer.Write(RestrictGirders, BinaryBooleanFormat.NonZeroDword);
writer.Write(WormSelectMode, true);
writer.Write(ExtendedChatControls, BinaryBooleanFormat.NonZeroDword);
writer.Write(HotSeatDelay);
writer.Write(EnableStockpiling, BinaryBooleanFormat.NonZeroDword);
writer.Write(CrateProbability);
writer.Write(CrateIntelligence);
writer.Write(HealthCrateEnergy);
writer.Write(BoobyTraps, BinaryBooleanFormat.NonZeroDword);
writer.Write(EnableSuperWeapons, BinaryBooleanFormat.NonZeroDword);
writer.Write(WormEnergy);
writer.Write(ArtilleryMode, BinaryBooleanFormat.NonZeroDword);
writer.Write(SuddenDeathDisableWormSelect, BinaryBooleanFormat.NonZeroDword);
writer.Write(UseOilDrums, BinaryBooleanFormat.NonZeroDword);
}
}
/// <inheritdoc/>
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
}
}

View File

@ -0,0 +1,182 @@
using System.Runtime.InteropServices;
namespace Syroot.Worms.Gen2.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 BlastPower;
/// <summary>
/// The offset to the bottom of an explosion, measured in percent.
/// </summary>
public int BlastBias;
/// <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;
}
}

View File

@ -0,0 +1,127 @@
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// 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
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _trashLength = 16;
private const string _signature = "WEPFILE"; // Zero-terminated.
private const int _weaponCount = 38;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="SchemeWeapons"/> class.
/// </summary>
public SchemeWeapons()
{
Weapons = new SchemeWeaponSetting[_weaponCount];
}
/// <summary>
/// Initializes a new instance of the <see cref="SchemeWeapons"/> 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 SchemeWeapons(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="SchemeWeapons"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public SchemeWeapons(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets the array of <see cref="SchemeWeaponSetting"/> instances, each mapping to one weapon at the index of
/// the <see cref="SchemeWeapon"/> enumeration.
/// </summary>
public SchemeWeaponSetting[] Weapons { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
reader.Seek(_trashLength);
if (reader.ReadString(BinaryStringFormat.ZeroTerminated) != _signature)
{
throw new InvalidDataException("Invalid WEP file signature.");
}
// Read the weapon settings.
Weapons = new SchemeWeaponSetting[_weaponCount];
for (int i = 0; i < _weaponCount; i++)
{
Weapons[i] = reader.ReadStruct<SchemeWeaponSetting>();
}
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
/// <summary>
/// Saves the data into the given <paramref name="stream"/> with the specified <paramref name="format"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
public void Save(Stream stream)
{
using (BinaryDataWriter writer = new BinaryDataWriter(stream, Encoding.ASCII))
{
// Write the header.
writer.Write(new byte[_trashLength]);
writer.Write(_signature, BinaryStringFormat.ZeroTerminated);
// Write the weapon settings.
foreach (SchemeWeaponSetting weapon in Weapons)
{
writer.Write(weapon);
}
}
}
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
{
Save(stream);
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Syroot.Worms.Gen2.Worms2
{
class TeamContainer
{
}
}

View File

@ -0,0 +1,41 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>.NET library to load and modify file formats of Team17 Worms games.</Description>
<Copyright>(c) Syroot, licensed under MIT</Copyright>
<AssemblyName>Syroot.Worms</AssemblyName>
<AssemblyTitle>Worms</AssemblyTitle>
<Authors>Syroot</Authors>
<VersionPrefix>0.1.0</VersionPrefix>
<PackageId>Syroot.Worms</PackageId>
<PackageTags>worms;team17</PackageTags>
<PackageReleaseNotes>Initial alpha release.</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/Syroot/Worms/master/res/Logo.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/Syroot/Worms</PackageProjectUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/Syroot/Worms/master/LICENSE</PackageLicenseUrl>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Syroot/Worms</RepositoryUrl>
<TargetFrameworks>net46;netstandard1.6</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Syroot.IO.BinaryData" Version="1.2.2" />
<PackageReference Include="Syroot.Maths" Version="1.3.1" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net45'">
<Reference Include="System" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<DebugType>portable</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>none</DebugType>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
</Project>

View File

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Metadata -->
<PropertyGroup>
<Authors>Syroot</Authors>
<Copyright>(c) Syroot, licensed under MIT</Copyright>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://gitlab.com/Syroot/Worms</RepositoryUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://gitlab.com/Syroot/Worms</PackageProjectUrl>
<PackageTags>team17;worms</PackageTags>
<RepositoryUrl>https://gitlab.com/Syroot/Worms</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)..\res\icon.png" Pack="true" PackagePath="" />
</ItemGroup>
<!-- Compilation -->
<PropertyGroup>
<IncludeSymbols>true</IncludeSymbols>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<TargetFrameworks>netstandard2.0;netstandard2.1</TargetFrameworks>
</PropertyGroup>
<!-- Output -->
<PropertyGroup>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<OutputPath>$(MSBuildThisFileDirectory)..\bin\$(MSBuildProjectName)</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'">
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
</Project>

View File

@ -1,38 +0,0 @@
using System;
using System.IO;
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
internal class ActionConverter : IBinaryConverter
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public object? Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
ByteConverter byteConverter)
{
ExplosionAction explosionAction = instance switch
{
LauncherStyle launcherStyle => launcherStyle.ExplosionAction,
ClusterTarget clusterTarget => clusterTarget.ExplosionAction,
_ => throw new NotImplementedException()
};
return explosionAction switch
{
ExplosionAction.Home => stream.ReadObject<HomeAction>(),
ExplosionAction.Bounce => stream.ReadObject<BounceAction>(),
ExplosionAction.Roam => stream.ReadObject<RoamAction>(),
ExplosionAction.Dig => stream.ReadObject<DigAction>(),
_ => null
};
}
/// <inheritdoc/>
public void Write(Stream stream, object instance, BinaryMemberAttribute memberAttribute, object value,
ByteConverter byteConverter)
{
stream.WriteObject(value);
}
}
}

View File

@ -1,29 +0,0 @@
namespace Syroot.Worms.Armageddon.ProjectX
{
public class BounceAction : IAction
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public CollisionFlags Collisions { get; set; }
public int Bounciness { get; set; }
public int Acceleration { get; set; }
public int Sound { get; set; }
public int Unknown1 { get; set; }
public int Unknown2 { get; set; }
public int ExplosionBias { get; set; }
public int ExplosionPower { get; set; }
public int ExplosionDamage { get; set; }
public int DamageRandomness { get; set; }
public int BounceCount { get; set; }
}
}

View File

@ -1,21 +0,0 @@
namespace Syroot.Worms.Armageddon.ProjectX
{
public class DigAction : IAction
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public int Unknown1 { get; set; }
public int Unknown2 { get; set; }
public int DiggingSound { get; set; }
public int SpriteJumping { get; set; }
public int Sprite1 { get; set; }
public int Sprite2 { get; set; }
public int Sprite3 { get; set; }
}
}

View File

@ -1,25 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class HomeAction : IAction
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Offset = 4)]
public Sprite Sprite { get; set; }
public HomeStyle HomeStyle { get; set; }
public int Delay { get; set; }
public int Duration { get; set; }
}
public enum HomeStyle
{
None,
Straight,
Intelligent
}
}

View File

@ -1,4 +0,0 @@
namespace Syroot.Worms.Armageddon.ProjectX
{
public interface IAction { }
}

View File

@ -1,46 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class RoamAction : IAction
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public CollisionFlags RoamCollisions { get; set; }
public CollisionFlags ExplosionCollisions { get; set; }
public int WalkSpeed { get; set; }
public int Unknown { get; set; }
public int JumpAngleEdge { get; set; }
public int JumpVelocityEdge { get; set; }
public int JumpSoundEdge { get; set; }
public int JumpAngle { get; set; }
public int JumpVelocity { get; set; }
public int JumpSound { get; set; }
public int TerrainOffset { get; set; }
[BinaryMember(BooleanCoding = BooleanCoding.Dword)]
public bool Fart { get; set; }
public int DiseasePower { get; set; }
public int SpriteFarting { get; set; }
public int SpriteFlying { get; set; }
public int SpriteFlying2 { get; set; }
public int SpriteTakeOff { get; set; }
public int SpriteDuringFlight { get; set; }
}
}

View File

@ -1,42 +0,0 @@
using System;
namespace Syroot.Worms.Armageddon.ProjectX
{
[Flags]
public enum CollisionFlags : int
{
None,
Unused0 = 1 << 0,
Terrain = 1 << 1,
WormsOnTerrain = 1 << 2,
WormsUsingWeapon = 1 << 3,
WormsInAir = 1 << 4,
WormsOnRope = 1 << 5,
FrozenWorms = 1 << 6,
Unused7 = 1 << 7,
KamikazeBomber = 1 << 8,
GasCanisters = 1 << 9,
Mines = 1 << 10,
Crates = 1 << 11,
DonorCards = 1 << 12,
Gravestones = 1 << 13,
Unused14 = 1 << 14,
OtherWeapons = 1 << 15,
LongbowArrows = 1 << 16,
OilDrums = 1 << 17,
Unused18 = 1 << 18,
Unused19 = 1 << 19,
Unused20 = 1 << 20,
Unused21 = 1 << 21,
Skimming = 1 << 22,
Unused23 = 1 << 23,
Unused24 = 1 << 24,
Unused25 = 1 << 25,
Unused26 = 1 << 26,
Unused27 = 1 << 27,
Unused28 = 1 << 28,
Unused29 = 1 << 29,
Unknown = 1 << 30,
Unused31 = 1 << 31
}
}

View File

@ -1,298 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon.ProjectX
{
/// <summary>
/// Represents a library stored in a PXL file which contains reusable weapons, files and scripts.
/// Used by WA PX. S. https://worms2d.info/Project_X/Library_file.
/// </summary>
public class Library : IList<LibraryItem>, ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1BCD0102;
private const byte _version = 0x00;
// ---- FIELDS -------------------------------------------------------------------------------------------------
private readonly List<LibraryItem> _list = new List<LibraryItem>();
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> class.
/// </summary>
public Library() { }
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> 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 Library(Stream stream) => Load(stream);
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Library(string fileName) => Load(fileName);
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <inheritdoc/>
public int Count => _list.Count;
/// <summary>
/// Gets or sets the ProjectX library version.
/// </summary>
public byte Version { get; set; }
/// <inheritdoc/>
bool ICollection<LibraryItem>.IsReadOnly => false;
// ---- OPERATORS ----------------------------------------------------------------------------------------------
/// <summary>
/// Gets the library entries matching the given key.
/// </summary>
/// <param name="key">The key of the entries to match.</param>
/// <returns>All matching entries.</returns>
public IEnumerable<LibraryItem> this[string key] => this.Where(x => x.Key == key);
/// <inheritdoc/>
public LibraryItem this[int index]
{
get => _list[index];
set => _list[index] = value;
}
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public void Add(LibraryItem item) => _list.Add(item);
/// <inheritdoc/>
public void Clear() => _list.Clear();
/// <inheritdoc/>
public bool Contains(LibraryItem item) => _list.Contains(item);
/// <inheritdoc/>
public void CopyTo(LibraryItem[] array, int arrayIndex) => _list.CopyTo(array, arrayIndex);
/// <inheritdoc/>
public IEnumerator<LibraryItem> GetEnumerator() => _list.GetEnumerator();
/// <summary>
/// Gets all attached files.
/// </summary>
/// <returns>The enumeration of attached files.</returns>
public IEnumerable<byte[]> GetFiles()
=> this.Where(x => x.Type == LibraryItemType.File).Select(x => (byte[])x.Value);
/// <summary>
/// Gets all attached scripts.
/// </summary>
/// <returns>The enumeration of attached scripts.</returns>
public IEnumerable<string> GetScripts()
=> this.Where(x => x.Type == LibraryItemType.Script).Select(x => (string)x.Value);
/// <summary>
/// Gets all attached weapons.
/// </summary>
/// <returns>The enumeration of attached weapons.</returns>
public IEnumerable<Weapon> GetWeapons()
=> this.Where(x => x.Type == LibraryItemType.Weapon).Select(x => (Weapon)x.Value);
/// <inheritdoc/>
public int IndexOf(LibraryItem item) => _list.IndexOf(item);
/// <inheritdoc/>
public void Insert(int index, LibraryItem item) => _list.Insert(index, item);
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Read the header.
if (reader.ReadInt32() != _signature)
throw new InvalidDataException("Invalid PXL file signature.");
Version = reader.Read1Byte();
if (Version != _version)
throw new InvalidDataException("Invalid PXL file version.");
// Read the items.
_list.Clear();
int itemCount = reader.ReadInt32();
for (int i = 0; i < itemCount; i++)
{
LibraryItemType type = reader.ReadEnum<LibraryItemType>(true);
string name = reader.ReadString(StringCoding.Int32CharCount);
switch (type)
{
case LibraryItemType.File:
_list.Add(new LibraryItem(name, reader.ReadBytes(reader.ReadInt32())));
break;
case LibraryItemType.Script:
_list.Add(new LibraryItem(name, reader.ReadString(StringCoding.Int32CharCount)));
break;
case LibraryItemType.Weapon:
_list.Add(new LibraryItem(name, reader.Load<Weapon>()));
break;
}
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Load(stream);
}
/// <inheritdoc/>
public bool Remove(LibraryItem item) => _list.Remove(item);
/// <inheritdoc/>
public void RemoveAt(int index) => _list.RemoveAt(index);
/// <summary>
/// Saves the data into the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to save the data to.</param>
public void Save(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Write the header.
writer.Write(_signature);
writer.Write(Version);
// Write the items.
writer.Write(Count);
foreach (LibraryItem item in _list)
{
writer.WriteEnum(item.Type, true);
writer.Write(item.Key, StringCoding.Int32CharCount);
switch (item.Type)
{
case LibraryItemType.File:
byte[] value = (byte[])item.Value;
writer.Write(value.Length);
writer.Write(value);
break;
case LibraryItemType.Script:
writer.Write((string)item.Value, StringCoding.Int32CharCount);
break;
case LibraryItemType.Weapon:
writer.Save((Weapon)item.Value);
break;
}
}
}
/// <summary>
/// Saves the data in the given file.
/// </summary>
/// <param name="fileName">The name of the file to save the data in.</param>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
// ---- METHODS ------------------------------------------------------------------------------------------------
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_list).GetEnumerator();
}
}
/// <summary>
/// Represents an entry in a Project X library.
/// </summary>
[DebuggerDisplay("LibraryItem Key={Key} Type={Type}")]
public class LibraryItem
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private object _value = null!;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="LibraryItem"/> class with the given <paramref name="key"/> and
/// <paramref name="value"/>.
/// </summary>
/// <param name="key">The key under which the item will be stored.</param>
/// <param name="value">The value which will be stored under the key. The type is inferred from this.</param>
public LibraryItem(string key, object value)
{
Key = key;
Value = value;
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the name under which this item is stored.
/// </summary>
public string Key { get; set; } = String.Empty;
/// <summary>
/// Gets the type of the item.
/// </summary>
public LibraryItemType Type { get; private set; }
/// <summary>
/// Gets or sets the data of the item.
/// </summary>
public object Value
{
get => _value;
set
{
// Validate the type.
if (value.GetType() == typeof(byte[]))
Type = LibraryItemType.File;
else if (value.GetType() == typeof(string))
Type = LibraryItemType.Script;
else if (value.GetType() == typeof(Weapon))
Type = LibraryItemType.Weapon;
else
throw new ArgumentException("Invalid LibraryItemType.", nameof(value));
_value = value;
}
}
}
/// <summary>
/// Represents the possible type of a library entry.
/// </summary>
public enum LibraryItemType : byte
{
/// <summary>The entry is a raw file in form of a byte array.</summary>
File = 2,
/// <summary>The entry is a script in form of a string.</summary>
Script = 4,
/// <summary>The entry is a weapon in form of a <see cref="Weapon"/> instance.</summary>
Weapon = 8
}
}

View File

@ -1,17 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public struct Mine
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Sensitivity;
[BinaryMember(Order = 2)] public int TimeBeforeOn;
[BinaryMember(Order = 3)] public CollisionFlags SensitiveTo;
[BinaryMember(Order = 4)] public int FuseTime;
[BinaryMember(Order = 5)] public int ExplosionBias;
[BinaryMember(Order = 6)] public int ExplosionPower;
[BinaryMember(Order = 7)] public int MaxDamage;
}
}

View File

@ -1,199 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon.ProjectX
{
/// <summary>
/// Represents a scheme stored in a PXS file which contains game settings, weapon tables, required libraries and
/// attached files and scripts.
/// Used by WA PX. S. https://worms2d.info/Project_X/Scheme_file.
/// </summary>
public class Scheme : ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const string _signature = "SCHM OF WAPX";
private const int _weaponsPerTable = 71;
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> class.
/// </summary>
public Scheme() { }
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> 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 Scheme(Stream stream) => Load(stream);
/// <summary>
/// Initializes a new instance of the <see cref="Scheme"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public Scheme(string fileName) => Load(fileName);
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
public int Version { get; set; }
public SchemeFlags Flags { get; set; }
public IList<Weapon[]> WeaponTables { get; set; } = new List<Weapon[]>();
public IDictionary<string, byte[]> Files { get; set; } = new Dictionary<string, byte[]>();
public IDictionary<string, string> Scripts { get; set; } = new Dictionary<string, string>();
public IList<string> Libraries { get; set; } = new List<string>();
public string GameSchemeName { get; set; } = String.Empty;
public Armageddon.Scheme? GameScheme { 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.ReadString(_signature.Length) != _signature)
throw new InvalidDataException("Invalid PXS file signature.");
Version = reader.ReadInt32();
// Read the scheme flags.
Flags = reader.ReadStruct<SchemeFlags>();
// Read the weapon tables.
int weaponTableCount = reader.ReadInt32();
WeaponTables = new List<Weapon[]>(weaponTableCount);
for (int i = 0; i < weaponTableCount; i++)
{
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));
// Read attached files.
int filesCount = reader.ReadInt32();
Files = new Dictionary<string, byte[]>(filesCount);
for (int i = 0; i < filesCount; i++)
{
string name = reader.ReadString(StringCoding.Int32CharCount);
int length = reader.ReadInt32();
Files.Add(name, reader.ReadBytes(length));
}
// Read attached scripts.
int scriptsCount = reader.ReadInt32();
Scripts = new Dictionary<string, string>(scriptsCount);
for (int i = 0; i < scriptsCount; i++)
Scripts.Add(reader.ReadString(StringCoding.Int32CharCount),
reader.ReadString(StringCoding.Int32CharCount));
// Read required libraries.
int librariesCount = reader.ReadInt32();
Libraries = new List<string>(reader.ReadStrings(librariesCount, StringCoding.Int32CharCount));
// Read a possibly attached scheme file.
if (reader.ReadBoolean())
{
byte[] schemeData = reader.ReadBytes(reader.ReadInt32());
using MemoryStream schemeStream = new MemoryStream(schemeData);
GameScheme = schemeStream.Load<Armageddon.Scheme>();
GameSchemeName = reader.ReadString(StringCoding.Int32CharCount);
}
else
{
GameScheme = null;
GameSchemeName = String.Empty;
}
}
/// <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, StringCoding.Raw);
writer.Write(Version);
// Write the scheme flags.
writer.WriteStruct(Flags);
// Write the weapon tables.
writer.Write(WeaponTables.Count);
foreach (Weapon[] weaponTable in WeaponTables)
for (int i = 0; i < _weaponsPerTable; i++)
writer.Save(weaponTable[i]);
// Write a placeholder array.
writer.Write(0);
// Write attached files.
writer.Write(Files.Count);
foreach (KeyValuePair<string, byte[]> file in Files)
{
writer.Write(file.Key, StringCoding.Int32CharCount);
writer.Write(file.Value.Length);
writer.Write(file.Value);
}
// Write attached scripts.
writer.Write(Scripts.Count);
foreach (KeyValuePair<string, string> script in Scripts)
{
writer.Write(script.Key, StringCoding.Int32CharCount);
writer.Write(script.Value, StringCoding.Int32CharCount);
}
// Write required libraries.
writer.Write(Libraries.Count);
writer.Write(Libraries, StringCoding.Int32CharCount);
// Write a possibly attached scheme file.
if (GameScheme != null)
{
writer.Write(true);
using MemoryStream schemeStream = new MemoryStream();
GameScheme.Save(schemeStream);
writer.Write((int)schemeStream.Position);
schemeStream.Position = 0;
schemeStream.CopyTo(writer);
writer.Write(GameSchemeName, StringCoding.Int32CharCount);
}
else
{
writer.Write(false);
}
}
/// <inheritdoc/>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
}
}

View File

@ -1,29 +0,0 @@
using System.Runtime.InteropServices;
namespace Syroot.Worms.Armageddon.ProjectX
{
/// <summary>
/// Represents global Project X scheme flags affecting general game behavior.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct SchemeFlags
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
public bool CyclicMaps;
public bool UnderwaterJetpack;
public bool UnderwaterRope;
public bool Unused1;
public bool Unused2;
public bool Unused3;
public bool Unused4;
public bool Unused5;
public bool Unused6;
public bool Unused7;
public bool Unused8;
public bool ShotDoesntEndTurn;
public bool LoseControlDoesntEndTurn;
public bool FiringPausesTimer;
public bool EnableSchemePowers;
}
}

View File

@ -1,15 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public struct Sound
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public ushort SoundIndex;
[BinaryMember(Order = 2, BooleanCoding = BooleanCoding.Word)] public bool RepeatSound;
[BinaryMember(Order = 3, BooleanCoding = BooleanCoding.Dword)] public bool UseExplosionSound;
[BinaryMember(Order = 4)] public int SoundBeforeExplosion;
[BinaryMember(Order = 5)] public int DelayBeforeExplosion;
}
}

View File

@ -1,27 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public struct Sprite
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int SpriteNumber;
[BinaryMember(Order = 2)] public SpriteAnimationType AnimationType;
[BinaryMember(Order = 3)] public int TrailSprite;
[BinaryMember(Order = 4)] public int TrailAmount;
[BinaryMember(Order = 5)] public int TrailVanishSpeed;
[BinaryMember(Order = 6)] public int Unknown;
}
public enum SpriteAnimationType : int
{
HorizontalVelocity,
Cycle,
TrackMovement,
TrackSpeed,
SlowCycle,
FasterCycle,
FastCycle
}
}

View File

@ -1,30 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class AirstrikeStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int PlaneSprite;
[BinaryMember(Order = 2)] public int BombsCount;
[BinaryMember(Order = 3)] public int DropDistance;
[BinaryMember(Order = 4)] public int HorizontalSpeed;
[BinaryMember(Order = 5)] public int Sound;
[BinaryMember(Order = 6)] public WeaponAirstrikeSubstyle AirstrikeSubstyle;
[BinaryMember(Order = 7, Converter = typeof(AirstrikeSubstyleConverter))] public IStyle? Style;
}
public enum WeaponAirstrikeSubstyle : int
{
Mines,
Worms,
Launcher
}
}

View File

@ -1,35 +0,0 @@
using System;
using System.IO;
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class AirstrikeSubstyleConverter : IBinaryConverter
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public object? Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
ByteConverter byteConverter)
{
WeaponAirstrikeSubstyle airstrikeSubstyle = instance switch
{
AirstrikeStyle airstrikeStyle => airstrikeStyle.AirstrikeSubstyle,
_ => throw new NotImplementedException(),
};
return airstrikeSubstyle switch
{
WeaponAirstrikeSubstyle.Mines => stream.ReadObject<MineStyle>(),
WeaponAirstrikeSubstyle.Launcher => stream.ReadObject<LauncherStyle>(),
_ => null
};
}
/// <inheritdoc/>
public void Write(Stream stream, object instance, BinaryMemberAttribute memberAttribute, object value,
ByteConverter byteConverter)
{
stream.WriteObject(value);
}
}
}

View File

@ -1,13 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class BaseballBatStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
[BinaryMember(Order = 2)] public int PushPower { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class BattleAxeStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int PercentualDamage { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class BlowtorchStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
[BinaryMember(Order = 2)] public int PushPower { get; set; }
[BinaryMember(Order = 3)] public int ImpactAngle { get; set; }
[BinaryMember(Order = 4)] public int TunellingTime { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class BowStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class CanisterStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int SpriteInactive { get; set; }
[BinaryMember(Order = 2)] public int SpriteActive { get; set; }
[BinaryMember(Order = 3)] public int DiseasePoints { get; set; }
[BinaryMember(Order = 4)] public int MaxDamage { get; set; }
}
}

View File

@ -1,23 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class DragonballStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int FiringSound { get; set; }
[BinaryMember(Order = 2)] public int ImpactSound { get; set; }
[BinaryMember(Order = 3)] public int BallSprite { get; set; }
[BinaryMember(Order = 4)] public int Damage { get; set; }
[BinaryMember(Order = 5)] public int Angle { get; set; }
[BinaryMember(Order = 6)] public int Force { get; set; }
[BinaryMember(Order = 7)] public int BallTime { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class FirepunchStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
[BinaryMember(Order = 2)] public int Angle { get; set; }
[BinaryMember(Order = 3)] public int PushPower { get; set; }
[BinaryMember(Order = 4)] public int JumpHeight { get; set; }
}
}

View File

@ -1,19 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class FlamethrowerStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int FuelAmount { get; set; }
[BinaryMember(Order = 2)] public int FireIntensity { get; set; }
[BinaryMember(Order = 3)] public int FireAmount { get; set; }
[BinaryMember(Order = 4)] public int FireBurnTime { get; set; }
[BinaryMember(Order = 5, BooleanCoding = BooleanCoding.Dword)] public bool RemainOnTerrain { get; set; }
}
}

View File

@ -1,37 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class GunStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int BulletCount { get; set; }
[BinaryMember(Order = 2)] public int ReloadTime { get; set; }
[BinaryMember(Order = 3)] public int BulletSpread { get; set; }
[BinaryMember(Order = 4)] public int Burst { get; set; }
[BinaryMember(Order = 5)] public int BurstSpread { get; set; }
[BinaryMember(Order = 6)] public CollisionFlags Collisions { get; set; }
[BinaryMember(Order = 7)] public int ExplosionBias { get; set; }
[BinaryMember(Order = 8)] public int ExplosionPower { get; set; }
[BinaryMember(Order = 9)] public int MaxDamage { get; set; }
[BinaryMember(Order = 10)] public int DamageSpread { get; set; }
[BinaryMember(Order = 11)] public int ExpEffect { get; set; }
[BinaryMember(Order = 12)] public int Range1 { get; set; }
[BinaryMember(Order = 13)] public int Range2 { get; set; }
[BinaryMember(Order = 14)] public int Range3 { get; set; }
}
}

View File

@ -1,4 +0,0 @@
namespace Syroot.Worms.Armageddon.ProjectX
{
public interface IStyle { }
}

View File

@ -1,11 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class JetpackStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Fuel { get; set; }
}
}

View File

@ -1,21 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class KamikazeStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int FlyingTime { get; set; }
[BinaryMember(Order = 2)] public int ExplosionDamage { get; set; }
[BinaryMember(Order = 3)] public int FireSound { get; set; }
[BinaryMember(Order = 4)] public int Damage { get; set; }
[BinaryMember(Order = 5)] public int ImpactForce { get; set; }
[BinaryMember(Order = 6)] public int ImpactAngle { get; set; }
}
}

View File

@ -1,71 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class LauncherStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int SpriteSize { get; set; }
[BinaryMember(Order = 2)] public int FixedSpeed { get; set; }
[BinaryMember(Order = 3, BooleanCoding = BooleanCoding.Dword)] public bool RunAway { get; set; }
[BinaryMember(Order = 4)] public CollisionFlags Collisions { get; set; }
[BinaryMember(Order = 5)] public int ExplosionBias { get; set; }
[BinaryMember(Order = 6)] public int ExplosionPushPower { get; set; }
[BinaryMember(Order = 7)] public int ExplosionDamage { get; set; }
[BinaryMember(Order = 8)] public int ExplosionDamageVariation { get; set; }
[BinaryMember(Order = 9)] public int ExplosionUnknown { get; set; }
[BinaryMember(Order = 10)] public Sprite Sprite { get; set; }
[BinaryMember(Order = 11)] public int VariableSpeed { get; set; }
[BinaryMember(Order = 12)] public int WindFactor { get; set; }
[BinaryMember(Order = 13)] public int MotionRandomness { get; set; }
[BinaryMember(Order = 14)] public int GravityFactor { get; set; }
[BinaryMember(Order = 15)] public int ExplosionCountdown { get; set; }
[BinaryMember(Order = 16)] public int ExplosionTimer { get; set; }
[BinaryMember(Order = 17)] public Sound Sound { get; set; }
[BinaryMember(Order = 18, BooleanCoding = BooleanCoding.Dword)] public bool ExplodeOnSpace { get; set; }
[BinaryMember(Order = 19)] public ExplosionAction ExplosionAction { get; set; }
[BinaryMember(Order = 20, Converter = typeof(ActionConverter))] public IAction? Action { get; set; }
[BinaryMember(Order = 21, OffsetOrigin = OffsetOrigin.Begin, Offset = 180)]
public ExplosionTarget ExplosionTarget { get; set; }
[BinaryMember(Order = 22, Offset = sizeof(int), Converter = typeof(TargetConverter))]
public ITarget? Target { get; set; }
}
public enum ExplosionAction : int
{
None,
Home,
Bounce,
Roam,
Dig
}
public enum ExplosionTarget : int
{
None,
Clusters,
Fire
}
}

View File

@ -1,11 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class MineStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public Mine Mine;
}
}

View File

@ -1,15 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class NinjaRopeStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int ShotCount { get; set; }
[BinaryMember(Order = 2)] public int Length { get; set; }
[BinaryMember(Order = 3)] public int AngleRestriction { get; set; }
}
}

View File

@ -1,13 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class NuclearTestStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int WaterRise { get; set; }
[BinaryMember(Order = 2)] public int DiseasePoints { get; set; }
}
}

View File

@ -1,11 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class ParachuteStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int WindResponse { get; set; }
}
}

View File

@ -1,17 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class PneumaticDrillStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
[BinaryMember(Order = 2)] public int PushPower { get; set; }
[BinaryMember(Order = 3)] public int ImpactAngle { get; set; }
[BinaryMember(Order = 4)] public int TunellingTime { get; set; }
}
}

View File

@ -1,15 +0,0 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class ProdStyle : IStyle
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Damage { get; set; }
[BinaryMember(Order = 2)] public int Force { get; set; }
[BinaryMember(Order = 3)] public int Angle { get; set; }
}
}

Some files were not shown because too many files have changed in this diff Show More