Compare commits

...

181 Commits

Author SHA1 Message Date
Ray
914acc2e1b Zero-terminate Data to prevent client-side bugs.
- Fixes chat messages displaying stale memory as the client discards the data length.
2024-05-16 21:30:35 +02:00
Ray
b4e6433545 Fix deprecation and nullability warnings. 2024-05-16 12:02:48 +02:00
Ray
63691f897b Update app target framework to .NET 8. 2024-05-16 12:02:01 +02:00
Ray
b509d7bdaf Update test dependencies. 2024-05-16 12:01:56 +02:00
Ray
046033bba7 Update platform toolset. 2024-05-16 12:01:14 +02:00
Ray
6dc2de2445 Update dependencies (same major version only). 2024-05-16 12:00:51 +02:00
Ray
48f1f91be3 Update copyright. 2024-05-16 11:58:06 +02:00
Ray
cbe1388fb0 Fix typo. 2021-09-12 16:56:41 +02:00
Ray
b68503e609 Release 4.0.4 2021-09-12 16:54:04 +02:00
Ray
5fdd97c5ad Add missing StrikeClusterDamage field. 2021-09-12 16:53:19 +02:00
Ray
6a418e84ae Update release notes. 2021-09-12 13:18:07 +02:00
Ray
8eb0a971e8 Release 4.0.3: Fix StackOverflowException when using legacy .NET versions.
Sadly requires all packages to update due to fixed version ProjectReferences.
2021-09-12 13:14:23 +02:00
Ray
6cba058138 Fix StreamShims Read method to not call itself. 2021-09-12 12:30:17 +02:00
Ray
03095916f1 MSBuild: Change common target paths in project files to fix building for DocFX. 2021-03-24 19:27:22 +01:00
Ray Koopa
9a218549e7 Mention new module folder. 2020-07-21 21:08:41 +02:00
Ray Koopa
a99a883f6f Move WormKit loaders, modules, and libraries to module sub folder. Add signature scanning and import replacing. 2020-07-21 21:06:03 +02:00
Ray Koopa
518207b7e6 Add AllowMultiInstance. 2020-07-20 20:17:20 +02:00
Ray Koopa
2b94e09e39 Move FrontendKitLib to WormKitTools to reuse it for other modules. 2020-07-20 18:38:10 +02:00
Ray Koopa
a314377c13 Move reusable FrontendKitWS code into own library. Fix small issue when determining fkNetcode INI path. 2020-07-16 16:01:27 +02:00
Ray Koopa
4e251959b3 Prevent trailing 0-bytes at the end of some sent Packet.Data. 2020-07-14 21:21:49 +02:00
Ray Koopa
2ea6af0324 Remove semaphores. 2020-07-14 21:11:05 +02:00
Ray Koopa
730b14cdfa Change version to 1.1.0 due to new features. 2020-07-14 21:00:28 +02:00
Ray Koopa
bb2b7e72b5 Rewrite server netcode to be asynchronous and support timeouts. Allow multiple proxy connections. 2020-07-14 20:53:11 +02:00
Ray Koopa
65522b6af5 Merge branch 'master' of https://gitlab.com/Syroot/Worms 2020-07-12 21:27:43 +02:00
Ray Koopa
4c27eb415c Read packets more strictly to prevent crashes from bogus data. 2020-07-12 21:27:32 +02:00
Ray Koopa
e9ba6895b8 Add FrontendKitWS and fkNetcode. 2020-07-12 18:37:31 +00:00
Ray Koopa
48e6988083 Use original logic if there's no fallback and / or webservice failed. 2020-07-12 20:20:32 +02:00
Ray Koopa
f242a6b745 Add versioning. 2020-07-12 18:27:59 +02:00
Ray Koopa
d0a01c6a13 Do not drop clients reporting unparsable IP addresses. 2020-07-12 17:40:36 +02:00
Ray Koopa
180a61a147 Extend fkNetcode with settings and better error handling. 2020-07-12 17:40:11 +02:00
Ray Koopa
71c8f33ea7 Add FrontendKitWS and fkNetcode. 2020-07-12 02:19:51 +02:00
Ray Koopa
db3a49539f Fix color output on Linux and Mac OS X, log time stamps with packets, allow configuring local end point with command line parameter. 2020-07-11 05:12:32 +02:00
Ray Koopa
4e1f9b17a8 Prepare game server to be published easily. 2020-07-11 03:14:57 +02:00
Ray Koopa
c97ef5deb2 Send message to users trying to host with bad IP. 2020-07-11 02:07:42 +02:00
Ray Koopa
0cfbc5b675 Fix rooms not being closed when last game is closed. 2020-07-11 01:50:25 +02:00
Ray Koopa
20d7c3c743 Fix game packets. 2020-07-10 23:00:16 +02:00
Ray Koopa
02a644abe9 Finish Worms 2 server (so far). 2020-07-10 21:01:09 +02:00
Ray Koopa
0fee2e1e13 Implement room chat and leaves. 2020-07-10 18:45:10 +02:00
Ray Koopa
9aad0faf6b Implement real packet handling. 2020-07-10 02:15:06 +02:00
Ray Koopa
ac2d12c1b6 Handle additional packets. 2020-07-09 17:06:37 +02:00
Ray Koopa
17b0edf67f Push current additions to Worms 2 server with test proxy. 2020-07-08 23:48:28 +02:00
Ray Koopa
ebdf7f5168 Add Worms2 server. 2020-07-07 00:46:30 +00:00
Ray Koopa
a308ae49b1 Add quick Worms 2 server PoC. Makes BinaryStream FixedString extensions globally available. 2020-07-07 02:45:00 +02:00
Ray Koopa
420810fad2 Remove old TODOs from BinaryStreamExtensions, they're not relevant. 2020-07-03 21:09:19 +02:00
Ray Koopa
b44ae666b6 Armageddon: Read and write signature as unsigned integer instead of string. 2020-07-03 13:57:34 +02:00
Ray Koopa
6d2864e6f7 Loading and saving extended options no longer needs to be unsafe. Remove unused "ClearExtendedOptions". 2020-07-03 13:48:18 +02:00
Ray Koopa
dd2e67eab9 Arnageddon
- Make Scheme.Extended a field rather than an uncommon ref property. Set ObjectCount to 8 by default.
- Make ExtendedOptions.Default public.
- Simplify comparison of ExtendedOptions instances.
2020-07-03 11:50:26 +02:00
Ray Koopa
4454cb1496 Merge branch 'master' of https://gitlab.com/Syroot/Worms 2020-07-02 05:29:15 +02:00
Ray Koopa
5b69f82a35 Syroot.Worms.Armageddon 4.0.1: Optimize WA v3 schemes to store only non-default extended options.
- Adds SchemeVersionExtensions.GetWeaponCount(), returning how many weapons are stored by the corresponding SchemeVersion.
- Adds ExtendedOptions.AsSpan() to return the unmanaged representation of the extended settings.
- Optimize usage of .NET Standard 2.0 Span backports.
2020-07-02 05:28:59 +02:00
Ray Koopa
08703b6c12 Add initial Blazor-based scheme editor. 2020-07-02 01:25:35 +02:00
Ray Koopa
9548855a8e Update README.md 2020-07-01 17:36:34 +00:00
Ray Koopa
7e13af88d1 Update README.md 2020-07-01 17:32:29 +00:00
Ray Koopa
ed4b69d4ad Update README.md 2020-07-01 17:22:17 +00:00
Ray Koopa
cc0ccaae7d Remove temporary code storing test files to disk. 2020-07-01 15:23:52 +02:00
Ray Koopa
bf0c60659a Fix several XML summaries. 2020-07-01 13:54:22 +02:00
Ray Koopa
ebba11bd59 Update project file. 2020-07-01 13:54:16 +02:00
Ray Koopa
f8b1b84f21 Archive: Ensure o call private directory directly while loading and saving. 2020-07-01 13:54:07 +02:00
Ray Koopa
b89ea5d7e9 Add WA archives to test. 2020-07-01 13:53:16 +02:00
Ray Koopa
c62d4a7551 Release v4.
- Fixes remaining ProjectX issues and failing tests.
- Relaxes dependencies on other libraries.
2020-07-01 13:31:02 +02:00
Ray Koopa
5321dfb49a Overhaul implementations and documentation. 2020-07-01 02:09:36 +02:00
Ray Koopa
8b92e6a8be Fix detection of SchemeSaveFormat when calling Save for file names. 2020-06-29 03:03:09 +02:00
Ray Koopa
861d5ea585 Implement W:A V3 schemes. 2020-06-28 23:22:08 +02:00
Ray Koopa
1d06fbd578 Setting RubberWorm version override transfers to extended options. 2020-06-28 19:52:11 +02:00
Ray Koopa
13583a6971 Prepare support for W:A 3.8 V3 schemes.
- Add all new V3 extended options. These will be moved to their own struct soon.
- Renames several existing properties and enums to be more concise.
- Convert RubberWorm probabilities to V3 values.
- Add test testing against a dump of all schemes uploaded to WSDB as of this commit.
2020-06-28 19:06:40 +02:00
Ray Koopa
10008eaf6e Rename FileTester to Tools and allow testing of single Streams. 2020-06-28 19:00:57 +02:00
Ray Koopa
66d4d15305 Relax NuGet package dependencies where possible. 2020-06-27 17:08:56 +02:00
Ray Koopa
7e3fcb766c Fix saving TeamContainer instances and add local test files for them. 2020-06-27 16:58:34 +02:00
Ray Koopa
fabc3e98b2 Properly leave open streams when saving to them for GeneratedMap and LandData instances. 2020-06-27 16:57:39 +02:00
Ray Koopa
ad2a7c79e1 Replace all inherited interface XML summaries with inheritdoc marker. 2020-06-27 16:35:11 +02:00
Ray Koopa
88d07a1ff1 Fix remaining Scheme bugs.
- Implement IEquatable.
- Fix RoundTimeSeconds not properly being parsed.
- Uniquely throw ArgumentOutOfRangeException even for rounding properties.
- Fix FallDamage not being stored properly.
- Add tests for rounding properties and local scheme test files.
- Implement equality operations for SchemeWeapon.
2020-06-27 16:30:49 +02:00
Ray Koopa
378d2474b1 Release 3.1.0 for affected packages. 2020-06-27 14:19:37 +02:00
Ray Koopa
b46cdadb89 Simplify Scheme usage.
- SchemeWeapon enum has been renamed to SchemeWeaponName.
- SchemeWeaponSetting has been renamed to SchemeWeapon.
- Scheme.FallDamage and Scheme.WaterRiseRate are now integral values, rounding down to the nearest valid setting.
- Static Scheme.ValidXxx properties were added to retrieve a list of valid fall damage, water rise, and object count values.
- Scheme properties uniquely throw ArgumentOutOfRangeExceptions if a value is outside of the allowed bounds.
2020-06-27 12:36:20 +02:00
Ray Koopa
e2b41157db Rename MEMBERS separator comments to FIELDS. 2020-06-27 12:31:43 +02:00
Ray Koopa
e72f6041e3 Release 3.0.1.
- Simplify scheme object count usage.
- Fix saving files.
- Uniquely leave open Stream instances when saving into them.
2020-06-26 19:05:46 +02:00
Ray Koopa
26a9125f0a Rewrite logic of parsing Scheme object count and type.
Mirrors frontend logic more closely now without the need for static lookup arrays.
2020-06-26 19:00:55 +02:00
Ray Koopa
57815e9072 Get rid of DisposableGCHandle.
Use Span functionality instead. This introduces some copies for .NET Standard 2.0 builds.
2020-06-26 18:57:01 +02:00
Ray Koopa
b4cf309156 Update target framework for most projects.
- Test projects now run on .NET Core 3.
- NuGet packages additionally target .NET Standard 2.1 to use Span functionality.
2020-06-26 18:54:53 +02:00
Ray Koopa
ed2785e339 Fix several issues when saving new files.
- Fix writing raw bytes.
- In case of saving into Stream instances, uniquely leave them open everywhere.
2020-06-26 18:53:25 +02:00
Ray Koopa
84ba8c56a0 Update readme. 2020-06-18 16:04:52 +02:00
Ray Koopa
c51f67dc46 Update copyright. 2020-06-18 16:04:42 +02:00
Ray Koopa
0ce2ce387e Publish split game-related NuGet packages. 2020-06-18 15:52:14 +02:00
Ray Koopa
717da50d80 Remove Discord link. Please use Issues for support. 2020-03-28 14:21:05 +00:00
Ray Koopa
e57c593efa Review code, update code standards and NuGet packages. 2019-09-27 20:13:24 +02:00
Ray Koopa
c5391c3d66 Add LevelInfo. 2019-03-02 10:32:59 +01:00
Ray Koopa
bd3d40245b Merge branch 'master' of https://gitlab.com/Syroot/Worms 2019-03-02 10:32:50 +01:00
Ray Koopa
93f9481dc9 Add Shell project. 2019-03-02 10:32:46 +01:00
Ray Koopa
0145636dc0 Delete desktop.ini 2019-03-02 09:29:19 +00:00
Ray Koopa
c7d7f5cb3e Move projects into specific sub-folders. 2019-01-28 06:30:58 +01:00
Ray Koopa
95b68d63c6 Add ChatMessageQuery/Reply. 2019-01-22 21:46:41 +01:00
Ray Koopa
5c84357edb Implement AddFriendQuery/Reply 2019-01-22 21:22:38 +01:00
Ray Koopa
e9c88caadc Try to fix failing connects. 2019-01-22 18:32:31 +01:00
Ray Koopa
1b527a3f20 Implement CmdFindUser 2019-01-22 18:22:01 +01:00
Ray Koopa
38035742d6 Dynamically implement channel commands. 2019-01-22 01:23:20 +01:00
Ray Koopa
a8073367f4 Delegate packet handling to IPacketFormat. 2019-01-22 00:47:53 +01:00
Ray Koopa
cc84ed3d5f Typo 2019-01-21 20:09:53 +01:00
Ray Koopa
e4104b8309 Implement propret channel join. 2019-01-20 20:49:20 +01:00
Ray Koopa
629103fce5 Implement proper disconnection from channel. 2019-01-20 03:19:49 +01:00
Ray Koopa
441648da6a Implement ChannelCmdPacket. 2019-01-20 00:14:22 +01:00
Ray Koopa
b527021df4 Implement ChannelList and ChannelLoginQuery 2019-01-19 15:38:48 +01:00
Ray Koopa
587ac06330 Implement WWPA packets, update OW ones to Span parsing, rename encodings. 2019-01-19 02:17:20 +01:00
Ray Koopa
899c031840 Use IOException to dismiss clients sending trash. 2019-01-18 20:51:14 +01:00
Ray Koopa
519a01b6f6 Delete old packet data stream. 2019-01-18 20:49:18 +01:00
Ray Koopa
7852ef9d5a Use new BinaryData package to work on spans rather than streams. 2019-01-18 20:44:02 +01:00
Ray Koopa
fcc2c74399 Add compression tests. 2019-01-16 13:32:41 +01:00
Ray Koopa
f066c27857 Remove debug remnants. 2019-01-16 06:29:11 +01:00
Ray Koopa
2d5fa21c00 Clone original WWPA compression as close as possible due to bug found in original implementation. 2019-01-16 06:28:14 +01:00
Ray Koopa
197a958a98 Port WWPA packet decompression to C#. 2019-01-16 01:27:34 +01:00
Ray Koopa
efc1a9fcff Implement WWPA packet format (WIP). 2019-01-15 22:48:56 +01:00
Ray Koopa
c0cab3ecf5 Release 1.0.0 of Mgame launcher. 2019-01-13 02:09:04 +01:00
Ray Koopa
13dee4ecbf Update readme. 2019-01-12 22:25:12 +01:00
Ray Koopa
a16d0a5146 Use RawBitmap as image data container everywhere. 2019-01-12 22:14:17 +01:00
Ray Koopa
077669b81c Split into game-specific libraries. 2019-01-12 22:02:35 +01:00
Ray Koopa
fd53660c5e Use new BinaryStream extensions. 2019-01-12 20:36:16 +01:00
Ray Koopa
9feea4313f Do not generate XML documentation for Debug 2019-01-12 20:34:42 +01:00
Ray Koopa
4741e0f425 Clean-up and re-use BinaryStream(Extensions). 2019-01-12 20:34:26 +01:00
Ray Koopa
cf7e69e026 Update IGD and LPD formats. 2019-01-12 17:39:13 +01:00
Ray Koopa
4aa9aef362 Update launcher for WWPA, supporting multiple executable paths. 2019-01-12 17:38:39 +01:00
Ray Koopa
dac33e441a Fix IGD bitmap width. 2019-01-06 23:44:51 +01:00
Ray Koopa
ff76e5b9c0 Obsolete BitmapData and rename it to RawBitmapData. 2019-01-06 23:17:46 +01:00
Ray Koopa
8a616939de Add IGD and LPD support. Remove Syroot.Maths reference. 2019-01-06 23:16:35 +01:00
Ray Koopa
83024baaf3 Rename PacketType to PacketFormat. 2019-01-06 23:16:13 +01:00
Ray Koopa
9b663bb72b Rename Top20Players packets to Top20. 2019-01-04 23:54:05 +01:00
Ray Koopa
645db214ca Name several unknown properties. 2019-01-04 23:51:48 +01:00
Ray Koopa
c33e1f7987 Add StartSingleGame query and reply. 2019-01-04 20:14:20 +01:00
Ray Koopa
41991d6d78 Add ChannelEnterFinishReply. 2019-01-04 19:57:38 +01:00
Ray Koopa
1a5bbe714f Add config for server. 2019-01-04 19:14:55 +01:00
Ray Koopa
1d02d3834b Update Costury. 2019-01-04 19:14:31 +01:00
Ray Koopa
220597e65e Move password encryption algorithm to separate class. 2019-01-04 14:11:59 +01:00
Ray Koopa
9720cf1a02 Add ChannelUnkInfo query and reply. 2019-01-04 05:05:59 +01:00
Ray Koopa
b61f190df6 Fix channel packet format. 2019-01-04 03:38:46 +01:00
Ray Koopa
7e801057ac Support channel packet format. 2019-01-04 03:21:28 +01:00
Ray Koopa
1d8c090957 Add ChannelEnterQuery and Reply. 2019-01-03 22:57:36 +01:00
Ray Koopa
ee17e5886e Implement ChannelInfosReply. 2019-01-03 21:48:31 +01:00
Ray Koopa
90110979c0 Remove Packet postfixes of packet classes. 2019-01-03 21:48:14 +01:00
Ray Koopa
f6b37eb96c Add Server Info Reply. Change handler method signature. 2019-01-02 18:20:27 +01:00
Ray Koopa
13f97d706a Remove Gen2 namespace from tests. 2019-01-02 16:30:37 +01:00
Ray Koopa
61377411a1 Finalize OW password encryption and decryption. 2019-01-02 16:29:18 +01:00
Ray Koopa
1c401235d5 Fix server directory. 2019-01-01 22:04:21 +01:00
Ray Koopa
e5352cadf2 Add configuration file and debugging features to launcher. 2019-01-01 22:04:07 +01:00
Ray Koopa
35946c8e84 Port (raw) password decryption code to C#. 2019-01-01 22:03:36 +01:00
Ray Koopa
24b545f8e2 Move server to correct subdirectory. 2019-01-01 22:03:10 +01:00
Ray Koopa
dd8b1a4be7 Push latest changes. 2018-12-26 01:38:21 +01:00
Ray Koopa
e9da2e440f Prepare encrypting password. 2018-12-26 01:37:58 +01:00
Ray Koopa
c5db3266d3 Implement login packets. 2018-12-25 23:09:22 +01:00
Ray Koopa
dfae4ef3de Add titles. 2018-12-25 22:16:49 +01:00
Ray Koopa
8103229703 Add Online Worms Server. 2018-12-25 22:13:51 +01:00
Ray Koopa
30c1454522 Add common server logging. 2018-12-25 22:12:37 +01:00
Ray Koopa
bb7d633f21 Simplify server architecture. 2018-12-25 17:36:36 +01:00
Ray Koopa
677b9eb9c7 Add server framework (WIP). 2018-12-25 17:08:43 +01:00
Ray Koopa
26363c9165 Dump KSF images with 0 based index. 2018-12-25 17:08:27 +01:00
Ray Koopa
06a2cad03b Add icon for launcher. 2018-12-25 17:07:59 +01:00
Ray Koopa
f850a01d19 Ensure to wait for process to exit before disposing file mapping. 2018-12-22 23:46:05 +01:00
Ray Koopa
a1de6d8c89 Add KSF and other Online Worms specific features. Remove Gen2 namespace as other generations are no longer focused. 2018-12-22 00:54:13 +01:00
Ray Koopa
5541f66a78 Generate XML documentation. 2018-10-22 13:56:15 +02:00
Ray Koopa
e31c4b4f90 Update package metadata. 2018-10-22 13:55:13 +02:00
Ray Koopa
55fdd54027 Update to BinaryData 5. 2018-10-16 00:57:08 +02:00
Ray Koopa
3877a8dc27
Update README.md 2017-12-07 15:21:34 +01:00
Ray Koopa
f60a17bfca Update repository 2017-08-25 20:10:55 +02:00
Ray Koopa
d57de03cf7 Remove unused ImageSharp reference, add link to NuGet 2017-05-03 15:51:45 +02:00
Ray Koopa
b24082bc24 Fixed XML summaries, added logo. 2017-05-03 15:46:44 +02:00
Ray Koopa
ff042f1fc2 Use BinaryData 2.0.0 RC to load ProjectX data more automatically. 2017-05-01 19:55:14 +02:00
Ray Koopa
5e23aef58c Fix WWP land data IMG alignment and accept bugged PX weapon blocks. 2017-05-01 14:39:14 +02:00
Ray Koopa
e4f3c0ced1 Update for Syroot.BinaryData 1.3.0 2017-05-01 13:37:16 +02:00
Ray Koopa
95687b273b Added support for saving Project X schemes and libraries. 2017-04-29 16:50:34 +02:00
Ray Koopa
ece703f755 Add support for loading Project X schemes and libraries. 2017-04-29 14:11:25 +02:00
Ray Koopa
380b896e5e Added support for generated map files. 2017-04-26 14:58:07 +02:00
Ray Koopa
619822902a Merge branch 'master' of https://github.com/Syroot/Worms 2017-04-26 14:57:00 +02:00
Ray Koopa
fb16f94cf6 Add support for LEV files. 2017-04-26 14:56:54 +02:00
Ray Koopa
accf37856c Added save support for Images and LandData. 2017-04-26 13:44:40 +02:00
Ray Koopa
feb2ed72f7 Added save support for Images and LandData. 2017-04-26 13:44:19 +02:00
Ray Koopa
ade95d4cd0 Add enums for simple team file editing, fix LandData for WWP. 2017-04-26 11:05:53 +02:00
Ray Koopa
e5b1b9441f Merge branch 'master' of https://github.com/Syroot/Worms 2017-04-25 20:43:33 +02:00
Ray Koopa
a965808afe Added enum for WWP points for weapons indices. 2017-04-25 20:43:31 +02:00
Ray Koopa
3bf7531167 Added support for WWP team files. 2017-04-25 20:12:31 +02:00
Ray Koopa
025637b7aa Merge branch 'master' of https://github.com/Syroot/Worms 2017-04-25 20:12:10 +02:00
Ray Koopa
ff03f73af6 Add support for WWP team files. 2017-04-25 20:12:09 +02:00
Ray Koopa
14e78bb43c Seperate row for WWP team files. 2017-04-25 18:44:26 +02:00
Ray Koopa
364d6c53c6 Added support for WGT team files (at least for WA). 2017-04-25 17:28:29 +02:00
Ray Koopa
ec3e79f8e1 Fix layout of ST1 files. 2017-04-23 17:24:02 +02:00
Ray Koopa
21b48ad76b Added support for ST1 team files. 2017-04-23 16:40:40 +02:00
Ray Koopa
cf37f99ece Not really needed anymore. 2017-04-23 02:13:02 +02:00
1164 changed files with 23273 additions and 10941 deletions

