From 6fc55ed311c3045230496de98069b80aa874926f Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Sun, 26 Jan 2025 11:56:57 -0600 Subject: [PATCH] Fix multiple inconsistencies when saving (#550) * debug_leave_town use same logic as normal town exit. fix #549 * Standardize all save party code paths Fix #480 Fix #204 Fix #267 * remove file_in_mem now that it is redundant * Print message when save file not chosen --- src/fileio/fileio.hpp | 2 +- src/fileio/fileio_party.cpp | 23 +++++++++++++------ src/game/boe.actions.cpp | 43 +++++++++++++---------------------- src/game/boe.actions.hpp | 2 +- src/game/boe.main.cpp | 10 ++++---- src/game/boe.town.cpp | 6 ++--- src/game/boe.town.hpp | 2 +- src/pcedit/pc.action.cpp | 3 +-- src/pcedit/pc.appleevents.mm | 2 -- src/pcedit/pc.graphics.cpp | 15 ++++++------ src/pcedit/pc.main.cpp | 16 +++++-------- src/pcedit/pc.menus.linux.cpp | 11 +++++---- src/pcedit/pc.menus.mac.mm | 3 +-- src/pcedit/pc.menus.win.cpp | 3 +-- 14 files changed, 64 insertions(+), 77 deletions(-) diff --git a/src/fileio/fileio.hpp b/src/fileio/fileio.hpp index 3eee5bfa..1ea9f448 100644 --- a/src/fileio/fileio.hpp +++ b/src/fileio/fileio.hpp @@ -28,7 +28,7 @@ fs::path nav_get_or_decode_party(); fs::path nav_put_or_temp_party(fs::path def = ""); bool load_party(fs::path file_to_load, cUniverse& univ); -bool save_party(fs::path dest_file, const cUniverse& univ); +bool save_party(cUniverse& univ, bool save_as = false); void init_directories(const char* exec_path); diff --git a/src/fileio/fileio_party.cpp b/src/fileio/fileio_party.cpp index c85c1a18..3cf8b160 100644 --- a/src/fileio/fileio_party.cpp +++ b/src/fileio/fileio_party.cpp @@ -437,18 +437,17 @@ bool load_party_v2(fs::path file_to_load, cUniverse& real_univ){ } else showWarning("There was an error loading the party custom graphics."); } + univ.file = file_to_load; real_univ = std::move(univ); return true; } -//mode; // 0 - normal 1 - save as -bool save_party(fs::path dest_file, const cUniverse& univ) { +static bool save_party_const(const cUniverse& univ, bool save_as) { // Make sure it has the proper file extension - std::string fname = dest_file.filename().string(); - size_t dot = fname.find_last_of('.'); - if(dot == std::string::npos || fname.substr(dot) != ".exg") - fname += ".exg"; - dest_file = dest_file.parent_path()/fname; + fs::path dest_file = univ.file; + if(dest_file.extension() != ".exg"){ + dest_file += ".exg"; + } tarball partyOut; cTagFile file; @@ -543,3 +542,13 @@ bool save_party(fs::path dest_file, const cUniverse& univ) { return true; } +bool save_party(cUniverse& univ, bool save_as) { + // univ.file can be empty for prefab parties, so a file browser might be needed + // even for a regular save. + if(save_as || univ.file.empty()){ + univ.file = nav_put_or_temp_party(); + } + // A file wasn't chosen + if(univ.file.empty()) return false; + return save_party_const(univ, save_as); +} diff --git a/src/game/boe.actions.cpp b/src/game/boe.actions.cpp index 3aca9af6..1b34cf19 100644 --- a/src/game/boe.actions.cpp +++ b/src/game/boe.actions.cpp @@ -1252,9 +1252,7 @@ void handle_victory(bool force, bool record) { menu_activate(); univ.party.scen_name = ""; // should be harmless... if(!force && cChoiceDlog("congrats-save",{"cancel","save"}).show() == "save"){ - // TODO: Wait, this shouldn't be a "save as" action, should it? It should save without asking for a location. - fs::path file = nav_put_or_temp_party(); - if(!file.empty()) save_party(file, univ); + do_save(); } } @@ -1450,9 +1448,7 @@ bool handle_action(const sf::Event& event, cFramerateLimiter& fps_limiter) { case TOOLBAR_SAVE: if(overall_mode == MODE_OUTDOORS) { - save_party(univ.file, univ); - need_redraw = true; - current_switch = 6; + do_save(); break; } break; @@ -2023,14 +2019,10 @@ void debug_leave_town() { print_buf(); return; } - univ.party.end_split(0); - overall_mode = MODE_OUTDOORS; - position_party(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y,univ.party.out_loc.x,univ.party.out_loc.y); - clear_map(); - add_string_to_buf("Debug: Reunite party and leave town."); + ASB("Debug: Reunite party and leave town."); print_buf(); - update_explored(univ.party.out_loc); - redraw_screen(REFRESH_ALL); + univ.party.end_split(0); + end_town_mode(false, {0,0}, true); } void debug_kill() { @@ -2777,25 +2769,24 @@ void post_load() { } //mode; // 0 - normal 1 - save as -void do_save(short mode) { +void do_save(bool save_as) { if(overall_mode != MODE_TOWN && overall_mode != MODE_OUTDOORS && overall_mode != MODE_STARTUP) { add_string_to_buf("Save: Only while outdoors, or in town and not looking/casting.", 2); print_buf(); return; } + if(univ.party.is_in_scenario()) save_outdoor_maps(); - fs::path file = univ.file; - if(mode == 1 || file.empty()) - file = nav_put_or_temp_party(file); - bool saved = false; - if(!file.empty()) { - univ.file = file; - saved = save_party(univ.file, univ); - } - if(saved) + if(save_party(univ, save_as)){ add_string_to_buf("Save: Game saved"); - + }else{ + add_string_to_buf("Save: Save not completed"); + } + + // Cancel switching PC order + current_switch = 6; + pause(6); redraw_screen(REFRESH_TEXT); } @@ -3307,9 +3298,7 @@ void start_new_game(bool force) { } party_in_memory = true; if(force) return; - fs::path file = nav_put_or_temp_party(); - if(!file.empty()) save_party(file, univ); - univ.file = file; + do_save(true); } void start_tutorial() { diff --git a/src/game/boe.actions.hpp b/src/game/boe.actions.hpp index 247e9ebf..a8cede38 100644 --- a/src/game/boe.actions.hpp +++ b/src/game/boe.actions.hpp @@ -20,7 +20,7 @@ bool handle_keystroke(const sf::Event& event, cFramerateLimiter& fps_limiter); bool handle_scroll(const sf::Event& event); void do_load(); void post_load(); -void do_save(short mode); +void do_save(bool save_as = false); void do_abort(); void increase_age(); void handle_hunting(); diff --git a/src/game/boe.main.cpp b/src/game/boe.main.cpp index 3adf75fa..2265b395 100644 --- a/src/game/boe.main.cpp +++ b/src/game/boe.main.cpp @@ -1140,9 +1140,7 @@ void handle_quit_event() { std::string choice = cChoiceDlog("quit-confirm-save", {"save","quit","cancel"}).show(); if(choice == "cancel") return; if(choice == "save") { - fs::path file = nav_put_or_temp_party(); - if(file.empty()) return; - save_party(file, univ); + do_save(); } } All_Done = true; @@ -1151,7 +1149,7 @@ void handle_quit_event() { if(choice == "cancel") return; if(choice == "save") - save_party(univ.file, univ); + do_save(); } else { std::string choice = cChoiceDlog("quit-confirm-nosave", {"quit", "cancel"}).show(); if(choice == "cancel") @@ -1329,10 +1327,10 @@ void handle_menu_choice(eMenu item_hit) { do_load(); break; case eMenu::FILE_SAVE: - do_save(0); + do_save(); break; case eMenu::FILE_SAVE_AS: - do_save(1); + do_save(true); break; case eMenu::FILE_NEW: new_party(); diff --git a/src/game/boe.town.cpp b/src/game/boe.town.cpp index 3f53c2d0..de1b30a2 100644 --- a/src/game/boe.town.cpp +++ b/src/game/boe.town.cpp @@ -513,7 +513,7 @@ void start_town_mode(short which_town, short entry_dir) { } -location end_town_mode(short switching_level,location destination) { // returns new party location +location end_town_mode(bool switching_level,location destination, bool debug_leave) { // returns new party location location to_return; bool data_saved = false,combat_end = false; @@ -576,7 +576,7 @@ location end_town_mode(short switching_level,location destination) { // returns // Check for exit specials, if leaving town - if(switching_level == 0) { + if(!switching_level && !debug_leave) { to_return = univ.party.out_loc; if(is_town()) { @@ -612,7 +612,7 @@ location end_town_mode(short switching_level,location destination) { // returns } } - if(switching_level == 0) { + if(!switching_level) { overall_mode = MODE_OUTDOORS; erase_out_specials(); diff --git a/src/game/boe.town.hpp b/src/game/boe.town.hpp index 66795f4d..760015b9 100644 --- a/src/game/boe.town.hpp +++ b/src/game/boe.town.hpp @@ -4,7 +4,7 @@ void force_town_enter(short which_town,location where_start); void start_town_mode(short which_town, short entry_dir); -location end_town_mode(short switching_level,location destination); // returns new party location +location end_town_mode(bool switching_level,location destination,bool debug_leave=false); // returns new party location void handle_leave_town_specials(short town_number, short which_spec,location start_loc) ; void handle_town_specials(short town_number, bool town_dead,location start_loc) ; bool abil_exists(eItemAbil abil); diff --git a/src/pcedit/pc.action.cpp b/src/pcedit/pc.action.cpp index 16f299de..146683f3 100644 --- a/src/pcedit/pc.action.cpp +++ b/src/pcedit/pc.action.cpp @@ -16,7 +16,6 @@ extern cUniverse univ; extern sf::RenderWindow mainPtr; -extern fs::path file_in_mem; extern sf::Texture pc_gworld; short which_pc_displayed,store_pc_trait_mode,store_which_to_edit; @@ -37,7 +36,7 @@ bool handle_action(const sf::Event & event) { bool to_return = false; - if(file_in_mem.empty()) + if(univ.file.empty()) return false; for(short i = 0; i < 6; i++) diff --git a/src/pcedit/pc.appleevents.mm b/src/pcedit/pc.appleevents.mm index 31c62c02..8a0557e3 100644 --- a/src/pcedit/pc.appleevents.mm +++ b/src/pcedit/pc.appleevents.mm @@ -16,7 +16,6 @@ extern bool verify_restore_quit(std::string dlog); extern bool All_Done, party_in_scen, scen_items_loaded; extern cUniverse univ; -extern fs::path file_in_mem; @interface AppleEventHandler : NSObject -(BOOL)application:(NSApplication*) app openFile:(NSString*) file; @@ -41,7 +40,6 @@ void set_up_apple_events() { std::copy(msg.get(), msg.get() + len, std::inserter(fileName, fileName.begin())); if(load_party(fileName, univ)) { - file_in_mem = fileName; party_in_scen = !univ.party.scen_name.empty(); if(!party_in_scen) load_base_item_defs(); scen_items_loaded = true; diff --git a/src/pcedit/pc.graphics.cpp b/src/pcedit/pc.graphics.cpp index d746e734..21e0ec31 100644 --- a/src/pcedit/pc.graphics.cpp +++ b/src/pcedit/pc.graphics.cpp @@ -24,7 +24,6 @@ extern cUniverse univ; extern sf::RenderWindow mainPtr; extern sf::View mainView; extern bool party_in_scen,scen_items_loaded; -extern fs::path file_in_mem; extern short store_flags[3]; extern short current_active_pc; @@ -254,7 +253,7 @@ void draw_main_screen() { TextStyle style; style.lineHeight = 10; - if(!file_in_mem.empty()) { + if(!univ.file.empty()) { dest_rect = dest_rec; dest_rect.left = 20; dest_rect.top = dest_rect.bottom - 10; @@ -273,21 +272,21 @@ void draw_main_screen() { dest_rect.right = whole_win_rect.right - 30; //What is this for? Commenting it out has no effect. dest_rect.left += 60; dest_rect.offset(0,21); - if(!file_in_mem.empty()) + if(!univ.file.empty()) win_draw_string(mainPtr,dest_rect,"Click on character to edit it.",eTextMode::WRAP,style); else win_draw_string(mainPtr,dest_rect,"Select Open from File menu.",eTextMode::WRAP,style); - if(!file_in_mem.empty() && party_in_scen && !scen_items_loaded){ + if(!univ.file.empty() && party_in_scen && !scen_items_loaded){ dest_rect.offset(200,0); win_draw_string(mainPtr,dest_rect,"Warning: Scenario item data could not be loaded.",eTextMode::WRAP,style); dest_rect.offset(-200,0); } dest_rect.offset(0,14); - if(!file_in_mem.empty()) + if(!univ.file.empty()) win_draw_string(mainPtr,dest_rect,"Press 'I' button to identify item, and 'D' button to drop item.",eTextMode::WRAP,style); style.pointSize = 12; dest_rect.offset(0,16); - if(!file_in_mem.empty()) + if(!univ.file.empty()) win_draw_string(mainPtr,dest_rect,"Back up save file before editing it!",eTextMode::WRAP,style); style.pointSize = 10; style.font = FONT_PLAIN; @@ -327,7 +326,7 @@ void do_button_action(short /*which_pc*/,short which_button) { void draw_items() { rectangle d_from = {12,28,24,42},i_from = {12,42,24,56},dest_rect; - if(file_in_mem.empty()) // save file loaded + if(univ.file.empty()) // save file loaded return; dest_rect = item_string_rects[0][0]; @@ -380,7 +379,7 @@ void display_party() { TextStyle style; style.lineHeight = 10; - if(file_in_mem.empty()) { // what if no party loaded? + if(univ.file.empty()) { // what if no party loaded? no_party_rect=pc_info_rect; no_party_rect.top+=5; no_party_rect.left+=5; diff --git a/src/pcedit/pc.main.cpp b/src/pcedit/pc.main.cpp index 722ade55..8b8b7814 100644 --- a/src/pcedit/pc.main.cpp +++ b/src/pcedit/pc.main.cpp @@ -57,7 +57,6 @@ bool All_Done = false; bool changed_display_mode = false; sf::RenderWindow mainPtr; sf::View mainView; -fs::path file_in_mem; bool party_in_scen = false; bool scen_items_loaded = false; @@ -100,7 +99,6 @@ static void process_args(int argc, char* argv[]) { } if(!file.empty()) { if(load_party(file, univ)) { - file_in_mem = file; party_in_scen = !univ.party.scen_name.empty(); if(!party_in_scen) load_base_item_defs(); scen_items_loaded = true; @@ -277,11 +275,10 @@ void handle_menu_choice(eMenu item_hit) { cChoiceDlog("about-pced").show(); break; case eMenu::FILE_SAVE: - save_party(file_in_mem, univ); + save_party(univ); break; case eMenu::FILE_SAVE_AS: - file = nav_put_party(); - if(!file.empty()) save_party(file, univ); + save_party(univ, true); break; case eMenu::FILE_OPEN: result = verify_restore_quit("save-open"); @@ -289,10 +286,9 @@ void handle_menu_choice(eMenu item_hit) { case eMenu::FILE_REVERT: result = cChoiceDlog("save-revert", {"okay", "cancel"}).show() == "okay"; if(result) { - file = item_hit == eMenu::FILE_OPEN ? nav_get_party() : file_in_mem; + file = item_hit == eMenu::FILE_OPEN ? nav_get_party() : univ.file; if(!file.empty()) { if(load_party(file, univ)) { - file_in_mem = file; party_in_scen = !univ.party.scen_name.empty(); if(!party_in_scen) load_base_item_defs(); scen_items_loaded = true; @@ -303,7 +299,7 @@ void handle_menu_choice(eMenu item_hit) { break; case eMenu::FILE_CLOSE: if(verify_restore_quit("save-close")) - file_in_mem = ""; + univ = cUniverse(); break; case eMenu::PREFS: pick_preferences(); @@ -450,7 +446,7 @@ void handle_menu_choice(eMenu item_hit) { bool verify_restore_quit(std::string dlog) { std::string choice; - if(file_in_mem.empty()) + if(univ.file.empty()) return true; cChoiceDlog verify(dlog, {"save", "quit", "cancel"}); choice = verify.show(); @@ -458,7 +454,7 @@ bool verify_restore_quit(std::string dlog) { return false; if(choice == "quit") return true; - save_party(file_in_mem, univ); + save_party(univ); return true; } diff --git a/src/pcedit/pc.menus.linux.cpp b/src/pcedit/pc.menus.linux.cpp index c405f374..7df09fad 100644 --- a/src/pcedit/pc.menus.linux.cpp +++ b/src/pcedit/pc.menus.linux.cpp @@ -1,13 +1,14 @@ +#include +#include +#include "tools/winutil.hpp" +#include "universe/universe.hpp" #include "pc.menus.hpp" #include "pc.menu.hpp" -#include "tools/winutil.hpp" -#include -#include extern sf::RenderWindow mainPtr; extern bool party_in_scen; -extern fs::path file_in_mem; +extern cUniverse univ; std::shared_ptr menu_ptr; @@ -16,7 +17,7 @@ void init_menubar() { } void menu_activate() { - menu_ptr->update_for_editor_state(!file_in_mem.empty(), party_in_scen); + menu_ptr->update_for_editor_state(!univ.file.empty(), party_in_scen); } bool menuBarProcessEvent (sf::Event const & event) { diff --git a/src/pcedit/pc.menus.mac.mm b/src/pcedit/pc.menus.mac.mm index 24453e14..55838005 100644 --- a/src/pcedit/pc.menus.mac.mm +++ b/src/pcedit/pc.menus.mac.mm @@ -20,7 +20,6 @@ extern short menuChoiceId; using MenuHandle = NSMenu*; extern cUniverse univ; -extern fs::path file_in_mem; extern bool scen_items_loaded, party_in_scen; MenuHandle menu_bar_handle; MenuHandle apple_menu, file_menu, reg_menu, extra_menu; @@ -83,7 +82,7 @@ void init_menubar() { } void menu_activate() { - if(file_in_mem.empty()) { + if(univ.file.empty()) { for(int i = 3; i < [file_menu numberOfItems]; i++) [[file_menu itemAtIndex: i] setEnabled: NO]; [[menu_bar_handle itemWithTitle: @"Edit Party"] setEnabled: NO]; diff --git a/src/pcedit/pc.menus.win.cpp b/src/pcedit/pc.menus.win.cpp index cf11e6a9..b1cf5eb4 100644 --- a/src/pcedit/pc.menus.win.cpp +++ b/src/pcedit/pc.menus.win.cpp @@ -22,7 +22,6 @@ enum { extern sf::RenderWindow mainPtr; extern cUniverse univ; extern bool scen_items_loaded, party_in_scen; -extern fs::path file_in_mem; LONG_PTR mainProc; HMENU menuHandle = NULL; accel_table_t accel; @@ -106,7 +105,7 @@ void init_menubar() { void menu_activate() { if(menuHandle == NULL) return; HMENU file_menu = GetSubMenu(menuHandle, FILE_MENU_POS); - if(file_in_mem.empty()) { + if(univ.file.empty()) { EnableMenuItem(menuHandle, PARTY_MENU_POS, MF_BYPOSITION | MF_GRAYED); EnableMenuItem(menuHandle, SCEN_MENU_POS, MF_BYPOSITION | MF_GRAYED); for(int i = 1; i < GetMenuItemCount(file_menu) - 1; i++)