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

@@ -2,13 +2,12 @@
<?xml-stylesheet href="dialog.xsl" type="text/xsl"?> <?xml-stylesheet href="dialog.xsl" type="text/xsl"?>
<dialog skin='light' defbtn='okay' debug='true'> <dialog skin='light' defbtn='okay' debug='true'>
<field name='name' top='34' left='351' width='125' height='32'>Scenario name</field> <field name='name' top='34' left='351' width='125' height='32'>Scenario name</field>
<field name='file' top='96' left='351' width='125' height='16'>filename</field> <field name='author' top='96' left='351' width='125' height='16'>Your name</field>
<button name='okay' type='regular' top='205' left='424'>OK</button> <button name='okay' type='regular' top='205' left='424'>OK</button>
<text size='large' top='6' left='50' width='194' height='14'>Create a new scenario:</text> <text size='large' top='6' left='50' width='194' height='14'>Create a new scenario:</text>
<text top='76' left='52' width='292' height='56'> <text top='76' left='52' width='292' height='56'>
What is the file name for your new scenario? What is your name, for crediting purposes? <br/>
(max. length 8 characters, letters only) <br/> This will be stored in the scenario but cannot easily be changed later.
Examples: thorham, dragonq
</text> </text>
<text top='32' left='52' width='292' height='40'> <text top='32' left='52' width='292' height='40'>
What is the name of your new scenario? What is the name of your new scenario?

View File

@@ -222,6 +222,15 @@
<reference key="NSOnImage" ref="229763992"/> <reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/> <reference key="NSMixedImage" ref="909111550"/>
</object> </object>
<object class="NSMenuItem" id="1044668105">
<reference key="NSMenu" ref="720053764"/>
<string key="NSTitle">Save as…</string>
<string key="NSKeyEquiv">S</string>
<int key="NSKeyEquivModMask">1048576</int>
<int key="NSMnemonicLoc">2147483647</int>
<reference key="NSOnImage" ref="229763992"/>
<reference key="NSMixedImage" ref="909111550"/>
</object>
<object class="NSMenuItem" id="579971712"> <object class="NSMenuItem" id="579971712">
<reference key="NSMenu" ref="720053764"/> <reference key="NSMenu" ref="720053764"/>
<string key="NSTitle">Revert to Saved</string> <string key="NSTitle">Revert to Saved</string>
@@ -1026,6 +1035,7 @@
<reference ref="776162233"/> <reference ref="776162233"/>
<reference ref="425164168"/> <reference ref="425164168"/>
<reference ref="579971712"/> <reference ref="579971712"/>
<reference ref="1044668105"/>
</array> </array>
<reference key="parent" ref="379814623"/> <reference key="parent" ref="379814623"/>
</object> </object>
@@ -1620,6 +1630,11 @@
<reference key="object" ref="368560496"/> <reference key="object" ref="368560496"/>
<reference key="parent" ref="399390342"/> <reference key="parent" ref="399390342"/>
</object> </object>
<object class="IBObjectRecord">
<int key="objectID">890</int>
<reference key="object" ref="1044668105"/>
<reference key="parent" ref="720053764"/>
</object>
</array> </array>
</object> </object>
<dictionary class="NSMutableDictionary" key="flattenedProperties"> <dictionary class="NSMutableDictionary" key="flattenedProperties">
@@ -1728,12 +1743,13 @@
<string key="887.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="887.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="888.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="888.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="889.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="889.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
<string key="890.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
</dictionary> </dictionary>
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
<nil key="activeLocalization"/> <nil key="activeLocalization"/>
<dictionary class="NSMutableDictionary" key="localizations"/> <dictionary class="NSMutableDictionary" key="localizations"/>
<nil key="sourceID"/> <nil key="sourceID"/>
<int key="maxID">889</int> <int key="maxID">890</int>
</object> </object>
<object class="IBClassDescriber" key="IBDocument.Classes"/> <object class="IBClassDescriber" key="IBDocument.Classes"/>
<int key="IBDocument.localizationMode">0</int> <int key="IBDocument.localizationMode">0</int>

View File