8
.gitattributes vendored Normal file
View File

@ -0,0 +1,8 @@
*.dat filter=lfs diff=lfs merge=lfs -text
*.img filter=lfs diff=lfs merge=lfs -text
*.pxl filter=lfs diff=lfs merge=lfs -text
*.pxs filter=lfs diff=lfs merge=lfs -text
*.wgt filter=lfs diff=lfs merge=lfs -text
*.wsc filter=lfs diff=lfs merge=lfs -text
*.wwp filter=lfs diff=lfs merge=lfs -text
src/test/Syroot.Worms.Armageddon.Test/Files/Schemes/WA/Wsdb/dump.csv filter=lfs diff=lfs merge=lfs -text

View File

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

View File

@ -1,41 +1,44 @@
# Worms # 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.
Right now, the following file formats are supported: 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:
## First Generation (2D) | Extension | Description | Games | Library | Load | Save |
Support for first generation 2D games is planned at a later stage. |-----------|-------------------|-------------|------------------------------------|:----:|:----:|
| 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` | ✔ | ✔ |
| Description | Extension | Games | Load | Save | Implementation of formats listed above as unsupported is planned for a later date.
|----------------|:---------:|:-------:|:----:|:----:|
| 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 |
## Second Generation (2D) The libraries are available on [NuGet](https://www.nuget.org/packages?q=Syroot.Worms).
Formats of the second generation 2D games are mostly focused right now.
| Description | Extension | Games | Load | Save | ## Modules
|-------------------|:---------:|:-----------:|:----:|:----:|
| 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 |
## Third Generation (3D) * `fkNetcode`: Patches Worms 2's outdated external IP detection and resolves it properly via a web service.
Third generation file formats used by the 3D games have not yet been looked into. * `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.

