mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-03-13 13:50:14 +03:00
Compare commits
No commits in common. "master" and "Worms.NET" have entirely different histories.
8
.gitattributes
vendored
8
.gitattributes
vendored
@ -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
|
2
LICENSE
2
LICENSE
@ -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
|
||||
|
71
README.md
71
README.md
@ -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.
|
||||
|
BIN
res/icon.ico
BIN
res/icon.ico
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
BIN
res/icon.png
BIN
res/icon.png
Binary file not shown.
Before Width: | Height: | Size: 7.6 KiB |
113
res/icon.svg
113
res/icon.svg
@ -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 |
@ -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>;
|
||||
}
|
||||
}
|
@ -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>;
|
@ -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;
|
||||
}
|
@ -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;
|
@ -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];
|
@ -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];
|
@ -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];
|
@ -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];
|
@ -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];
|
@ -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>;
|
@ -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>;
|
@ -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];
|
@ -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];
|
35
src/Syroot.Worms.Test/Program.cs
Normal file
35
src/Syroot.Worms.Test/Program.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
src/Syroot.Worms.Test/Syroot.Worms.Test.csproj
Normal file
12
src/Syroot.Worms.Test/Syroot.Worms.Test.csproj
Normal 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>
|
91
src/Syroot.Worms.UnitTest/Common/TestHelpers.cs
Normal file
91
src/Syroot.Worms.UnitTest/Common/TestHelpers.cs
Normal 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
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
25
src/Syroot.Worms.UnitTest/Gen2/ImageTests.cs
Normal file
25
src/Syroot.Worms.UnitTest/Gen2/ImageTests.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
29
src/Syroot.Worms.UnitTest/Gen2/PaletteTests.cs
Normal file
29
src/Syroot.Worms.UnitTest/Gen2/PaletteTests.cs
Normal 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.
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
21
src/Syroot.Worms.UnitTest/Syroot.Worms.UnitTest.csproj
Normal file
21
src/Syroot.Worms.UnitTest/Syroot.Worms.UnitTest.csproj
Normal 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>
|
@ -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
|
||||
|
33
src/Syroot.Worms/Core/BinaryReaderExtensions.cs
Normal file
33
src/Syroot.Worms/Core/BinaryReaderExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
32
src/Syroot.Worms/Core/BinaryWriterExtensions.cs
Normal file
32
src/Syroot.Worms/Core/BinaryWriterExtensions.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
34
src/Syroot.Worms/Core/ByteArrayExtensions.cs
Normal file
34
src/Syroot.Worms/Core/ByteArrayExtensions.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
@ -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>
|
@ -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.
|
@ -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>
|
@ -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.
|
@ -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 ---------------------------------------------------------------------------------------------
|
||||
|
@ -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 ---------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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 ---------------------------------------------------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
230
src/Syroot.Worms/Gen2/Archive.cs
Normal file
230
src/Syroot.Worms/Gen2/Archive.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
147
src/Syroot.Worms/Gen2/Armageddon/LandData.cs
Normal file
147
src/Syroot.Worms/Gen2/Armageddon/LandData.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/Mission.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/Mission.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class Mission
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/MonoMap.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/MonoMap.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class MonoMap
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/Replay.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/Replay.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class Replay
|
||||
{
|
||||
}
|
||||
}
|
1100
src/Syroot.Worms/Gen2/Armageddon/Scheme.cs
Normal file
1100
src/Syroot.Worms/Gen2/Armageddon/Scheme.cs
Normal file
File diff suppressed because it is too large
Load Diff
1624
src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs
Normal file
1624
src/Syroot.Worms/Gen2/Armageddon/SchemeEnums.cs
Normal file
File diff suppressed because it is too large
Load Diff
35
src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs
Normal file
35
src/Syroot.Worms/Gen2/Armageddon/SchemeWeaponSetting.cs
Normal 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;
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
Normal file
10
src/Syroot.Worms/Gen2/Armageddon/TeamContainer.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Armageddon
|
||||
{
|
||||
class TeamContainer
|
||||
{
|
||||
}
|
||||
}
|
158
src/Syroot.Worms/Gen2/Image.cs
Normal file
158
src/Syroot.Worms/Gen2/Image.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
147
src/Syroot.Worms/Gen2/Worms2/LandData.cs
Normal file
147
src/Syroot.Worms/Gen2/Worms2/LandData.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/Mission.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/Mission.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class Mission
|
||||
{
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/MonoMap.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/MonoMap.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class MonoMap
|
||||
{
|
||||
}
|
||||
}
|
225
src/Syroot.Worms/Gen2/Worms2/SchemeEnums.cs
Normal file
225
src/Syroot.Worms/Gen2/Worms2/SchemeEnums.cs
Normal 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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
182
src/Syroot.Worms/Gen2/Worms2/SchemeWeaponSetting.cs
Normal file
182
src/Syroot.Worms/Gen2/Worms2/SchemeWeaponSetting.cs
Normal 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;
|
||||
}
|
||||
}
|
127
src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs
Normal file
127
src/Syroot.Worms/Gen2/Worms2/SchemeWeapons.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
Normal file
10
src/Syroot.Worms/Gen2/Worms2/TeamContainer.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Syroot.Worms.Gen2.Worms2
|
||||
{
|
||||
class TeamContainer
|
||||
{
|
||||
}
|
||||
}
|
41
src/Syroot.Worms/Syroot.Worms.csproj
Normal file
41
src/Syroot.Worms/Syroot.Worms.csproj
Normal 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>
|
@ -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>
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
public interface IAction { }
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
public interface IStyle { }
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
using Syroot.BinaryData;
|
||||
|
||||
namespace Syroot.Worms.Armageddon.ProjectX
|
||||
{
|
||||
public class MineStyle : IStyle
|
||||
{
|
||||
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||
|
||||
[BinaryMember(Order = 1)] public Mine Mine;
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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; }
|
||||
}
|
||||
}
|
@ -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
Loading…
x
Reference in New Issue
Block a user