@@ -68,6 +68,7 @@ BEGIN
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "Close Scenario\tCtrl+W", IDM_FILE_CLOSE MENUITEM "Close Scenario\tCtrl+W", IDM_FILE_CLOSE
MENUITEM "&Save Scenario\tCtrl+S", IDM_FILE_SAVE MENUITEM "&Save Scenario\tCtrl+S", IDM_FILE_SAVE
MENUITEM "Save &As\tCtrl+Shift+S", IDM_FILE_SAVE_AS
MENUITEM "Revert to Saved", IDM_FILE_REVERT MENUITEM "Revert to Saved", IDM_FILE_REVERT
MENUITEM SEPARATOR MENUITEM SEPARATOR
MENUITEM "&Quit\tCtrl+Q", IDM_FILE_QUIT MENUITEM "&Quit\tCtrl+Q", IDM_FILE_QUIT

View File

@@ -68,6 +68,7 @@
#define IDM_SCEN_CUSTOM_PICS 163 #define IDM_SCEN_CUSTOM_PICS 163
#define IDM_SCEN_CUSTOM_SHEETS 164 #define IDM_SCEN_CUSTOM_SHEETS 164
#define IDM_SCEN_CUSTOM_SNDS 165 #define IDM_SCEN_CUSTOM_SNDS 165
#define IDM_FILE_SAVE_AS 166
// Next default values for new objects // Next default values for new objects
// //
@@ -76,6 +77,6 @@
#define _APS_NEXT_RESOURCE_VALUE 103 #define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40014 #define _APS_NEXT_COMMAND_VALUE 40014
#define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 166 #define _APS_NEXT_SYMED_VALUE 167
#endif #endif
#endif #endif

View File

@@ -64,6 +64,7 @@ cScenario::cScenario() {
rating = 0; rating = 0;
difficulty = 0; difficulty = 0;
intro_pic = intro_mess_pic = 0; intro_pic = intro_mess_pic = 0;
adjust_diff = true;
bg_out = 10; bg_out = 10;
bg_fight = 4; bg_fight = 4;
bg_town = 13; bg_town = 13;

View File

@@ -2802,7 +2802,7 @@ bool save_check(std::string which_dlog) {
else if(choice == "cancel") else if(choice == "cancel")
return false; return false;
town->set_up_lights(); town->set_up_lights();
save_scenario(scenario.scen_file); save_scenario();
return true; return true;
} }

View File