BIN
res/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
res/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

113
res/icon.svg Normal file
View File

@ -0,0 +1,113 @@
<?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>

After

Width:  |  Height:  |  Size: 9.7 KiB

8
src/010editor/Common.bt Normal file
View File

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

18
src/010editor/IMG.bt Normal file
View File

@ -0,0 +1,18 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: IMG.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms Armageddon and Worms World Party image files.
// Category: Worms
// File Mask: *.img
// ID Bytes:
// History:
// 0.1.0 2020-06-29 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
Image image <open=true>;

74
src/010editor/Image.bt Normal file
View File

@ -0,0 +1,74 @@
#include "Common.bt"
typedef struct(char description, char align)
{
uint signature <format=hex>;
if (signature != 0x1A474D49) // "IMG\x1A"
{
Warning("Invalid IMG signature.");
Exit(-1);
}
uint fileSize;
if (description)
string description;
ubyte bpp;
enum <ubyte> Flags
{
IMG_COMPRESSED = 1 << 6,
IMG_PALETTIZED = 1 << 7
} flags;
if (flags & IMG_PALETTIZED)
{
ushort colorCount;
struct Color
{
ubyte r;
ubyte g;
ubyte b;
} colors[colorCount];
}
ushort width;
ushort height;
if (align)
FAlign(4);
if (flags & IMG_COMPRESSED)
char data[GetCompressedImgSize()];
else
char data[bpp / 8.0 * width * height];
} Image;
int GetCompressedImgSize()
{
local int pos = FTell();
local int start = pos;
local int cmd;
while ((cmd = ReadByte(pos++)) != -1)
{
// Read a byte.
if ((cmd & 0x80) != 0)
{
local int arg1 = cmd >> 3 & 0b1111; // bits 2-5
local int arg2 = ReadByte(pos++);
if (arg2 == -1)
break;
// Arg2 = bits 6-16
arg2 = ((cmd << 8) | arg2) & 0x7FF;
if (arg1 == 0)
{
// Command: 0x80 0x00
if (arg2 == 0)
break;
if (ReadByte(pos++) == -1)
break;
}
}
}
return pos - start;
}

32
src/010editor/LEV.bt Normal file
View File

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

29
src/010editor/OW_KSF.bt Normal file
View File

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

20
src/010editor/OW_PAL.bt Normal file
View File

@ -0,0 +1,20 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: OW_PAL.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Online Worms PAL color palettes.
// Category: Worms
// File Mask: *.pal
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
LittleEndian();
struct Color
{
ubyte r, g, b;
} colors[256];

View File

@ -0,0 +1,44 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: W2_LandDAT.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms 2 land generator data files.
// Category: Worms
// File Mask: land.dat
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
uint signature <format=hex>;
if (signature != 0x1A444E4C) // "LND\x1A"
{
Warning("Invalid LND signature.");
Exit(-1);
}
int fileSize;
int mapWidth;
int mapHeight;
int hasCavernBorder;
int numObjectLocations;
struct ObjectLocation
{
int x;
int y;
} objectLocations[numObjectLocations];
int unknown;
Image foregroundImage(true, false);
Image collisionImage(true, false);
Image backgroundImage(true, false);
Image unknownImage(true, false);
ubyte landTexPathLength;
char landTexPath[landTexPathLength];
ubyte waterDirPathLength;
char waterDirPath[waterDirPathLength];

View File

@ -0,0 +1,43 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: WA3.0_LandDAT.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms Armageddon (older than 3.6.28.0) land generator data files.
// Category: Worms
// File Mask: land.dat
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
uint signature <format=hex>;
if (signature != 0x1A444E4C) // "LND\x1A"
{
Warning("Invalid LND signature.");
Exit(-1);
}
int fileSize;
int mapWidth;
int mapHeight;
int hasCavernBorder;
int waterHeight;
int numObjectLocations;
struct ObjectLocation
{
int x;
int y;
} objectLocations[numObjectLocations];
Image foregroundImage(false, false);
Image collisionImage(false, false);
Image backgroundImage(false, false);
ubyte landTexPathLength;
char landTexPath[landTexPathLength];
ubyte waterDirPathLength;
char waterDirPath[waterDirPathLength];

View File

@ -0,0 +1,44 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: WA3.6_LandDAT.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms Armageddon (3.6.28.0 and newer) land generator data files.
// Category: Worms
// File Mask: land.dat
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
uint signature <format=hex>;
if (signature != 0x1A444E4C) // "LND\x1A"
{
Warning("Invalid LND signature.");
Exit(-1);
}
int fileSize;
int mapWidth;
int mapHeight;
int hasCavernBorder;
int waterHeight;
int holeCount;
int numObjectLocations;
struct ObjectLocation
{
int x;
int y;
} objectLocations[numObjectLocations];
Image foregroundImage(false, false);
Image collisionImage(false, false);
Image backgroundImage(false, false);
ubyte landTexPathLength;
char landTexPath[landTexPathLength];
ubyte waterDirPathLength;
char waterDirPath[waterDirPathLength];

51
src/010editor/WWPA_IGD.bt Normal file
View File

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

35
src/010editor/WWPA_LPD.bt Normal file
View File

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

View File

@ -0,0 +1,44 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: WWPA_LandDAT.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms World Party Aqua land generator data files.
// Category: Worms
// File Mask: land.dat
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
uint signature <format=hex>;
if (signature != 0x1B444E4C) // "LND\x1B"
{
Warning("Invalid LND signature.");
Exit(-1);
}
int fileSize;
int mapWidth;
int mapHeight;
int hasCavernBorder;
int waterHeight;
int holeCount;
int numObjectLocations;
struct ObjectLocation
{
int x;
int y;
} objectLocations[numObjectLocations];
Image foregroundImage(false, true);
Image collisionImage(false, true);
Image backgroundImage(false, true);
ubyte landTexPathLength;
char landTexPath[landTexPathLength];
ubyte waterDirPathLength;
char waterDirPath[waterDirPathLength];

View File

