From 0900dd5f928acf9cd35e1d89fd5f46daf700c339 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 20 Feb 2026 20:53:13 +0100 Subject: [PATCH 1/5] Fix ICU error message --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ba56ace..5ad2d45a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,7 +379,7 @@ if(LIBLCF_WITH_ICU) set(LCF_SUPPORT_ICU 1) else() if(NOT WIN32) - message(FATAL_ERROR "ICU not found. Use LCF_SUPPORT_ICU=0 to disable ICU support (not recommended).") + message(FATAL_ERROR "ICU not found. Use LIBLCF_WITH_ICU=0 to disable ICU support (not recommended).") endif() message(STATUS "ICU not found. Using the system library.") From c09ec75797a45e26ab0a250c2ad40ce9c6eb4779 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 20 Feb 2026 21:10:01 +0100 Subject: [PATCH 2/5] Add Maniac Zoom Event command and maniac_image_data chunk --- generator/csv/enums_easyrpg.csv | 1 + generator/csv/fields_easyrpg.csv | 1 + src/generated/lcf/lsd/chunks.h | 2 ++ src/generated/lcf/rpg/eventcommand.h | 6 ++++-- src/generated/lcf/rpg/savepicture.h | 3 +++ src/generated/lsd_savepicture.cpp | 8 ++++++++ src/generated/rpg_savepicture.cpp | 5 +++++ 7 files changed, 24 insertions(+), 2 deletions(-) diff --git a/generator/csv/enums_easyrpg.csv b/generator/csv/enums_easyrpg.csv index c3f269fe..7c377c0c 100644 --- a/generator/csv/enums_easyrpg.csv +++ b/generator/csv/enums_easyrpg.csv @@ -37,6 +37,7 @@ EventCommand,Code,Maniac_WritePicture,3026 EventCommand,Code,Maniac_AddMoveRoute,3027 EventCommand,Code,Maniac_EditTile,3028 EventCommand,Code,Maniac_ControlTextProcessing,3029 +EventCommand,Code,Maniac_Zoom,3032 EventPage,ManiacEventInfo,action,0 EventPage,ManiacEventInfo,touched,1 EventPage,ManiacEventInfo,collision,2 diff --git a/generator/csv/fields_easyrpg.csv b/generator/csv/fields_easyrpg.csv index 98f8d278..7db0cd04 100644 --- a/generator/csv/fields_easyrpg.csv +++ b/generator/csv/fields_easyrpg.csv @@ -17,6 +17,7 @@ SavePicture,easyrpg_flip,f,Enum,0xC8,0,0,1,How to flip the picture SavePicture,easyrpg_blend_mode,f,Int32,0xC9,0,0,1,Blend mode to use for blit. See Bitmap::BlendMode SavePicture,easyrpg_type,f,Enum,0xCA,0,0,1,Type of this picture SavePicture,maniac_current_magnify_height,f,Double,0x0A,100.0,0,0,Current zoom level of picture (y direction). +SavePicture,maniac_image_data,f,Vector,0x1C,,0,0,Deflate compressed image data of a picture modified with EditPicture command SavePicture,maniac_finish_magnify_height,f,Int32,0x24,100,0,0,Final zoom level to animate picture to (y direction). SaveEasyRpgWindow,texts,f,Array,0x01,,0,0,Texts to render SaveEasyRpgWindow,width,f,Int32,0x02,0,0,0,Window width (px) diff --git a/src/generated/lcf/lsd/chunks.h b/src/generated/lcf/lsd/chunks.h index ab4e6c04..65c4d506 100644 --- a/src/generated/lcf/lsd/chunks.h +++ b/src/generated/lcf/lsd/chunks.h @@ -348,6 +348,8 @@ namespace LSD_Reader { easyrpg_type = 0xCA, /** Current zoom level of picture (y direction). */ maniac_current_magnify_height = 0x0A, + /** Deflate compressed image data of a picture modified with EditPicture command */ + maniac_image_data = 0x1C, /** Final zoom level to animate picture to (y direction). */ maniac_finish_magnify_height = 0x24 }; diff --git a/src/generated/lcf/rpg/eventcommand.h b/src/generated/lcf/rpg/eventcommand.h index 0e5ed36e..a5ac46f0 100644 --- a/src/generated/lcf/rpg/eventcommand.h +++ b/src/generated/lcf/rpg/eventcommand.h @@ -192,7 +192,8 @@ namespace rpg { Maniac_WritePicture = 3026, Maniac_AddMoveRoute = 3027, Maniac_EditTile = 3028, - Maniac_ControlTextProcessing = 3029 + Maniac_ControlTextProcessing = 3029, + Maniac_Zoom = 3032 }; static constexpr auto kCodeTags = lcf::EnumTags{ Code::END, "END", @@ -358,7 +359,8 @@ namespace rpg { Code::Maniac_WritePicture, "Maniac_WritePicture", Code::Maniac_AddMoveRoute, "Maniac_AddMoveRoute", Code::Maniac_EditTile, "Maniac_EditTile", - Code::Maniac_ControlTextProcessing, "Maniac_ControlTextProcessing" + Code::Maniac_ControlTextProcessing, "Maniac_ControlTextProcessing", + Code::Maniac_Zoom, "Maniac_Zoom" }; int32_t code = 0; diff --git a/src/generated/lcf/rpg/savepicture.h b/src/generated/lcf/rpg/savepicture.h index bb8e09e8..2285985c 100644 --- a/src/generated/lcf/rpg/savepicture.h +++ b/src/generated/lcf/rpg/savepicture.h @@ -16,6 +16,7 @@ #include #include #include +#include #include "lcf/enum_tags.h" #include "lcf/context.h" #include @@ -161,6 +162,7 @@ namespace rpg { int32_t easyrpg_blend_mode = 0; int32_t easyrpg_type = 0; double maniac_current_magnify_height = 100.0; + std::vector maniac_image_data; int32_t maniac_finish_magnify_height = 100; }; inline std::ostream& operator<<(std::ostream& os, SavePicture::Effect code) { @@ -237,6 +239,7 @@ namespace rpg { && l.easyrpg_blend_mode == r.easyrpg_blend_mode && l.easyrpg_type == r.easyrpg_type && l.maniac_current_magnify_height == r.maniac_current_magnify_height + && l.maniac_image_data == r.maniac_image_data && l.maniac_finish_magnify_height == r.maniac_finish_magnify_height; } diff --git a/src/generated/lsd_savepicture.cpp b/src/generated/lsd_savepicture.cpp index caa8d12f..073c245f 100644 --- a/src/generated/lsd_savepicture.cpp +++ b/src/generated/lsd_savepicture.cpp @@ -314,6 +314,13 @@ static TypedField static_maniac_current_magnify_height 0, 0 ); +static TypedField> static_maniac_image_data( + &rpg::SavePicture::maniac_image_data, + LSD_Reader::ChunkSavePicture::maniac_image_data, + "maniac_image_data", + 0, + 0 +); static TypedField static_maniac_finish_magnify_height( &rpg::SavePicture::maniac_finish_magnify_height, LSD_Reader::ChunkSavePicture::maniac_finish_magnify_height, @@ -367,6 +374,7 @@ Field const* Struct::fields[] = { &static_easyrpg_blend_mode, &static_easyrpg_type, &static_maniac_current_magnify_height, + &static_maniac_image_data, &static_maniac_finish_magnify_height, NULL }; diff --git a/src/generated/rpg_savepicture.cpp b/src/generated/rpg_savepicture.cpp index afa98f98..a43cb6bb 100644 --- a/src/generated/rpg_savepicture.cpp +++ b/src/generated/rpg_savepicture.cpp @@ -67,6 +67,11 @@ std::ostream& operator<<(std::ostream& os, const SavePicture& obj) { os << ", easyrpg_blend_mode="<< obj.easyrpg_blend_mode; os << ", easyrpg_type="<< obj.easyrpg_type; os << ", maniac_current_magnify_height="<< obj.maniac_current_magnify_height; + os << ", maniac_image_data="; + for (size_t i = 0; i < obj.maniac_image_data.size(); ++i) { + os << (i == 0 ? "[" : ", ") << obj.maniac_image_data[i]; + } + os << "]"; os << ", maniac_finish_magnify_height="<< obj.maniac_finish_magnify_height; os << "}"; return os; From 07342243baa26b1a560e94673a6a204263f1d2e3 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 20 Feb 2026 21:13:07 +0100 Subject: [PATCH 3/5] Add a new picture type "canvas" for pictures that were drawn on. Not really needed as the image_data chunk can be checked but helps when analyzing savegames --- generator/csv/enums_easyrpg.csv | 1 + src/generated/lcf/rpg/savepicture.h | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/generator/csv/enums_easyrpg.csv b/generator/csv/enums_easyrpg.csv index 7c377c0c..7f883b93 100644 --- a/generator/csv/enums_easyrpg.csv +++ b/generator/csv/enums_easyrpg.csv @@ -55,5 +55,6 @@ SavePicture,EasyRpgFlip,y,2 SavePicture,EasyRpgFlip,both,3 SavePicture,EasyRpgType,default,0 SavePicture,EasyRpgType,window,1 +SavePicture,EasyRpgType,canvas,2 Skill,HpType,cost,0 Skill,HpType,percent,1 diff --git a/src/generated/lcf/rpg/savepicture.h b/src/generated/lcf/rpg/savepicture.h index 2285985c..8a3ef5e4 100644 --- a/src/generated/lcf/rpg/savepicture.h +++ b/src/generated/lcf/rpg/savepicture.h @@ -97,11 +97,13 @@ namespace rpg { ); enum EasyRpgType { EasyRpgType_default = 0, - EasyRpgType_window = 1 + EasyRpgType_window = 1, + EasyRpgType_canvas = 2 }; static constexpr auto kEasyRpgTypeTags = lcf::makeEnumTags( "default", - "window" + "window", + "canvas" ); int ID = 0; From 8752b739618e8658ba517ba486681a95667bca7a Mon Sep 17 00:00:00 2001 From: Ghabry Date: Fri, 20 Feb 2026 21:16:05 +0100 Subject: [PATCH 4/5] Dump the chunk bytes when it is "corrupted" As this is forwarded to the Player log now this helps in analyzing modified chunks by Manics --- src/lcf/reader_lcf.h | 9 ++++++++- src/reader_lcf.cpp | 4 ++++ src/reader_struct_impl.h | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/lcf/reader_lcf.h b/src/lcf/reader_lcf.h index ffce0819..f1318499 100644 --- a/src/lcf/reader_lcf.h +++ b/src/lcf/reader_lcf.h @@ -190,11 +190,18 @@ class LcfReader { * In debug builds, dumps the content of the * skipped chunk to stderr. * - * @param chunk_info chunk that will be skipped. + * @param chunk_info chunk that will be skipped and dumped. * @param where name of the caller that caused the skip, for finding unknown chunks */ void Skip(const struct LcfReader::Chunk& chunk_info, const char* where); + /** + * Like Skip but only dumps the content of the skipped chunk on stderr. + * + * @chunk_Info chunk that will be skipped and dumped. + */ + void Dump(const struct LcfReader::Chunk& chunk_info); + /** * Encodes a string to UTF-8 using the set encoding * in the reader constructor. diff --git a/src/reader_lcf.cpp b/src/reader_lcf.cpp index 386c8b0a..8104276d 100644 --- a/src/reader_lcf.cpp +++ b/src/reader_lcf.cpp @@ -282,6 +282,10 @@ void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info, const char* wher Log::Debug("Skipped Chunk %02X (%" PRIu32 " byte) in lcf at %" PRIX32 " (%s)", chunk_info.ID, chunk_info.length, Tell(), where); + Dump(chunk_info); +} + +void LcfReader::Dump(const struct LcfReader::Chunk& chunk_info) { std::stringstream ss; ss << std::hex; diff --git a/src/reader_struct_impl.h b/src/reader_struct_impl.h index 87cd1317..58da11a0 100644 --- a/src/reader_struct_impl.h +++ b/src/reader_struct_impl.h @@ -81,7 +81,8 @@ void Struct::ReadLcf(S& obj, LcfReader& stream) { if (bytes_read != chunk_info.length) { Log::Warning("%s: Corrupted Chunk 0x%02" PRIx32 " (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s : Read %" PRIu32 " bytes!", Struct::name, chunk_info.ID, chunk_info.length, off, it->second->name, bytes_read); - stream.Seek(off + chunk_info.length); + stream.Seek(off); + stream.Dump(chunk_info); } } else { From cd865d095d738f1b117cbe80c32e89fc37d6bd42 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Sat, 21 Feb 2026 18:09:21 +0100 Subject: [PATCH 5/5] Dump everything, not just the expected bytes --- src/lcf/reader_lcf.h | 4 ++-- src/reader_lcf.cpp | 6 +++--- src/reader_struct_impl.h | 5 ++++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lcf/reader_lcf.h b/src/lcf/reader_lcf.h index f1318499..d1914fd5 100644 --- a/src/lcf/reader_lcf.h +++ b/src/lcf/reader_lcf.h @@ -198,9 +198,9 @@ class LcfReader { /** * Like Skip but only dumps the content of the skipped chunk on stderr. * - * @chunk_Info chunk that will be skipped and dumped. + * @param length how many bytes to dump */ - void Dump(const struct LcfReader::Chunk& chunk_info); + void Dump(uint32_t length); /** * Encodes a string to UTF-8 using the set encoding diff --git a/src/reader_lcf.cpp b/src/reader_lcf.cpp index 8104276d..8991f388 100644 --- a/src/reader_lcf.cpp +++ b/src/reader_lcf.cpp @@ -282,14 +282,14 @@ void LcfReader::Skip(const struct LcfReader::Chunk& chunk_info, const char* wher Log::Debug("Skipped Chunk %02X (%" PRIu32 " byte) in lcf at %" PRIX32 " (%s)", chunk_info.ID, chunk_info.length, Tell(), where); - Dump(chunk_info); + Dump(chunk_info.length); } -void LcfReader::Dump(const struct LcfReader::Chunk& chunk_info) { +void LcfReader::Dump(uint32_t length) { std::stringstream ss; ss << std::hex; - for (uint32_t i = 0; i < chunk_info.length; ++i) { + for (uint32_t i = 0; i < length; ++i) { uint8_t byte; LcfReader::Read(byte); ss << std::setfill('0') << std::setw(2) << (int)byte << " "; diff --git a/src/reader_struct_impl.h b/src/reader_struct_impl.h index 58da11a0..95350098 100644 --- a/src/reader_struct_impl.h +++ b/src/reader_struct_impl.h @@ -15,6 +15,7 @@ #include "lcf/lmt/reader.h" #include "lcf/lmu/reader.h" #include "lcf/lsd/reader.h" +#include "lcf/reader_lcf.h" #include "reader_struct.h" #include "lcf/rpg/save.h" #include "log.h" @@ -82,7 +83,9 @@ void Struct::ReadLcf(S& obj, LcfReader& stream) { Log::Warning("%s: Corrupted Chunk 0x%02" PRIx32 " (size: %" PRIu32 ", pos: 0x%" PRIx32 "): %s : Read %" PRIu32 " bytes!", Struct::name, chunk_info.ID, chunk_info.length, off, it->second->name, bytes_read); stream.Seek(off); - stream.Dump(chunk_info); + stream.Dump(bytes_read); + + stream.Seek(off + chunk_info.length); } } else {