Tweak New Scenario dialog and add Save As option
- You now specify your name instead of the scenario filename in the first dialog - A file dialog pops up after the second dialog, to let you choose the filename and location - Fixed using Warrior's Grove even if you chose not to - Fixed not recognizing .EXS as a valid legacy-scenario extension and appending .boes, resulting in .EXS.boes - Adjust Difficulty scenario flag set on by default
This commit is contained in:
@@ -2802,7 +2802,7 @@ bool save_check(std::string which_dlog) {
|
||||
else if(choice == "cancel")
|
||||
return false;
|
||||
town->set_up_lights();
|
||||
save_scenario(scenario.scen_file);
|
||||
save_scenario();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -2793,69 +2793,81 @@ void edit_scen_details() {
|
||||
info_dlg.run();
|
||||
}
|
||||
|
||||
static bool edit_make_scen_1_event_filter(cDialog& me, std::string, eKeyMod) {
|
||||
short i,j;
|
||||
|
||||
std::string str = me["file"].getText();
|
||||
j = str.length();
|
||||
if(j == 0) {
|
||||
giveError("You've left the file name empty.","",&me);
|
||||
return true;
|
||||
}
|
||||
if(j > 50) {
|
||||
giveError("The file name can be at most 50 characters long.","",&me);
|
||||
return true;
|
||||
}
|
||||
for(i = 0; i < j; i++)
|
||||
if((str[i] < 97) || (str[i] > 122)) {
|
||||
giveError("The file name must consist of only lower case letters.","",&me);
|
||||
return true;
|
||||
}
|
||||
me.setResult(true);
|
||||
me.toast(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool edit_make_scen_1(std::string& filename,std::string& title,bool& grass) {
|
||||
bool edit_make_scen_1(std::string& author,std::string& title,bool& grass) {
|
||||
cDialog new_dlog("make-scenario1");
|
||||
new_dlog["okay"].attachClickHandler(edit_make_scen_1_event_filter);
|
||||
new_dlog["okay"].attachClickHandler(std::bind(&cDialog::toast, &new_dlog, true));
|
||||
new_dlog["cancel"].attachClickHandler(std::bind(&cDialog::toast, &new_dlog, false));
|
||||
new_dlog.setResult(false);
|
||||
|
||||
new_dlog.run();
|
||||
if(!new_dlog.getResult<bool>()) return false;
|
||||
if(!new_dlog.accepted()) return false;
|
||||
|
||||
title = new_dlog["name"].getText();
|
||||
filename = new_dlog["file"].getText();
|
||||
author = new_dlog["author"].getText();
|
||||
grass = dynamic_cast<cLed&>(new_dlog["surface"]).getState() != led_off;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool edit_make_scen_2_event_filter(cDialog& me, std::string, eKeyMod) {
|
||||
short i,j,k;
|
||||
|
||||
i = me["out-w"].getTextAsNum();
|
||||
if(cre(i, 1,50,"Outdoors width must be between 1 and 50.","",&me)) return true;
|
||||
j = me["out-h"].getTextAsNum();
|
||||
if(cre(j, 1,50,"Outdoors height must be between 1 and 50.","",&me)) return true;
|
||||
if(cre(i * j, 1,100,"The total number of outdoor sections (width times height) must be between 1 and 100.","",&me)) return true;
|
||||
i = me["town-s"].getTextAsNum();
|
||||
j = me["town-m"].getTextAsNum();
|
||||
k = me["town-l"].getTextAsNum();
|
||||
if(cre(i, 0,200,"Number of small towns must be between 0 and 200.","",&me)) return true;
|
||||
if(cre(j, 1,200,"Number of medium towns must be between 1 and 200. The first town (Town 0) must always be of medium size.","",&me)) return true;
|
||||
if(cre(k, 0,200,"Number of large towns must be between 0 and 200.","",&me)) return true;
|
||||
if(cre(i + j + k, 1,200,"The total number of towns must be from 1 to 200 (you must have at least 1 town).","",&me)) return true;
|
||||
|
||||
me.toast(true);
|
||||
static bool make_scen_check_out(cDialog& me, std::string which, bool losing) {
|
||||
if(!losing) return true;
|
||||
int w = me["out-w"].getTextAsNum(), h = me["out-h"].getTextAsNum();
|
||||
if(w < 0 || w > 50 || h < 0 || h > 50) {
|
||||
std::ostringstream error;
|
||||
error << "Outdoors ";
|
||||
if(which == "out-w")
|
||||
error << "width";
|
||||
else if(which == "out-h")
|
||||
error << "height";
|
||||
error << " must be between 1 and 50.";
|
||||
giveError(error.str(), &me);
|
||||
return false;
|
||||
}
|
||||
int total = w * h;
|
||||
if(total < 1 || total > 50) {
|
||||
giveError("The total number of outdoor sections (width times height) must be between 1 and 100.", &me);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool make_scen_check_towns(cDialog& me, std::string which, bool losing) {
|
||||
if(!losing) return true;
|
||||
int sm = me["town-s"].getTextAsNum(), med = me["town-m"].getTextAsNum(), lg = me["town-l"].getTextAsNum();
|
||||
if(sm < 0 || sm > 200 || med < 0 || med > 200 || lg < 0 || lg > 200) {
|
||||
std::ostringstream error;
|
||||
error << "Number of ";
|
||||
if(which == "town-s")
|
||||
error << "small";
|
||||
else if(which == "town-m")
|
||||
error << "medium";
|
||||
else if(which == "town-l")
|
||||
error << "large";
|
||||
error << " must be between 0 and 200";
|
||||
giveError(error.str(), &me);
|
||||
return false;
|
||||
}
|
||||
// TODO: Shouldn't this only be checked when exiting the dialog? At least for the case of no towns.
|
||||
int total = sm + med + lg;
|
||||
if(total < 1 || total > 200) {
|
||||
giveError("The total number of towns must be from 1 to 200 (you must have at least 1 town).", &me);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool edit_make_scen_2(short& out_w, short& out_h, short& town_l, short& town_m, short& town_s, bool& def_town) {
|
||||
cDialog new_dlog("make-scenario2");
|
||||
new_dlog["okay"].attachClickHandler(edit_make_scen_2_event_filter);
|
||||
new_dlog["okay"].attachClickHandler(std::bind(&cDialog::toast, &new_dlog, true));
|
||||
new_dlog["cancel"].attachClickHandler(std::bind(&cDialog::toast, &new_dlog, false));
|
||||
new_dlog.setResult(false);
|
||||
new_dlog.attachFocusHandlers(make_scen_check_out, {"out-w", "out-h"});
|
||||
new_dlog.attachFocusHandlers(make_scen_check_towns, {"town-s", "town-m", "town-l"});
|
||||
new_dlog["warrior-grove"].attachFocusHandler([](cDialog& me, std::string, bool losing) -> bool {
|
||||
if(losing) return true;
|
||||
if(me["town-m"].getTextAsNum() < 1) {
|
||||
giveError("Warrior's Grove replaces your first medium town. As such, you must have at least one medium town in order to use it.", &me);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
new_dlog.run();
|
||||
if(!new_dlog.accepted()) return false;
|
||||
@@ -2865,7 +2877,7 @@ bool edit_make_scen_2(short& out_w, short& out_h, short& town_l, short& town_m,
|
||||
town_l = new_dlog["town-l"].getTextAsNum();
|
||||
town_m = new_dlog["town-m"].getTextAsNum();
|
||||
town_s = new_dlog["town-s"].getTextAsNum();
|
||||
def_town = dynamic_cast<cLed&>(new_dlog["warrior-grove"]).getState();
|
||||
def_town = dynamic_cast<cLed&>(new_dlog["warrior-grove"]).getState() != led_off;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2874,19 +2886,19 @@ extern eScenMode overall_mode;
|
||||
bool build_scenario() {
|
||||
short width, height, lg, med, sm;
|
||||
bool default_town, grass;
|
||||
std::string filename, title;
|
||||
std::string author, title;
|
||||
short i;
|
||||
cTown* warriors_grove = nullptr;
|
||||
std::vector<cShop> warriors_grove_shops;
|
||||
|
||||
if(!edit_make_scen_1(filename, title, grass))
|
||||
if(!edit_make_scen_1(author, title, grass))
|
||||
return false;
|
||||
filename += ".boes";
|
||||
if(!edit_make_scen_2(width, height, lg, med, sm, default_town))
|
||||
return false;
|
||||
|
||||
scenario = cScenario();
|
||||
scenario.scen_name = title;
|
||||
scenario.contact_info[0] = author;
|
||||
scenario.default_ground = grass ? 2 : 0;
|
||||
|
||||
fs::path basePath = progDir/"Scenario Editor"/"Blades of Exile Base"/"bladbase.exs";
|
||||
@@ -3061,7 +3073,8 @@ bool build_scenario() {
|
||||
cur_town = 0;
|
||||
town = scenario.towns[0];
|
||||
|
||||
save_scenario(progDir/filename);
|
||||
scenario.scen_file.clear();
|
||||
save_scenario();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "gzstream.h"
|
||||
#include "tinyprint.h"
|
||||
#include "map_parse.hpp"
|
||||
#include "winutil.hpp"
|
||||
|
||||
#define DONE_BUTTON_ITEM 1
|
||||
|
||||
@@ -914,7 +915,16 @@ struct overrides_sheet {
|
||||
}
|
||||
};
|
||||
|
||||
void save_scenario(fs::path toFile) {
|
||||
void save_scenario(bool rename) {
|
||||
fs::path toFile = scenario.scen_file;
|
||||
if(rename || toFile.empty()) {
|
||||
fs::path def = scenario.scen_file;
|
||||
if(def.empty())
|
||||
def = progDir/"Blades of Exile Scenarios/myscenario.boes";
|
||||
toFile = nav_put_scenario(def);
|
||||
if(toFile.empty()) return;
|
||||
}
|
||||
|
||||
scenario.format.prog_make_ver[0] = 2;
|
||||
scenario.format.prog_make_ver[1] = 0;
|
||||
scenario.format.prog_make_ver[2] = 0;
|
||||
@@ -1072,8 +1082,13 @@ void save_scenario(fs::path toFile) {
|
||||
// Make sure it has the proper file extension
|
||||
std::string fname = toFile.filename().string();
|
||||
size_t dot = fname.find_last_of('.');
|
||||
if(dot == std::string::npos || fname.substr(dot) != ".boes") {
|
||||
if(dot != std::string::npos && fname.substr(dot) == ".exs")
|
||||
std::string ext;
|
||||
if(dot != std::string::npos) {
|
||||
ext = fname.substr(dot);
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
|
||||
}
|
||||
if(ext != ".boes") {
|
||||
if(ext == ".exs")
|
||||
fname.replace(dot,4,".boes");
|
||||
else fname += ".boes";
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
|
||||
void save_scenario(fs::path toFile);
|
||||
void save_scenario(bool rename = false);
|
||||
|
||||
void start_data_dump();
|
||||
void scen_text_dump();
|
||||
|
@@ -196,6 +196,7 @@ void Handle_Update() {
|
||||
restore_cursor();
|
||||
}
|
||||
|
||||
extern fs::path progDir;
|
||||
void handle_menu_choice(eMenu item_hit) {
|
||||
bool isEdit = false, isHelp = false;
|
||||
std::string helpDlog;
|
||||
@@ -222,7 +223,10 @@ void handle_menu_choice(eMenu item_hit) {
|
||||
}
|
||||
break;
|
||||
case eMenu::FILE_SAVE:
|
||||
save_scenario(scenario.scen_file);
|
||||
save_scenario();
|
||||
break;
|
||||
case eMenu::FILE_SAVE_AS:
|
||||
save_scenario(true);
|
||||
break;
|
||||
case eMenu::FILE_NEW:
|
||||
if(build_scenario()) {
|
||||
|
@@ -14,7 +14,7 @@ void shut_down_menus(short mode);
|
||||
|
||||
enum class eMenu {
|
||||
NONE, ABOUT, QUIT, FRILL, UNFRILL,
|
||||
FILE_NEW, FILE_OPEN, FILE_CLOSE, FILE_SAVE, FILE_REVERT,
|
||||
FILE_NEW, FILE_OPEN, FILE_CLOSE, FILE_SAVE, FILE_SAVE_AS, FILE_REVERT,
|
||||
EDIT_UNDO, EDIT_REDO, EDIT_CUT, EDIT_COPY, EDIT_PASTE, EDIT_DELETE, EDIT_SELECT_ALL,
|
||||
HELP_TOC, HELP_START, HELP_TEST, HELP_DIST, HELP_CONTEST,
|
||||
// Scenario menu
|
||||
|
@@ -45,7 +45,7 @@ void init_menubar() {
|
||||
help_menu = [[menu_bar_handle itemWithTitle: @"Help"] submenu];
|
||||
|
||||
static const eMenu file_choices[] = {
|
||||
eMenu::FILE_NEW, eMenu::FILE_OPEN, eMenu::NONE, eMenu::FILE_CLOSE, eMenu::FILE_SAVE, eMenu::FILE_REVERT,
|
||||
eMenu::FILE_NEW, eMenu::FILE_OPEN, eMenu::NONE, eMenu::FILE_CLOSE, eMenu::FILE_SAVE, eMenu::FILE_SAVE_AS, eMenu::FILE_REVERT,
|
||||
};
|
||||
static const eMenu edit_choices[] = {
|
||||
eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE,
|
||||
|
@@ -73,7 +73,7 @@ void init_menubar() {
|
||||
inited = true;
|
||||
|
||||
static const eMenu file_choices[] = {
|
||||
eMenu::FILE_NEW, eMenu::FILE_OPEN, eMenu::NONE, eMenu::FILE_CLOSE, eMenu::FILE_SAVE, eMenu::FILE_REVERT, eMenu::NONE, eMenu::QUIT,
|
||||
eMenu::FILE_NEW, eMenu::FILE_OPEN, eMenu::NONE, eMenu::FILE_CLOSE, eMenu::FILE_SAVE, eMenu::FILE_SAVE_AS, eMenu::FILE_REVERT, eMenu::NONE, eMenu::QUIT,
|
||||
};
|
||||
static const eMenu edit_choices[] = {
|
||||
eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE,
|
||||
|
Reference in New Issue
Block a user