@ -0,0 +1,43 @@
//------------------------------------------------
//--- 010 Editor v10.0.2 Binary Template
//
// File: WWP_LandDAT.bt
// Authors: Syroot
// Version: 0.1.0
// Purpose: Parse Worms World Party land generator data files.
// Category: Worms
// File Mask: land.dat
// ID Bytes:
// History:
// 0.1.0 2020-06-30 Initial version.
//------------------------------------------------
#include "Image.bt"
LittleEndian();
uint signature <format=hex>;
if (signature != 0x1A444E4C) // "LND\x1A"
{
Warning("Invalid LND signature.");
Exit(-1);
}
int fileSize;
int mapWidth;
int mapHeight;
int hasCavernBorder;
int waterHeight;
int numObjectLocations;
struct ObjectLocation
{
int x;
int y;
} objectLocations[numObjectLocations];
Image foregroundImage(false, true);
Image collisionImage(false, true);
Image backgroundImage(false, true);
ubyte landTexPathLength;
char landTexPath[landTexPathLength];
ubyte waterDirPathLength;
char waterDirPath[waterDirPathLength];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,34 +1,189 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio Version 16
VisualStudioVersion = 15.0.26403.7 VisualStudioVersion = 16.0.30204.135
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms", "library\Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms.UnitTest", "Syroot.Worms.UnitTest\Syroot.Worms.UnitTest.csproj", "{493816DB-A1A1-4981-9F5F-8044499937B6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Scratchpad", "tool\Syroot.Worms.Scratchpad\Syroot.Worms.Scratchpad.csproj", "{0D7F9DC3-7268-494E-BA1E-6C01525EB9AB}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Test", "Syroot.Worms.Test\Syroot.Worms.Test.csproj", "{2D796945-A523-4A22-BDEE-702D6BA36F69}" 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 EndProject
Global Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Armageddon", "library\Syroot.Worms.Armageddon\Syroot.Worms.Armageddon.csproj", "{D9694108-539C-4DEE-B5DD-284208D48B46}"
GlobalSection(SolutionConfigurationPlatforms) = preSolution EndProject
Debug|Any CPU = Debug|Any CPU 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}"
Release|Any CPU = Release|Any CPU EndProject
EndGlobalSection Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.WorldParty", "library\Syroot.Worms.WorldParty\Syroot.Worms.WorldParty.csproj", "{4E124BBA-15B5-422E-93D5-96EA7D4180F3}"
GlobalSection(ProjectConfigurationPlatforms) = postSolution EndProject
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Worms2", "library\Syroot.Worms.Worms2\Syroot.Worms.Worms2.csproj", "{BBCECFCC-F2FD-4C4D-A6E9-CC7AA5F10FDD}"
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Debug|Any CPU.Build.0 = Debug|Any CPU EndProject
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.ActiveCfg = Release|Any CPU Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Mgame", "library\Syroot.Worms.Mgame\Syroot.Worms.Mgame.csproj", "{BD8079D9-FDB5-4C7D-8AD4-C80ADC4A4B26}"
{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}.Release|Any CPU.Build.0 = Release|Any CPU EndProject
{493816DB-A1A1-4981-9F5F-8044499937B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test Projects", "Test Projects", "{99E56312-A064-4AD3-8443-0B56A5F76E6B}"
{493816DB-A1A1-4981-9F5F-8044499937B6}.Debug|Any CPU.Build.0 = Debug|Any CPU EndProject
{493816DB-A1A1-4981-9F5F-8044499937B6}.Release|Any CPU.ActiveCfg = Release|Any CPU Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Library Projects", "Library Projects", "{9E964426-D744-405A-9EAA-D8D7A310B614}"
{493816DB-A1A1-4981-9F5F-8044499937B6}.Release|Any CPU.Build.0 = Release|Any CPU EndProject
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tool Projects", "Tool Projects", "{0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}"
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Debug|Any CPU.Build.0 = Debug|Any CPU EndProject
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Release|Any CPU.ActiveCfg = Release|Any CPU 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}"
{2D796945-A523-4A22-BDEE-702D6BA36F69}.Release|Any CPU.Build.0 = Release|Any CPU EndProject
EndGlobalSection 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}"
GlobalSection(SolutionProperties) = preSolution EndProject
HideSolutionNode = FALSE 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}"
EndGlobalSection EndProject
EndGlobal 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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,147 +0,0 @@
using System.IO;
using System.Text;
using Syroot.IO;
using Syroot.Maths;
using Syroot.Worms.Core;
namespace Syroot.Worms.Gen2.Armageddon
{
/// <summary>
/// Represents map configuration stored by the land generator in LAND.DAT files.
/// Used by WA and WWP. S. https://worms2d.info/Land_Data_file.
/// </summary>
public class LandData : ILoadableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _signature = 0x1A444E4C; // "LND", 0x1A
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class.
/// </summary>
public LandData()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given
/// <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public LandData(Stream stream)
{
Load(stream);
}
/// <summary>
/// Initializes a new instance of the <see cref="LandData"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public LandData(string fileName)
{
Load(fileName);
}
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the size of the landscape in pixels.
/// </summary>
public Vector2 Size { get; set; }
/// <summary>
/// Gets or sets a value indicating whether an indestructible top border will be enabled.
/// </summary>
public bool TopBorder { get; set; }
/// <summary>
/// Gets or sets the height of the water in pixels.
/// </summary>
public int WaterHeight { get; set; }
/// <summary>
/// Gets or sets an array of coordinates at which objects can be placed.
/// </summary>
public Vector2[] ObjectLocations { get; set; }
/// <summary>
/// Gets or sets the visual foreground image.
/// </summary>
public Image Foreground { get; set; }
/// <summary>
/// Gets or sets the collision mask of the landscape.
/// </summary>
public Image CollisionMask { get; set; }
/// <summary>
/// Gets or sets the visual background image.
/// </summary>
public Image Background { get; set; }
/// <summary>
/// Gets or sets the path to the land image file.
/// </summary>
public string LandTexturePath { get; set; }
/// <summary>
/// Gets or sets the path to the Water.dir file.
/// </summary>
public string WaterDirPath { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Loads the data from the given <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
public void Load(Stream stream)
{
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII, true))
{
// Read the header.
if (reader.ReadInt32() != _signature)
{
throw new InvalidDataException("Invalid LND file signature.");
}
int fileLength = reader.ReadInt32();
// Read the data.
Size = reader.ReadStruct<Vector2>();
TopBorder = reader.ReadBoolean(BinaryBooleanFormat.NonZeroDword);
WaterHeight = reader.ReadInt32();
// Read the possible object coordinate array.
int badObjectLocations = reader.ReadInt32(); // TODO: Check what this is used for.
ObjectLocations = new Vector2[reader.ReadInt32()];
for (int i = 0; i < ObjectLocations.Length; i++)
{
ObjectLocations[i] = reader.ReadStruct<Vector2>();
}
// Read the image data.
Foreground = new Image(stream);
CollisionMask = new Image(stream);
Background = new Image(stream);
// Read the file paths.
LandTexturePath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
WaterDirPath = reader.ReadString(BinaryStringFormat.ByteLengthPrefix);
}
}
/// <summary>
/// Loads the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
{
Load(stream);
}
}
}
}

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,35 +0,0 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Syroot.Worms.Gen2.Armageddon
{
/// <summary>
/// Represents the configuration of a weapon.
/// </summary>
[DebuggerDisplay("Ammo={Ammunition} Power={Power} Delay={Delay} Prob={Probability}")]
[StructLayout(LayoutKind.Sequential)]
public struct SchemeWeaponSetting
{
/// <summary>
/// The amount of this weapon with which a team is equipped at game start. 10 and negative values represent
/// infinity.
/// </summary>
public sbyte Ammunition;
/// <summary>
/// The power of this weapon.
/// </summary>
public byte Power;
/// <summary>
/// The number of turns required to be taken by each team before this weapon becomes available. Negative values
/// represent infinity.
/// </summary>
public sbyte Delay;
/// <summary>
/// The percentual chance of this weapon to appear in crates. Has no effect for super weapons.
/// </summary>
public sbyte Probability;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,182 +0,0 @@
using System.Runtime.InteropServices;
namespace Syroot.Worms.Gen2.Worms2
{
/// <summary>
/// Represents the configuration of a weapon.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct SchemeWeaponSetting
{
/// <summary>
/// The amount of this weapon with which a team is equipped at game start. 10 and negative values represent
/// infinity.
/// </summary>
public int Ammunition;
/// <summary>
/// The number of turns required to be taken by each team before this weapon becomes available.
/// </summary>
public int Delay;
/// <summary>
/// Retreat time after using this weapon. 0 uses the setting from the game options.
/// </summary>
public int RetreatTime;
/// <summary>
/// <c>true</c> to preselect this weapon in the next turn; otherwise <c>false</c>.
/// </summary>
public bool Remember;
/// <summary>
/// An unused field with unknown value.
/// </summary>
public int Unused1;
/// <summary>
/// The amount of this weapon added to the team armory when collected from a crate.
/// </summary>
public int CrateAmmunition;
/// <summary>
/// The amount of bullets shot at once.
/// </summary>
public int BulletCount;
/// <summary>
/// The percentual chance of this weapon to appear in crates.
/// </summary>
public int Probability;
/// <summary>
/// The damage measured in health points which also determines the blast radius.
/// </summary>
public int Damage;
/// <summary>
/// The pushing power measured in percent.
/// </summary>
public int BlastPower;
/// <summary>
/// The offset to the bottom of an explosion, measured in percent.
/// </summary>
public int BlastBias;
/// <summary>
/// The milliseconds required before this weapon starts flying towards its target.
/// </summary>
public int HomingDelay;
/// <summary>
/// The length in milliseconds this weapon flies towards its target before giving up.
/// </summary>
public int HomingTime;
/// <summary>
/// The percentual amount this weaopn is affected by wind.
/// </summary>
public int WindResponse;
/// <summary>
/// An unused field with unknown value.
/// </summary>
public int Unused2;
/// <summary>
/// The number of clusters into which this weapon explodes.
/// </summary>
public int ClusterCount;
/// <summary>
/// The speed in which clusters are dispersed in percent.
/// </summary>
public int ClusterLaunchPower;
/// <summary>
/// The angle in which clusters are dispersed in degrees.
/// </summary>
public int ClusterLaunchAngle;
/// <summary>
/// The damage of clusters measured in health points which also determines the blast radius.
/// </summary>
public int ClusterDamage;
/// <summary>
/// Overrides the fuse of this weapon, 0 for default.
/// </summary>
public int Fuse;
/// <summary>
/// The amount of fire created.
/// </summary>
public int FireAmount;
/// <summary>
/// The speed in which fire spreads, measured in percent.
/// </summary>
public int FireSpreadSpeed;
/// <summary>
/// The period in which fire burns, measured in percent.
/// </summary>
public int FireTime;
/// <summary>
/// The melee impact force in percent.
/// </summary>
public int MeleeForce;
/// <summary>
/// The melee impact angle in degrees.
/// </summary>
public int MeleeAngle;
/// <summary>
/// The melee damage in health points.
/// </summary>
public int MeleeDamage;
/// <summary>
/// The height of the fire punch jump, measured in percent.
/// </summary>
public int FirePunchHeight;
/// <summary>
/// The damage a dragon ball causes, measured in health points.
/// </summary>
public int DragonBallDamage;
/// <summary>
/// The power in which a dragon ball launches hit worms, measured in percent.
/// </summary>
public int DragonBallPower;
/// <summary>
/// The angle in which a dragon ball launches hit worms, measured in degrees.
/// </summary>
public int DragonBallAngle;
/// <summary>
/// The life time of a launched dragon ball measured in milliseconds.
/// </summary>
public int DragonBallTime;
/// <summary>
/// The length of digging measured in milliseconds. Applies to Kamikaze and digging tools.
/// </summary>
public int DiggingTime;
/// <summary>
/// The amount of airstrike clusters thrown.
/// </summary>
public int StrikeClusterCount;
/// <summary>
/// The angle in which bullets are dispersed, measured in degrees.
/// </summary>
public int BulletSpreadAngle;
}
}

View File

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

View File

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

View File

@ -1,41 +0,0 @@
<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>

39
src/build.xml Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(MSBuildThisFileDirectory)..\..\build.xml" />
<!-- Metadata -->
<PropertyGroup>
<AssemblyName>Syroot.Worms.Armageddon.ProjectX</AssemblyName>
<Description>.NET library for loading and modifying files of Worms Armageddon ProjectX.</Description>
<PackageReleaseNotes>Fix StackOverflowException when using legacy .NET versions.</PackageReleaseNotes>
<PackageTags>$(PackageTags);project x;worms armageddon</PackageTags>
<Version>4.0.3</Version>
</PropertyGroup>
<!-- References -->
<ItemGroup>
<PackageReference Include="Syroot.BinaryData.Serialization" Version="5.2.1" />
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
<ProjectReference Include="..\Syroot.Worms.Armageddon\Syroot.Worms.Armageddon.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,53 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class ClusterTarget : ITarget
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int ClusterCount { get; set; }
[BinaryMember(Order = 2)] public int DispersionPower { get; set; }
[BinaryMember(Order = 3)] public int Speed { get; set; }
[BinaryMember(Order = 4)] public int EjectionAngle { get; set; }
[BinaryMember(Order = 5)] public int DispersionAngle { get; set; }
[BinaryMember(Order = 6)] public CollisionFlags Collisions { get; set; }
[BinaryMember(Order = 7)] public int ExplosionBias { get; set; }
[BinaryMember(Order = 8)] public int ExplosionPushPower { get; set; }
[BinaryMember(Order = 9)] public int ExplosionDamage { get; set; }
[BinaryMember(Order = 10)] public int ExplosionDamageVariation { get; set; }
[BinaryMember(Order = 11)] public int SpriteCount { get; set; }
[BinaryMember(Order = 12)] public Sprite Sprite { get; set; }
[BinaryMember(Order = 13)] public int Acceleration { get; set; }
[BinaryMember(Order = 14)] public int WindResponse { get; set; }
[BinaryMember(Order = 15)] public int MotionRandomness { get; set; }
[BinaryMember(Order = 16)] public int GravityFactor { get; set; }
[BinaryMember(Order = 17)] public int Unused1 { get; set; }
[BinaryMember(Order = 18)] public int Unused2 { get; set; }
[BinaryMember(Order = 19)] public Sound Sound { get; set; }
[BinaryMember(Order = 20, BooleanCoding = BooleanCoding.Dword)] public bool ExplodeOnSpace { get; set; }
[BinaryMember(Order = 21)] public ExplosionAction ExplosionAction { get; set; }
[BinaryMember(Order = 22, Converter = typeof(ActionConverter))] public IAction? Action { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
public class FireTarget : ITarget
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public int Power { get; set; }
[BinaryMember(Order = 2)] public int Spread { get; set; }
[BinaryMember(Order = 3)] public int Time { get; set; }
[BinaryMember(Order = 4, BooleanCoding = BooleanCoding.Dword)] public bool StayBetweenTurns { get; set; }
}
}

View File

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

View File

@ -0,0 +1,35 @@
using System;
using System.IO;
using Syroot.BinaryData;
namespace Syroot.Worms.Armageddon.ProjectX
{
internal class TargetConverter : IBinaryConverter
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public object? Read(Stream stream, object instance, BinaryMemberAttribute memberAttribute,
ByteConverter byteConverter)
{
ExplosionTarget explosionTarget = instance switch
{
LauncherStyle launcherStyle => launcherStyle.ExplosionTarget,
_ => throw new NotImplementedException(),
};
return explosionTarget switch
{
ExplosionTarget.Clusters => stream.ReadObject<ClusterTarget>(),
ExplosionTarget.Fire => stream.ReadObject<FireTarget>(),
_ => null,
};
}
/// <inheritdoc/>
public void Write(Stream stream, object instance, BinaryMemberAttribute memberAttribute, object value,
ByteConverter byteConverter)
{
stream.WriteObject(value);
}
}
}

View File

