New editor commands: Resize Outdoors and Import Sector
This includes the following changes (mostly related to the above): - Move loc_compare functor to location.hpp - Add reattach() function to rebind a town or outdoor section to a different scenario object. (I don't think this is strictly necessary, as the scenario reference is only used in limited situations in the game itself, not in the editor, but it's better not to keep a reference to freed memory around when importing a town or sector from another scenario, even if the reference is never accessed.) - Fix imported towns not being officially "loaded" until you explicitly use Load a New Town to reload them - Fix Choose button in Load New Sector dialog - More functions in the vector2d implementation
This commit is contained in:
43
rsrc/dialogs/resize-outdoors.xml
Normal file
43
rsrc/dialogs/resize-outdoors.xml
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='no'?>
|
||||
<?xml-stylesheet href="dialog.xsl" type="text/xsl"?>
|
||||
<dialog skin='dark' defbtn='okay'>
|
||||
<pict type='dlog' num='16' top='8' left='8'/>
|
||||
<text size='large' top='8' left='50' width='200' height='17'>Resize/Shift Outdoors</text>
|
||||
|
||||
<text top='30' left='100' width='60' height='16'>Extend top</text>
|
||||
<text name='top' framed='true' top='50' left='100' width='60' height='16'>0</text>
|
||||
<button name='top-m' type='small' top='72' left='109'>-</button>
|
||||
<button name='top-p' type='small' top='72' left='135'>+</button>
|
||||
|
||||
<text top='120' left='10' width='60' height='16'>Extend left</text>
|
||||
<text name='left' framed='true' top='140' left='10' width='60' height='16'>0</text>
|
||||
<button name='left-m' type='small' top='162' left='19'>-</button>
|
||||
<button name='left-p' type='small' top='162' left='45'>+</button>
|
||||
|
||||
<text top='120' left='190' width='70' height='16'>Extend right</text>
|
||||
<text name='right' framed='true' top='140' left='190' width='60' height='16'>0</text>
|
||||
<button name='right-m' type='small' top='162' left='199'>-</button>
|
||||
<button name='right-p' type='small' top='162' left='225'>+</button>
|
||||
|
||||
<text top='210' left='100' width='80' height='16'>Extend bottom</text>
|
||||
<text name='bottom' framed='true' top='230' left='100' width='60' height='16'>0</text>
|
||||
<button name='bottom-m' type='small' top='252' left='109'>-</button>
|
||||
<button name='bottom-p' type='small' top='252' left='135'>+</button>
|
||||
|
||||
<text framed='true' top='110' left='90' width='80' height='80'/>
|
||||
|
||||
<text top='115' left='95' width='80' height='16'>Width:</text>
|
||||
<text name='w-old' top='130' left='95' width='20' height='16'/>
|
||||
<text top='130' left='120' width='20' height='16'>--></text>
|
||||
<text name='w-new' top='130' left='145' width='20' height='16'/>
|
||||
|
||||
<text top='155' left='95' width='80' height='16'>Height:</text>
|
||||
<text name='h-old' top='170' left='95' width='20' height='16'/>
|
||||
<text top='170' left='120' width='20' height='16'>--></text>
|
||||
<text name='h-new' top='170' left='145' width='20' height='16'/>
|
||||
|
||||
<text top='30' left='270' width='200' height='16'>Sections to be deleted:</text>
|
||||
<text name='delete' framed='true' top='50' left='270' width='200' height='200'/>
|
||||
<button name='okay' type='regular' top='270' left='407'>OK</button>
|
||||
<button name='cancel' type='regular' def-key='esc' top='270' left='342'>Cancel</button>
|
||||
</dialog>
|
@@ -348,6 +348,14 @@
|
||||
<reference key="NSOnImage" ref="229763992"/>
|
||||
<reference key="NSMixedImage" ref="909111550"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="872790335">
|
||||
<reference key="NSMenu" ref="399390342"/>
|
||||
<string key="NSTitle">Resize Outdoors</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="229763992"/>
|
||||
<reference key="NSMixedImage" ref="909111550"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="610226442">
|
||||
<reference key="NSMenu" ref="399390342"/>
|
||||
<bool key="NSIsDisabled">YES</bool>
|
||||
@@ -457,6 +465,14 @@
|
||||
<reference key="NSOnImage" ref="229763992"/>
|
||||
<reference key="NSMixedImage" ref="909111550"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="327378958">
|
||||
<reference key="NSMenu" ref="399390342"/>
|
||||
<string key="NSTitle"> Import Outdoor Sector</string>
|
||||
<string key="NSKeyEquiv"/>
|
||||
<int key="NSMnemonicLoc">2147483647</int>
|
||||
<reference key="NSOnImage" ref="229763992"/>
|
||||
<reference key="NSMixedImage" ref="909111550"/>
|
||||
</object>
|
||||
<object class="NSMenuItem" id="580939217">
|
||||
<reference key="NSMenu" ref="399390342"/>
|
||||
<string key="NSTitle"> Edit Saved Item Rectangles</string>
|
||||
@@ -1267,6 +1283,8 @@
|
||||
<reference ref="963208893"/>
|
||||
<reference ref="1072664025"/>
|
||||
<reference ref="368560496"/>
|
||||
<reference ref="872790335"/>
|
||||
<reference ref="327378958"/>
|
||||
</array>
|
||||
<reference key="parent" ref="741259600"/>
|
||||
</object>
|
||||
@@ -1635,6 +1653,16 @@
|
||||
<reference key="object" ref="1044668105"/>
|
||||
<reference key="parent" ref="720053764"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">891</int>
|
||||
<reference key="object" ref="872790335"/>
|
||||
<reference key="parent" ref="399390342"/>
|
||||
</object>
|
||||
<object class="IBObjectRecord">
|
||||
<int key="objectID">892</int>
|
||||
<reference key="object" ref="327378958"/>
|
||||
<reference key="parent" ref="399390342"/>
|
||||
</object>
|
||||
</array>
|
||||
</object>
|
||||
<dictionary class="NSMutableDictionary" key="flattenedProperties">
|
||||
@@ -1744,12 +1772,14 @@
|
||||
<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>
|
||||
<string key="891.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||
<string key="892.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">890</int>
|
||||
<int key="maxID">892</int>
|
||||
</object>
|
||||
<object class="IBClassDescriber" key="IBDocument.Classes"/>
|
||||
<int key="IBDocument.localizationMode">0</int>
|
||||
|
@@ -87,6 +87,7 @@ BEGIN
|
||||
POPUP "&Scenario"
|
||||
BEGIN
|
||||
MENUITEM "&Create New Town", IDM_SCEN_NEW_TOWN
|
||||
MENUITEM "Resize Outdoors", IDM_SCEN_RESIZE_OUTDOORS
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Scenario Details", IDM_SCEN_DETAILS
|
||||
MENUITEM "Scenario Intr&o Text", IDM_SCEN_INTRO
|
||||
@@ -100,6 +101,7 @@ BEGIN
|
||||
MENUITEM " Edit Scenario &Text", IDM_SCEN_ADV_TEXT
|
||||
MENUITEM " Edit Journal Entries", IDM_SCEN_ADV_JOURNAL
|
||||
MENUITEM " &Import Town", IDM_SCEN_ADV_IMPORT_TOWN
|
||||
MENUITEM " Import Outdoor Sector", IDM_SCEN_ADV_IMPORT_OUT
|
||||
MENUITEM " Edit Saved Item &Rectangles", IDM_SCEN_ADV_SAVE_RECTS
|
||||
MENUITEM " Edit &Horses", IDM_SCEN_ADV_HORSES
|
||||
MENUITEM " Edit &Boats", IDM_SCEN_ADV_BOATS
|
||||
|
@@ -69,6 +69,8 @@
|
||||
#define IDM_SCEN_CUSTOM_SHEETS 164
|
||||
#define IDM_SCEN_CUSTOM_SNDS 165
|
||||
#define IDM_FILE_SAVE_AS 166
|
||||
#define IDM_SCEN_RESIZE_OUTDOORS 167
|
||||
#define IDM_SCEN_ADV_IMPORT_OUT 168
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
@@ -77,6 +79,6 @@
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40014
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 167
|
||||
#define _APS_NEXT_SYMED_VALUE 169
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -41,6 +41,13 @@ location loc(){
|
||||
return location();
|
||||
}
|
||||
|
||||
bool loc_compare::operator()(location a, location b) const {
|
||||
// This is just a lexicographical ordering.
|
||||
if(a.x != b.x) return a.x < b.x;
|
||||
if(a.y != b.y) return a.y < b.y;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool location::in(rectangle r){
|
||||
if(y >= r.top && y <= r.bottom && x >= r.left && x <= r.right)
|
||||
return true;
|
||||
|
@@ -28,6 +28,10 @@ struct location {
|
||||
}
|
||||
};
|
||||
|
||||
struct loc_compare {
|
||||
bool operator()(location a, location b) const;
|
||||
};
|
||||
|
||||
class rectangle_size_delegate {
|
||||
friend struct rectangle;
|
||||
rectangle& forRect;
|
||||
|
@@ -35,7 +35,7 @@ void cOutdoors::append(legacy::outdoor_record_type& old){
|
||||
for(i = 0; i < 48; i++)
|
||||
for(j = 0; j < 48; j++){
|
||||
terrain[i][j] = old.terrain[i][j];
|
||||
if(scenario.ter_types[terrain[i][j]].i == 3000) // marker to indicate it used to be a special spot
|
||||
if(scenario->ter_types[terrain[i][j]].i == 3000) // marker to indicate it used to be a special spot
|
||||
special_spot[i][j] = true;
|
||||
else special_spot[i][j] = false;
|
||||
// Convert roads that crossed grass/hill boundaries
|
||||
@@ -49,19 +49,19 @@ void cOutdoors::append(legacy::outdoor_record_type& old){
|
||||
if(old.terrain[i][j] == 81 && i > 0 && i < 47 && j > 0 && j < 47) {
|
||||
if(old.terrain[i+1][j] == 81) {
|
||||
ter_num_t connect = old.terrain[i-1][j];
|
||||
if(connect == 80 || scenario.ter_types[connect].trim_type == eTrimType::CITY)
|
||||
if(connect == 80 || scenario->ter_types[connect].trim_type == eTrimType::CITY)
|
||||
terrain[i][j] = 44;
|
||||
} else if(old.terrain[i-1][j] == 81) {
|
||||
ter_num_t connect = old.terrain[i+1][j];
|
||||
if(connect == 80 || scenario.ter_types[connect].trim_type == eTrimType::CITY)
|
||||
if(connect == 80 || scenario->ter_types[connect].trim_type == eTrimType::CITY)
|
||||
terrain[i][j] = 40;
|
||||
} else if(old.terrain[i][j+1] == 81) {
|
||||
ter_num_t connect = old.terrain[i][j-1];
|
||||
if(connect == 80 || scenario.ter_types[connect].trim_type == eTrimType::CITY)
|
||||
if(connect == 80 || scenario->ter_types[connect].trim_type == eTrimType::CITY)
|
||||
terrain[i][j] = 42;
|
||||
} else if(old.terrain[i][j-1] == 81) {
|
||||
ter_num_t connect = old.terrain[i][j+1];
|
||||
if(connect == 80 || scenario.ter_types[connect].trim_type == eTrimType::CITY)
|
||||
if(connect == 80 || scenario->ter_types[connect].trim_type == eTrimType::CITY)
|
||||
terrain[i][j] = 38;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ cOutdoors::cWandering::cWandering() {
|
||||
std::fill(friendly.begin(), friendly.end(), 0);
|
||||
}
|
||||
|
||||
cOutdoors::cOutdoors(cScenario& scenario) : scenario(scenario) {
|
||||
cOutdoors::cOutdoors(cScenario& scenario) : scenario(&scenario) {
|
||||
short i,j;
|
||||
location locs[4] = {loc(8,8),loc(32,8),loc(8,32),loc(32,32)};
|
||||
bg_out = bg_fight = bg_town = bg_dungeon = -1;
|
||||
@@ -192,3 +192,7 @@ bool cOutdoors::cWandering::isNull(){
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void cOutdoors::reattach(cScenario& scen) {
|
||||
scenario = &scen;
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ enum eAmbientSound {
|
||||
};
|
||||
|
||||
class cOutdoors {
|
||||
cScenario& scenario;
|
||||
cScenario* scenario;
|
||||
public:
|
||||
class cWandering { // formerly out_wandering_type
|
||||
public:
|
||||
@@ -79,6 +79,7 @@ public:
|
||||
|
||||
explicit cOutdoors(cScenario& scenario);
|
||||
void append(legacy::outdoor_record_type& old);
|
||||
void reattach(cScenario& to);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -39,12 +39,12 @@ void cTinyTown::append(legacy::tiny_tr_type& old, int town_num){
|
||||
for(j = 0; j < 32; j++) {
|
||||
ter[i][j] = old.terrain[i][j];
|
||||
light[i / 8][j] = old.lighting[i / 8][j];
|
||||
if(scenario.ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
if(scenario->ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
the_field.loc.x = i;
|
||||
the_field.loc.y = j;
|
||||
preset_fields.push_back(the_field);
|
||||
}
|
||||
if(scenario.ter_types[ter[i][j]].boat_over) {
|
||||
if(scenario->ter_types[ter[i][j]].boat_over) {
|
||||
// Try to fix specials that could be triggered while in a boat
|
||||
// (Boats never triggered specials in the old BoE, so we probably don't want them to trigger.)
|
||||
int found_spec = -1;
|
||||
@@ -108,12 +108,12 @@ void cMedTown::append(legacy::ave_tr_type& old, int town_num){
|
||||
for(j = 0; j < 48; j++) {
|
||||
ter[i][j] = old.terrain[i][j];
|
||||
light[i / 8][j] = old.lighting[i / 8][j];
|
||||
if(scenario.ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
if(scenario->ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
the_field.loc.x = i;
|
||||
the_field.loc.y = j;
|
||||
preset_fields.push_back(the_field);
|
||||
}
|
||||
if(scenario.ter_types[ter[i][j]].boat_over) {
|
||||
if(scenario->ter_types[ter[i][j]].boat_over) {
|
||||
// Try to fix specials that could be triggered while in a boat
|
||||
// (Boats never triggered specials in the old BoE, so we probably don't want them to trigger.)
|
||||
int found_spec = -1;
|
||||
@@ -177,12 +177,12 @@ void cBigTown::append(legacy::big_tr_type& old, int town_num){
|
||||
for(j = 0; j < 64; j++) {
|
||||
ter[i][j] = old.terrain[i][j];
|
||||
light[i / 8][j] = old.lighting[i / 8][j];
|
||||
if(scenario.ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
if(scenario->ter_types[ter[i][j]].i == 3000) { // marker to indicate it used to be a special spot
|
||||
the_field.loc.x = i;
|
||||
the_field.loc.y = j;
|
||||
preset_fields.push_back(the_field);
|
||||
}
|
||||
if(scenario.ter_types[ter[i][j]].boat_over) {
|
||||
if(scenario->ter_types[ter[i][j]].boat_over) {
|
||||
// Try to fix specials that could be triggered while in a boat
|
||||
// (Boats never triggered specials in the old BoE, so we probably don't want them to trigger.)
|
||||
int found_spec = -1;
|
||||
|
@@ -75,7 +75,7 @@ void cTown::append(legacy::town_record_type& old){
|
||||
strong_barriers = defy_scrying = defy_mapping = false;
|
||||
}
|
||||
|
||||
cTown::cTown(cScenario& scenario) : scenario(scenario) {
|
||||
cTown::cTown(cScenario& scenario) : scenario(&scenario) {
|
||||
short i;
|
||||
cTown::cWandering d_wan = {0,0,0,0};
|
||||
|
||||
@@ -191,7 +191,7 @@ void cTown::set_up_lights() {
|
||||
for(short j = 0; j < this->max_dim(); j++) {
|
||||
l.x = i;
|
||||
l.y = j;
|
||||
rad = scenario.ter_types[this->terrain(i,j)].light_radius;
|
||||
rad = scenario->ter_types[this->terrain(i,j)].light_radius;
|
||||
if(rad > 0) {
|
||||
for(where.x = std::max(0,i - rad); where.x < min(this->max_dim(),short(i + rad + 1)); where.x++)
|
||||
for(where.y = std::max(0,j - rad); where.y < min(this->max_dim(),short(j + rad + 1)); where.y++)
|
||||
@@ -216,7 +216,7 @@ short cTown::light_obscurity(short x,short y) {
|
||||
|
||||
what_terrain = this->terrain(x,y);
|
||||
|
||||
store = scenario.ter_types[what_terrain].blockage;
|
||||
store = scenario->ter_types[what_terrain].blockage;
|
||||
if(store == eTerObstruct::BLOCK_SIGHT || store == eTerObstruct::BLOCK_MOVE_AND_SIGHT)
|
||||
return 5;
|
||||
if(store == eTerObstruct::BLOCK_MOVE_AND_SHOOT)
|
||||
@@ -240,3 +240,7 @@ cTown::cItem::cItem(location loc, short num, ::cItem& item) : cItem() {
|
||||
if(item.variety == eItemType::GOLD || item.variety == eItemType::FOOD)
|
||||
charges = get_ran(1,4,6);
|
||||
}
|
||||
|
||||
void cTown::reattach(cScenario& scen) {
|
||||
scenario = &scen;
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ class cScenario;
|
||||
|
||||
class cTown { // formerly town_record_type
|
||||
protected:
|
||||
cScenario& scenario;
|
||||
cScenario* scenario;
|
||||
public:
|
||||
class cWandering { // formerly wandering_type
|
||||
public:
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
|
||||
explicit cTown(cScenario& scenario);
|
||||
void append(legacy::town_record_type& old);
|
||||
void reattach(cScenario& to);
|
||||
virtual void writeTerrainTo(std::ostream& file) = 0;
|
||||
virtual void readTerrainFrom(std::istream& file) = 0;
|
||||
};
|
||||
|
@@ -214,7 +214,7 @@ static bool handle_lb_action(location the_point) {
|
||||
if(!save_check("save-section-confirm"))
|
||||
break;
|
||||
}
|
||||
spot_hit = pick_out(cur_out);
|
||||
spot_hit = pick_out(cur_out, scenario);
|
||||
if(spot_hit != cur_out) {
|
||||
cur_out = spot_hit;
|
||||
current_terrain = scenario.outdoors[cur_out.x][cur_out.y];
|
||||
|
@@ -2965,6 +2965,7 @@ bool build_scenario() {
|
||||
}
|
||||
}
|
||||
if(med > 0) med--;
|
||||
warriors_grove->reattach(scenario);
|
||||
}
|
||||
|
||||
scenario.shops.push_back(cShop('heal'));
|
||||
|
@@ -289,6 +289,12 @@ void handle_menu_choice(eMenu item_hit) {
|
||||
set_up_main_screen();
|
||||
change_made = true;
|
||||
break;
|
||||
case eMenu::OUT_RESIZE:
|
||||
if(resize_outdoors())
|
||||
change_made = true;
|
||||
if(overall_mode == MODE_MAIN_SCREEN)
|
||||
set_up_main_screen();
|
||||
break;
|
||||
case eMenu::SCEN_DETAILS:
|
||||
edit_scen_details();
|
||||
change_made = true;
|
||||
@@ -327,12 +333,28 @@ void handle_menu_choice(eMenu item_hit) {
|
||||
break;
|
||||
case eMenu::TOWN_IMPORT:
|
||||
if(change_made) {
|
||||
giveError("You need to save the changes made to your scenario before you can add a new town.");
|
||||
giveError("You need to save the changes made to your scenario before you can import a town.");
|
||||
return;
|
||||
}
|
||||
if(cTown* town = pick_import_town(0)) {
|
||||
if(cTown* town = pick_import_town()) {
|
||||
town->reattach(scenario);
|
||||
delete scenario.towns[cur_town];
|
||||
scenario.towns[cur_town] = town;
|
||||
::town = town;
|
||||
change_made = true;
|
||||
redraw_screen();
|
||||
}
|
||||
break;
|
||||
case eMenu::OUT_IMPORT:
|
||||
if(change_made) {
|
||||
giveError("You need to save the changes made to your scenario before you can import a sector.");
|
||||
return;
|
||||
}
|
||||
if(cOutdoors* out = pick_import_out()) {
|
||||
out->reattach(scenario);
|
||||
delete scenario.outdoors[cur_out.x][cur_out.y];
|
||||
scenario.outdoors[cur_out.x][cur_out.y] = out;
|
||||
current_terrain = out;
|
||||
change_made = true;
|
||||
redraw_screen();
|
||||
}
|
||||
|
@@ -18,8 +18,8 @@ enum class eMenu {
|
||||
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
|
||||
TOWN_CREATE, SCEN_DETAILS, SCEN_INTRO, TOWN_START,
|
||||
SCEN_SPECIALS, SCEN_TEXT, SCEN_JOURNALS, TOWN_IMPORT,
|
||||
TOWN_CREATE, OUT_RESIZE, SCEN_DETAILS, SCEN_INTRO, TOWN_START,
|
||||
SCEN_SPECIALS, SCEN_TEXT, SCEN_JOURNALS, TOWN_IMPORT, OUT_IMPORT,
|
||||
SCEN_SAVE_ITEM_RECTS, SCEN_HORSES, SCEN_BOATS,
|
||||
TOWN_VARYING, SCEN_TIMERS, SCEN_ITEM_SHORTCUTS, TOWN_DELETE,
|
||||
SCEN_DATA_DUMP, SCEN_TEXT_DUMP,
|
||||
|
@@ -52,8 +52,9 @@ void init_menubar() {
|
||||
eMenu::EDIT_CUT, eMenu::EDIT_COPY, eMenu::EDIT_PASTE, eMenu::EDIT_DELETE, eMenu::EDIT_SELECT_ALL,
|
||||
};
|
||||
static const eMenu scen_choices[] = {
|
||||
eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_SHEETS, eMenu::SCEN_PICS, eMenu::SCEN_SNDS, eMenu::NONE, eMenu::NONE,
|
||||
eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS,
|
||||
eMenu::TOWN_CREATE, eMenu::OUT_RESIZE, eMenu::NONE,
|
||||
eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_SHEETS, eMenu::SCEN_PICS, eMenu::SCEN_SNDS, eMenu::NONE, eMenu::NONE,
|
||||
eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::OUT_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS,
|
||||
eMenu::SCEN_HORSES, eMenu::SCEN_BOATS, eMenu::TOWN_VARYING, eMenu::SCEN_TIMERS, eMenu::SCEN_ITEM_SHORTCUTS,
|
||||
eMenu::TOWN_DELETE, eMenu::SCEN_DATA_DUMP, eMenu::SCEN_TEXT_DUMP,
|
||||
};
|
||||
|
@@ -80,8 +80,9 @@ void init_menubar() {
|
||||
eMenu::EDIT_CUT, eMenu::EDIT_COPY, eMenu::EDIT_PASTE, eMenu::EDIT_DELETE, eMenu::EDIT_SELECT_ALL,
|
||||
};
|
||||
static const eMenu scen_choices[] = {
|
||||
eMenu::TOWN_CREATE, eMenu::NONE, eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_SHEETS, eMenu::SCEN_PICS, eMenu::SCEN_SNDS, eMenu::NONE, eMenu::NONE,
|
||||
eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS,
|
||||
eMenu::TOWN_CREATE, eMenu::OUT_RESIZE, eMenu::NONE,
|
||||
eMenu::SCEN_DETAILS, eMenu::SCEN_INTRO, eMenu::TOWN_START, eMenu::SCEN_SHEETS, eMenu::SCEN_PICS, eMenu::SCEN_SNDS, eMenu::NONE, eMenu::NONE,
|
||||
eMenu::SCEN_SPECIALS, eMenu::SCEN_TEXT, eMenu::SCEN_JOURNALS, eMenu::TOWN_IMPORT, eMenu::OUT_IMPORT, eMenu::SCEN_SAVE_ITEM_RECTS,
|
||||
eMenu::SCEN_HORSES, eMenu::SCEN_BOATS, eMenu::TOWN_VARYING, eMenu::SCEN_TIMERS, eMenu::SCEN_ITEM_SHORTCUTS,
|
||||
eMenu::TOWN_DELETE, eMenu::SCEN_DATA_DUMP, eMenu::SCEN_TEXT_DUMP,
|
||||
};
|
||||
|
@@ -1121,7 +1121,7 @@ short edit_talk_node(short which_node) {
|
||||
return talk_dlg.accepted() ? -1 : talk_edit_stack.top().first;
|
||||
}
|
||||
|
||||
static void put_out_loc_in_dlog(cDialog& me, location cur_loc) {
|
||||
static void put_out_loc_in_dlog(cDialog& me, location cur_loc, cScenario& scenario) {
|
||||
std::ostringstream str;
|
||||
str << "X = " << cur_loc.x;
|
||||
me["x"].setText(str.str());
|
||||
@@ -1131,7 +1131,7 @@ static void put_out_loc_in_dlog(cDialog& me, location cur_loc) {
|
||||
me["title"].setText(scenario.outdoors[cur_loc.x][cur_loc.y]->out_name);
|
||||
}
|
||||
|
||||
static bool pick_out_event_filter(cDialog& me, std::string item_hit, location& cur_loc) {
|
||||
static bool pick_out_event_filter(cDialog& me, std::string item_hit, location& cur_loc, cScenario& scenario) {
|
||||
if(item_hit == "xminus") {
|
||||
if(cur_loc.x == 0) beep();
|
||||
else cur_loc.x--;
|
||||
@@ -1145,12 +1145,16 @@ static bool pick_out_event_filter(cDialog& me, std::string item_hit, location& c
|
||||
if(cur_loc.y >= scenario.outdoors.height() - 1) beep();
|
||||
else cur_loc.y++;
|
||||
} else if(item_hit == "choose") {
|
||||
int i = cur_loc.x * scenario.outdoors.width() + cur_loc.y;
|
||||
int i = cur_loc.x * scenario.outdoors.height() + cur_loc.y;
|
||||
if(&scenario != &::scenario)
|
||||
scenario.outdoors.swap(::scenario.outdoors);
|
||||
i = choose_text(STRT_SECTOR, i, &me, "Which sector?");
|
||||
cur_loc.x = i / scenario.outdoors.width();
|
||||
cur_loc.y = i % scenario.outdoors.width();
|
||||
if(&scenario != &::scenario)
|
||||
scenario.outdoors.swap(::scenario.outdoors);
|
||||
cur_loc.x = i / scenario.outdoors.height();
|
||||
cur_loc.y = i % scenario.outdoors.height();
|
||||
}
|
||||
put_out_loc_in_dlog(me, cur_loc);
|
||||
put_out_loc_in_dlog(me, cur_loc, scenario);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1161,25 +1165,28 @@ static bool finish_pick_out(cDialog& me, bool okay, location& cur_loc, location
|
||||
return true;
|
||||
}
|
||||
|
||||
location pick_out(location default_loc) {
|
||||
location pick_out(location default_loc,cScenario& scenario) {
|
||||
using namespace std::placeholders;
|
||||
location prev_loc = default_loc;
|
||||
if(default_loc.x < 0)
|
||||
default_loc.x = 0;
|
||||
if(default_loc.y < 0)
|
||||
default_loc.y = 0;
|
||||
|
||||
cDialog out_dlg("select-sector");
|
||||
out_dlg["okay"].attachClickHandler(std::bind(finish_pick_out, _1, true, std::ref(default_loc), prev_loc));
|
||||
out_dlg["cancel"].attachClickHandler(std::bind(finish_pick_out, _1, false, std::ref(default_loc), prev_loc));
|
||||
out_dlg.attachClickHandlers(std::bind(pick_out_event_filter, _1, _2, std::ref(default_loc)), {"xplus", "xminus", "yplus", "yminus", "choose"});
|
||||
out_dlg.attachClickHandlers(std::bind(pick_out_event_filter, _1, _2, std::ref(default_loc), std::ref(scenario)), {"xplus", "xminus", "yplus", "yminus", "choose"});
|
||||
|
||||
out_dlg["width"].setTextToNum(scenario.outdoors.width());
|
||||
out_dlg["height"].setTextToNum(scenario.outdoors.height());
|
||||
put_out_loc_in_dlog(out_dlg, default_loc);
|
||||
put_out_loc_in_dlog(out_dlg, default_loc, scenario);
|
||||
|
||||
out_dlg.run();
|
||||
return default_loc;
|
||||
}
|
||||
|
||||
bool new_town(short which_town) {
|
||||
std::cout << "Town creation currently disabled.\n";
|
||||
short i,j;
|
||||
|
||||
cChoiceDlog new_dlg("new-town", {"okay", "cancel"});
|
||||
@@ -1222,13 +1229,171 @@ void delete_last_town() {
|
||||
delete last_town;
|
||||
}
|
||||
|
||||
cTown* pick_import_town(short def) {
|
||||
cTown* pick_import_town() {
|
||||
cScenario temp_scenario;
|
||||
fs::path path = nav_get_scenario();
|
||||
load_scenario(path, temp_scenario);
|
||||
short town_num = pick_town_num("select-import-town", def, temp_scenario);
|
||||
short town_num = pick_town_num("select-import-town", 0, temp_scenario);
|
||||
if(town_num < 0) return nullptr;
|
||||
cTown* town = temp_scenario.towns[town_num];
|
||||
temp_scenario.towns[town_num] = nullptr;
|
||||
return town;
|
||||
}
|
||||
|
||||
using loc_set = std::set<location, loc_compare>;
|
||||
static void fill_resize_outdoors(cDialog& me, int top, int left, int right, int bottom, loc_set& del) {
|
||||
me["top"].setTextToNum(top);
|
||||
me["left"].setTextToNum(left);
|
||||
me["right"].setTextToNum(right);
|
||||
me["bottom"].setTextToNum(bottom);
|
||||
|
||||
me["w-new"].setTextToNum(scenario.outdoors.width() + left + right);
|
||||
me["h-new"].setTextToNum(scenario.outdoors.height() + top + bottom);
|
||||
if(left >= 0 && right >= 0 && top >= 0 && bottom >= 0)
|
||||
me["delete"].setText("(none)");
|
||||
else {
|
||||
del.clear();
|
||||
while(left < 0) {
|
||||
for(int y = 0; y < scenario.outdoors.height(); y++)
|
||||
del.insert(loc(-left - 1, y));
|
||||
left++;
|
||||
}
|
||||
while(top < 0) {
|
||||
for(int x = 0; x < scenario.outdoors.width(); x++)
|
||||
del.insert(loc(x, -top - 1));
|
||||
top++;
|
||||
}
|
||||
while(right < 0) {
|
||||
for(int y = 0; y < scenario.outdoors.height(); y++)
|
||||
del.insert(loc(scenario.outdoors.width() + right, y));
|
||||
right++;
|
||||
}
|
||||
while(bottom < 0) {
|
||||
for(int x = 0; x < scenario.outdoors.width(); x++)
|
||||
del.insert(loc(x, scenario.outdoors.height() + bottom));
|
||||
bottom++;
|
||||
}
|
||||
std::ostringstream list;
|
||||
for(location l : del) {
|
||||
list << '(' << l.x << ", " << l.y << ") " << scenario.outdoors[l.x][l.y]->out_name << '|';
|
||||
}
|
||||
me["delete"].setText(list.str());
|
||||
}
|
||||
}
|
||||
|
||||
static bool resize_outdoors_filter(cDialog& me, std::string btn, rectangle& mod, loc_set& del) {
|
||||
int dir = btn.back() == 'p' ? 1 : -1;
|
||||
btn.erase(btn.end() - 2, btn.end());
|
||||
|
||||
// Make sure the change won't put the width/height below 1 or over 50
|
||||
if(btn == "top" || btn == "bottom") {
|
||||
int h = scenario.outdoors.height() + mod.top + mod.bottom;
|
||||
if((dir == 1 && h >= 50) || (dir == -1 && h <= 1)) {
|
||||
beep();
|
||||
return true;
|
||||
}
|
||||
} else if(btn == "left" || btn == "right") {
|
||||
int w = scenario.outdoors.width() + mod.left + mod.right;
|
||||
if((dir == 1 && w >= 50) || (dir == -1 && w <= 1)) {
|
||||
beep();
|
||||
return true;
|
||||
}
|
||||
} else return true; // Should be unreachable
|
||||
|
||||
if(btn == "top")
|
||||
mod.top += dir;
|
||||
else if(btn == "left")
|
||||
mod.left += dir;
|
||||
else if(btn == "right")
|
||||
mod.right += dir;
|
||||
else if(btn == "bottom")
|
||||
mod.bottom += dir;
|
||||
|
||||
fill_resize_outdoors(me, mod.top, mod.left, mod.right, mod.bottom, del);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool resize_outdoors() {
|
||||
using namespace std::placeholders;
|
||||
loc_set del;
|
||||
rectangle mod;
|
||||
cDialog size_dlg("resize-outdoors");
|
||||
size_dlg["w-old"].setTextToNum(scenario.outdoors.width());
|
||||
size_dlg["h-old"].setTextToNum(scenario.outdoors.height());
|
||||
fill_resize_outdoors(size_dlg, mod.top, mod.left, mod.right, mod.bottom, del);
|
||||
|
||||
size_dlg["okay"].attachClickHandler(std::bind(&cDialog::toast, &size_dlg, true));
|
||||
size_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, &size_dlg, false));
|
||||
size_dlg.attachClickHandlers(std::bind(resize_outdoors_filter, _1, _2, std::ref(mod), std::ref(del)), {
|
||||
"top-p", "top-m", "left-p", "left-m", "right-p", "right-m", "bottom-p", "bottom-m"
|
||||
});
|
||||
|
||||
size_dlg.run();
|
||||
if(!size_dlg.accepted()) return false;
|
||||
|
||||
for(location l : del) {
|
||||
delete scenario.outdoors[l.x][l.y];
|
||||
scenario.outdoors[l.x][l.y] = nullptr;
|
||||
}
|
||||
|
||||
size_t old_w = scenario.outdoors.width(), old_h = scenario.outdoors.height();
|
||||
size_t new_w = old_w + mod.left + mod.right, new_h = old_h + mod.top + mod.bottom;
|
||||
|
||||
if(new_w > old_w)
|
||||
scenario.outdoors.resize(new_w, scenario.outdoors.height());
|
||||
if(new_h > old_h)
|
||||
scenario.outdoors.resize(scenario.outdoors.width(), new_h);
|
||||
|
||||
if(mod.top > 0) {
|
||||
int y = new_h - mod.top;
|
||||
while(y--) {
|
||||
scenario.outdoors.row(y + mod.top) = std::move(scenario.outdoors.row(y));
|
||||
}
|
||||
} else if(mod.top < 0) {
|
||||
for(int y = -mod.top; y < old_h; y++) {
|
||||
scenario.outdoors.row(y + mod.top) = std::move(scenario.outdoors.row(y));
|
||||
}
|
||||
}
|
||||
|
||||
if(mod.left > 0) {
|
||||
int x = new_w - mod.left;
|
||||
while(x--) {
|
||||
scenario.outdoors.col(x + mod.left) = std::move(scenario.outdoors.col(x));
|
||||
}
|
||||
} else if(mod.left < 0) {
|
||||
for(int x = -mod.left; x < old_w; x++) {
|
||||
scenario.outdoors.col(x + mod.left) = std::move(scenario.outdoors.col(x));
|
||||
}
|
||||
}
|
||||
|
||||
scenario.outdoors.resize(new_w, new_h);
|
||||
for(int y = 0; y < new_h; y++) {
|
||||
for(int x = 0; x < new_w; x++) {
|
||||
if(scenario.outdoors[x][y] == nullptr)
|
||||
scenario.outdoors[x][y] = new cOutdoors(scenario);
|
||||
}
|
||||
}
|
||||
|
||||
// Update current location - point to same sector if possible
|
||||
cur_out.x += mod.left;
|
||||
cur_out.y += mod.top;
|
||||
if(cur_out.x >= new_w || cur_out.x < 0)
|
||||
cur_out.x = 0;
|
||||
if(cur_out.y >= new_h || cur_out.y < 0)
|
||||
cur_out.y = 0;
|
||||
current_terrain = scenario.outdoors[cur_out.x][cur_out.y];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
cOutdoors* pick_import_out() {
|
||||
cScenario temp_scenario;
|
||||
fs::path path = nav_get_scenario();
|
||||
load_scenario(path, temp_scenario);
|
||||
location sector = pick_out({-1,-1},temp_scenario);
|
||||
if(sector.x < 0 && sector.y < 0)
|
||||
return nullptr;
|
||||
cOutdoors* out = temp_scenario.outdoors[sector.x][sector.y];
|
||||
temp_scenario.outdoors[sector.x][sector.y] = nullptr;
|
||||
return out;
|
||||
}
|
||||
|
@@ -11,9 +11,11 @@ void edit_town_events();
|
||||
void edit_advanced_town();
|
||||
void edit_basic_dlog(short which_node);
|
||||
short edit_talk_node(short which_node);
|
||||
location pick_out(location default_loc);
|
||||
cTown* pick_import_town(short def);
|
||||
location pick_out(location default_loc,cScenario& scenario);
|
||||
cTown* pick_import_town();
|
||||
cOutdoors* pick_import_out();
|
||||
bool new_town(short which_town);
|
||||
bool resize_outdoors();
|
||||
void edit_placed_item(short which_i);
|
||||
|
||||
void delete_last_town();
|
||||
|
@@ -160,10 +160,3 @@ void map_data::writeTo(std::ostream& out) {
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
bool loc_compare::operator()(location a, location b) const {
|
||||
// This is just a lexicographical ordering.
|
||||
if(a.x != b.x) return a.x < b.x;
|
||||
if(a.y != b.y) return a.y < b.y;
|
||||
return false;
|
||||
}
|
||||
|
@@ -32,10 +32,6 @@ enum class eMapFeature {
|
||||
FIELD,
|
||||
};
|
||||
|
||||
struct loc_compare {
|
||||
bool operator()(location a, location b) const;
|
||||
};
|
||||
|
||||
class map_data {
|
||||
std::vector<std::vector<int>> grid;
|
||||
using feature_t = std::pair<eMapFeature,int>;
|
||||
|
@@ -11,8 +11,6 @@
|
||||
|
||||
// Tried using boost::multi_array, but it kept causing weird issues, so I decided to make my own.
|
||||
// TODO: Fill out missing members (should have equivalents for most of the stuff in std::vector)
|
||||
// TODO: Add row-wise access using the included row_ref, and support for row/column assignment
|
||||
// (These would be very useful for implementing a resize outdoors function in the scenario editor.)
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -33,6 +31,26 @@ public:
|
||||
Type& operator[](size_t x) {
|
||||
return ref.data[ref.w * y + x];
|
||||
}
|
||||
const Type& operator[](size_t x) const {
|
||||
return ref.data[ref.w * y + x];
|
||||
}
|
||||
row_ref operator=(row_ref&& other) {
|
||||
row_ref& me = *this;
|
||||
for(int i = 0; i < ref.width(); i++) {
|
||||
me[i] = std::move(other[i]);
|
||||
other[i] = Type();
|
||||
}
|
||||
return me;
|
||||
}
|
||||
row_ref operator=(const row_ref& other) {
|
||||
row_ref& me = *this;
|
||||
for(int i = 0; i < ref.width(); i++) {
|
||||
me[i] = other[i];
|
||||
}
|
||||
return me;
|
||||
}
|
||||
// Seems like defining a move assignment operator deletes the copy constructor. Don't want that.
|
||||
row_ref(const row_ref&) = default;
|
||||
};
|
||||
class col_ref {
|
||||
friend class vector2d<Type, Alloc>;
|
||||
@@ -43,6 +61,26 @@ public:
|
||||
Type& operator[](size_t y) {
|
||||
return ref.data[ref.w * y + x];
|
||||
}
|
||||
const Type& operator[](size_t y) const {
|
||||
return ref.data[ref.w * y + x];
|
||||
}
|
||||
col_ref operator=(col_ref&& other) {
|
||||
col_ref& me = *this;
|
||||
for(int i = 0; i < ref.height(); i++) {
|
||||
me[i] = std::move(other[i]);
|
||||
other[i] = Type();
|
||||
}
|
||||
return me;
|
||||
}
|
||||
col_ref operator=(const col_ref& other) {
|
||||
col_ref& me = *this;
|
||||
for(int i = 0; i < ref.height(); i++) {
|
||||
me[i] = other[i];
|
||||
}
|
||||
return me;
|
||||
}
|
||||
// Seems like defining a move assignment operator deletes the copy constructor. Don't want that.
|
||||
col_ref(const col_ref&) = default;
|
||||
};
|
||||
class const_row_ref {
|
||||
friend class vector2d<Type, Alloc>;
|
||||
@@ -70,6 +108,18 @@ public:
|
||||
const_col_ref operator[](size_t x) const {
|
||||
return const_col_ref(*this, x);
|
||||
}
|
||||
col_ref col(size_t x) {
|
||||
return col_ref(*this, x);
|
||||
}
|
||||
const_col_ref col(size_t x) const {
|
||||
return const_col_ref(*this, x);
|
||||
}
|
||||
row_ref row(size_t x) {
|
||||
return row_ref(*this, x);
|
||||
}
|
||||
const_row_ref row(size_t x) const {
|
||||
return const_row_ref(*this, x);
|
||||
}
|
||||
size_t width() const {
|
||||
return w;
|
||||
}
|
||||
@@ -86,8 +136,27 @@ public:
|
||||
return data.size();
|
||||
}
|
||||
void resize(size_t width, size_t height) {
|
||||
if(w > width) {
|
||||
size_t dx = w - width;
|
||||
for(int y = 1; y < h; y++) {
|
||||
std::move(data.begin() + w * y, data.begin() + w * (y + 1) - dx, data.begin() + width * y);
|
||||
}
|
||||
}
|
||||
size_t old_w = w, old_h = h;
|
||||
w = width; h = height;
|
||||
data.resize(w * h);
|
||||
if(old_w < width) {
|
||||
size_t dx = width - old_w;
|
||||
for(int y = old_h - 1; y > 0; y--) {
|
||||
std::move_backward(data.begin() + old_w * y, data.begin() + old_w * (y + 1), data.begin() + w * (y + 1) - dx);
|
||||
std::fill_n(data.begin() + old_w + w * (y - 1), dx, Type());
|
||||
}
|
||||
}
|
||||
}
|
||||
void swap(vector2d& other) {
|
||||
data.swap(other.data);
|
||||
std::swap(w, other.w);
|
||||
std::swap(h, other.h);
|
||||
}
|
||||
bool empty() const {
|
||||
return data.empty();
|
||||
|
Reference in New Issue
Block a user