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:
2015-06-24 14:42:22 -04:00
parent 0bb34130c3
commit 2951e0228c
13 changed files with 117 additions and 67 deletions

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
void save_scenario(fs::path toFile);
void save_scenario(bool rename = false);
void start_data_dump();
void scen_text_dump();

View File

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

View File

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

View File

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

View File

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