@ -0,0 +1,398 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon.ProjectX
{
[DebuggerDisplay("Weapon Name={Name}")]
public class Weapon : ILoadable, ISaveable
{
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
[BinaryMember(Order = 1)] public WeaponVersion Version { get; set; }
[BinaryMember(Order = 2)] public long Checksum { get; set; }
[BinaryMember(Order = 3)] public int TableRow { get; set; }
[BinaryMember(Order = 4)] public bool Remembered { get; set; }
[BinaryMember(Order = 5)] public bool UsableInCavern { get; set; }
[BinaryMember(Order = 6)] public int Shots { get; set; }
[BinaryMember(Order = 7)] public bool ShotEndsTurn { get; set; }
[BinaryMember(Order = 8)] public int RetreatTime { get; set; }
[BinaryMember(Order = 9)] public int Unknown1 { get; set; }
[BinaryMember(Order = 10)] public int CrateChance { get; set; }
[BinaryMember(Order = 11)] public int CrateCount { get; set; }
[BinaryMember(Order = 12)] public int Unknown2 { get; set; }
[BinaryMember(Order = 13)] public WeaponActivation Activation { get; set; }
[BinaryMember(Order = 14)] public int NotUsed { get; set; }
[BinaryMember(Order = 15)] public int ThrowHerdCount { get; set; }
[BinaryMember(Order = 16)] public int AirstrikeSubtype { get; set; }
[BinaryMember(Order = 17)] public WeaponSpacebarAction SpacebarAction { get; set; }
[BinaryMember(Order = 18)] public WeaponCrosshairAction CrosshairAction { get; set; }
[BinaryMember(Order = 19)] public WeaponThrowAction ThrowAction { get; set; }
[BinaryMember(Order = 20)] public IStyle? Style { get; set; }
[BinaryMember(Order = 21)] public bool AmmunitionOverride { get; set; }
[BinaryMember(Order = 22)] public int Ammunition { get; set; }
[BinaryMember(Order = 23)] public int Unknown3 { get; set; }
[BinaryMember(Order = 24)] public int WeaponSprite { get; set; }
[BinaryMember(Order = 25)] public string NameLong { get; set; } = String.Empty;
[BinaryMember(Order = 26)] public string Name { get; set; } = String.Empty;
[BinaryMember(Order = 27)] public string GridImageFile { get; set; } = String.Empty;
[BinaryMember(Order = 28)] public string GfxDirectoryFile { get; set; } = String.Empty;
[BinaryMember(Order = 29)] public string[] SpriteNames { get; } = new string[5];
[BinaryMember(Order = 30)] public bool DelayOverride { get; set; }
[BinaryMember(Order = 31)] public int Delay { get; set; }
[BinaryMember(Order = 32)] public bool UseLibrary { get; set; }
[BinaryMember(Order = 33)] public string LibraryName { get; set; } = String.Empty;
[BinaryMember(Order = 34)] public string LibraryWeaponName { get; set; } = String.Empty;
[BinaryMember(Order = 35)] public string AimSpriteEven { get; set; } = String.Empty;
[BinaryMember(Order = 36)] public string AimSpriteUphill { get; set; } = String.Empty;
[BinaryMember(Order = 37)] public string AimSpriteDownhill { get; set; } = String.Empty;
[BinaryMember(Order = 38)] public string PickSpriteEven { get; set; } = String.Empty;
[BinaryMember(Order = 39)] public string PickSpriteUphill { get; set; } = String.Empty;
[BinaryMember(Order = 40)] public string PickSpriteDownhill { get; set; } = String.Empty;
[BinaryMember(Order = 41)] public string FireSpriteEven { get; set; } = String.Empty;
[BinaryMember(Order = 42)] public string FireSpriteUphill { get; set; } = String.Empty;
[BinaryMember(Order = 43)] public string FireSpriteDownhill { get; set; } = String.Empty;
[BinaryMember(Order = 44)] public bool AimSpriteOverride { get; set; }
[BinaryMember(Order = 45)] public bool PickSpriteOverride { get; set; }
[BinaryMember(Order = 46)] public bool FireSpriteOverride { get; set; }
[BinaryMember(Order = 47)] public bool Utility { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Read the header.
long offset = reader.Position;
Version = reader.ReadEnum<WeaponVersion>(true);
Checksum = reader.ReadInt64();
// Read general settings.
TableRow = reader.ReadInt32();
Remembered = reader.ReadBoolean(BooleanCoding.Dword);
UsableInCavern = reader.ReadBoolean(BooleanCoding.Dword);
Shots = reader.ReadInt32();
ShotEndsTurn = reader.ReadBoolean(BooleanCoding.Dword);
RetreatTime = reader.ReadInt32();
Unknown1 = reader.ReadInt32();
CrateChance = reader.ReadInt32();
CrateCount = reader.ReadInt32();
Unknown2 = reader.ReadInt32();
// Read the activation and the corresponding weapon settings.
Activation = reader.ReadEnum<WeaponActivation>(false);
switch (Activation)
{
case WeaponActivation.Airstrike:
AirstrikeSubtype = reader.ReadInt32();
Style = reader.ReadObject<AirstrikeStyle>();
break;
case WeaponActivation.Crosshair:
NotUsed = reader.ReadInt32();
CrosshairAction = reader.ReadEnum<WeaponCrosshairAction>(false);
Style = CrosshairAction switch
{
WeaponCrosshairAction.Bow => reader.ReadObject<BowStyle>(),
WeaponCrosshairAction.Flamethrower => reader.ReadObject<FlamethrowerStyle>(),
WeaponCrosshairAction.Gun => reader.ReadObject<GunStyle>(),
WeaponCrosshairAction.Launcher => reader.ReadObject<LauncherStyle>(),
_ => null
};
break;
case WeaponActivation.Spacebar:
SpacebarAction = reader.ReadEnum<WeaponSpacebarAction>(false);
Style = SpacebarAction switch
{
WeaponSpacebarAction.Armageddon => reader.ReadObject<LauncherStyle>(),
WeaponSpacebarAction.BaseballBat => reader.ReadObject<BaseballBatStyle>(),
WeaponSpacebarAction.BattleAxe => reader.ReadObject<BattleAxeStyle>(),
WeaponSpacebarAction.Blowtorch => reader.ReadObject<BlowtorchStyle>(),
WeaponSpacebarAction.Dragonball => reader.ReadObject<DragonballStyle>(),
WeaponSpacebarAction.Firepunch => reader.ReadObject<FirepunchStyle>(),
WeaponSpacebarAction.Jetpack => reader.ReadObject<JetpackStyle>(),
WeaponSpacebarAction.Kamikaze => reader.ReadObject<KamikazeStyle>(),
WeaponSpacebarAction.NinjaRope => reader.ReadObject<NinjaRopeStyle>(),
WeaponSpacebarAction.NuclearTest => reader.ReadObject<NuclearTestStyle>(),
WeaponSpacebarAction.Parachute => reader.ReadObject<ParachuteStyle>(),
WeaponSpacebarAction.PneumaticDrill => reader.ReadObject<PneumaticDrillStyle>(),
WeaponSpacebarAction.Prod => reader.ReadObject<ProdStyle>(),
WeaponSpacebarAction.SuicideBomber => reader.ReadObject<SuicideBomberStyle>(),
_ => null
};
break;
case WeaponActivation.Throw:
ThrowHerdCount = reader.ReadInt32();
ThrowAction = reader.ReadEnum<WeaponThrowAction>(false);
Style = ThrowAction switch
{
WeaponThrowAction.Canister => reader.ReadObject<CanisterStyle>(),
WeaponThrowAction.Launcher => reader.ReadObject<LauncherStyle>(),
WeaponThrowAction.Mine => reader.ReadObject<MineStyle>(),
_ => null
};
break;
}
// Read additional settings.
reader.Position = offset + 468;
AmmunitionOverride = reader.ReadBoolean(BooleanCoding.Dword);
Ammunition = reader.ReadInt32();
Unknown3 = reader.ReadInt32();
WeaponSprite = reader.ReadInt32();
NameLong = reader.ReadString(StringCoding.Int32CharCount);
Name = reader.ReadString(StringCoding.Int32CharCount);
GridImageFile = reader.ReadString(StringCoding.Int32CharCount);
GfxDirectoryFile = reader.ReadString(StringCoding.Int32CharCount);
for (int i = 0; i < SpriteNames.Length; i++)
SpriteNames[i] = reader.ReadString(StringCoding.Int32CharCount);
DelayOverride = reader.ReadBoolean(BooleanCoding.Dword);
Delay = reader.ReadInt32();
UseLibrary = reader.ReadBoolean();
if (UseLibrary)
{
LibraryName = reader.ReadString(StringCoding.Int32CharCount);
LibraryWeaponName = reader.ReadString(StringCoding.Int32CharCount);
}
AimSpriteEven = reader.ReadString(StringCoding.Int32CharCount);
AimSpriteUphill = reader.ReadString(StringCoding.Int32CharCount);
AimSpriteDownhill = reader.ReadString(StringCoding.Int32CharCount);
PickSpriteEven = reader.ReadString(StringCoding.Int32CharCount);
PickSpriteUphill = reader.ReadString(StringCoding.Int32CharCount);
PickSpriteDownhill = reader.ReadString(StringCoding.Int32CharCount);
FireSpriteEven = reader.ReadString(StringCoding.Int32CharCount);
FireSpriteUphill = reader.ReadString(StringCoding.Int32CharCount);
FireSpriteDownhill = reader.ReadString(StringCoding.Int32CharCount);
AimSpriteOverride = reader.ReadBoolean();
PickSpriteOverride = reader.ReadBoolean();
FireSpriteOverride = reader.ReadBoolean();
if (Version == WeaponVersion.Version_0_8_0)
Utility = reader.ReadBoolean();
}
/// <inheritdoc/>
public void Save(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Write the header.
long offset = writer.Position;
writer.WriteEnum(Version, true);
writer.Write(Checksum);
// Write the general settings.
writer.Write(TableRow);
writer.Write(Remembered, BooleanCoding.Dword);
writer.Write(UsableInCavern, BooleanCoding.Dword);
writer.Write(Shots);
writer.Write(ShotEndsTurn, BooleanCoding.Dword);
writer.Write(RetreatTime);
writer.Write(Unknown1);
writer.Write(CrateChance);
writer.Write(CrateCount);
writer.Write(Unknown2);
// Write the activation and the corresponding weapon settings.
writer.WriteEnum(Activation, true);
switch (Activation)
{
case WeaponActivation.Airstrike:
writer.Write(AirstrikeSubtype);
writer.WriteObject(Style);
break;
case WeaponActivation.Crosshair:
writer.Write(NotUsed);
writer.WriteEnum(CrosshairAction, true);
if (CrosshairAction != WeaponCrosshairAction.None)
writer.WriteObject(Style);
break;
case WeaponActivation.Spacebar:
writer.WriteEnum(SpacebarAction, true);
switch (SpacebarAction)
{
case WeaponSpacebarAction.Armageddon:
case WeaponSpacebarAction.BaseballBat:
case WeaponSpacebarAction.BattleAxe:
case WeaponSpacebarAction.Blowtorch:
case WeaponSpacebarAction.Dragonball:
case WeaponSpacebarAction.Firepunch:
case WeaponSpacebarAction.Jetpack:
case WeaponSpacebarAction.Kamikaze:
case WeaponSpacebarAction.NinjaRope:
case WeaponSpacebarAction.NuclearTest:
case WeaponSpacebarAction.Parachute:
case WeaponSpacebarAction.PneumaticDrill:
case WeaponSpacebarAction.Prod:
case WeaponSpacebarAction.SuicideBomber:
writer.WriteObject(Style);
break;
}
break;
case WeaponActivation.Throw:
writer.Write(ThrowHerdCount);
writer.WriteEnum(ThrowAction, true);
if (ThrowAction != WeaponThrowAction.None)
writer.WriteObject(Style);
break;
}
// Write additional settings.
writer.Position = offset + 468;
writer.Write(AmmunitionOverride, BooleanCoding.Dword);
writer.Write(Ammunition);
writer.Write(Unknown3);
writer.Write(WeaponSprite);
writer.Write(NameLong, StringCoding.Int32CharCount);
writer.Write(Name, StringCoding.Int32CharCount);
writer.Write(GridImageFile, StringCoding.Int32CharCount);
writer.Write(GfxDirectoryFile, StringCoding.Int32CharCount);
writer.Write(SpriteNames, StringCoding.Int32CharCount);
writer.Write(DelayOverride, BooleanCoding.Dword);
writer.Write(Delay);
writer.Write(UseLibrary);
if (UseLibrary)
{
writer.Write(LibraryName, StringCoding.Int32CharCount);
writer.Write(LibraryWeaponName, StringCoding.Int32CharCount);
}
writer.Write(AimSpriteEven, StringCoding.Int32CharCount);
writer.Write(AimSpriteUphill, StringCoding.Int32CharCount);
writer.Write(AimSpriteDownhill, StringCoding.Int32CharCount);
writer.Write(PickSpriteEven, StringCoding.Int32CharCount);
writer.Write(PickSpriteUphill, StringCoding.Int32CharCount);
writer.Write(PickSpriteDownhill, StringCoding.Int32CharCount);
writer.Write(FireSpriteEven, StringCoding.Int32CharCount);
writer.Write(FireSpriteUphill, StringCoding.Int32CharCount);
writer.Write(FireSpriteDownhill, StringCoding.Int32CharCount);
writer.Write(AimSpriteOverride);
writer.Write(PickSpriteOverride);
writer.Write(FireSpriteOverride);
if (Version == WeaponVersion.Version_0_8_0)
writer.Write(Utility);
}
}
public enum WeaponVersion : int
{
Version_0_8_0_pre = 0x5ABBDD05,
Version_0_8_0 = 0x5ABBDD06
}
public enum WeaponActivation : int
{
None,
Crosshair,
Throw,
Airstrike,
Spacebar
}
public enum WeaponSpacebarAction : int
{
None,
Firepunch,
BaseballBat,
Dragonball,
Kamikaze,
SuicideBomber,
NinjaRope,
Bungee,
PneumaticDrill,
Prod,
Teleport,
Blowtorch,
Parachute,
Surrender,
SkipGo,
SelectWorm,
NuclearTest,
Girder,
BattleAxe,
Utility,
Freeze,
Earthquake,
ScalesOfJustice,
Jetpack,
Armageddon
}
public enum WeaponCrosshairAction : int
{
None,
Flamethrower,
Gun,
Launcher,
Bow
}
public enum WeaponThrowAction : int
{
None,
Mine,
Launcher,
Canister
}
public enum WeaponSpriteNameIndex
{
Unknown0,
Launcher,
Cluster,
Home,
Unknown4
}
}

View File

