diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 2c8916777c..9342f93d40 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -4,6 +4,7 @@ - Feature: [#18732] [Plugin] API to get the guests thoughts. - Feature: [#18744] Cheat to allow using a regular path as a queue path. - Feature: [#19023] Add Canadian French translation. +- Feature: [#19378] Add command to combine CSG1i.DAT and CSG1.DAT. - Feature: [objects#226] Port RCT1 Corkscrew Coaster train. - Feature: [objects#229] Port RCT1 go karts with helmets. - Improved: [#11473] Hot reload for plug-ins now works on macOS. diff --git a/src/openrct2/CmdlineSprite.cpp b/src/openrct2/CmdlineSprite.cpp index b67d6314ab..6f53885b1f 100644 --- a/src/openrct2/CmdlineSprite.cpp +++ b/src/openrct2/CmdlineSprite.cpp @@ -33,6 +33,8 @@ using namespace OpenRCT2::Drawing; +static int32_t CmdLineForSpriteCombine(const char** argv, int32_t argc); + class SpriteFile { public: @@ -611,6 +613,57 @@ int32_t CmdLineForSprite(const char** argv, int32_t argc) return 1; } + if (_strcmpi(argv[0], "combine") == 0) + { + return CmdLineForSpriteCombine(argv, argc); + } + fprintf(stderr, "Unknown sprite command.\n"); return 1; } + +static int32_t CmdLineForSpriteCombine(const char** argv, int32_t argc) +{ + if (argc < 4) + { + fprintf(stdout, "usage: sprite combine \n"); + return -1; + } + + const utf8* indexFile = argv[1]; + const utf8* dataFile = argv[2]; + const utf8* outputPath = argv[3]; + + auto fileHeader = OpenRCT2::FileStream(indexFile, OpenRCT2::FILE_MODE_OPEN); + auto fileData = OpenRCT2::FileStream(dataFile, OpenRCT2::FILE_MODE_OPEN); + auto fileHeaderSize = fileHeader.GetLength(); + auto fileDataSize = fileData.GetLength(); + + uint32_t numEntries = fileHeaderSize / sizeof(RCTG1Element); + + RCTG1Header header = {}; + header.num_entries = numEntries; + header.total_size = fileDataSize; + OpenRCT2::FileStream outputStream(outputPath, OpenRCT2::FILE_MODE_WRITE); + + outputStream.Write(&header, sizeof(RCTG1Header)); + auto g1Elements32 = std::make_unique(numEntries); + fileHeader.Read(g1Elements32.get(), numEntries * sizeof(RCTG1Element)); + for (uint32_t i = 0; i < numEntries; i++) + { + // RCT1 used zoomed offsets that counted from the beginning of the file, rather than from the current sprite. + if (g1Elements32[i].flags & G1_FLAG_HAS_ZOOM_SPRITE) + { + g1Elements32[i].zoomed_offset = i - g1Elements32[i].zoomed_offset; + } + + outputStream.Write(&g1Elements32[i], sizeof(RCTG1Element)); + } + + std::vector data; + data.resize(fileDataSize); + fileData.Read(data.data(), fileDataSize); + outputStream.Write(data.data(), fileDataSize); + + return 1; +} diff --git a/src/openrct2/cmdline/SpriteCommands.cpp b/src/openrct2/cmdline/SpriteCommands.cpp index 2ec38a727a..b2889b83b3 100644 --- a/src/openrct2/cmdline/SpriteCommands.cpp +++ b/src/openrct2/cmdline/SpriteCommands.cpp @@ -36,6 +36,7 @@ const CommandLineCommand CommandLine::SpriteCommands[] // Main commands DefineCommand("append", " [x_offset y_offset]", SpriteOptions, HandleSprite), DefineCommand("build", " [silent]", SpriteOptions, HandleSprite), + DefineCommand("combine", " ", SpriteOptions, HandleSprite), DefineCommand("create", "", SpriteOptions, HandleSprite), DefineCommand("details", " [idx]", SpriteOptions, HandleSprite), DefineCommand("export", " ", SpriteOptions, HandleSprite),