@@ -2793,69 +2793,81 @@ void edit_scen_details() {
info_dlg.run(); info_dlg.run();
} }
static bool edit_make_scen_1_event_filter(cDialog& me, std::string, eKeyMod) { bool edit_make_scen_1(std::string& author,std::string& title,bool& grass) {
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) {
cDialog new_dlog("make-scenario1"); 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["cancel"].attachClickHandler(std::bind(&cDialog::toast, &new_dlog, false));
new_dlog.setResult(false);
new_dlog.run(); new_dlog.run();
if(!new_dlog.getResult<bool>()) return false; if(!new_dlog.accepted()) return false;
title = new_dlog["name"].getText(); 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; grass = dynamic_cast<cLed&>(new_dlog["surface"]).getState() != led_off;
return true; return true;
} }
static bool edit_make_scen_2_event_filter(cDialog& me, std::string, eKeyMod) { static bool make_scen_check_out(cDialog& me, std::string which, bool losing) {
short i,j,k; if(!losing) return true;
int w = me["out-w"].getTextAsNum(), h = me["out-h"].getTextAsNum();
i = me["out-w"].getTextAsNum(); if(w < 0 || w > 50 || h < 0 || h > 50) {
if(cre(i, 1,50,"Outdoors width must be between 1 and 50.","",&me)) return true; std::ostringstream error;
j = me["out-h"].getTextAsNum(); error << "Outdoors ";
if(cre(j, 1,50,"Outdoors height must be between 1 and 50.","",&me)) return true; if(which == "out-w")
if(cre(i * j, 1,100,"The total number of outdoor sections (width times height) must be between 1 and 100.","",&me)) return true; error << "width";
i = me["town-s"].getTextAsNum(); else if(which == "out-h")
j = me["town-m"].getTextAsNum(); error << "height";
k = me["town-l"].getTextAsNum(); error << " must be between 1 and 50.";
if(cre(i, 0,200,"Number of small towns must be between 0 and 200.","",&me)) return true; giveError(error.str(), &me);
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; return false;
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; int total = w * h;
if(total < 1 || total > 50) {
me.toast(true); 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; 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) { 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"); 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["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(); new_dlog.run();
if(!new_dlog.accepted()) return false; 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_l = new_dlog["town-l"].getTextAsNum();
town_m = new_dlog["town-m"].getTextAsNum(); town_m = new_dlog["town-m"].getTextAsNum();
town_s = new_dlog["town-s"].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; return true;
} }
@@ -2874,19 +2886,19 @@ extern eScenMode overall_mode;
bool build_scenario() { bool build_scenario() {
short width, height, lg, med, sm; short width, height, lg, med, sm;
bool default_town, grass; bool default_town, grass;
std::string filename, title; std::string author, title;
short i; short i;
cTown* warriors_grove = nullptr; cTown* warriors_grove = nullptr;
std::vector<cShop> warriors_grove_shops; std::vector<cShop> warriors_grove_shops;
if(!edit_make_scen_1(filename, title, grass)) if(!edit_make_scen_1(author, title, grass))
return false; return false;
filename += ".boes";
if(!edit_make_scen_2(width, height, lg, med, sm, default_town)) if(!edit_make_scen_2(width, height, lg, med, sm, default_town))
return false; return false;
scenario = cScenario(); scenario = cScenario();
scenario.scen_name = title; scenario.scen_name = title;
scenario.contact_info[0] = author;
scenario.default_ground = grass ? 2 : 0; scenario.default_ground = grass ? 2 : 0;
fs::path basePath = progDir/"Scenario Editor"/"Blades of Exile Base"/"bladbase.exs"; fs::path basePath = progDir/"Scenario Editor"/"Blades of Exile Base"/"bladbase.exs";
@@ -3061,7 +3073,8 @@ bool build_scenario() {
cur_town = 0; cur_town = 0;
town = scenario.towns[0]; town = scenario.towns[0];
save_scenario(progDir/filename); scenario.scen_file.clear();
save_scenario();
return true; return true;
} }

View File

@@ -19,6 +19,7 @@
#include "gzstream.h" #include "gzstream.h"
#include "tinyprint.h" #include "tinyprint.h"
#include "map_parse.hpp" #include "map_parse.hpp"
#include "winutil.hpp"
#define DONE_BUTTON_ITEM 1 #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[0] = 2;
scenario.format.prog_make_ver[1] = 0; scenario.format.prog_make_ver[1] = 0;
scenario.format.prog_make_ver[2] = 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 // Make sure it has the proper file extension
std::string fname = toFile.filename().string(); std::string fname = toFile.filename().string();
size_t dot = fname.find_last_of('.'); size_t dot = fname.find_last_of('.');
if(dot == std::string::npos || fname.substr(dot) != ".boes") { std::string ext;
if(dot != std::string::npos && fname.substr(dot) == ".exs") 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"); fname.replace(dot,4,".boes");
else fname += ".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 start_data_dump();
void scen_text_dump(); void scen_text_dump();

View File

@@ -196,6 +196,7 @@ void Handle_Update() {
restore_cursor(); restore_cursor();
} }
extern fs::path progDir;
void handle_menu_choice(eMenu item_hit) { void handle_menu_choice(eMenu item_hit) {
bool isEdit = false, isHelp = false; bool isEdit = false, isHelp = false;
std::string helpDlog; std::string helpDlog;
@@ -222,7 +223,10 @@ void handle_menu_choice(eMenu item_hit) {
} }
break; break;
case eMenu::FILE_SAVE: case eMenu::FILE_SAVE:
save_scenario(scenario.scen_file); save_scenario();
break;
case eMenu::FILE_SAVE_AS:
save_scenario(true);
break; break;
case eMenu::FILE_NEW: case eMenu::FILE_NEW:
if(build_scenario()) { if(build_scenario()) {

View File

@@ -14,7 +14,7 @@ void shut_down_menus(short mode);
enum class eMenu { enum class eMenu {
NONE, ABOUT, QUIT, FRILL, UNFRILL, 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, 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, HELP_TOC, HELP_START, HELP_TEST, HELP_DIST, HELP_CONTEST,
// Scenario menu // Scenario menu

View File

@@ -45,7 +45,7 @@ void init_menubar() {
help_menu = [[menu_bar_handle itemWithTitle: @"Help"] submenu]; help_menu = [[menu_bar_handle itemWithTitle: @"Help"] submenu];
static const eMenu file_choices[] = { 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[] = { static const eMenu edit_choices[] = {
eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE, eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE,

View File

@@ -73,7 +73,7 @@ void init_menubar() {
inited = true; inited = true;
static const eMenu file_choices[] = { 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[] = { static const eMenu edit_choices[] = {
eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE, eMenu::EDIT_UNDO, eMenu::EDIT_REDO, eMenu::NONE,