@ -0,0 +1,175 @@
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents <see cref="MapGenSettings"/> stored in a LEV file.
/// Used by WA and WWP. S. https://worms2d.info/Monochrome_map_(.bit,_.lev).
/// </summary>
public class GeneratedMap : ILoadableFile, ISaveableFile
{
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="GeneratedMap"/> class.
/// </summary>
public GeneratedMap() { }
/// <summary>
/// Initializes a new instance of the <see cref="GeneratedMap"/> 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 GeneratedMap(Stream stream) => Load(stream);
/// <summary>
/// Initializes a new instance of the <see cref="GeneratedMap"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public GeneratedMap(string fileName) => Load(fileName);
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the <see cref="MapGenSettings"/>.
/// </summary>
public MapGenSettings Settings { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
Settings = reader.ReadStruct<MapGenSettings>();
}
/// <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);
writer.WriteStruct(Settings);
}
/// <inheritdoc/>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
}
/// <summary>
/// Represents the required configuration for the land generator to create a map. This structure appears in LEV
/// files (being their only content), in BIT files (being the header) and in PNG maps stored by WA (being the data
/// of the w2lv or waLV chunks).
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct MapGenSettings
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
/// <summary>Random seed to generate the land shape (no effect in BIT files).</summary>
public int LandSeed;
/// <summary>Random seed to generate object placements.</summary>
public int ObjectSeed;
/// <summary><see langword="true"/> treats the generated map as a cavern, otherwise as an island, depending on
/// <see cref="Style"/>.</summary>
public bool Cavern;
/// <summary>Style of the land generated, dependending on <see cref="Cavern"/>.</summary>
public MapGenStyle Style;
/// <summary><see langword="true"/> to disable an indestructible border being placed around the map.</summary>
public bool NoIndiBorders;
/// <summary>Probability percentage of map objects to appear on the land, from 0-100.</summary>
public int ObjectPercentage;
/// <summary>Probability percentage of bridges to appear on the land, from 0-100.</summary>
public int BridgePercentage;
/// <summary>Height of the water in percent, from 0-99.</summary>
public int WaterLevel;
/// <summary>Version of the structure, determining the available <see cref="SoilTextureIndex"/> values in Worms
/// Armageddon.</summary>
public MapGenVersion Version;
/// <summary>Texture index determining the style of the generated map.</summary>
public MapGenSoil SoilTextureIndex;
/// <summary>Water color used for the map (deprecated, used only in Worms Armageddon 1.0).</summary>
public int WaterColor;
}
/// <summary>
/// Represents the possible land styles.
/// </summary>
public enum MapGenStyle : int
{
/// <summary>A single island or a cavern.</summary>
OneIslandOrCavern,
/// <summary>Two islands or a double-layer cavern.</summary>
TwoIslandsOrCaverns,
/// <summary>One flat island or a cavern open at the bottom.</summary>
OneFlatIslandOrCavernOpenBottom,
/// <summary>Two flat islands or a cavern open at the left or right.</summary>
TwoFlatIslandsOrCavernOpenLeftRight
}
/// <summary>
/// Represents the possible versions which can be stored in the <see cref="MapGenSettings.Version"/> field.
/// </summary>
public enum MapGenVersion : short
{
/// <summary>Game version 3.0. Last soil texture indices are 26 = Tribal, 27 = Tribal, 28 = Urban. Additionally,
/// floor and ceiling trimming is more severe.</summary>
Version_3_0_0_0 = -1,
/// <summary>Game version 3.5. Last soil texture indices are 26 = Tribal, 27 = Urban, 28 = undefined.</summary>
Version_3_5_0_0 = 0,
/// <summary>Game version 3.6.26.4. Last soil texture indices are 26 = Tools, 27 = Tribal, Urban = 28 (same as
/// in WWP).</summary>
Version_3_6_26_4 = 1
}
/// <summary>
/// Represents the possible soil styles. In case of Worms Armageddon, this list matches
/// <see cref="MapGenVersion.Version_3_6_26_4"/>.
/// </summary>
public enum MapGenSoil : short
{
ClassicBeach,
ClassicDesert,
ClassicFarm,
ClassicForest,
ClassicHell,
Art,
Cheese,
Construction,
Desert,
Dungeon,
Easter,
Forest,
Fruit,
Gulf,
Hell,
Hospital,
Jungle,
Manhattan,
Medieval,
Music,
Pirate,
Snow,
Space,
Sports,
Tentacle,
Time,
Tools,
Tribal,
Urban
}
}

View File

@ -0,0 +1,246 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.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, ISaveableFile
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
private bool _alignImgData;
// ---- 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 format version of the file.
/// </summary>
public LandDataVersion Version { get; set; }
/// <summary>
/// Gets or sets a value indicating whether image data is aligned by 4-bytes. This is the case only for WWP.
/// </summary>
public bool AlignImgData
{
get => _alignImgData;
set => _alignImgData = value;
}
/// <summary>
/// Gets or sets the size of the landscape in pixels.
/// </summary>
public Size Size { get; set; }
/// <summary>
/// Gets or sets a value indicating whether an indestructible top border will be enabled.
/// </summary>
public bool TopBorder { get; set; }
/// <summary>
/// Gets or sets the height of the water in pixels.
/// </summary>
public int WaterHeight { get; set; }
/// <summary>
/// Gets or sets an unknown value only available in newer W:A versions (apparently since 3.6.28.0).
/// </summary>
public int? Unknown { get; set; }
/// <summary>
/// Gets or sets an array of coordinates at which objects can be placed.
/// </summary>
public IList<Point> ObjectLocations { get; set; } = new List<Point>();
/// <summary>
/// Gets or sets the visual foreground image.
/// </summary>
public Img Foreground { get; set; } = new Img();
/// <summary>
/// Gets or sets the collision mask of the landscape.
/// </summary>
public Img CollisionMask { get; set; } = new Img();
/// <summary>
/// Gets or sets the visual background image.
/// </summary>
public Img Background { get; set; } = new Img();
/// <summary>
/// Gets or sets the path to the land image file.
/// </summary>
public string LandTexturePath { get; set; } = String.Empty;
/// <summary>
/// Gets or sets the path to the Water.dir file.
/// </summary>
public string WaterDirPath { get; set; } = String.Empty;
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
int readLocationCount()
{
int oldLocationCount = reader.ReadInt32();
int oldImgStart = oldLocationCount * Unsafe.SizeOf<Point>();
// Check whether the old IMG start would be invalid.
bool isNew = false;
using (reader.TemporarySeek(oldImgStart))
isNew = reader.EndOfStream || reader.ReadUInt32() != Img.Signature;
if (isNew)
{
Unknown = oldLocationCount;
return reader.ReadInt32();
}
else
{
Unknown = null;
return oldLocationCount;
}
}
Img readImage(ref bool aligned)
{
long imgStart = reader.Position;
Img img = new Img(reader.BaseStream, aligned);
// If reading the next image fails, the previous data was aligned and must be reread.
if (!aligned)
{
if (reader.ReadUInt32() == Img.Signature)
{
reader.Position -= sizeof(uint);
}
else
{
reader.Position = imgStart;
img = new Img(reader.BaseStream, true);
aligned = true;
}
}
return img;
}
// Read the header.
Version = reader.ReadEnum<LandDataVersion>(true);
int fileSize = reader.ReadInt32();
// Read the data.
Size = reader.ReadStruct<Size>();
TopBorder = reader.ReadBoolean(BooleanCoding.Dword);
WaterHeight = reader.ReadInt32();
// Read the object locations.
int locationCount = readLocationCount();
ObjectLocations = new List<Point>(locationCount);
for (int i = 0; i < locationCount; i++)
ObjectLocations.Add(reader.ReadStruct<Point>());
// Read the image data, which alignment must be detected by trial-and-error.
_alignImgData = Version == LandDataVersion.WormsWorldPartyAqua;
long foreImgLocation = reader.Position;
Foreground = readImage(ref _alignImgData);
CollisionMask = readImage(ref _alignImgData);
Background = new Img(reader.BaseStream, _alignImgData);
// Read the file paths.
LandTexturePath = reader.ReadString(StringCoding.ByteCharCount);
WaterDirPath = reader.ReadString(StringCoding.ByteCharCount);
}
/// <inheritdoc/>
public void Load(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Load(stream);
}
/// <inheritdoc/>
public void Save(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
// Write the header.
writer.WriteEnum(Version, true);
uint fileSizeOffset = writer.ReserveOffset();
// Write the data.
writer.WriteStruct(Size);
writer.Write(TopBorder, BooleanCoding.Dword);
writer.Write(WaterHeight);
if (Unknown.HasValue)
writer.Write(Unknown.Value);
// Write the possible object coordinate array.
writer.Write(ObjectLocations.Count);
for (int i = 0; i < ObjectLocations.Count; i++)
writer.WriteStruct(ObjectLocations[i]);
// Write the image data.
Foreground.Save(writer.BaseStream, _alignImgData);
CollisionMask.Save(writer.BaseStream, _alignImgData);
Background.Save(writer.BaseStream, _alignImgData);
// Write the file paths.
writer.Write(LandTexturePath, StringCoding.ByteCharCount);
writer.Write(WaterDirPath, StringCoding.ByteCharCount);
writer.SatisfyOffset(fileSizeOffset, (uint)writer.Position);
}
/// <inheritdoc/>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
}
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
/// <summary>
/// Represents the version of <see cref="LandData"/> files, encoded as the signature.
/// </summary>
public enum LandDataVersion : uint
{
/// <summary>Found in W2, WA, WWP, and OW.</summary>
Team17 = 0x1A444E4C, // "LND\x1A"
/// <summary>Found only in WWPA.</summary>
WormsWorldPartyAqua = 0x1B444E4C // "LND\x1B"
}
}

View File

