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
This commit is contained in:
2025-01-26 11:56:57 -06:00
committed by GitHub
parent 1dcc400923
commit 6fc55ed311
14 changed files with 64 additions and 77 deletions

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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);

View File

@@ -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++)

View File

@@ -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<NSApplicationDelegate>
-(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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -1,13 +1,14 @@
#include <memory>
#include <SFML/Graphics/RenderWindow.hpp>
#include "tools/winutil.hpp"
#include "universe/universe.hpp"
#include "pc.menus.hpp"
#include "pc.menu.hpp"
#include "tools/winutil.hpp"
#include <SFML/Graphics/RenderWindow.hpp>
#include <memory>
extern sf::RenderWindow mainPtr;
extern bool party_in_scen;
extern fs::path file_in_mem;
extern cUniverse univ;
std::shared_ptr<OpenBoEPCEditMenu> 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) {

View File

@@ -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];

View File

@@ -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++)