From 5272175a2154c5509ae72309a557f54b9a015427 Mon Sep 17 00:00:00 2001 From: modeco80 Date: Mon, 8 May 2023 18:58:27 -0400 Subject: [PATCH] tools: Add jsfscramble (Jedi Starfighter cheat scrambler tool) --- src/tools/CMakeLists.txt | 9 +++-- src/tools/eupak/main.cpp | 4 +-- src/tools/jsfscramble.cpp | 69 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+), 4 deletions(-) create mode 100755 src/tools/jsfscramble.cpp diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 2e4531e..1d1b524 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -14,7 +14,12 @@ target_link_libraries(texdump PUBLIC europa ) -add_executable(paktest paktest.cpp) -target_link_libraries(paktest PUBLIC +add_executable(jsfscramble jsfscramble.cpp) +target_link_libraries(jsfscramble PUBLIC europa ) + +#add_executable(paktest paktest.cpp) +#target_link_libraries(paktest PUBLIC +# europa +# ) diff --git a/src/tools/eupak/main.cpp b/src/tools/eupak/main.cpp index dd8b13d..bdf21cb 100644 --- a/src/tools/eupak/main.cpp +++ b/src/tools/eupak/main.cpp @@ -121,7 +121,7 @@ int main(int argc, char** argv) { args.outputFile = eupak::fs::path(createParser.get("output")); if(createParser.is_used("--archive-version")) { - auto& versionStr = createParser.get("--archive-version"); + const auto& versionStr = createParser.get("--archive-version"); if(versionStr == "starfighter") { args.pakVersion = europa::structs::PakHeader::Version::Ver4; @@ -145,4 +145,4 @@ int main(int argc, char** argv) { } return 0; -} \ No newline at end of file +} diff --git a/src/tools/jsfscramble.cpp b/src/tools/jsfscramble.cpp new file mode 100755 index 0000000..9a776e3 --- /dev/null +++ b/src/tools/jsfscramble.cpp @@ -0,0 +1,69 @@ +// +// EuropaTools +// +// (C) 2021-2023 modeco80 +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +// A utility to scramble strings. + +#include +#include +#include +#include + +// Define this to enable an "interactive" mode where the scramble routine will +// dump out whatever it does to standard out. Undefine this to make it not do so. +#define INTERACTIVE + +template +inline std::string StringPrintf(std::string_view format, Args&&... args) { + char buffer[1024]; + auto len = std::snprintf(&buffer[0], sizeof(buffer) - 1, format.data(), static_cast(args)...); + if(len == -1) + return ""; + buffer[len] = '\0'; + return { buffer, static_cast(len) }; +} + +std::uint32_t swsfScramble(const std::string& code) { + // The input string needs to be processed before actually scrambling: + // - prepend "code_" to it + // - make it lowercase + auto copy = StringPrintf("code_%s", code.c_str()); + std::uint32_t tally {}; + for(auto& c : copy) + c = tolower(c); + +#ifdef INTERACTIVE + std::printf("working with string \"%s\"\n", copy.c_str()); +#endif + + // Now actually do the scramble. The algorithm is pretty simple. + for(auto* p = copy.data(); *p; ++p) { +#ifdef INTERACTIVE + std::uint32_t clone = *p; + std::printf("load character '%c' -> 0x%08x (%d)\n", *p, clone, clone); + + clone += tally * 5; + std::printf("add (0x%08x (%d) * 5) (%d) -> 0x%08x (%d)\n", tally, tally, tally * 5, clone, clone); + + tally = clone; +#else + tally = *p + (tally * 5); +#endif + } + + return tally; +} + +int main(int argc, char** argv) { + if(argc < 2) { + std::printf("usage: %s [code-string]\n", argv[0]); + return 0; + } + + auto result = swsfScramble(argv[1]); + std::printf("scrambled is: 0x%08x (%d)\n", result, result); +} \ No newline at end of file