@ -0,0 +1,226 @@
using System;
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents which worms are cured from being poisoned if a worm collects a health crate.
/// </summary>
public enum HealthCure : byte
{
/// <summary>Cures only the worm collecting the health crate.</summary>
Single,
/// <summary>Cures the team of the worm collecting the health crate.</summary>
Team,
/// <summary>Cures all allied teams of the worm collecting the health crate.</summary>
Allies,
/// <summary>Cures nobody.</summary>
Nobody = Byte.MaxValue
}
/// <summary>
/// Represents the types of objects which can appear on the map.
/// </summary>
[Flags]
public enum MapObjectType
{
/// <summary>Neither mines or oil drums are placed on the map.</summary>
None,
/// <summary>Only mines are placed on the map.</summary>
Mines = 1 << 0,
/// <summary>Only oil drums are placed on the map.</summary>
OilDrums = 1 << 1,
/// <summary>Both mines and oil drums are placed on the map.</summary>
Both = Mines | OilDrums
}
/// <summary>
/// Represents the possible cavern roof extension directions.
/// </summary>
public enum Roofing : byte
{
/// <summary>Does not extend the roof.</summary>
Default,
/// <summary>Extends the roof infinitely upwards.</summary>
Up,
/// <summary>Extends the roof infinitely up- and sidewards.</summary>
UpSide
}
/// <summary>
/// Gets or sets a value determining which kinds of weapons can be dropped while rolling during roping.
/// </summary>
public enum RopeRollDrops : byte
{
/// <summary>No weapons can be dropped while rolling.</summary>
None,
/// <summary>Weapons which are droppable from a rope can be dropped while rolling.</summary>
Rope,
/// <summary>Weapons which are droppable from a rope or while jumping can be dropped while rolling.</summary>
RopeJump
}
/// <summary>
/// Represents the known versions of scheme file formats.
/// </summary>
public enum SchemeVersion : byte
{
/// <summary>WA 3.0 and WWP, original format.</summary>
Version1 = 1,
/// <summary>WA 3.5 and newer, storing super weapons.</summary>
Version2 = 2,
/// <summary>WA 3.7.3 and newer, storing new options.</summary>
Version3 = 3
}
/// <summary>
/// Represents extension methods for <see cref="SchemeVersion"/> instances.
/// </summary>
public static class SchemeVersionExtensions
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Returns how many <see cref="SchemeWeapon"/> instances are stored in the <paramref name="version"/>.
/// </summary>
/// <param name="version">The <see cref="SchemeVersion"/>.</param>
/// <returns>The number of weapons stored for this version.</returns>
public static int GetWeaponCount(this SchemeVersion version) => version == SchemeVersion.Version1 ? 45 : 64;
}
/// <summary>
/// Represents the gravity simulation used in a game (as originating from RubberWorm).
/// </summary>
public enum RwGravityType : byte
{
/// <summary>No RubberWorm gravity logic is used.</summary>
None,
/// <summary>Default gravity, but affecting more objects.</summary>
Default,
/// <summary>Gravity is calculated as a constant force black hole.</summary>
BlackHoleConstant,
/// <summary>Gravity is calculated as a linear force / proportional black hole.</summary>
BlackHoleLinear
}
/// <summary>
/// Represents the known identifiers of scheme editors stored in schemes modified by them.
/// </summary>
public enum SchemeEditor : byte
{
/// <summary>Default (game editor or those that do not set a recognition byte).</summary>
None,
/// <summary>LeTotalKiller's PHP online editor.</summary>
LeTotalKiller = 0x5F,
/// <summary>SchemeEddy's Win32 editor.</summary>
SchemeEddy = 0x89
}
/// <summary>
/// Represents the effects an enabled <see cref="Scheme.SheepHeaven"/> has on the game.
/// </summary>
[Flags]
public enum SheepHeavenFlags : byte
{
/// <summary>Crates always eject a sheep when exploding.</summary>
Explode = 1 << 0,
/// <summary>Extended fuse timer on sheep weapons.</summary>
Fuse = 1 << 1,
/// <summary>Crates have higher probability to contain sheep weapons.</summary>
Odds = 1 << 2,
/// <summary>Enabled all of the sheep heaven effects.</summary>
All = Explode | Fuse | Odds
}
/// <summary>
/// Represents the possible loss of control when skimming on water.
/// </summary>
public enum SkimControlLoss : byte
{
/// <summary>Control is lost when skimming.</summary>
Lost,
/// <summary>Control is retained but the rope cannot be shot again until landing.</summary>
Kept,
/// <summary>Control is retained and the rope can be shot even before landing.</summary>
KeptWithRope
}
/// <summary>
/// Represents the possible methods of triggering skip walking to speed up the walking speed.
/// </summary>
public enum SkipWalk : byte
{
/// <summary>Skip walking is possible by right clicking during the turn.</summary>
Default,
/// <summary>Skip walking is possible by using the up and down arrow keys.</summary>
Facilitated,
/// <summary>Skip walking is prevented.</summary>
Disabled = Byte.MaxValue
}
/// <summary>
/// Represents the stockpiling mode of weapon armory between rounds.
/// </summary>
public enum Stockpiling : byte
{
/// <summary>Each round starts with the exact amount of weapons set in the scheme.</summary>
Off,
/// <summary>Weapons collected additionally to the ones set in the scheme are transfered to the next round.</summary>
On,
/// <summary>Weapons are only given out at start of first round, and not renewed in following rounds.</summary>
Anti
}
/// <summary>
/// Represents the method to determine the next turn's worm.
/// </summary>
public enum WormSelect : byte
{
/// <summary>Worms are selected in the order in which they appear in the team.</summary>
Sequential,
/// <summary>Worms are selected by the player.</summary>
Manual,
/// <summary>Worms are selected randomly.</summary>
Random
}
/// <summary>
/// Represents the event triggered when the round timer runs out.
/// </summary>
public enum SuddenDeathEvent : byte
{
/// <summary>The round ends and is drawn.</summary>
RoundEnd,
/// <summary>A nuklear test is triggered.</summary>
NuclearStrike,
/// <summary>The worms health is reduced to 1.</summary>
HealthDrop,
/// <summary>No special event is triggered and the water only rises in the rate specified in the scheme.</summary>
WaterRise
}
/// <summary>
/// Represents the objects or effects worms phase through.
/// </summary>
public enum WormPhasing : byte
{
/// <summary>Worms are affected as usual.</summary>
None,
/// <summary>Worms are not affected by other worms.</summary>
Worms,
/// <summary>Worms are not affected by other worms and weapons.</summary>
WormsWeapons,
/// <summary>Worms are not affected by other worms, weapons, and damage.</summary>
WormsWeaponsDamage
}
/// <summary>
/// Represents the possible loss of control on high speed horizontal collisions.
/// </summary>
public enum XImpactControlLoss : byte
{
/// <summary>Control is lost.</summary>
Loss,
/// <summary>Control is retained.</summary>
Kept = Byte.MaxValue
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,46 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Syroot.Worms.Armageddon
{
partial class Scheme
{
// ---- CLASSES, STRUCTS & ENUMS -------------------------------------------------------------------------------
/// <summary>
/// Represents a list of <see cref="SchemeWeapon"/> instances which can be accessed by <see cref="Weapon"/>.
/// </summary>
public class WeaponList : IReadOnlyCollection<SchemeWeapon>
{
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
private readonly SchemeWeapon[] _array = new SchemeWeapon[64];
/// <summary>
/// Gets a reference to the weapon with the given <paramref name="index"/>.
/// </summary>
/// <param name="index">The index of the weapon to access.</param>
/// <returns>A reference to the <see cref="SchemeWeapon"/>.</returns>
public ref SchemeWeapon this[int index] => ref _array[index];
/// <summary>
/// Gets a reference to the weapon with the given <paramref name="name"/>.
/// </summary>
/// <param name="name">The <see cref="Weapon"/> of the weapon to access.</param>
/// <returns>A reference to the <see cref="SchemeWeapon"/>.</returns>
public ref SchemeWeapon this[Weapon name] => ref _array[(int)name];
/// <inheritdoc/>
public int Count => _array.Length;
/// <inheritdoc/>
public IEnumerator<SchemeWeapon> GetEnumerator() => ((IEnumerable<SchemeWeapon>)_array).GetEnumerator();
internal Span<SchemeWeapon> AsSpan(int length) => _array.AsSpan(0, length);
/// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => _array.GetEnumerator();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents the configuration of a weapon in a <see cref="Scheme"/>.
/// </summary>
[DebuggerDisplay("Ammo={Ammo} Power={Power} Delay={Delay} Crates={Crates}")]
[StructLayout(LayoutKind.Sequential)]
public struct SchemeWeapon : IEquatable<SchemeWeapon>
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
/// <summary>Amount with which a team is equipped at game start. 10 and negative values represent infinity.</summary>
public sbyte Ammo;
/// <summary>Intensity of this weapon.</summary>
public byte Power;
/// <summary>Number of turns required to be taken by each team before this weapon becomes available. Negative
/// values represent infinity.</summary>
public sbyte Delay;
/// <summary>Probability of this weapon to appear in crates. Has no effect on super weapons.</summary>
public sbyte Prob;
// ---- OPERATORS ----------------------------------------------------------------------------------------------
/// <summary>
/// Returns whether two <see cref="SchemeWeapon"/> instances are equal by value.
/// </summary>
/// <param name="left">The first instance to compare.</param>
/// <param name="right">The second instance to compare.</param>
/// <returns>Whether the instances are equal.</returns>
public static bool operator ==(SchemeWeapon left, SchemeWeapon right) => left.Equals(right);
/// <summary>
/// Returns whether two <see cref="SchemeWeapon"/> instances are inequal by value.
/// </summary>
/// <param name="left">The first instance to compare.</param>
/// <param name="right">The second instance to compare.</param>
/// <returns>Whether the instances are inequal.</returns>
public static bool operator !=(SchemeWeapon left, SchemeWeapon right) => !(left == right);
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public override bool Equals(object obj) => obj is SchemeWeapon weapon && Equals(weapon);
/// <inheritdoc/>
public bool Equals(SchemeWeapon other)
=> Ammo == other.Ammo
&& Power == other.Power
&& Delay == other.Delay
&& Prob == other.Prob;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(Ammo, Power, Delay, Prob);
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(MSBuildThisFileDirectory)..\..\build.xml" />
<!-- Metadata -->
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>.NET library for loading and modifying files of Team17's Worms Armageddon.</Description>
<PackageReleaseNotes>Fix StackOverflowException when using legacy .NET versions.</PackageReleaseNotes>
<PackageTags>$(PackageTags);worms armageddon</PackageTags>
<Version>4.0.3</Version>
</PropertyGroup>
<!-- References -->
<ItemGroup>
<ProjectReference Include="..\Syroot.Worms\Syroot.Worms.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,311 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents a team stored in a <see cref="TeamContainer"/> file.
/// </summary>
public class Team : ILoadable, ISaveable
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const int _missionCount = 33;
private const int _trainingMissionCount = 6;
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets the name of the team.
/// </summary>
public string Name { get; set; } = String.Empty;
/// <summary>
/// Gets the 8 worm names.
/// </summary>
public string[] WormNames { get; } = new string[8];
/// <summary>
/// Gets or sets the AI intelligence difficulty level, from 0-5, where 0 is human-controlled.
/// </summary>
public byte CpuLevel { get; set; }
/// <summary>
/// Gets or sets the name of soundbank for the voice of team worms.
/// </summary>
public string SoundBankName { get; set; } = String.Empty;
public byte SoundBankLocation { get; set; }
/// <summary>
/// Gets or sets the name of the team fanfare.
/// </summary>
public string FanfareName { get; set; } = String.Empty;
/// <summary>
/// Gets or sets a value indicating whether the fanfare with the name stored in <see cref="FanfareName"/>
/// (<see langword="true"/>) or the player's countries' fanfare should be played (<see langword="false"/>).
/// </summary>
public byte UseCustomFanfare { get; set; }
/// <summary>
/// Gets or sets the sprite index of the team grave, -1 being a custom bitmap grave.
/// </summary>
public sbyte GraveSprite { get; set; }
/// <summary>
/// Gets or sets the file name of the team grave bitmap if it uses a custom one.
/// </summary>
public string GraveFileName { get; set; } = String.Empty;
/// <summary>
/// Gets or sets the team grave bitmap if it uses a custom one.
/// </summary>
public RawBitmap Grave { get; set; } = new RawBitmap();
/// <summary>
/// Gets or sets the team's special weapon.
/// </summary>
public TeamWeapon TeamWeapon { get; set; }
/// <summary>
/// Gets or sets the number of games lost.
/// </summary>
public int GamesLost { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games lost.
/// </summary>
public int DeathmatchesLost { get; set; }
/// <summary>
/// Gets or sets the number of games won.
/// </summary>
public int GamesWon { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games won.
/// </summary>
public int DeathmatchesWon { get; set; }
/// <summary>
/// Gets or sets the number of games drawn.
/// </summary>
public int GamesDrawn { get; set; }
/// <summary>
/// Gets or sets the number of deathmatch games drawn.
/// </summary>
public int DeathmatchesDrawn { get; set; }
/// <summary>
/// Gets or sets the number of opponent worms killed by this team.
/// </summary>
public int Kills { get; set; }
/// <summary>
/// Gets or sets the number of opponent worms killed by this team in deathmatches.
/// </summary>
public int DeathmatchKills { get; set; }
/// <summary>
/// Gets or sets the number of worms which got killed in this team.
/// </summary>
public int Deaths { get; set; }
/// <summary>
/// Gets or sets the number of worms which got killed in this team in deathmatches.
/// </summary>
public int DeathmatchDeaths { get; set; }
/// <summary>
/// Gets the array of 33 mission statuses.
/// </summary>
public TeamMissionStatus[] MissionStatuses { get; } = new TeamMissionStatus[_missionCount];
/// <summary>
/// Gets or sets the file name of the team flag.
/// </summary>
public string FlagFileName { get; set; } = String.Empty;
/// <summary>
/// Gets or sets the bitmap of the team flag.
/// </summary>
public RawBitmap Flag { get; set; } = new RawBitmap();
/// <summary>
/// Gets or sets the deathmatch rank this team reached.
/// </summary>
public byte DeathmatchRank { get; set; }
/// <summary>
/// Gets or sets the seconds the team required to finish all 6 training missions.
/// </summary>
public int[] TrainingMissionTimes { get; set; } = new int[_trainingMissionCount];
public int[] Unknown1 { get; set; } = new int[10];
/// <summary>
/// Gets or sets the medals the team achieved in all 6 training missions.
/// </summary>
public byte[] TrainingMissionMedals { get; set; } = new byte[_trainingMissionCount];
public byte[] Unknown2 { get; set; } = new byte[10];
public int[] Unknown3 { get; set; } = new int[7];
public byte Unknown4 { get; set; }
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <inheritdoc/>
public void Load(Stream stream)
{
using BinaryStream reader = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
Name = reader.ReadString(17);
for (int i = 0; i < WormNames.Length; i++)
WormNames[i] = reader.ReadString(17);
CpuLevel = reader.Read1Byte();
SoundBankName = reader.ReadString(0x20);
SoundBankLocation = reader.Read1Byte();
FanfareName = reader.ReadString(0x20);
UseCustomFanfare = reader.Read1Byte();
GraveSprite = reader.ReadSByte();
if (GraveSprite < 0)
{
GraveFileName = reader.ReadString(0x20);
Grave = new RawBitmap()
{
BitsPerPixel = 8,
Size = new Size(24, 32),
Palette = reader.ReadColors(256),
Data = reader.ReadBytes(24 * 32)
};
}
TeamWeapon = reader.ReadEnum<TeamWeapon>(true);
GamesLost = reader.ReadInt32();
DeathmatchesLost = reader.ReadInt32();
GamesWon = reader.ReadInt32();
DeathmatchesWon = reader.ReadInt32();
GamesDrawn = reader.ReadInt32();
DeathmatchesDrawn = reader.ReadInt32();
Kills = reader.ReadInt32();
DeathmatchKills = reader.ReadInt32();
Deaths = reader.ReadInt32();
DeathmatchDeaths = reader.ReadInt32();
for (int i = 0; i < _missionCount; i++)
MissionStatuses[i] = reader.ReadStruct<TeamMissionStatus>();
FlagFileName = reader.ReadString(0x20);
Flag = new RawBitmap()
{
BitsPerPixel = 8,
Size = new Size(20, 17),
Palette = reader.ReadColors(256),
Data = reader.ReadBytes(20 * 17)
};
DeathmatchRank = reader.Read1Byte();
TrainingMissionTimes = reader.ReadInt32s(_trainingMissionCount);
Unknown1 = reader.ReadInt32s(10);
TrainingMissionMedals = reader.ReadBytes(_trainingMissionCount);
Unknown2 = reader.ReadBytes(10);
Unknown3 = reader.ReadInt32s(7);
Unknown4 = reader.Read1Byte();
}
/// <inheritdoc/>
public void Save(Stream stream)
{
using BinaryStream writer = new BinaryStream(stream, encoding: Encoding.ASCII, leaveOpen: true);
writer.WriteFixedString(Name, 17);
for (int i = 0; i < WormNames.Length; i++)
writer.WriteFixedString(WormNames[i], 17);
writer.Write(CpuLevel);
writer.WriteFixedString(SoundBankName, 0x20);
writer.Write(SoundBankLocation);
writer.WriteFixedString(FanfareName, 0x20);
writer.Write(UseCustomFanfare);
writer.Write(GraveSprite);
if (GraveSprite < 0)
{
writer.WriteFixedString(GraveFileName, 0x20);
writer.WriteColors(Grave.Palette!);
writer.Write(Grave.Data);
}
writer.WriteEnum(TeamWeapon, true);
writer.Write(GamesLost);
writer.Write(DeathmatchesLost);
writer.Write(GamesWon);
writer.Write(DeathmatchesWon);
writer.Write(GamesDrawn);
writer.Write(DeathmatchesDrawn);
writer.Write(Kills);
writer.Write(DeathmatchKills);
writer.Write(Deaths);
writer.Write(DeathmatchDeaths);
for (int i = 0; i < MissionStatuses.Length; i++)
writer.WriteStruct(ref MissionStatuses[i]);
writer.WriteFixedString(FlagFileName, 0x20);
writer.WriteColors(Flag.Palette!);
writer.Write(Flag.Data);
writer.Write(DeathmatchRank);
writer.Write(TrainingMissionTimes);
writer.Write(Unknown1);
writer.Write(TrainingMissionMedals);
writer.Write(Unknown2);
writer.Write(Unknown3);
writer.Write(Unknown4);
}
}
/// <summary>
/// Represents a team's progress in a mission.
/// </summary>
[DebuggerDisplay("TeamMissionStatus Attemps={Attempts} Medal={Medal}")]
public struct TeamMissionStatus
{
// ---- FIELDS -------------------------------------------------------------------------------------------------
/// <summary>The number of attempts the team required to solve the mission.</summary>
public int Attempts;
/// <summary>The medal the team got to solve the mission.</summary>
public int Medal;
}
/// <summary>
/// Represents the special weapon of a team.
/// </summary>
public enum TeamWeapon : byte
{
/// <summary>The Flame Thrower weapon.</summary>
Flamethrower,
/// <summary>The Mole Bomb weapon.</summary>
MoleBomb,
/// <summary>The Old Woman weapon.</summary>
OldWoman,
/// <summary>The Homing Pigeon weapon.</summary>
HomingPigeon,
/// <summary>The Sheep Launcher weapon.</summary>
SheepLauncher,
/// <summary>The Mad Cow weapon.</summary>
MadCow,
/// <summary>The Holy Hand Grenade weapon.</summary>
HolyHandGrenade,
/// <summary>The Super Sheep or Aqua Sheep weapon.</summary>
SuperSheep
}
}

View File

@ -0,0 +1,156 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Syroot.BinaryData;
using Syroot.Worms.IO;
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents the list of teams and unlocked game features stored in WGT files.
/// Used by WA. S. https://worms2d.info/Team_file.
/// </summary>
public class TeamContainer : ILoadableFile, ISaveableFile
{
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
private const string _signature = "WGT"; // 0-terminated.
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> class.
/// </summary>
public TeamContainer() { }
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> 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 TeamContainer(Stream stream) => Load(stream);
/// <summary>
/// Initializes a new instance of the <see cref="TeamContainer"/> class, loading the data from the given file.
/// </summary>
/// <param name="fileName">The name of the file to load the data from.</param>
public TeamContainer(string fileName) => Load(fileName);
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
/// <summary>
/// Gets or sets a value possibly indicating a version of the file format.
/// </summary>
public byte Version { get; set; }
/// <summary>
/// Gets or sets the unlocked utilities, weapon upgrades, and game cheats.
/// </summary>
public UnlockedFeatures UnlockedFeatures { get; set; }
/// <summary>
/// Gets or sets an unknown value.
/// </summary>
public byte Unknown { get; set; }
/// <summary>
/// Gets or sets the list of <see cref="Team"/> instances stored.
/// </summary>
public IList<Team> Teams { get; set; } = new List<Team>();
// ---- 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(StringCoding.ZeroTerminated) != _signature)
throw new InvalidDataException("Invalid WGT file signature.");
Version = reader.Read1Byte(); // Really version?
// Read global settings.
byte teamCount = reader.Read1Byte();
UnlockedFeatures = reader.ReadEnum<UnlockedFeatures>(false);
Unknown = reader.Read1Byte();
// Read the teams.
Teams = new List<Team>();
while (teamCount-- > 0)
Teams.Add(reader.Load<Team>());
}
/// <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.ZeroTerminated);
writer.Write(Version);
// Write global settings.
writer.Write((byte)Teams.Count);
writer.WriteEnum(UnlockedFeatures, false);
writer.Write(Unknown);
// Write the teams.
foreach (Team team in Teams)
team.Save(writer.BaseStream);
}
/// <inheritdoc/>
public void Save(string fileName)
{
using FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.None);
Save(stream);
}
}
/// <summary>
/// Represents unlockable features of the game.
/// </summary>
[Flags]
public enum UnlockedFeatures : int
{
/// <summary>No features have been unlocked yet.</summary>
None,
/// <summary>The utility weapon Laser Sight can be configured.</summary>
UtilityLaserSight = 1 << 0,
/// <summary>The utility weapon Fast Walk can be configured.</summary>
UtilityFastWalk = 1 << 1,
/// <summary>The utility weapon Invisibility can be configured.</summary>
UtilityInvisibility = 1 << 2,
/// <summary>The utility weapon Low Gravity can be configured.</summary>
UtilityLowGravity = 1 << 3,
/// <summary>The utility weapon Jetpack can be configured.</summary>
UtilityJetpack = 1 << 4,
/// <summary>The Grenade upgrade can be enabled.</summary>
UpgradedGrenade = 1 << 8,
/// <summary>The Shotgun upgrade can be enabled.</summary>
UpgradedShotgun = 1 << 9,
/// <summary>The cluster upgrade can be enabled.</summary>
UpgradedClusters = 1 << 10,
/// <summary>The Longbow upgrade can be enabled.</summary>
UpgradedLongbow = 1 << 11,
/// <summary>The upgrade of Super Sheeps to become Aqua Sheeps can be enabled.</summary>
AquaSheep = 1 << 12,
/// <summary>Worms can have infinite health and are killable only by drowning them.</summary>
GodWorms = 1 << 16,
/// <summary>Blood effects when hitting worms can be enabled.</summary>
BloodFx = 1 << 17,
/// <summary>Every crate explodes with a sheep.</summary>
SheepHeaven = 1 << 18,
/// <summary>Map terrain can be indestructible and Full Wormage scheme is accessible.</summary>
IndestructibleAndFullWormage = 1 << 24
}
}

