diff --git a/src/cache.cpp b/src/cache.cpp index afc411270f..4d54b1eb70 100644 --- a/src/cache.cpp +++ b/src/cache.cpp @@ -82,7 +82,7 @@ namespace { std::unordered_map> cache_tiles; // rect, flip_x, flip_y, tone, blend - using effect_key_type = std::tuple; + using effect_key_type = std::tuple; std::map> cache_effects; std::string system_name; @@ -465,6 +465,7 @@ BitmapRef Cache::Tile(StringView filename, int tile_id) { BitmapRef Cache::SpriteEffect(const BitmapRef& src_bitmap, const Rect& rect, bool flip_x, bool flip_y, const Tone& tone, const Color& blend) { const effect_key_type key { src_bitmap->GetId(), + src_bitmap->GetTransparent(), rect, flip_x, flip_y, @@ -472,6 +473,8 @@ BitmapRef Cache::SpriteEffect(const BitmapRef& src_bitmap, const Rect& rect, boo blend }; + assert(!src_bitmap->GetId().empty()); + const auto it = cache_effects.find(key); if (it == cache_effects.end() || it->second.expired()) { diff --git a/src/filesystem_zip.cpp b/src/filesystem_zip.cpp index eee40b0e36..8fab26ec17 100644 --- a/src/filesystem_zip.cpp +++ b/src/filesystem_zip.cpp @@ -83,8 +83,8 @@ ZipFilesystem::ZipFilesystem(std::string base_path, FilesystemView parent_fs, St int items = 0; while (ReadCentralDirectoryEntry(zip_is, filepath, entry, is_utf8)) { // Only consider Non-ASCII & Non-UTF8 for encoding detection - // Skip directories, files already contain the paths - if (is_utf8 || filepath.back() == '/' || Utils::StringIsAscii(filepath)) { + // Directories are skipped as most of them are usually ASCII and do not help with the detection + if (is_utf8 || filepath.back() == '/' || Utils::StringIsAscii(std::get<1>(FileFinder::GetPathAndFilename(filepath)))) { continue; } // Codepath will be only entered by Windows "compressed folder" ZIPs (uses local encoding) and diff --git a/src/game_interpreter.cpp b/src/game_interpreter.cpp index 0f4312d8f6..98b9edef57 100644 --- a/src/game_interpreter.cpp +++ b/src/game_interpreter.cpp @@ -25,6 +25,7 @@ #include #include #include "game_interpreter.h" +#include "async_handler.h" #include "audio.h" #include "dynrpg.h" #include "filefinder.h" @@ -4061,19 +4062,15 @@ bool Game_Interpreter::CommandManiacGetSaveInfo(lcf::rpg::EventCommand const& co continue; } - // When the picture exists: Data is reused and effects finish immediately - // When not: Default data is used - // New features (spritesheets etc.) are always set due to how the patch works - // We are incompatible here and only set name and spritesheet and reuse stuff like the layer + // An existing picture is overwritten + // Default data is used with the exceptions listed below Game_Pictures::ShowParams params; - auto& pic = Main_Data::game_pictures->GetPicture(pic_id); - if (pic.Exists()) { - params = pic.GetShowParams(); - } else { - params.top_trans = 100; - params.map_layer = 7; - params.battle_layer = 7; - } + params.use_transparent_color = true; + params.top_trans = 100; // Full transparent by default + params.map_layer = 7; + params.battle_layer = 7; + + // Spritesheet configured to match the FaceSet layout params.name = FileFinder::MakePath("..\\FaceSet", face_names[i]); params.spritesheet_cols = 4; params.spritesheet_rows = 4; @@ -4525,14 +4522,13 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con int operation = com.parameters[0]; - static bool was_loaded = false; // FIXME + auto load_global_save = [&]() { + Main_Data::global_save_opened = true; - if (operation == 0 || (!was_loaded && (operation == 4 || operation == 5))) { - was_loaded = true; // Load auto lgs = FileFinder::Save().OpenFile("Save.lgs"); if (!lgs) { - return true; + return; } lcf::LcfReader reader(lgs); @@ -4540,7 +4536,7 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con reader.ReadString(header, reader.ReadInt()); if (header.length() != 13 || header != "LcfGlobalSave") { Output::Debug("This is not a valid global save."); - return true; + return; } lcf::LcfReader::Chunk chunk; @@ -4565,15 +4561,18 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con reader.Skip(chunk, "CommandManiacControlGlobalSave"); } } - } - + }; - if (operation == 0 || operation == 1) { - // Open / Close (no-op) + if (operation == 0) { + // Open + load_global_save(); + } else if (operation == 1) { + // Close + Main_Data::global_save_opened = false; } else if (operation == 2 || operation == 3) { // 2: Save (write to file) // 3: Save and Close - if (!was_loaded) { + if (!Main_Data::global_save_opened) { return true; } @@ -4598,7 +4597,17 @@ bool Game_Interpreter::CommandManiacControlGlobalSave(lcf::rpg::EventCommand con writer.WriteInt(2); writer.WriteInt(Main_Data::game_variables_global->GetSize() * sizeof(int32_t)); writer.Write(Main_Data::game_variables_global->GetData()); + + AsyncHandler::SaveFilesystem(); + + if (operation == 3) { + Main_Data::global_save_opened = false; + } } else if (operation == 4 || operation == 5) { + if (!Main_Data::global_save_opened) { + load_global_save(); + } + int type = com.parameters[2]; int game_state_idx = ValueOrVariableBitfield(com.parameters[1], 0, com.parameters[3]); int global_save_idx = ValueOrVariableBitfield(com.parameters[1], 1, com.parameters[4]); diff --git a/src/main_data.cpp b/src/main_data.cpp index 86d4a8cc31..cb170499d8 100644 --- a/src/main_data.cpp +++ b/src/main_data.cpp @@ -71,6 +71,7 @@ namespace Main_Data { std::unique_ptr game_targets; std::unique_ptr game_quit; std::unique_ptr game_ineluki; + bool global_save_opened = false; std::unique_ptr game_switches_global; std::unique_ptr game_variables_global; @@ -125,6 +126,9 @@ void Main_Data::Cleanup() { game_quit.reset(); game_system.reset(); game_ineluki.reset(); + global_save_opened = false; + game_switches_global.reset(); + game_variables_global.reset(); } const std::string& Main_Data::GetDefaultProjectPath() { diff --git a/src/main_data.h b/src/main_data.h index e2d199eb96..ced8e4228f 100644 --- a/src/main_data.h +++ b/src/main_data.h @@ -58,6 +58,7 @@ namespace Main_Data { extern std::unique_ptr game_targets; extern std::unique_ptr game_quit; extern std::unique_ptr game_ineluki; + extern bool global_save_opened; extern std::unique_ptr game_switches_global; // Used by Global Save command extern std::unique_ptr game_variables_global; diff --git a/src/player.cpp b/src/player.cpp index 1cb57fe309..f78ba74e0d 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -1161,7 +1161,6 @@ void Player::LoadSavegame(const std::string& save_name, int save_id) { if (!load_on_map) { Scene::PopUntil(Scene::Title); } - Game_Map::Dispose(); Main_Data::game_switches->SetLowerLimit(lcf::Data::switches.size()); Main_Data::game_switches->SetData(std::move(save->system.switches)); @@ -1180,17 +1179,26 @@ void Player::LoadSavegame(const std::string& save_name, int save_id) { int map_id = Main_Data::game_player->GetMapId(); FileRequestAsync* map = Game_Map::RequestMap(map_id); - save_request_id = map->Bind([save=std::move(*save)](auto* request) { OnMapSaveFileReady(request, std::move(save)); }); + save_request_id = map->Bind( + [save=std::move(*save), load_on_map, save_id](auto* request) { + Game_Map::Dispose(); + + OnMapSaveFileReady(request, std::move(save)); + + if (load_on_map) { + // Increment frame counter for consistency with a normal savegame load + IncFrame(); + static_cast(Scene::instance.get())->StartFromSave(save_id); + } + } + ); Main_Data::game_system->ReloadSystemGraphic(); map->Start(); + // load_on_map is handled in the async callback if (!load_on_map) { Scene::Push(std::make_shared(save_id)); - } else { - // Increment frame counter for consistency with a normal savegame load - IncFrame(); - static_cast(Scene::instance.get())->StartFromSave(save_id); } }