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:
@@ -2,13 +2,12 @@
|
||||
<?xml-stylesheet href="dialog.xsl" type="text/xsl"?>
|
||||
<dialog skin='light' defbtn='okay' debug='true'>
|
||||
<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>
|
||||
<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'>
|
||||
What is the file name for your new scenario?
|
||||
(max. length 8 characters, letters only) <br/>
|
||||
Examples: thorham, dragonq
|
||||
What is your name, for crediting purposes? <br/>
|
||||
This will be stored in the scenario but cannot easily be changed later.
|
||||
</text>
|
||||
<text top='32' left='52' width='292' height='40'>
|
||||
What is the name of your new scenario?
|
||||
|
@@ -222,6 +222,15 @@
|
||||
<reference key="NSOnImage" ref="229763992"/>
|
||||
<reference key="NSMixedImage" ref="909111550"/>
|
||||
</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">
|
||||
<reference key="NSMenu" ref="720053764"/>
|
||||
<string key="NSTitle">Revert to Saved</string>
|
||||
@@ -1026,6 +1035,7 @@
|
||||
<reference ref="776162233"/>
|
||||
<reference ref="425164168"/>
|
||||
<reference ref="579971712"/>
|
||||
<reference ref="1044668105"/>
|
||||
</array>
|
||||
<reference key="parent" ref="379814623"/>
|
||||
</object>
|
||||
@@ -1620,6 +1630,11 @@
|
||||
<reference key="object" ref="368560496"/>
|
||||
<reference key="parent" ref="399390342"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">890</int>
|
||||
<reference key="object" ref="1044668105"/>
|
||||
<reference key="parent" ref="720053764"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -1728,12 +1743,13 @@
|
||||
<string key="887.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="890.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
</dictionary>
|
||||
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
|
||||
<nil key="activeLocalization"/>
|
||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||
<nil key="sourceID"/>
|
||||
<int key="maxID">889</int>
|
||||
<int key="maxID">890</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
|
@@ -68,6 +68,7 @@ BEGIN
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Close Scenario\tCtrl+W", IDM_FILE_CLOSE
|
||||
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 SEPARATOR
|
||||
MENUITEM "&Quit\tCtrl+Q", IDM_FILE_QUIT
|
||||
|
@@ -68,6 +68,7 @@
|
||||
#define IDM_SCEN_CUSTOM_PICS 163
|
||||
#define IDM_SCEN_CUSTOM_SHEETS 164
|
||||
#define IDM_SCEN_CUSTOM_SNDS 165
|
||||
#define IDM_FILE_SAVE_AS 166
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
@@ -76,6 +77,6 @@
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40014
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 166
|
||||
#define _APS_NEXT_SYMED_VALUE 167
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -64,6 +64,7 @@ cScenario::cScenario() {
|
||||
rating = 0;
|
||||
difficulty = 0;
|
||||
intro_pic = intro_mess_pic = 0;
|
||||
adjust_diff = true;
|
||||
bg_out = 10;
|
||||
bg_fight = 4;
|
||||
bg_town = 13;
|
||||
|
@@ -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;
|
||||
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;
|
||||
}
|
||||
|
||||
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_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