View File

@ -0,0 +1,152 @@
namespace Syroot.Worms.Armageddon
{
/// <summary>
/// Represents the weapons in the game.
/// </summary>
public enum Weapon
{
/// <summary>The Bazooka weapon.</summary>
Bazooka,
/// <summary>The Homing Missile weapon.</summary>
HomingMissile,
/// <summary>The Mortar weapon.</summary>
Mortar,
/// <summary>The Grenade weapon.</summary>
Grenade,
/// <summary>The Cluster Bomb weapon.</summary>
ClusterBomb,
/// <summary>The Skunk weapon.</summary>
Skunk,
/// <summary>The Petrol Bomb weapon.</summary>
PetrolBomb,
/// <summary>The Banana Bomb weapon.</summary>
BananaBomb,
/// <summary>The Handgun weapon.</summary>
Handgun,
/// <summary>The Shotgun weapon.</summary>
Shotgun,
/// <summary>The Uzi weapon.</summary>
Uzi,
/// <summary>The Minigun weapon.</summary>
Minigun,
/// <summary>The Longbow weapon.</summary>
Longbow,
/// <summary>The Airstrike weapon.</summary>
Airstrike,
/// <summary>The Napalm Strike weapon.</summary>
NapalmStrike,
/// <summary>The Mine weapon.</summary>
Mine,
/// <summary>The Firepunch weapon.</summary>
Firepunch,
/// <summary>The Dragonball weapon.</summary>
Dragonball,
/// <summary>The Kamikaze weapon.</summary>
Kamikaze,
/// <summary>The Prod weapon.</summary>
Prod,
/// <summary>The Battle Axe weapon.</summary>
BattleAxe,
/// <summary>The Blowtorch weapon.</summary>
Blowtorch,
/// <summary>The Pneumatic Drill weapon.</summary>
PneumaticDrill,
/// <summary>The Girder weapon.</summary>
Girder,
/// <summary>The Ninja Rope weapon.</summary>
NinjaRope,
/// <summary>The Parachute weapon.</summary>
Parachute,
/// <summary>The Bungee weapon.</summary>
Bungee,
/// <summary>The Teleport weapon.</summary>
Teleport,
/// <summary>The Dynamite weapon.</summary>
Dynamite,
/// <summary>The Sheep weapon.</summary>
Sheep,
/// <summary>The Baseball Bat weapon.</summary>
BaseballBat,
/// <summary>The Flame Thrower weapon.</summary>
Flamethrower,
/// <summary>The Homing Pigeon weapon.</summary>
HomingPigeon,
/// <summary>The Mad Cow weapon.</summary>
MadCow,
/// <summary>The Holy Hand Grenade weapon.</summary>
HolyHandGrenade,
/// <summary>The Old Woman weapon.</summary>
OldWoman,
/// <summary>The Sheep Launcher weapon.</summary>
SheepLauncher,
/// <summary>The Super Sheep or Aqua Sheep weapon.</summary>
SuperSheep,
/// <summary>The Mole Bomb weapon.</summary>
MoleBomb,
/// <summary>The Jetpack utility.</summary>
Jetpack,
/// <summary>The Low Gravity utility.</summary>
LowGravity,
/// <summary>The Laser Sight utility.</summary>
LaserSight,
/// <summary>The Fast Walk utility.</summary>
FastWalk,
/// <summary>The Invisibility utility.</summary>
Invisibility,
/// <summary>The Damage x2 utility.</summary>
DamageX2,
/// <summary>The Freeze super weapon.</summary>
Freeze,
/// <summary>The Super Banana Bomb super weapon.</summary>
SuperBananaBomb,
/// <summary>The Mine Strike super weapon.</summary>
MineStrike,
/// <summary>The Girder Starter Pack super weapon.</summary>
GirderStarterPack,
/// <summary>The Earthquake super weapon.</summary>
Earthquake,
/// <summary>The Scales Of Justice super weapon.</summary>
ScalesOfJustice,
/// <summary>The Ming Vase super weapon.</summary>
MingVase,
/// <summary>The Mike's Carpet Bomb super weapon.</summary>
MikesCarpetBomb,
/// <summary>The Patsy's Magic Bullet super weapon.</summary>
MagicBullet,
/// <summary>The Indian Nuclear Test super weapon.</summary>
NuclearTest,
/// <summary>The Select Worm super weapon.</summary>
SelectWorm,
/// <summary>The Salvation Army super weapon.</summary>
SalvationArmy,
/// <summary>The Mole Squadron super weapon.</summary>
MoleSquadron,
/// <summary>The MB Bomb super weapon.</summary>
MBBomb,
/// <summary>The Concrete Donkey super weapon.</summary>
ConcreteDonkey,
/// <summary>The Suicide Bomber super weapon.</summary>
SuicideBomber,
/// <summary>The Sheep Strike super weapon.</summary>
SheepStrike,
/// <summary>The Mail Strike super weapon.</summary>
MailStrike,
/// <summary>The Armageddon super weapon.</summary>
Armageddon
}
/// <summary>
/// Represents utility methods for <see cref="Weapon"/> instances.
/// </summary>
public static class WeaponTools
{
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
/// <summary>
/// Returns a value indicating whether the <paramref name="weapon"/> is handled as a super weapon.
/// </summary>
/// <param name="weapon">The <see cref="Weapon"/> to check for being a super weapon.</param>
/// <returns>Whether the weapon is a super weapon.</returns>
public static bool IsSuperWeapon(this Weapon weapon) => weapon >= Weapon.Freeze;
}
}

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