diff --git a/rsrc/dialogs/edit-out-roomdescs.xml b/rsrc/dialogs/edit-out-roomdescs.xml deleted file mode 100644 index c28a79d0..00000000 --- a/rsrc/dialogs/edit-out-roomdescs.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - Descriptive message - - - - - - - - - - Enter the descriptions for each of the special outdoor rectangles you may have made, or press the delete button to remove them. - Maximum length: 30 characters. - - - Outdoor area descriptions - Upper left corner - - - - - - - - - \ No newline at end of file diff --git a/rsrc/dialogs/edit-shop.xml b/rsrc/dialogs/edit-shop.xml index 4b19b62a..462937fa 100644 --- a/rsrc/dialogs/edit-shop.xml +++ b/rsrc/dialogs/edit-shop.xml @@ -85,6 +85,6 @@ + \ No newline at end of file diff --git a/rsrc/dialogs/edit-text.xml b/rsrc/dialogs/edit-text.xml index 65d901a6..f88d60b2 100644 --- a/rsrc/dialogs/edit-text.xml +++ b/rsrc/dialogs/edit-text.xml @@ -1,12 +1,13 @@ - - - + Text number: + + \ No newline at end of file diff --git a/rsrc/dialogs/edit-town-roomdescs.xml b/rsrc/dialogs/edit-town-roomdescs.xml deleted file mode 100644 index bcf0ceec..00000000 --- a/rsrc/dialogs/edit-town-roomdescs.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - Descriptive message - - - - - - - - - - - - - - - - - - Enter the descriptions for each of the special town rectangles you may have made, or press the delete button to remove them. - Maximum length: 30 characters. - - - Town area descriptions - Upper left corner - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/rsrc/graphics.exd/mac/edbuttons.png b/rsrc/graphics.exd/mac/edbuttons.png index f7557717..118789ab 100644 Binary files a/rsrc/graphics.exd/mac/edbuttons.png and b/rsrc/graphics.exd/mac/edbuttons.png differ diff --git a/rsrc/strings/outdoor-default.txt b/rsrc/strings/outdoor-default.txt deleted file mode 100644 index 72b031c2..00000000 --- a/rsrc/strings/outdoor-default.txt +++ /dev/null @@ -1,300 +0,0 @@ -Area name -Rectangle 1 -Rectangle 2 -Rectangle 3 -Rectangle 4 -Rectangle 5 -Rectangle 6 -Rectangle 7 -Rectangle 8 -Comment -*Begin special strs -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -*End of special strs - - - - - - - - -From here on, reserved for future use - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rsrc/strings/scen-default.txt b/rsrc/strings/scen-default.txt deleted file mode 100644 index bba7f051..00000000 --- a/rsrc/strings/scen-default.txt +++ /dev/null @@ -1,300 +0,0 @@ -Scen name -Who wrote 1 -Who wrote 2 -Contact info - - - - - - -Begin journal strs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -End journal strs -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item - -Unused Special Item -End special item descs -*Begin special strs -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -*End special strs -From here on, reserved for furute use - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/rsrc/strings/town-default.txt b/rsrc/strings/town-default.txt deleted file mode 100644 index c0c4879d..00000000 --- a/rsrc/strings/town-default.txt +++ /dev/null @@ -1,300 +0,0 @@ -Town name -Rectangle 1 -Rectangle 2 -Rectangle 3 -Rectangle 4 -Rectangle 5 -Rectangle 6 -Rectangle 7 -Rectangle 8 -Rectangle 9 -Rectangle 10 -Rectangle 11 -Rectangle 12 -Rectangle 13 -Rectangle 14 -Rectangle 15 -Rectangle 16 -Comment 1 -Comment 2 -Comment 3 -*Begin special strs -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* -* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/classes/location.hpp b/src/classes/location.hpp index f20dc222..98f85d50 100644 --- a/src/classes/location.hpp +++ b/src/classes/location.hpp @@ -78,10 +78,26 @@ struct rectangle { struct info_rect_t : public rectangle { std::string descr; + + info_rect_t(int t, int l, int b, int r, const std::string& s) : rectangle(t,l,b,r), descr(s) {} + info_rect_t(const rectangle& r) : rectangle(r) {} + // Declaring one constructor suppresses all implicit constructors, so declare them explicitly + info_rect_t() = default; + info_rect_t(const info_rect_t& other) = default; + // Ditto for assignment operator + info_rect_t& operator=(const info_rect_t& other) = default; }; struct sign_loc_t : public location { std::string text; + + sign_loc_t(int x, int y, const std::string& s) : location(x,y), text(s) {} + sign_loc_t(const location& loc) : location(loc) {} + // Declaring one constructor suppresses all implicit constructors, so declare them explicitly + sign_loc_t() = default; + sign_loc_t(const sign_loc_t& other) = default; + // Ditto for assignment operator + sign_loc_t& operator=(const sign_loc_t& other) = default; }; struct spec_loc_t : public location { diff --git a/src/classes/monster.cpp b/src/classes/monster.cpp index c464da06..8055ec61 100644 --- a/src/classes/monster.cpp +++ b/src/classes/monster.cpp @@ -382,16 +382,17 @@ std::map::iterator cMonster::addAbil(eMonstAbilTemplate wha cMonster::cMonster(){ magic_res = poison_res = fire_res = cold_res = 100; mindless = invuln = guard = invisible = false; - level = m_health = armor = skill = speed = 0; + level = m_health = armor = skill = 0; + speed = 4; default_facial_pic = default_attitude = 0; ambient_sound = 0; corpse_item = corpse_item_chance = treasure = 0; mu = cl = 0; summon_type = 0; - picture_num = 0; + picture_num = 149; x_width = y_width = 1; see_spec = -1; - m_type = eRace::UNKNOWN; + m_type = eRace::HUMAN; } cTownperson::cTownperson() { diff --git a/src/classes/outdoors.cpp b/src/classes/outdoors.cpp index 0925adc8..e78729b5 100644 --- a/src/classes/outdoors.cpp +++ b/src/classes/outdoors.cpp @@ -74,6 +74,9 @@ void cOutdoors::append(legacy::outdoor_record_type& old){ special_locs[i].spec = -1; else special_locs[i].spec = old.special_id[i]; } + city_locs.resize(8); + sign_locs.resize(8); + info_rect.resize(8); for(i = 0; i < 8; i++){ city_locs[i].x = old.exit_locs[i].x; city_locs[i].y = old.exit_locs[i].y; @@ -123,7 +126,7 @@ cOutdoors::cWandering::cWandering() { std::fill(friendly.begin(), friendly.end(), 0); } -cOutdoors::cOutdoors(cScenario& scenario, bool init_strings) : 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; @@ -134,25 +137,11 @@ cOutdoors::cOutdoors(cScenario& scenario, bool init_strings) : scenario(scenario special_spot[i][j] = false; } - for(i = 0; i < 8; i++) { - city_locs[i].x = 100; - sign_locs[i].x = 100; - } for(i = 0; i < 4; i++) { wandering_locs[i] = locs[i]; } - if(!init_strings) return; - std::string temp_str; - for(i = 0; i < 120; i++) { - temp_str = get_str("outdoor-default",i + 1); - if(i == 0) out_name = temp_str; - else if(i == 9) comment = temp_str; - else if(i < 9) info_rect[i-1].descr = temp_str; - else if(i >= 10 && i < 100) - spec_strs[i-10] = temp_str; - else if(i >= 100 && i < 108) - sign_locs[i-100].text = temp_str; - } + out_name = "Area name"; + comment = "Comment"; } void cOutdoors::cWandering::append(legacy::out_wandering_type old){ diff --git a/src/classes/outdoors.hpp b/src/classes/outdoors.hpp index 62a85cdb..f3e89144 100644 --- a/src/classes/outdoors.hpp +++ b/src/classes/outdoors.hpp @@ -61,23 +61,23 @@ public: short x,y; // Used while loading legacy scenarios. ter_num_t terrain[48][48]; std::vector special_locs; - std::array city_locs; - std::array sign_locs; + std::vector city_locs; + std::vector sign_locs; std::array wandering, special_enc; location wandering_locs[4]; std::vector specials; std::string out_name; // Using std::array here so we can have .size() // This'll make the transition smoother once it becomes a vector. - std::array info_rect; + std::vector info_rect; std::string comment; - std::array spec_strs; + std::vector spec_strs; bool special_spot[48][48]; eAmbientSound ambient_sound; snd_num_t out_sound; int bg_out, bg_fight, bg_town, bg_dungeon; - explicit cOutdoors(cScenario& scenario, bool init_strings = false); + explicit cOutdoors(cScenario& scenario); void append(legacy::outdoor_record_type& old); }; diff --git a/src/classes/regtown.cpp b/src/classes/regtown.cpp index 00bf24a8..9505b5aa 100644 --- a/src/classes/regtown.cpp +++ b/src/classes/regtown.cpp @@ -74,6 +74,7 @@ void cTinyTown::append(legacy::tiny_tr_type& old, int town_num){ } } } + room_rect.resize(16); for(i = 0; i < 16; i++) { room_rect[i].top = old.room_rect[i].top; room_rect[i].left = old.room_rect[i].left; @@ -142,6 +143,7 @@ void cMedTown::append(legacy::ave_tr_type& old, int town_num){ } } } + room_rect.resize(16); for(i = 0; i < 16; i++) { room_rect[i].top = old.room_rect[i].top; room_rect[i].left = old.room_rect[i].left; @@ -210,6 +212,7 @@ void cBigTown::append(legacy::big_tr_type& old, int town_num){ } } } + room_rect.resize(16); for(i = 0; i < 16; i++) { room_rect[i].top = old.room_rect[i].top; room_rect[i].left = old.room_rect[i].left; @@ -270,7 +273,7 @@ unsigned char& cBigTown::lighting(size_t i, size_t r){ return light[i][r]; } -cBigTown::cBigTown(cScenario& scenario, bool init_strings) : cTown(scenario, init_strings) { +cBigTown::cBigTown(cScenario& scenario) : cTown(scenario) { for(size_t i = 0; i < max_dim(); i++) for(size_t j = 0; j < max_dim(); j++) { terrain(i,j) = scenario.default_ground; @@ -279,7 +282,7 @@ cBigTown::cBigTown(cScenario& scenario, bool init_strings) : cTown(scenario, ini init_start(); } -cMedTown::cMedTown(cScenario& scenario, bool init_strings) : cTown(scenario, init_strings) { +cMedTown::cMedTown(cScenario& scenario) : cTown(scenario) { for(size_t i = 0; i < max_dim(); i++) for(size_t j = 0; j < max_dim(); j++) { terrain(i,j) = scenario.default_ground; @@ -288,7 +291,7 @@ cMedTown::cMedTown(cScenario& scenario, bool init_strings) : cTown(scenario, ini init_start(); } -cTinyTown::cTinyTown(cScenario& scenario, bool init_strings) : cTown(scenario, init_strings) { +cTinyTown::cTinyTown(cScenario& scenario) : cTown(scenario) { for(size_t i = 0; i < max_dim(); i++) for(size_t j = 0; j < max_dim(); j++) { terrain(i,j) = scenario.default_ground; diff --git a/src/classes/regtown.hpp b/src/classes/regtown.hpp index aea3487f..5f9c54a0 100644 --- a/src/classes/regtown.hpp +++ b/src/classes/regtown.hpp @@ -31,7 +31,7 @@ public: unsigned char& lighting(size_t i, size_t r); size_t max_dim() const; - explicit cBigTown(cScenario& scenario, bool init_strings = false); + explicit cBigTown(cScenario& scenario); void writeTerrainTo(std::ostream& file); void readTerrainFrom(std::istream& file); }; @@ -45,7 +45,7 @@ public: unsigned char& lighting(size_t i, size_t r); size_t max_dim() const; - explicit cMedTown(cScenario& scenario, bool init_strings = false); + explicit cMedTown(cScenario& scenario); void writeTerrainTo(std::ostream& file); void readTerrainFrom(std::istream& file); }; @@ -59,7 +59,7 @@ public: unsigned char& lighting(size_t i, size_t r); size_t max_dim() const; - explicit cTinyTown(cScenario& scenario, bool init_strings = false); + explicit cTinyTown(cScenario& scenario); void writeTerrainTo(std::ostream& file); void readTerrainFrom(std::istream& file); }; diff --git a/src/classes/scenario.cpp b/src/classes/scenario.cpp index 99e4a60f..ecaac48e 100644 --- a/src/classes/scenario.cpp +++ b/src/classes/scenario.cpp @@ -49,7 +49,7 @@ cScenario& cScenario::operator=(cScenario&& other) { return *this = const_cast(other); } -cScenario::cScenario(bool init_strings) { +cScenario::cScenario() { short i; std::string temp_str; @@ -71,34 +71,14 @@ cScenario::cScenario(bool init_strings) { for(i = 0; i < 3; i++) { store_item_towns[i] = -1; } - for(i = 0; i < special_items.size(); i++) { - special_items[i].special = -1; - } for(i = 0; i < scenario_timers.size(); i++) { scenario_timers[i].node = -1; } - for(i = 0; i < scen_items.size(); i++) { - scen_items[i] = cItem(); - } - if(!init_strings) return; + scen_name = "Scen name"; + who_wrote[0] = "Who wrote 1"; + who_wrote[1] = "Who wrote 2"; contact_info[0] = "Name not given"; - for(i = 0; i < 270; i++) { - temp_str = get_str("scen-default",i + 1); - if(i == 0) scen_name = temp_str; - else if(i == 1 || i == 2) - who_wrote[i-1] = temp_str; - else if(i == 3) - contact_info[1] = temp_str; - else if(i >= 4 && i < 10) - intro_strs[i-4] = temp_str; - else if(i >= 10 && i < 60) - journal_strs[i-10] = temp_str; - else if(i >= 60 && i < 160) { - if(i % 2 == 0) special_items[(i-60)/2].name = temp_str; - else special_items[(i-60)/2].descr = temp_str; - } else if(i >= 260) continue; // These were never ever used, for some reason. - else spec_strs[i-160] = temp_str; - } + contact_info[1] = "Contact info"; } cScenario::cItemStorage::cItemStorage() : ter_type(-1), property(0) { @@ -136,6 +116,7 @@ void cScenario::append(legacy::scenario_data_type& old){ store_item_rects[i].right = old.store_item_rects[i].right; store_item_towns[i] = old.store_item_towns[i]; } + special_items.resize(50); for(i = 0; i < 50; i++) { special_items[i].flags = old.special_items[i]; special_items[i].special = old.special_item_special[i]; @@ -147,7 +128,9 @@ void cScenario::append(legacy::scenario_data_type& old){ boats[i].append(old.scen_boats[i]); horses[i].append(old.scen_horses[i]); } + ter_types.resize(256); scen_specials.resize(256); + scen_monsters.resize(256); for(i = 0; i < 256; i++){ ter_types[i].i = i; ter_types[i].append(old.ter_types[i]); @@ -174,6 +157,7 @@ cScenario::cItemStorage& cScenario::cItemStorage::operator = (legacy::item_stora void cScenario::append(legacy::scen_item_data_type& old){ short i; + scen_items.resize(400); for(i = 0; i < 400; i++) scen_items[i].append(old.scen_items[i]); for(i = 0; i < 256; i++) { @@ -229,3 +213,73 @@ ter_num_t cScenario::get_trim_terrain(unsigned short ground, unsigned short trim } return 90; } + +bool cScenario::is_ter_used(ter_num_t ter) { + if(ter >= ter_types.size()) return false; + if(ter <= 90) return true; + for(int sx = 0; sx < outdoors.width(); sx++) { + for(int sy = 0; sy < outdoors.height(); sy++) { + for(int x = 0; x < 48; x++) { + for(int y = 0; y < 48; y++) { + if(outdoors[sx][sy]->terrain[x][y] == ter) + return true; + } + } + } + } + for(int i = 0; i < towns.size(); i++) { + for(int x = 0; x < towns[i]->max_dim(); x++) { + for(int y = 0; y < towns[i]->max_dim(); y++) { + if(towns[i]->terrain(x,y) == ter) + return true; + } + } + } + return false; +} + +bool cScenario::is_monst_used(mon_num_t monst) { + if(monst >= scen_monsters.size()) return false; + for(int sx = 0; sx < outdoors.width(); sx++) { + for(int sy = 0; sy < outdoors.height(); sy++) { + for(int i = 0; i < outdoors[sx][sy]->wandering.size(); i++) { + for(int j = 0; j < outdoors[sx][sy]->wandering[i].monst.size(); j++) { + if(outdoors[sx][sy]->wandering[i].monst[j] == monst) + return true; + } + for(int j = 0; j < outdoors[sx][sy]->wandering[i].friendly.size(); j++) { + if(outdoors[sx][sy]->wandering[i].friendly[j] == monst) + return true; + } + } + for(int i = 0; i < outdoors[sx][sy]->special_enc.size(); i++) { + for(int j = 0; j < outdoors[sx][sy]->special_enc[i].monst.size(); j++) { + if(outdoors[sx][sy]->special_enc[i].monst[j] == monst) + return true; + } + for(int j = 0; j < outdoors[sx][sy]->special_enc[i].friendly.size(); j++) { + if(outdoors[sx][sy]->special_enc[i].friendly[j] == monst) + return true; + } + } + } + } + for(int i = 0; i < towns.size(); i++) { + for(int j = 0; j < towns[i]->creatures.size(); j++) { + if(towns[i]->creatures[j].number == monst) + return true; + } + } + return false; +} + +bool cScenario::is_item_used(item_num_t item) { + if(item >= scen_items.size()) return false; + for(int i = 0; i < towns.size(); i++) { + for(int j = 0; j < towns[i]->preset_items.size(); j++) { + if(towns[i]->preset_items[j].code == item) + return true; + } + } + return false; +} diff --git a/src/classes/scenario.hpp b/src/classes/scenario.hpp index d0989707..17af9c34 100644 --- a/src/classes/scenario.hpp +++ b/src/classes/scenario.hpp @@ -69,15 +69,15 @@ public: std::array town_mods; rectangle store_item_rects[3]; short store_item_towns[3]; - std::array special_items; + std::vector special_items; std::vector quests; std::vector shops; short rating,uses_custom_graphics; std::vector custom_graphics; - std::array scen_monsters; + std::vector scen_monsters; std::array boats; std::array horses; - std::array ter_types; + std::vector ter_types; std::array scenario_timers; std::vector scen_specials; cItemStorage storage_shortcuts[10]; @@ -86,21 +86,19 @@ public: short last_town_edited; scenario_header_flags format; std::string campaign_id; // A hopefully unique identifier to specify the campaign this scenario is a part of. - std::array scen_items; + std::vector scen_items; std::string scen_name; std::string who_wrote[2]; std::string contact_info[2]; std::string intro_strs[6]; - // Using std::array here so we can have .size() - // This'll make the transition smoother once it becomes a vector. - std::array journal_strs; - std::array spec_strs; + std::vector journal_strs; + std::vector spec_strs; bool adjust_diff; bool is_legacy; fs::path scen_file; // transient vector2d outdoors; std::vector towns; - template void addTown() {towns.push_back(new Town(*this, true));} + template void addTown() {towns.push_back(new Town(*this));} void append(legacy::scenario_data_type& old); void append(legacy::scen_item_data_type& old); @@ -112,9 +110,13 @@ public: ter_num_t get_ter_from_ground(unsigned short ground); ter_num_t get_trim_terrain(unsigned short ground, unsigned short trim_g, eTrimType trim); + bool is_ter_used(ter_num_t ter); + bool is_monst_used(mon_num_t monst); + bool is_item_used(item_num_t item); + cScenario& operator=(cScenario&& other); cScenario(cScenario&) = delete; - explicit cScenario(bool init_strings = false); + explicit cScenario(); ~cScenario(); }; diff --git a/src/classes/talking.cpp b/src/classes/talking.cpp index e2c55382..85bd6cf8 100644 --- a/src/classes/talking.cpp +++ b/src/classes/talking.cpp @@ -17,6 +17,7 @@ void cSpeech::append(legacy::talking_record_type& old, std::vector& shops){ int i,j; + talk_nodes.resize(60); for(i = 0; i < 60; i++){ talk_nodes[i].personality = old.talk_nodes[i].personality; for(j = 0; j < 4; j++){ diff --git a/src/classes/talking.hpp b/src/classes/talking.hpp index 65116e78..e4f7d34b 100644 --- a/src/classes/talking.hpp +++ b/src/classes/talking.hpp @@ -36,15 +36,19 @@ class cSpeech { // formerly talking_record_type public: class cNode { // formerly talking_node_type public: - short personality; - eTalkNode type; + short personality = -1; + eTalkNode type = eTalkNode::REGULAR; char link1[4],link2[4]; short extras[4]; std::string str1, str2; - cNode() {std::fill(extras, extras + 4, -1);} + cNode() { + std::fill(extras, extras + 4, -1); + std::fill(link1, link1 + 4, 'x'); + std::fill(link2, link2 + 4, 'x'); + } }; cPersonality people[10]; - std::array talk_nodes; + std::vector talk_nodes; void append(legacy::talking_record_type& old, std::vector& shops); void writeTo(std::ostream& file) const; diff --git a/src/classes/town.cpp b/src/classes/town.cpp index 01c4413e..4260563e 100644 --- a/src/classes/town.cpp +++ b/src/classes/town.cpp @@ -46,6 +46,7 @@ void cTown::append(legacy::town_record_type& old){ temp.append(old.preset_fields[i]); preset_fields.push_back(temp); } + sign_locs.resize(15); for(i = 0; i < 15; i++){ sign_locs[i].x = old.sign_locs[i].x; sign_locs[i].y = old.sign_locs[i].y; @@ -74,7 +75,7 @@ void cTown::append(legacy::town_record_type& old){ strong_barriers = defy_scrying = defy_mapping = false; } -cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) { +cTown::cTown(cScenario& scenario) : scenario(scenario) { short i; cTown::cWandering d_wan = {0,0,0,0}; @@ -95,9 +96,6 @@ cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) { spec_on_entry = -1; spec_on_entry_if_dead = -1; spec_on_hostile = -1; - for(i = 0; i < 15; i++) { - sign_locs[i].x = 100; - } for(i = 0; i < 8; i++) { timers[i].time = 0; timers[i].node = -1; @@ -105,34 +103,11 @@ cTown::cTown(cScenario& scenario, bool init_strings) : scenario(scenario) { difficulty = 0; bg_town = bg_fight = -1; strong_barriers = defy_scrying = defy_mapping = is_hidden = has_tavern = false; - for(i = 0; i < 60; i++) { - talking.talk_nodes[i].personality = -1; - talking.talk_nodes[i].type = eTalkNode::REGULAR; - talking.talk_nodes[i].extras[0] = 0; - talking.talk_nodes[i].extras[1] = 0; - talking.talk_nodes[i].extras[2] = 0; - talking.talk_nodes[i].extras[3] = -1; - talking.talk_nodes[i].str1 = ""; - talking.talk_nodes[i].str2 = ""; - for(int j = 0; j < 4; j++) { - talking.talk_nodes[i].link1[j] = 'x'; - talking.talk_nodes[i].link2[j] = 'x'; - } - } - if(!init_strings) return; - std::string temp_str; - for(i = 0; i < 180; i++) { - temp_str = get_str("town-default",i + 1); - if(i == 0) town_name = temp_str; - else if(i >= 1 && i < 17) - room_rect[i-1].descr = temp_str; - else if(i >= 17 && i < 20) - comment[i-17] = temp_str; - else if(i >= 20 && i < 120) - spec_strs[i-20] = temp_str; - else if(i >= 120 && i < 140) - sign_locs[i-120].text = temp_str; - } + + town_name = "Town name"; + comment[0] = "Comment 1"; + comment[1] = "Comment 2"; + comment[2] = "Comment 3"; for(i = 0; i < 10; i++) { talking.people[i].title = "Unused"; diff --git a/src/classes/town.hpp b/src/classes/town.hpp index c1efc336..7fd3ac2f 100644 --- a/src/classes/town.hpp +++ b/src/classes/town.hpp @@ -74,7 +74,7 @@ public: std::array wandering; location wandering_locs[4]; std::vector special_locs; - std::array sign_locs; + std::vector sign_locs; eLighting lighting_type; location start_locs[4]; location exit_locs[4]; @@ -94,9 +94,9 @@ public: std::string town_name; // Using std::array here so we can have .size() // This'll make the transition smoother once it becomes a vector. - std::array room_rect; + std::vector room_rect; std::array comment; - std::array spec_strs; + std::vector spec_strs; cSpeech talking; virtual ~cTown(){} @@ -111,7 +111,7 @@ public: void set_up_lights(); short light_obscurity(short x,short y); // Obscurity function used for calculating lighting - explicit cTown(cScenario& scenario, bool init_strings = false); + explicit cTown(cScenario& scenario); void append(legacy::town_record_type& old); virtual void writeTerrainTo(std::ostream& file) = 0; virtual void readTerrainFrom(std::istream& file) = 0; diff --git a/src/pcedit/pc.menus.mac.mm b/src/pcedit/pc.menus.mac.mm index 9c61afde..28761fd8 100644 --- a/src/pcedit/pc.menus.mac.mm +++ b/src/pcedit/pc.menus.mac.mm @@ -113,7 +113,7 @@ void update_item_menu() { [items_menu[j] removeAllItems]; if(!scen_items_loaded) { [[items_menu[j] addItemWithTitle: @"Items Not Loaded" action: @selector(itemMenu:) keyEquivalent: @""] setEnabled: NO]; - } else for(int i = 0; i < per_menu; i++) { + } else for(int i = 0; i < per_menu && i + j * per_menu < item_list.size(); i++) { ItemWrapper* item = [ItemWrapper withItem: i + per_menu * j]; NSString* item_name = [NSString stringWithCString: item_list[i + j * per_menu].full_name.c_str() encoding: NSASCIIStringEncoding]; NSMenuItem* choice = [items_menu[j] addItemWithTitle: item_name action: @selector(itemMenu:) keyEquivalent: @""]; diff --git a/src/pcedit/pc.menus.win.cpp b/src/pcedit/pc.menus.win.cpp index 8416b2b7..1d67eb45 100644 --- a/src/pcedit/pc.menus.win.cpp +++ b/src/pcedit/pc.menus.win.cpp @@ -120,7 +120,7 @@ void update_item_menu() { while(GetMenuItemCount(items_menu)) RemoveMenu(items_menu, 0, MF_BYPOSITION); if(!scen_items_loaded) { AppendMenuA(items_menu, MF_STRING | MF_GRAYED, 1000, "Items Not Loaded"); - } else for(int i = 0; i < per_menu; i++) { + } else for(int i = 0; i < per_menu && i + j * per_menu < item_list.size(); i++) { cItem& item = item_list[i + j * per_menu]; UINT flags = MF_STRING | MF_ENABLED; if(i % per_col == 0) flags |= MF_MENUBARBREAK; diff --git a/src/scenedit/scen.actions.cpp b/src/scenedit/scen.actions.cpp index 5a7ea9fd..019d071d 100644 --- a/src/scenedit/scen.actions.cpp +++ b/src/scenedit/scen.actions.cpp @@ -34,7 +34,6 @@ short current_block_edited = 0; short current_terrain_type = 0; short safety = 0; location spot_hit,last_spot_hit(-1,-1),mouse_spot(-1,-1); -bool sign_error_received = false; short copied_spec = -1; cTown::cItem store_place_item; @@ -61,7 +60,7 @@ extern bool change_made; rectangle left_buttons[NLS][2]; // 0 - whole, 1 - blue button std::array left_button_status; -std::array right_button_status; +std::vector right_button_status; rectangle right_buttons[NRSONPAGE]; rectangle palette_buttons_from[71]; rectangle palette_buttons[10][6]; @@ -198,16 +197,16 @@ static bool handle_lb_action(location the_point) { break; case LB_EDIT_TEXT: right_sbar->setPosition(0); - start_string_editing(0,0); + start_string_editing(STRS_SCEN,0); break; case LB_EDIT_SPECITEM: - start_special_item_editing(); + start_special_item_editing(false); break; case LB_EDIT_QUEST: - start_quest_editing(); + start_quest_editing(false); break; case LB_EDIT_SHOPS: - start_shops_editing(); + start_shops_editing(false); break; case LB_LOAD_OUT: if(change_made) { @@ -259,7 +258,7 @@ static bool handle_lb_action(location the_point) { static bool handle_rb_action(location the_point, bool option_hit) { long right_top = right_sbar->getPosition(); - for(int i = 0; i < NRSONPAGE; i++) + for(int i = 0; i < NRSONPAGE && i + right_top < NRS; i++) if(!mouse_button_held && (the_point.in(right_buttons[i]) ) && (right_button_status[i + right_top].action != RB_CLEAR)) { @@ -278,16 +277,61 @@ static bool handle_rb_action(location the_point, bool option_hit) { switch(right_button_status[i + right_top].action) { case RB_CLEAR: break; - case RB_TER: - edit_ter_type(j); - break; case RB_MONST: - edit_monst_type(j); - start_monster_editing(1); + size_before = scenario.scen_monsters.size(); + if(option_hit) { + if(j == size_before - 1 && !scenario.is_monst_used(j)) + scenario.scen_monsters.pop_back(); + else if(j == size_before) { + scenario.scen_monsters.resize(size_before + 8); + for(; j < scenario.scen_monsters.size(); j++) + scenario.scen_monsters[j].m_name = "New Monster"; + } else { + scenario.scen_monsters[j] = cMonster(); + scenario.scen_monsters[j].m_name = "Unused Monster"; + } + } else { + if(j == size_before) { + scenario.scen_monsters.emplace_back(); + scenario.scen_monsters.back().m_name = "New Monster"; + } + if(!edit_monst_type(j) && j == size_before && scenario.scen_monsters.back().m_name == "New Monster") + scenario.scen_monsters.pop_back(); + } + start_monster_editing(size_before == scenario.scen_monsters.size()); + if(size_before > scenario.scen_monsters.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_ITEM: - edit_item_type(j); - start_item_editing(1); + size_before = scenario.scen_items.size(); + if(option_hit) { + if(j == size_before - 1 && !scenario.is_item_used(j)) + scenario.scen_items.pop_back(); + else if(j == size_before) { + scenario.scen_items.resize(size_before + 8); + for(; j < scenario.scen_items.size(); j++) { + scenario.scen_items[j].full_name = "New Item"; + scenario.scen_items[j].name = "Item"; + } + } else { + scenario.scen_items[j] = cItem(); + scenario.scen_items[j].full_name = "Unused Item"; + scenario.scen_items[j].name = "Item"; + } + } else { + if(j == size_before) { + scenario.scen_items.emplace_back(); + scenario.scen_items.back().full_name = "New Item"; + scenario.scen_items.back().name = "Item"; + } + if(!edit_item_type(j) && j == size_before && scenario.scen_items.back().name == "New Item") + scenario.scen_items.pop_back(); + } + start_item_editing(size_before == scenario.scen_items.size()); + if(size_before > scenario.scen_items.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_SCEN_SPEC: size_before = scenario.scen_specials.size(); @@ -300,8 +344,7 @@ static bool handle_rb_action(location the_point, bool option_hit) { } else { if(j == size_before) scenario.scen_specials.emplace_back(); - if(!edit_spec_enc(j,0,nullptr) && j == size_before) - scenario.scen_specials.pop_back(); + edit_spec_enc(j,0,nullptr); } start_special_editing(0,size_before == scenario.scen_specials.size()); if(size_before > scenario.scen_specials.size()) @@ -319,8 +362,7 @@ static bool handle_rb_action(location the_point, bool option_hit) { } else { if(j == size_before) current_terrain->specials.emplace_back(); - if(!edit_spec_enc(j,1,nullptr) && j == size_before) - current_terrain->specials.pop_back(); + edit_spec_enc(j,1,nullptr); } start_special_editing(1,size_before == current_terrain->specials.size()); if(size_before > current_terrain->specials.size()) @@ -338,8 +380,7 @@ static bool handle_rb_action(location the_point, bool option_hit) { } else { if(j == size_before) town->specials.emplace_back(); - if(!edit_spec_enc(j,2,nullptr) && j == size_before) - town->specials.pop_back(); + edit_spec_enc(j,2,nullptr); } start_special_editing(2,size_before == town->specials.size()); if(size_before > town->specials.size()) @@ -347,55 +388,205 @@ static bool handle_rb_action(location the_point, bool option_hit) { right_sbar->setPosition(pos_before); break; case RB_SCEN_STR: - if(option_hit) - scenario.spec_strs[j] = get_str("scen-default", j + 161); - else edit_text_str(j,0); - start_string_editing(0,1); + size_before = scenario.spec_strs.size(); + if(option_hit) { + if(j == size_before - 1) + scenario.spec_strs.pop_back(); + else if(j == size_before) + scenario.spec_strs.resize(size_before + 8, "*"); + else scenario.spec_strs[j] = "*"; + } else { + if(j == size_before) + scenario.spec_strs.emplace_back("*"); + if(!edit_text_str(j,STRS_SCEN) && j == size_before && scenario.spec_strs[j] == "*") + scenario.spec_strs.pop_back(); + } + start_string_editing(STRS_SCEN,size_before == scenario.spec_strs.size()); + if(size_before > scenario.spec_strs.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; - case RB_OUT_STR: - if(option_hit) - current_terrain->spec_strs[j] = get_str("outdoor-default", j + 11); - else edit_text_str(j,1); - start_string_editing(1,1); + size_before = current_terrain->spec_strs.size(); + if(option_hit) { + if(j == size_before - 1) + current_terrain->spec_strs.pop_back(); + else if(j == size_before) + current_terrain->spec_strs.resize(size_before + 8, "*"); + else current_terrain->spec_strs[j] = "*"; + } else { + if(j == size_before) + current_terrain->spec_strs.emplace_back("*"); + if(!edit_text_str(j,STRS_OUT) && j == size_before && current_terrain->spec_strs[j] == "*") + current_terrain->spec_strs.pop_back(); + } + start_string_editing(STRS_OUT,size_before == current_terrain->spec_strs.size()); + if(size_before > current_terrain->spec_strs.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_TOWN_STR: - if(option_hit) - town->spec_strs[j] = get_str("town-default", j + 21); - else edit_text_str(j,2); - start_string_editing(2,1); + size_before = town->spec_strs.size(); + if(option_hit) { + if(j == size_before - 1) + town->spec_strs.pop_back(); + else if(j == size_before) + town->spec_strs.resize(size_before + 8, "*"); + else town->spec_strs[j] = "*"; + } else { + if(j == size_before) + town->spec_strs.emplace_back("*"); + if(!edit_text_str(j,STRS_TOWN) && j == size_before && town->spec_strs[j] == "*") + town->spec_strs.pop_back(); + } + start_string_editing(STRS_TOWN,size_before == town->spec_strs.size()); + if(size_before > town->spec_strs.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_SPEC_ITEM: - edit_spec_item(j); - start_special_item_editing(); + size_before = scenario.special_items.size(); + if(option_hit) { + if(j == size_before - 1) + scenario.special_items.pop_back(); + else if(j == size_before) + break; + else { + scenario.special_items[j] = cSpecItem(); + scenario.special_items[j].name = "Unused Special Item"; + } + } else { + if(j == size_before) { + scenario.special_items.emplace_back(); + scenario.special_items.back().name = "New Special Item"; + } + if(!edit_spec_item(j) && j == size_before) + scenario.special_items.pop_back(); + } + start_special_item_editing(size_before == scenario.special_items.size()); + if(size_before > scenario.special_items.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_JOURNAL: - if(option_hit) - scenario.journal_strs[j] = get_str("scen-default", j + 11); - else edit_text_str(j,3); - start_string_editing(3,1); + size_before = scenario.journal_strs.size(); + if(option_hit) { + if(j == size_before - 1) + scenario.journal_strs.pop_back(); + else if(j == size_before) + scenario.journal_strs.resize(size_before + 8, "*"); + else scenario.journal_strs[j] = "*"; + } else { + if(j == size_before) + scenario.journal_strs.emplace_back("*"); + if(!edit_text_str(j,STRS_JOURNAL) && j == size_before && scenario.journal_strs[j] == "*") + scenario.journal_strs.pop_back(); + } + start_string_editing(STRS_JOURNAL,size_before == scenario.journal_strs.size()); + if(size_before > scenario.journal_strs.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_DIALOGUE: - edit_talk_node(j); - start_dialogue_editing(1); + size_before = town->talking.talk_nodes.size(); + if(option_hit) { + if(j == size_before) + break; + town->talking.talk_nodes.erase(town->talking.talk_nodes.begin() + j); + } else { + if(j == size_before) + town->talking.talk_nodes.emplace_back(); + // TODO: Mustn't do this if the Create New button was clicked to make more nodes! Ditto with special nodes. + if(edit_talk_node(j) == town->talking.talk_nodes.size() - 1) + town->talking.talk_nodes.pop_back(); + } + start_dialogue_editing(size_before == town->talking.talk_nodes.size()); + if(size_before > town->talking.talk_nodes.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_PERSONALITY: edit_basic_dlog(j); start_dialogue_editing(1); break; case RB_OUT_SIGN: - if(option_hit) - current_terrain->spec_strs[j] = get_str("outdoor-default", j + 101); - else edit_text_str(j,4); - start_string_editing(4,1); + size_before = current_terrain->sign_locs.size(); + if(option_hit) { + if(j == size_before - 1) + current_terrain->sign_locs.pop_back(); + else if(j == size_before) + break; + else current_terrain->sign_locs[j] = {-1, -1, "*"}; + } else { + if(j == size_before) + current_terrain->sign_locs.emplace_back(-1,-1,"*"); + if(!edit_text_str(j,STRS_OUT_SIGN) && j == size_before && current_terrain->sign_locs[j].text == "*") + current_terrain->sign_locs.pop_back(); + } + start_string_editing(STRS_OUT_SIGN,size_before == current_terrain->sign_locs.size()); + if(size_before > current_terrain->sign_locs.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_TOWN_SIGN: - if(option_hit) - town->spec_strs[j] = get_str("town-default", j + 121); - else edit_text_str(j,5); - start_string_editing(5,1); + size_before = town->sign_locs.size(); + if(option_hit) { + if(j == size_before - 1) + town->sign_locs.pop_back(); + else if(j == size_before) + break; + else town->sign_locs[j] = {-1, -1, "*"}; + } else { + if(j == size_before) + town->sign_locs.emplace_back(-1,-1,"*"); + if(!edit_text_str(j,STRS_TOWN_SIGN) && j == size_before && town->sign_locs[j].text == "*") + town->sign_locs.pop_back(); + } + start_string_editing(STRS_TOWN_SIGN,size_before == town->sign_locs.size()); + if(size_before > town->sign_locs.size()) + pos_before--; + right_sbar->setPosition(pos_before); + break; + case RB_OUT_RECT: + size_before = current_terrain->info_rect.size(); + if(option_hit) { + if(j == size_before - 1) + current_terrain->info_rect.pop_back(); + else if(j == size_before) + break; + else current_terrain->info_rect[j] = {0, 0, 0, 0, "*"}; + } else { + if(j == size_before) + current_terrain->info_rect.emplace_back(0,0,0,0,"*"); + if(!edit_text_str(j,STRS_OUT_RECT) && j == size_before && current_terrain->info_rect[j].descr == "*") + current_terrain->info_rect.pop_back(); + } + start_string_editing(STRS_OUT_RECT,size_before == current_terrain->info_rect.size()); + if(size_before > current_terrain->info_rect.size()) + pos_before--; + right_sbar->setPosition(pos_before); + break; + case RB_TOWN_RECT: + size_before = town->room_rect.size(); + if(option_hit) { + if(j == size_before - 1) + town->room_rect.pop_back(); + else if(j == size_before) + break; + else town->room_rect[j] = {0, 0, 0, 0, "*"}; + } else { + if(j == size_before) + town->room_rect.emplace_back(0,0,0,0,"*"); + if(!edit_text_str(j,STRS_TOWN_RECT) && j == size_before && town->room_rect[j].descr == "*") + town->room_rect.pop_back(); + } + start_string_editing(STRS_TOWN_RECT,size_before == town->room_rect.size()); + if(size_before > town->room_rect.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_QUEST: + size_before = scenario.quests.size(); if(option_hit) { if(j == scenario.quests.size() - 1) scenario.quests.pop_back(); @@ -403,18 +594,32 @@ static bool handle_rb_action(location the_point, bool option_hit) { scenario.quests[j] = cQuest(); scenario.quests[j].name = "Unused Quest"; } - } else edit_quest(j); - start_quest_editing(); + } else { + if(!edit_quest(j) && j == size_before && scenario.quests[j].name == "New Quest") + scenario.quests.pop_back(); + } + start_quest_editing(size_before == scenario.quests.size()); + if(size_before > scenario.quests.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; case RB_SHOP: + size_before = scenario.shops.size(); if(option_hit) { if(j == scenario.shops.size() - 1) scenario.shops.pop_back(); else scenario.shops[j] = cShop("Unused Shop"); - } else edit_shop(j); - start_shops_editing(); + } else { + if(!edit_shop(j) && j == size_before && scenario.shops[j].getName() == "New Shop") + scenario.shops.pop_back(); + } + start_shops_editing(size_before == scenario.shops.size()); + if(size_before > scenario.shops.size()) + pos_before--; + right_sbar->setPosition(pos_before); break; } + change_made = true; mouse_button_held = false; return true; } @@ -507,8 +712,13 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { town->room_rect[x].descr = ""; if(!edit_area_rect_str(x,1)) town->room_rect[x].right = 0; - x = 500; + break; } + if(x == town->room_rect.size()) { + town->room_rect.emplace_back(working_rect); + if(!edit_area_rect_str(x,1)) + town->room_rect.pop_back(); + } } else { for(x = 0; x < current_terrain->info_rect.size(); x++) @@ -517,13 +727,15 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { current_terrain->info_rect[x].descr = ""; if(!edit_area_rect_str(x,0)) current_terrain->info_rect[x].right = 0; - x = 500; + break; } - + if(x == current_terrain->info_rect.size()) { + current_terrain->info_rect.emplace_back(working_rect); + if(!edit_area_rect_str(x,0)) + current_terrain->info_rect.pop_back(); + } } - if(x < 500) - giveError("You have placed the maximum number of area rectangles (16 in town, 8 outdoors)."); - else change_made = true; + change_made = true; } overall_mode = MODE_DRAWING; set_cursor(wand_curs); @@ -729,10 +941,11 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { for(x = 0; x < town->sign_locs.size(); x++) if((town->sign_locs[x].x == spot_hit.x) && (town->sign_locs[x].y == spot_hit.y)) { edit_sign(x,scenario.ter_types[town->terrain(spot_hit.x,spot_hit.y)].picture); - x = 30; + break; } - if(x == 15) { - giveError("Either this space is not a sign, or you have already placed too many signs on this level."); + if(x == town->sign_locs.size()) { + town->sign_locs.emplace_back(spot_hit); + edit_sign(x,scenario.ter_types[town->terrain(spot_hit.x,spot_hit.y)].picture); } } if(!editing_town) { @@ -741,8 +954,9 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { edit_sign(x,scenario.ter_types[current_terrain->terrain[spot_hit.x][spot_hit.y]].picture); x = 30; } - if(x == 8) { - giveError("Either this space is not a sign, or you have already placed too many signs on this level."); + if(x == current_terrain->sign_locs.size()) { + current_terrain->sign_locs.emplace_back(spot_hit); + edit_sign(x,scenario.ter_types[town->terrain(spot_hit.x,spot_hit.y)].picture); } } set_cursor(wand_curs); @@ -861,6 +1075,15 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { overall_mode = MODE_DRAWING; set_cursor(wand_curs); break; + case MODE_ERASE_TOWN_ENTRANCE: + for(x = current_terrain->city_locs.size() - 1; x >= 0; x--) { + if(current_terrain->city_locs[x] == spot_hit) + current_terrain->city_locs.erase(current_terrain->city_locs.begin() + x); + } + set_cursor(wand_curs); + overall_mode = MODE_DRAWING; + change_made = true; + break; case MODE_SET_OUT_START: //edit out start loc if(cChoiceDlog("set-out-start-confirm", {"okay", "cancel"}).show() == "cancel") break; @@ -876,7 +1099,7 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { change_made = true; break; case MODE_ERASE_CREATURE: //delete monst - for(x = 0; x < 60; x++) + for(x = 0; x < town->creatures.size(); x++) if(monst_on_space(spot_hit,x)) { town->creatures[x].number = 0; break; @@ -947,36 +1170,65 @@ static bool handle_terrain_action(location the_point, bool ctrl_hit) { return false; } -static bool handle_terpal_action(location cur_point) { +static bool handle_terpal_action(location cur_point, bool option_hit) { for(int i = 0; i < 256; i++) if(cur_point.in(terrain_rects[i])) { + int k = pal_sbar->getPosition() * 16 + i; rectangle temp_rect = terrain_rects[i]; temp_rect.offset(RIGHT_AREA_UL_X, RIGHT_AREA_UL_Y ); flash_rect(temp_rect); if(overall_mode < MODE_MAIN_SCREEN) { switch(draw_mode) { case DRAW_TERRAIN: - set_new_terrain(pal_sbar->getPosition() * 16 + i); + set_new_terrain(k); break; case DRAW_ITEM: - if(scenario.scen_items[mode_count].variety == eItemType::NO_ITEM) { + if(k >= scenario.scen_items.size()) + break; + if(scenario.scen_items[k].variety == eItemType::NO_ITEM) { giveError("This item has its Variety set to No Item. You can only place items with a Variety set to an actual item type."); break; } overall_mode = MODE_PLACE_ITEM; - mode_count = pal_sbar->getPosition() * 16 + i; + mode_count = k; set_string("Place the item:",scenario.scen_items[mode_count].full_name.c_str()); break; case DRAW_MONST: + if(k + 1 >= scenario.scen_monsters.size()) + break; overall_mode = MODE_PLACE_CREATURE; - mode_count = pal_sbar->getPosition() * 16 + i + 1; + mode_count = k + 1; set_string("Place the monster:",scenario.scen_monsters[mode_count].m_name.c_str()); break; } } else { - edit_ter_type(i); - set_up_terrain_buttons(true); + short size_before = scenario.ter_types.size(), pos_before = pal_sbar->getPosition(); + i += pos_before * 16; + if(option_hit) { + if(i == size_before - 1 && !scenario.is_ter_used(i)) + scenario.ter_types.pop_back(); + else if(i == size_before) { + scenario.ter_types.resize(size_before + 16); + for(; i < scenario.ter_types.size(); i++) + scenario.ter_types[i].name = "New Terrain"; + } else { + scenario.ter_types[i] = cTerrain(); + scenario.ter_types[i].name = "Unused Terrain"; + } + } else { + if(i == size_before) { + scenario.ter_types.emplace_back(); + scenario.ter_types.back().name = "New Terrain"; + } + if(!edit_ter_type(i) && i == size_before && scenario.ter_types.back().name == "New Terrain") + scenario.ter_types.pop_back(); + } + if(size_before / 16 > scenario.ter_types.size() / 16) + pos_before--; + pal_sbar->setPosition(pos_before); + set_up_terrain_buttons(false); + change_made = true; } place_location(); return true; @@ -1078,6 +1330,15 @@ static bool handle_toolpal_action(location cur_point2) { set_cursor(hand_curs); overall_mode = MODE_EDIT_TOWN_ENTRANCE; break; + case PAL_ERASE_TOWN: + if(editing_town) { + set_string("Can only erase town entrances outdoors",""); + break; + } + set_string("Erase town entrance","Select town to erase"); + set_cursor(eraser_curs); + overall_mode = MODE_ERASE_TOWN_ENTRANCE; + break; case PAL_EDIT_ITEM: if(!editing_town) { set_string("Edit placed item","Not while outdoors."); @@ -1315,7 +1576,7 @@ void handle_action(location the_point,sf::Event /*event*/) { cur_point.x -= RIGHT_AREA_UL_X; cur_point.y -= RIGHT_AREA_UL_Y; - if(handle_terpal_action(cur_point)) + if(handle_terpal_action(cur_point, option_hit)) return; cur_point2 = cur_point; cur_point2.x -= 5; @@ -1357,6 +1618,7 @@ void swap_terrain() { } void set_new_terrain(ter_num_t selected_terrain) { + if(selected_terrain >= scenario.ter_types.size()) return; current_terrain_type = selected_terrain; // if(selected_terrain < 2) // current_ground = 0; @@ -1758,8 +2020,8 @@ void set_terrain(location l,ter_num_t terrain_type) { if((town->sign_locs[i].x == l.x) && (town->sign_locs[i].y == l.y)) which_sign = i; } - for(i = 0; i < town->sign_locs.size(); i++) - if(which_sign < 0) { + if(which_sign < 0) { + for(i = 0; i < town->sign_locs.size(); i++) if(town->sign_locs[i].x == 100) which_sign = i; else { @@ -1767,19 +2029,13 @@ void set_terrain(location l,ter_num_t terrain_type) { if(scenario.ter_types[ter].special != eTerSpec::IS_A_SIGN) which_sign = i; } - } - if(which_sign >= 0) { - static_cast(town->sign_locs[which_sign]) = l; - edit_sign(which_sign,scenario.ter_types[terrain_type].picture); - sign_error_received = false; } - else { - town->terrain(l.x,l.y) = current_ground; - if(!sign_error_received) { - giveError("Towns can have at most 15 signs. Outdoor sections can have at most 8. When the party looks at this sign, they will get no message."); - sign_error_received = true; - } + if(which_sign < 0) { + which_sign = town->sign_locs.size(); + town->sign_locs.emplace_back(); } + static_cast(town->sign_locs[which_sign]) = l; + edit_sign(which_sign,scenario.ter_types[terrain_type].picture); mouse_button_held = false; } if(scenario.ter_types[terrain_type].special == eTerSpec::IS_A_SIGN && !editing_town) { @@ -1793,8 +2049,8 @@ void set_terrain(location l,ter_num_t terrain_type) { if((current_terrain->sign_locs[i].x == l.x) && (current_terrain->sign_locs[i].y == l.y)) which_sign = i; } - for(i = 0; i < current_terrain->sign_locs.size(); i++) - if(which_sign < 0) { + if(which_sign < 0) { + for(i = 0; i < current_terrain->sign_locs.size(); i++) if(current_terrain->sign_locs[i].x == 100) which_sign = i; else { @@ -1802,19 +2058,13 @@ void set_terrain(location l,ter_num_t terrain_type) { if(scenario.ter_types[ter].special != eTerSpec::IS_A_SIGN) which_sign = i; } - } - if(which_sign >= 0) { - static_cast(current_terrain->sign_locs[which_sign]) = l; - edit_sign(which_sign,scenario.ter_types[terrain_type].picture); - sign_error_received = false; } - else { - current_terrain->terrain[l.x][l.y] = current_ground; - if(!sign_error_received) { - giveError("Towns can have at most 15 signs. Outdoor sections can have at most 8. When the party looks at this sign, they will get no message."); - sign_error_received = true; - } + if(which_sign < 0) { + which_sign = current_terrain->sign_locs.size(); + current_terrain->sign_locs.emplace_back(); } + static_cast(current_terrain->sign_locs[which_sign]) = l; + edit_sign(which_sign,scenario.ter_types[terrain_type].picture); mouse_button_held = false; } } @@ -2114,8 +2364,13 @@ void town_entry(location spot_hit) { } x = 500; } - if(y == -2) - giveError("You can't set more than 8 town entrances in any outdoor section."); + if(y == -2) { + y = pick_town_num("select-town-enter",0,scenario); + if(y >= 0) { + current_terrain->city_locs.emplace_back(spot_hit); + current_terrain->city_locs.back().spec = y; + } + } } } @@ -2249,36 +2504,37 @@ void start_terrain_editing() { set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"",true); } -void start_monster_editing(short just_redo_text) { +void start_monster_editing(bool just_redo_text) { + int num_options = scenario.scen_monsters.size() + 1; short i; - bool draw_full = false; - if(overall_mode == MODE_EDIT_TYPES) - draw_full = true; - if(just_redo_text == 0) { + if(!just_redo_text) { overall_mode = MODE_MAIN_SCREEN; right_sbar->show(); pal_sbar->hide(); right_sbar->setPosition(0); reset_rb(); - right_sbar->setMaximum(255 - NRSONPAGE); + right_sbar->setMaximum(num_options - 1 - NRSONPAGE); } - for(i = 1; i < scenario.scen_monsters.size(); i++) { - set_rb(i - 1,RB_MONST, i,std::to_string(i) + " - " + scenario.scen_monsters[i].m_name); + for(i = 1; i < num_options; i++) { + std::string title; + if(i == scenario.scen_monsters.size()) + title = "Create New Monster"; + else title = scenario.scen_monsters[i].m_name; + title = std::to_string(i) + " - " + title; + set_rb(i - 1,RB_MONST, i, title); } - if(draw_full) - redraw_screen(); - else for(i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i,0); - set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"",true); + set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"Alt-click to delete",true); + redraw_screen(); } -void start_item_editing(short just_redo_text) { +void start_item_editing(bool just_redo_text) { + int num_options = scenario.scen_items.size() + 1; short i; bool draw_full = false; - if(just_redo_text == 0) { + if(!just_redo_text) { if(overall_mode < MODE_MAIN_SCREEN) set_up_main_screen(); if(overall_mode == MODE_EDIT_TYPES) @@ -2289,53 +2545,59 @@ void start_item_editing(short just_redo_text) { right_sbar->setPosition(0); reset_rb(); - right_sbar->setMaximum(400 - NRSONPAGE); + right_sbar->setMaximum(num_options - NRSONPAGE); } - for(i = 0; i < scenario.scen_items.size(); i++) { - set_rb(i,RB_ITEM, i,std::to_string(i) + " - " + scenario.scen_items[i].full_name); + for(i = 0; i < num_options; i++) { + std::string title; + if(i == scenario.scen_items.size()) + title = "Create New Item"; + else title = scenario.scen_items[i].full_name; + title = std::to_string(i) + " - " + title; + set_rb(i,RB_ITEM, i, title); } - if(draw_full) - redraw_screen(); - else for(i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i,0); - set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"",true); + set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"Alt-click to delete",true); + redraw_screen(); } -void start_special_item_editing() { +void start_special_item_editing(bool just_redo_text) { + int num_options = scenario.special_items.size() + 1; short i; - bool draw_full = false; - if(overall_mode < MODE_MAIN_SCREEN) - set_up_main_screen(); - if(overall_mode == MODE_EDIT_TYPES) - draw_full = true; - overall_mode = MODE_MAIN_SCREEN; - right_sbar->show(); - pal_sbar->hide(); - - right_sbar->setPosition(0); - reset_rb(); - right_sbar->setMaximum(50 - NRSONPAGE); - for(i = 0; i < scenario.special_items.size(); i++) { - set_rb(i,RB_SPEC_ITEM, i,std::to_string(i) + " - " + scenario.special_items[i].name); + if(!just_redo_text) { + if(overall_mode < MODE_MAIN_SCREEN) + set_up_main_screen(); + overall_mode = MODE_MAIN_SCREEN; + right_sbar->show(); + pal_sbar->hide(); + + right_sbar->setPosition(0); + reset_rb(); + right_sbar->setMaximum(num_options - NRSONPAGE); } - if(draw_full) - redraw_screen(); - else for(i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i,0); - set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"",true); + for(i = 0; i < num_options; i++) { + std::string title; + if(i == scenario.special_items.size()) + title = "Create New Special Item"; + else title = scenario.special_items[i].name; + title = std::to_string(i) + " - " + title; + set_rb(i,RB_SPEC_ITEM, i, title); + } + set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"Alt-click to delete",true); + redraw_screen(); } -void start_quest_editing() { +void start_quest_editing(bool just_redo_text) { int num_options = scenario.quests.size() + 1; - if(overall_mode < MODE_MAIN_SCREEN) - set_up_main_screen(); - overall_mode = MODE_MAIN_SCREEN; - right_sbar->show(); - pal_sbar->hide(); - right_sbar->setPosition(0); - reset_rb(); - right_sbar->setMaximum(num_options - NRSONPAGE); + if(!just_redo_text) { + if(overall_mode < MODE_MAIN_SCREEN) + set_up_main_screen(); + overall_mode = MODE_MAIN_SCREEN; + right_sbar->show(); + pal_sbar->hide(); + right_sbar->setPosition(0); + reset_rb(); + right_sbar->setMaximum(num_options - NRSONPAGE); + } for(int i = 0; i < num_options; i++) { std::string title; if(i == scenario.quests.size()) @@ -2344,20 +2606,22 @@ void start_quest_editing() { title = std::to_string(i) + " - " + title; set_rb(i, RB_QUEST, i, title); } + set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Alt-click to delete",true); redraw_screen(); - set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Command-click or right-click to delete",true); } -void start_shops_editing() { +void start_shops_editing(bool just_redo_text) { int num_options = scenario.shops.size() + 1; - if(overall_mode < MODE_MAIN_SCREEN) - set_up_main_screen(); - overall_mode = MODE_MAIN_SCREEN; - right_sbar->show(); - pal_sbar->hide(); - right_sbar->setPosition(0); - reset_rb(); - right_sbar->setMaximum(num_options - NRSONPAGE); + if(!just_redo_text) { + if(overall_mode < MODE_MAIN_SCREEN) + set_up_main_screen(); + overall_mode = MODE_MAIN_SCREEN; + right_sbar->show(); + pal_sbar->hide(); + right_sbar->setPosition(0); + reset_rb(); + right_sbar->setMaximum(num_options - NRSONPAGE); + } for(int i = 0; i < num_options; i++) { std::string title; if(i == scenario.shops.size()) @@ -2366,31 +2630,29 @@ void start_shops_editing() { title = std::to_string(i) + " - " + title; set_rb(i, RB_SHOP, i, title); } + set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Alt-click to delete",true); redraw_screen(); - set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Command-click or right-click to delete",true); } extern size_t num_strs(short mode); // defined in scen.keydlgs.cpp // mode 0 - scen 1 - out 2 - town 3 - journal // if just_redo_text not 0, simply need to update text portions -void start_string_editing(short mode,short just_redo_text) { +void start_string_editing(eStrMode mode,short just_redo_text) { long pos; - bool draw_full = false; if(just_redo_text == 0) { if(overall_mode < MODE_MAIN_SCREEN) set_up_main_screen(); - if(overall_mode == MODE_EDIT_TYPES) - draw_full = true; overall_mode = MODE_MAIN_SCREEN; right_sbar->show(); pal_sbar->hide(); reset_rb(); - right_sbar->setMaximum(num_strs(mode) - NRSONPAGE); + right_sbar->setMaximum(num_strs(mode) + 1 - NRSONPAGE); } - for(size_t i = 0; i < num_strs(mode); i++) { + size_t num_strs = ::num_strs(mode); + for(size_t i = 0; i < num_strs; i++) { std::ostringstream str; switch(mode) { case 0: @@ -2417,23 +2679,37 @@ void start_string_editing(short mode,short just_redo_text) { str << i << " - " << town->sign_locs[i].text.substr(0,30); set_rb(i,RB_TOWN_SIGN, i,str.str()); break; + case 6: + str << i << " - " << current_terrain->info_rect[i].descr.substr(0,30); + set_rb(i,RB_OUT_RECT, i,str.str()); + break; + case 7: + str << i << " - " << town->room_rect[i].descr.substr(0,30); + set_rb(i,RB_TOWN_RECT, i,str.str()); + break; } } + std::string make_new = std::to_string(num_strs) + " - Create New String"; + switch(mode) { + case 0: set_rb(num_strs, RB_SCEN_STR, num_strs, make_new); break; + case 1: set_rb(num_strs, RB_OUT_STR, num_strs, make_new); break; + case 2: set_rb(num_strs, RB_TOWN_STR, num_strs, make_new); break; + case 3: set_rb(num_strs, RB_JOURNAL, num_strs, make_new); break; + case 4: set_rb(num_strs, RB_OUT_SIGN, num_strs, make_new); break; + case 5: set_rb(num_strs, RB_TOWN_SIGN, num_strs, make_new); break; + case 6: set_rb(num_strs, RB_OUT_RECT, num_strs, make_new); break; + case 7: set_rb(num_strs, RB_TOWN_RECT, num_strs, make_new); break; + } pos = right_sbar->getPosition(); - if(draw_full) - redraw_screen(); - else for(int i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i + pos,0); - set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Command-click to clear",true); + set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Alt-click to delete",true); + redraw_screen(); } // mode 0 - scen 1 - out 2 - town // if just_redo_text not 0, simply need to update text portions void start_special_editing(short mode,short just_redo_text) { - short i; size_t num_specs; - bool draw_full = false; switch(mode) { case 0: num_specs = scenario.scen_specials.size(); break; case 1: num_specs = current_terrain->specials.size(); break; @@ -2443,8 +2719,6 @@ void start_special_editing(short mode,short just_redo_text) { if(just_redo_text == 0) { if(overall_mode < MODE_MAIN_SCREEN) set_up_main_screen(); - if(overall_mode == MODE_EDIT_TYPES) - draw_full = true; overall_mode = MODE_MAIN_SCREEN; right_sbar->show(); pal_sbar->hide(); @@ -2476,23 +2750,17 @@ void start_special_editing(short mode,short just_redo_text) { case 1: set_rb(num_specs, RB_OUT_SPEC, num_specs, make_new); break; case 2: set_rb(num_specs, RB_TOWN_SPEC, num_specs, make_new); break; } - if(draw_full) - redraw_screen(); - else for(i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i,0); - set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Command-click to clear",true); + set_lb(NLS - 3,LB_TEXT,LB_NO_ACTION,"Alt-click to delete",true); + redraw_screen(); } // if restoring is 1, this is just a redraw, so don't move scroll bar position void start_dialogue_editing(short restoring) { short i,j; char s[15] = " , "; - bool draw_full = false; if(overall_mode < MODE_MAIN_SCREEN) set_up_main_screen(); - if(overall_mode == MODE_EDIT_TYPES) - draw_full = true; overall_mode = MODE_MAIN_SCREEN; right_sbar->show(); pal_sbar->hide(); @@ -2507,7 +2775,8 @@ void start_dialogue_editing(short restoring) { strb << "Personality " << (i + cur_town * 10) << " - " << town->talking.people[i].title; set_rb(i,RB_PERSONALITY, i, strb.str()); } - for(i = 0; i < 60; i++) { + size_t n_nodes = town->talking.talk_nodes.size(); + for(i = 0; i < n_nodes; i++) { for(j = 0; j < 4; j++) { s[j] = town->talking.talk_nodes[i].link1[j]; s[j + 6] = town->talking.talk_nodes[i].link2[j]; @@ -2516,11 +2785,9 @@ void start_dialogue_editing(short restoring) { strb << "Node " << i << " - Per. " << town->talking.talk_nodes[i].personality << ", " << s; set_rb(10 + i,RB_DIALOGUE, i, strb.str()); } - if(draw_full) - redraw_screen(); - else for(i = 0; i < NRSONPAGE; i++) - draw_rb_slot(i,0); - set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"",true); + set_rb(10 + n_nodes, RB_DIALOGUE, n_nodes, "Create New Node"); + set_lb(NLS - 3,LB_CLEAR,LB_NO_ACTION,"Alt-click node to delete",true); + redraw_screen(); } bool save_check(std::string which_dlog) { diff --git a/src/scenedit/scen.actions.hpp b/src/scenedit/scen.actions.hpp index fda53318..c03c349f 100644 --- a/src/scenedit/scen.actions.hpp +++ b/src/scenedit/scen.actions.hpp @@ -1,3 +1,6 @@ + +#include "scen.global.hpp" + void init_current_terrain(); void init_screen_locs(); void handle_action(location the_point,sf::Event event); @@ -27,12 +30,12 @@ void set_up_main_screen(); void start_town_edit(); void start_out_edit(); void start_terrain_editing(); -void start_monster_editing(short just_redo_text); -void start_item_editing(short just_redo_text); -void start_special_item_editing(); -void start_quest_editing(); -void start_shops_editing(); -void start_string_editing(short mode,short just_redo_text); +void start_monster_editing(bool just_redo_text); +void start_item_editing(bool just_redo_text); +void start_special_item_editing(bool just_redo_text); +void start_quest_editing(bool just_redo_text); +void start_shops_editing(bool just_redo_text); +void start_string_editing(eStrMode mode,short just_redo_text); void start_special_editing(short mode,short just_redo_text); void town_entry(location spot_hit); void start_dialogue_editing(short restoring); diff --git a/src/scenedit/scen.btnmg.cpp b/src/scenedit/scen.btnmg.cpp index d7ac6e95..b455d037 100644 --- a/src/scenedit/scen.btnmg.cpp +++ b/src/scenedit/scen.btnmg.cpp @@ -19,7 +19,7 @@ extern short current_rs_top; bool left_buttons_active = 1,right_buttons_active = 0; extern std::array left_button_status; -extern std::array right_button_status; +extern std::vector right_button_status; extern std::shared_ptr right_sbar; // for following, lb stands for left button(s) @@ -64,20 +64,12 @@ void set_lb(short slot, eLBMode mode, eLBAction action, std::string label, bool void init_rb() { - short i; - right_sbar->setPosition(0); - for(i = 0; i < NRS; i++) { - right_button_status[i] = {RB_CLEAR, 0, ""}; - } + right_button_status.clear(); } void reset_rb() { - short i; - - for(i = 0; i < NRS; i++) { - right_button_status[i] = {RB_CLEAR, 0, ""}; - } + right_button_status.clear(); draw_rb(); right_sbar->setMaximum(0); right_sbar->setPosition(0); @@ -92,11 +84,11 @@ void set_rb(short slot, eRBAction action, int n, std::string label, bool do_draw for(i = 0; i < NRS; i++) if(right_button_status[i].action == RB_CLEAR) { slot = i; - i = NRS + 5000; + break; } - if(i < NRS + 5000) - return; } + if(slot >= NRS) + right_button_status.resize(slot + 1); right_button_status[slot].action = action; right_button_status[slot].i = n; right_button_status[slot].label = label; diff --git a/src/scenedit/scen.btnmg.hpp b/src/scenedit/scen.btnmg.hpp index fbc971c4..53dd2e43 100644 --- a/src/scenedit/scen.btnmg.hpp +++ b/src/scenedit/scen.btnmg.hpp @@ -21,7 +21,6 @@ enum eLBAction { enum eRBAction { RB_CLEAR = 0, - RB_TER = 1, RB_MONST = 2, RB_ITEM = 3, RB_SCEN_SPEC = 4, @@ -38,6 +37,8 @@ enum eRBAction { RB_TOWN_SIGN = 15, RB_QUEST = 16, RB_SHOP = 17, + RB_OUT_RECT = 18, + RB_TOWN_RECT = 19, }; enum eLBMode { diff --git a/src/scenedit/scen.core.cpp b/src/scenedit/scen.core.cpp index 762c695f..c4c8e040 100644 --- a/src/scenedit/scen.core.cpp +++ b/src/scenedit/scen.core.cpp @@ -531,8 +531,9 @@ static bool edit_ter_obj(cDialog& me, ter_num_t which_ter) { return true; } -void edit_ter_type(ter_num_t which) { +bool edit_ter_type(ter_num_t which) { using namespace std::placeholders; + ter_num_t first = which; cDialog ter_dlg("edit-terrain"); // Attach handlers ter_dlg["pict"].attachFocusHandler(std::bind(check_range,_1,_2,_3,0,2999,"terrain graphic")); @@ -563,6 +564,7 @@ void edit_ter_type(ter_num_t which) { }); fill_ter_info(ter_dlg,which); ter_dlg.run(); + return ter_dlg.accepted() || which != first; } static void put_monst_info_in_dlog(cDialog& me, cMonster& monst, mon_num_t which) { @@ -811,8 +813,9 @@ static bool pick_monst_picture(cDialog& me) { return result; } -short edit_monst_type(short which) { +bool edit_monst_type(short which) { using namespace std::placeholders; + mon_num_t first = which; cMonster monst = scenario.scen_monsters[which]; cDialog monst_dlg("edit-monster"); @@ -829,12 +832,19 @@ short edit_monst_type(short which) { monst_dlg["priest"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 7, "priest spells")); monst_dlg["treas"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 4, "treasure")); monst_dlg.attachFocusHandlers(check_monst_dice,{"dice1","dice2","dice3","sides1","sides2","sides3"}); - monst_dlg.attachClickHandlers(std::bind(edit_monst_type_event_filter,_1,_2,std::ref(monst),std::ref(which)),{"okay","abils","left","right","picktype","picktype1","picktype2","picktype3"}); + monst_dlg.attachClickHandlers(std::bind(edit_monst_type_event_filter,_1,_2,std::ref(monst),std::ref(which)),{"okay","abils","picktype","picktype1","picktype2","picktype3"}); + + if(scenario.scen_monsters.size() == 1){ + monst_dlg["left"].hide(); + monst_dlg["right"].hide(); + } else { + monst_dlg.attachClickHandlers(std::bind(edit_monst_type_event_filter,_1,_2,std::ref(monst),std::ref(which)),{"left","right"}); + } put_monst_info_in_dlog(monst_dlg, monst, which); monst_dlg.run(); - return 0; + return monst_dlg.accepted() || first != which; } static void put_monst_abils_in_dlog(cDialog& me, cMonster& monst) { @@ -1665,8 +1675,10 @@ static bool change_item_variety(cDialog& me, std::string group, const cItem& ite return true; } -short edit_item_type(short which) { +bool edit_item_type(short which) { using namespace std::placeholders; + if(which == scenario.scen_items.size()) + scenario.scen_items.resize(which + 1); cItem item = scenario.scen_items[which]; cDialog item_dlg("edit-item"); @@ -1680,12 +1692,19 @@ short edit_item_type(short which) { item_dlg["weight"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 250, "Weight")); item_dlg["class"].attachFocusHandler(std::bind(check_range, _1, _2, _3, 0, 100, "Special Class")); item_dlg["variety"].attachFocusHandler(std::bind(change_item_variety, _1, _2, std::ref(item))); - item_dlg.attachClickHandlers(std::bind(edit_item_type_event_filter, _1, _2, std::ref(item), std::ref(which)), {"okay", "cancel", "prev", "next", "abils", "choosepic", "choosetp", "choosemiss", "desc"}); + item_dlg.attachClickHandlers(std::bind(edit_item_type_event_filter, _1, _2, std::ref(item), std::ref(which)), {"okay", "cancel", "abils", "choosepic", "choosetp", "choosemiss", "desc"}); + + if(scenario.scen_items.size() == 1) { + item_dlg["prev"].hide(); + item_dlg["next"].hide(); + } else { + item_dlg.attachClickHandlers(std::bind(edit_item_type_event_filter, _1, _2, std::ref(item), std::ref(which)), {"prev", "next"}); + } put_item_info_in_dlog(item_dlg, item, which); item_dlg.run(); - return 0; + return item_dlg.accepted(); } static void put_item_abils_in_dlog(cDialog& me, cItem& item, short which) { @@ -1964,18 +1983,28 @@ static bool edit_spec_item_event_filter(cDialog& me, std::string hit, cSpecItem& return true; } -void edit_spec_item(short which_item) { +bool edit_spec_item(short which_item) { + short first = which_item; using namespace std::placeholders; cSpecItem item = scenario.special_items[which_item]; cDialog item_dlg("edit-special-item"); item_dlg["spec"].attachFocusHandler(std::bind(check_range_msg, _1, _2, _3, -1, 255, "Scenario special node called", "-1 for no special")); - item_dlg.attachClickHandlers(std::bind(edit_spec_item_event_filter, _1, _2, std::ref(item), std::ref(which_item)), {"okay", "cancel", "clear", "edit-spec", "left", "right"}); + item_dlg.attachClickHandlers(std::bind(edit_spec_item_event_filter, _1, _2, std::ref(item), std::ref(which_item)), {"okay", "cancel", "clear", "edit-spec"}); + + if(scenario.special_items.size() == 1) { + item_dlg["left"].hide(); + item_dlg["right"].hide(); + } else { + item_dlg.attachClickHandlers(std::bind(edit_spec_item_event_filter, _1, _2, std::ref(item), std::ref(which_item)), {"left", "right"}); + } put_spec_item_in_dlog(item_dlg, item, which_item); item_dlg["clear"].hide(); item_dlg.run(); + + return item_dlg.accepted() || first != which_item; } static void put_quest_in_dlog(cDialog& me, const cQuest& quest, size_t which_quest) { @@ -2043,7 +2072,7 @@ static bool change_quest_dlog_page(cDialog& me, std::string dir, cQuest& quest, return true; } -void edit_quest(size_t which_quest) { +bool edit_quest(size_t which_quest) { using namespace std::placeholders; if(which_quest == scenario.quests.size()) { scenario.quests.resize(which_quest + 1); @@ -2075,6 +2104,7 @@ void edit_quest(size_t which_quest) { put_quest_in_dlog(quest_dlg, quest, which_quest); quest_dlg.run(); + return quest_dlg.accepted(); } static bool put_shop_item_in_dlog(cPict& pic, cControl& num, cControl& title, const cShop& shop, int which) { @@ -2383,7 +2413,7 @@ static bool add_shop_entry(cDialog& me, std::string type, cShop& shop, size_t wh return true; } -void edit_shop(size_t which_shop, cDialog* parent) { +bool edit_shop(size_t which_shop, cDialog* parent) { using namespace std::placeholders; if(which_shop == scenario.shops.size()) scenario.shops.emplace_back("New Shop"); @@ -2413,6 +2443,7 @@ void edit_shop(size_t which_shop, cDialog* parent) { dynamic_cast(shop_dlg["items"]).setPageCount(6); put_shop_in_dlog(shop_dlg, shop, which_shop); shop_dlg.run(); + return shop_dlg.accepted(); } static void put_save_rects_in_dlog(cDialog& me) { @@ -2864,7 +2895,7 @@ bool build_scenario() { if(!edit_make_scen_2(width, height, lg, med, sm, default_town)) return false; - scenario = cScenario(true); + scenario = cScenario(); scenario.scen_name = title; scenario.default_ground = grass ? 2 : 0; diff --git a/src/scenedit/scen.core.hpp b/src/scenedit/scen.core.hpp index 4adf726c..1ad23226 100644 --- a/src/scenedit/scen.core.hpp +++ b/src/scenedit/scen.core.hpp @@ -2,14 +2,14 @@ class cDialog; void edit_custom_pics_types(); -void edit_ter_type(ter_num_t which_ter); -short edit_monst_type(short which_monst); +bool edit_ter_type(ter_num_t which_ter); +bool edit_monst_type(short which_monst); cMonster edit_monst_abil(cMonster starting_record,short which_monst,cDialog& parent); -short edit_item_type(short which_item); +bool edit_item_type(short which_item); cItem edit_item_abil(cItem starting_record,short which_item,cDialog& parent); -void edit_spec_item(short which_item); -void edit_quest(size_t which_quest); -void edit_shop(size_t which_shop, cDialog* parent = nullptr); +bool edit_spec_item(short which_item); +bool edit_quest(size_t which_quest); +bool edit_shop(size_t which_shop, cDialog* parent = nullptr); void edit_save_rects(); void edit_horses(); void edit_add_town(); diff --git a/src/scenedit/scen.fileio.cpp b/src/scenedit/scen.fileio.cpp index 23739aee..a8f115a4 100644 --- a/src/scenedit/scen.fileio.cpp +++ b/src/scenedit/scen.fileio.cpp @@ -777,7 +777,7 @@ static void writeDialogueToXml(ticpp::Printer&& data, cSpeech& talk, int town_nu cSpeech::cNode& node = talk.talk_nodes[i]; if(node.personality == -1) continue; // TODO: Is it safe to assume the two links run together like this? - if(std::string(node.link1, 8) == "xxxxxxxx") + if(std::string(node.link1, 8) == "xxxxxxxx" && node.str1.empty() && node.str2.empty()) continue; data.OpenElement("node"); data.PushAttribute("for", node.personality); diff --git a/src/scenedit/scen.global.hpp b/src/scenedit/scen.global.hpp index 38389137..99dabc06 100644 --- a/src/scenedit/scen.global.hpp +++ b/src/scenedit/scen.global.hpp @@ -1,4 +1,7 @@ +#ifndef BOE_SCEN_GLOBAL_HPP +#define BOE_SCEN_GLOBAL_HPP + #define DRAG_EDGE 15 #define DISPLAY_LEFT 23 @@ -11,7 +14,7 @@ #define NLS 25 // number of left slots for buttons -#define NRS 400 +#define NRS right_button_status.size() // number of right slots for scrolling list #define NRSONPAGE 33 // number of right slots for scrolling list on page at 1 time @@ -69,6 +72,7 @@ enum eScenMode { MODE_SET_OUT_START = 47, MODE_ERASE_CREATURE = 48, MODE_ERASE_ITEM = 49, + MODE_ERASE_TOWN_ENTRANCE = 50, MODE_MAIN_SCREEN = 60, MODE_INTRO_SCREEN = 61, MODE_EDIT_TYPES = 62, // currently only used for editing terrain, but I'd like to use it for editing monsters and items too. @@ -80,6 +84,12 @@ enum eDrawMode { DRAW_ITEM = 2, }; +enum eStrMode { + STRS_SCEN, STRS_OUT, STRS_TOWN, STRS_JOURNAL, + STRS_OUT_SIGN, STRS_TOWN_SIGN, + STRS_OUT_RECT, STRS_TOWN_RECT, +}; + enum ePalBtn { PAL_BLANK = -1, PAL_PENCIL = 0, PAL_BRUSH_LG = 1, PAL_BRUSH_SM = 2, PAL_SPRAY_LG = 3, PAL_SPRAY_SM = 4, PAL_DROPPER = 5, PAL_RECT_HOLLOW = 6, PAL_RECT_FILLED = 7, @@ -90,3 +100,5 @@ enum ePalBtn { PAL_SFX_SB = 50, PAL_SFX_MB = 51, PAL_SFX_LB = 52, PAL_SFX_SS = 53, PAL_SFX_LS = 54, PAL_SFX_ASH = 55, PAL_SFX_BONE = 56, PAL_SFX_ROCK = 57, PAL_ARROW_UP = 9, PAL_ARROW_DOWN = 69, PAL_TERRAIN = 29, PAL_ITEM = 39, PAL_MONST = 49, }; + +#endif diff --git a/src/scenedit/scen.graphics.cpp b/src/scenedit/scen.graphics.cpp index d6ca5cf7..3f29dc64 100644 --- a/src/scenedit/scen.graphics.cpp +++ b/src/scenedit/scen.graphics.cpp @@ -51,7 +51,7 @@ extern std::shared_ptr right_sbar, pal_sbar; extern bool left_buttons_active,right_buttons_active; extern std::array left_button_status; -extern std::array right_button_status; +extern std::vector right_button_status; short mini_map_scales[3] = {12, 6, 4}; // TODO: What is this for? //extern btn_t buttons[]; @@ -453,7 +453,7 @@ void draw_lb_slot (short which,short mode) { void draw_rb() { long pos = right_sbar->getPosition(); - for(long i = pos; i < pos + NRSONPAGE; i++) + for(long i = pos; i < pos + NRSONPAGE && i < NRS; i++) draw_rb_slot(i,0); } @@ -463,7 +463,7 @@ void draw_rb_slot (short which,short mode) { long pos; pos = right_sbar->getPosition(); - if((which < pos) || (which >= pos + NRSONPAGE)) + if(which < pos || which >= pos + NRSONPAGE || which >= NRS) return; tileImage(mainPtr,right_buttons[which - pos],bg[17]); @@ -480,7 +480,7 @@ void draw_rb_slot (short which,short mode) { void set_up_terrain_buttons(bool reset) { short i,j,pic,small_i; - rectangle ter_from,ter_from_base = {0,0,36,28}; + rectangle ter_from,ter_from_base = {0,0,36,28}, ter_plus_from = {120,123,136,139}; rectangle tiny_from,tiny_to; rectangle palette_from,palette_to = palette_button_base; @@ -488,23 +488,28 @@ void set_up_terrain_buttons(bool reset) { switch(draw_mode) { case DRAW_TERRAIN: max = scenario.ter_types.size(); break; case DRAW_ITEM: max = scenario.scen_items.size(); break; - case DRAW_MONST: max = scenario.scen_monsters.size(); break; + case DRAW_MONST: max = scenario.scen_monsters.size(); max--; break; default: return; } + if(overall_mode == MODE_EDIT_TYPES) max++; if(reset) pal_sbar->setPosition(0); - pal_sbar->setMaximum((max / 16) - 16); + pal_sbar->setMaximum((max - 241) / 16); tileImage(terrain_buttons_gworld,terrain_buttons_rect,bg[17]); frame_rect(terrain_buttons_gworld, terrain_buttons_rect, sf::Color::Black); int first = pal_sbar->getPosition() * 16; - if(draw_mode == DRAW_MONST) first++; + if(draw_mode == DRAW_MONST) first++, max++; int end = min(first + 256, max); // first make terrain buttons for(i = first; i < end; i++) { switch(draw_mode){ case DRAW_TERRAIN: + if(i == scenario.ter_types.size()) { + rect_draw_some_item(editor_mixed, ter_plus_from, terrain_buttons_gworld, terrain_rects[i - first]); + break; + } ter_from = ter_from_base; pic = scenario.ter_types[i].picture; if(pic >= 1000) { @@ -767,6 +772,15 @@ void draw_terrain(){ tiny_to.offset(0,-7); } small_i = get_small_icon(t_to_draw); + // Special case for towns + if(small_i == 22 && !editing_town) { + bool have_town = false; + for(i = 0; i < current_terrain->city_locs.size(); i++) { + if(current_terrain->city_locs[i] == which_pt) + have_town = true; + } + if(!have_town) small_i += 3; + } tiny_from = base_small_button_from; tiny_from.offset(7 * (small_i % 10),7 * (small_i / 10)); if(small_i > 0) { diff --git a/src/scenedit/scen.keydlgs.cpp b/src/scenedit/scen.keydlgs.cpp index 52f5cc96..745c496f 100644 --- a/src/scenedit/scen.keydlgs.cpp +++ b/src/scenedit/scen.keydlgs.cpp @@ -28,7 +28,7 @@ std::vector field_pics = {0,3,5,6,7,8,9,10,11,12,13,14,15,24,25,26,27 std::vector boom_pics = {0,1,2,3,4,8,16,24,32}; std::vector lgdlog_pics = {0,72}; -size_t num_strs(short str_mode) { +size_t num_strs(eStrMode str_mode) { switch(str_mode) { case 0: return scenario.spec_strs.size(); case 1: return current_terrain->spec_strs.size(); @@ -36,10 +36,73 @@ size_t num_strs(short str_mode) { case 3: return scenario.journal_strs.size(); case 4: return current_terrain->sign_locs.size(); case 5: return town->sign_locs.size(); + case 6: return current_terrain->info_rect.size(); + case 7: return town->room_rect.size(); } return 0; } +static void ensure_str(eStrMode str_mode, size_t which) { + if(which >= num_strs(str_mode)) { + switch(str_mode) { + case 0: scenario.spec_strs.resize(which + 1, "*"); break; + case 1: current_terrain->spec_strs.resize(which + 1, "*"); break; + case 2: town->spec_strs.resize(which + 1, "*"); break; + case 3: scenario.journal_strs.resize(which + 1, "*"); break; + case 4: current_terrain->sign_locs.resize(which + 1, {-1, -1, "*"}); break; + case 5: town->sign_locs.resize(which + 1, {-1, -1, "*"}); break; + case 6: current_terrain->info_rect.resize(which + 1, {-1, -1, -1, -1, "*"}); break; + case 7: town->room_rect.resize(which + 1, {-1, -1, -1, -1, "*"}); break; + } + } +} + +static std::string& fetch_str(eStrMode str_mode, size_t which) { + ensure_str(str_mode, which); + switch(str_mode) { + case 0: return scenario.spec_strs[which]; + case 1: return current_terrain->spec_strs[which]; + case 2: return town->spec_strs[which]; + case 3: return scenario.journal_strs[which]; + case 4: return current_terrain->sign_locs[which].text; + case 5: return town->sign_locs[which].text; + case 6: return current_terrain->info_rect[which].descr; + case 7: return town->room_rect[which].descr; + } + throw "Invalid string mode " + std::to_string(str_mode) + " (valid are 0-5)"; +} + +static std::string str_info(eStrMode str_mode, size_t which) { + ensure_str(str_mode, which); + std::ostringstream sout; + switch(str_mode) { + case 0: case 1: case 2: case 3: + sout << which; + break; + case 4: + sout << "(" << current_terrain->sign_locs[which].x; + sout << ", " << current_terrain->sign_locs[which].y << ")"; + break; + case 5: + sout << "(" << town->sign_locs[which].x; + sout << ", " << town->sign_locs[which].y << ")"; + break; + case 6: + sout << "(" << current_terrain->info_rect[which].left; + sout << ", " << current_terrain->info_rect[which].top; + sout << ")|(" << current_terrain->info_rect[which].right; + sout << ", " << current_terrain->info_rect[which].bottom << ")"; + break; + case 7: + sout << "(" << town->room_rect[which].left; + sout << ", " << town->room_rect[which].top; + sout << ")|(" << town->room_rect[which].right; + sout << ", " << town->room_rect[which].bottom << ")"; + break; + } + return sout.str(); +} + //cre = check range error bool cre(short val,short min,short max,std::string text1,std::string text2,cDialog* parent) { if((val < min) || (val > max)) { @@ -352,20 +415,9 @@ short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent, std return dlog.show(cur_choice); } -static bool edit_text_event_filter(cDialog& me, std::string item_hit, short& which_str, short str_mode) { +static bool edit_text_event_filter(cDialog& me, std::string item_hit, short& which_str, eStrMode str_mode) { std::string newVal = me["text"].getText(); - if(str_mode == 0) - scenario.spec_strs[which_str] = newVal; - if(str_mode == 1) - current_terrain->spec_strs[which_str] = newVal; - if(str_mode == 2) - town->spec_strs[which_str] = newVal; - if(str_mode == 3) - scenario.journal_strs[which_str] = newVal; - if(str_mode == 4) - current_terrain->sign_locs[which_str].text = newVal; - if(str_mode == 5) - town->sign_locs[which_str].text = newVal; + fetch_str(str_mode, which_str) = newVal; if(item_hit == "okay") me.toast(true); else if(item_hit == "left" || item_hit == "right") { if(item_hit[0] == 'l') @@ -374,44 +426,24 @@ static bool edit_text_event_filter(cDialog& me, std::string item_hit, short& whi if(which_str < 0) which_str = num_strs(str_mode) - 1; if(which_str >= num_strs(str_mode)) which_str = 0; } - me["num"].setTextToNum(which_str); - if(str_mode == 0) - me["text"].setText(scenario.spec_strs[which_str]); - if(str_mode == 1) - me["text"].setText(current_terrain->spec_strs[which_str]); - if(str_mode == 2) - me["text"].setText(town->spec_strs[which_str]); - if(str_mode == 3) - me["text"].setText(scenario.journal_strs[which_str]); - if(str_mode == 4) - me["text"].setText(current_terrain->sign_locs[which_str].text); - if(str_mode == 5) - me["text"].setText(town->sign_locs[which_str].text); + me["num"].setText(str_info(str_mode, which_str)); + me["text"].setText(fetch_str(str_mode, which_str)); return true; } -// mode 0 - scen 1 - out 2 - town -void edit_text_str(short which_str,short mode) { +bool edit_text_str(short which_str,eStrMode mode) { using namespace std::placeholders; + short first = which_str; cDialog dlog("edit-text"); dlog.attachClickHandlers(std::bind(edit_text_event_filter, _1, _2, std::ref(which_str), mode), {"okay", "left", "right"}); + dlog["cancel"].attachClickHandler(std::bind(&cDialog::toast, _1, false)); - dlog["num"].setTextToNum(which_str); - if(mode == 0) - dlog["text"].setText(scenario.spec_strs[which_str]); - if(mode == 1) - dlog["text"].setText(current_terrain->spec_strs[which_str]); - if(mode == 2) - dlog["text"].setText(town->spec_strs[which_str]); - if(mode == 3) - dlog["text"].setText(scenario.journal_strs[which_str]); - if(mode == 4) - dlog["text"].setText(current_terrain->sign_locs[which_str].text); - if(mode == 5) - dlog["text"].setText(town->sign_locs[which_str].text); + dlog["num"].setText(str_info(mode, which_str)); + dlog["text"].setText(fetch_str(mode, which_str)); dlog.run(); + return dlog.accepted() || which_str != first; } static bool edit_area_rect_event_filter(cDialog& me, std::string item_hit, short which_str, short str_mode) { @@ -560,14 +592,30 @@ static bool commit_spec_enc(cDialog& me, std::string item_hit, node_stack_t& edi } static bool discard_spec_enc(cDialog& me, node_stack_t& edit_stack) { - if(edit_stack.size() > 1) { - std::string action = cChoiceDlog("discard-special-node", {"save", "cancel", "revert"}).show(); + std::string action = "revert"; + int stack_size = edit_stack.size(); + if(stack_size > 1) { + action = cChoiceDlog("discard-special-node", {"save", "cancel", "revert"}).show(); if(action == "save") return true; - if(action == "cancel") return me.toast(false); - edit_stack.pop(); - if(edit_stack.size() == 1) - me["back"].hide(); - } else me.toast(false); + } + auto cur = edit_stack.top(); + auto& list = cur.mode == 0 ? scenario.scen_specials : (cur.mode == 1 ? current_terrain->specials : town->specials); + if(cur.which == list.size() - 1 && list[cur.which].type == eSpecType::NONE && list[cur.which].jumpto == -1) + list.pop_back(); + edit_stack.pop(); + if(action == "cancel") { + while(!edit_stack.empty()) { + auto cur = edit_stack.top(); + auto& list = cur.mode == 0 ? scenario.scen_specials : (cur.mode == 1 ? current_terrain->specials : town->specials); + if(cur.which == list.size() - 1 && list[cur.which].type == eSpecType::NONE && list[cur.which].jumpto == -1) + list.pop_back(); + edit_stack.pop(); + } + } else if(edit_stack.size() == 1) + me["back"].hide(); + if(edit_stack.empty()) + me.toast(false); + else put_spec_enc_in_dlog(me, edit_stack); return true; } @@ -757,19 +805,19 @@ static bool edit_spec_enc_value(cDialog& me, std::string item_hit, node_stack_t& case 'm': choose_string = false; store = me["msg2"].getTextAsNum(); - edit_spec_text(mode, &val, &store, &me); + edit_spec_text(eStrMode(mode), &val, &store, &me); me["msg2"].setTextToNum(store); store = val; break; case 'M': case '$': choose_string = false; - edit_spec_text(mode, &val, nullptr, &me); + edit_spec_text(eStrMode(mode), &val, nullptr, &me); store = val; break; case 'd': choose_string = false; store = val; - edit_dialog_text(mode, &store, &me); + edit_dialog_text(eStrMode(mode), &store, &me); break; case 's': case 'S': choose_string = false; @@ -859,18 +907,24 @@ bool edit_spec_enc(short which_node,short mode,cDialog* parent) { giveError("That special node does not exist. You can create a new node by setting the field to -1 and trying again.", parent); return false; } + if(scenario.scen_specials[which_node].pic < 0) + scenario.scen_specials[which_node].pic = 0; the_node = scenario.scen_specials[which_node]; } else if(mode == 1) { if(which_node >= current_terrain->specials.size()) { giveError("That special node does not exist. You can create a new node by setting the field to -1 and trying again.", parent); return false; } + if(current_terrain->specials[which_node].pic < 0) + current_terrain->specials[which_node].pic = 0; the_node = current_terrain->specials[which_node]; } else if(mode == 2) { if(which_node >= town->specials.size()) { giveError("That special node does not exist. You can create a new node by setting the field to -1 and trying again.", parent); return false; } + if(town->specials[which_node].pic < 0) + town->specials[which_node].pic = 0; the_node = town->specials[which_node]; } @@ -924,7 +978,7 @@ short get_fresh_spec(short which_mode) { return num_specs; } -static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short str_mode, short* str1, short* str2) { +static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, eStrMode str_mode, short* str1, short* str2) { std::string str; size_t i; @@ -933,46 +987,13 @@ static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short if(!str.empty()) { if(*str1 < 0) { size_t n = num_strs(str_mode); - for(i = 0; i < n; i++) - switch(str_mode) { - case 0: - // TODO: This could overwrite a string if it's unlucky enough to start with * - if(scenario.spec_strs[i][0] == '*') { - *str1 = i; - i = 500; - } - break; - case 1: - if(current_terrain->spec_strs[i][0] == '*') { - *str1 = i; - i = 500; - } - break; - case 2: - if(town->spec_strs[i][0] == '*') { - *str1 = i; - i = 500; - } - break; - case 3: - if(scenario.journal_strs[i][0] == '*') { - *str1 = i; - i = 500; - } - break; - case 4: - if(current_terrain->sign_locs[i].text[0] == '*') { - *str1 = i; - i = 500; - } - break; - case 5: - if(town->sign_locs[i].text[0] == '*') { - *str1 = i; - i = 500; - } - break; + for(i = 0; i < n; i++) { + std::string& str = fetch_str(str_mode, i); + if(!str.empty() && str[0] == '*') { + *str1 = i; + i = 500; } + } if(i < 500) { giveError("There are no more free message slots.", "To free up some slots, go into Edit Town/Out/Scenario Text to clear some messages.", &me); @@ -980,72 +1001,20 @@ static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short } } if(*str1 >= 0) { - switch(str_mode) { - case 0: - scenario.spec_strs[*str1] = str; - break; - case 1: - current_terrain->spec_strs[*str1] = str; - break; - case 2: - town->spec_strs[*str1] = str; - break; - case 3: - scenario.journal_strs[*str1] = str; - break; - case 4: - current_terrain->sign_locs[*str1].text = str; - break; - case 5: - town->sign_locs[*str1].text = str; - break; - } + fetch_str(str_mode, *str1) = str; } } str = str2 == nullptr ? "" : me["str2"].getText(); if(!str.empty()) { if(*str2 < 0) { size_t n = num_strs(str_mode); - for(i = 160; i < n; i++) - switch(str_mode) { - case 0: - if(scenario.spec_strs[i][0] == '*') { - *str2 = i; - i = 500; - } - break; - case 1: - if(current_terrain->spec_strs[i][0] == '*') { - *str2 = i; - i = 500; - } - break; - case 2: - if(town->spec_strs[i][0] == '*') { - *str2 = i; - i = 500; - } - break; - case 3: - if(scenario.journal_strs[i][0] == '*') { - *str2 = i; - i = 500; - } - break; - case 4: - if(current_terrain->sign_locs[i].text[0] == '*') { - *str2 = i; - i = 500; - } - break; - case 5: - if(town->sign_locs[i].text[0] == '*') { - *str2 = i; - i = 500; - } - break; - + for(i = 0; i < n; i++) { + std::string& str = fetch_str(str_mode, i); + if(!str.empty() && str[0] == '*') { + *str2 = i; + i = 500; } + } if(i < 500) { giveError("There are no more free message slots.", "To free up some slots, go into Edit Town/Out/Scenario Text to clear some messages.", &me); @@ -1053,26 +1022,7 @@ static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short } } if(*str2 >= 0) { - switch(str_mode) { - case 0: - scenario.spec_strs[*str2] = str; - break; - case 1: - current_terrain->spec_strs[*str2] = str; - break; - case 2: - town->spec_strs[*str2] = str; - break; - case 3: - scenario.journal_strs[*str2] = str; - break; - case 4: - current_terrain->sign_locs[*str2].text = str; - break; - case 5: - town->sign_locs[*str2].text = str; - break; - } + fetch_str(str_mode, *str2) = str; } } me.toast(true); @@ -1081,51 +1031,28 @@ static bool edit_spec_text_event_filter(cDialog& me, std::string item_hit, short } // mode 0 - scen 1 - out 2 - town -void edit_spec_text(short mode,short *str1,short *str2,cDialog* parent) { +void edit_spec_text(eStrMode mode,short *str1,short *str2,cDialog* parent) { using namespace std::placeholders; - short num_s_strs[3] = {100,90,100}; cDialog edit(str2 ? "edit-special-text" : "edit-special-text-sm", parent); edit.attachClickHandlers(std::bind(edit_spec_text_event_filter, _1, _2, mode, str1, str2), {"okay", "cancel"}); - if(*str1 >= num_s_strs[mode]) + if(*str1 >= num_strs(mode)) *str1 = -1; if(*str1 >= 0){ - if(mode == 0) - edit["str1"].setText(scenario.spec_strs[*str1]); - if(mode == 1) - edit["str1"].setText(current_terrain->spec_strs[*str1]); - if(mode == 2) - edit["str1"].setText(town->spec_strs[*str1]); - if(mode == 3) - edit["str1"].setText(scenario.journal_strs[*str1]); - if(mode == 4) - edit["str1"].setText(current_terrain->sign_locs[*str1].text); - if(mode == 5) - edit["str1"].setText(town->sign_locs[*str1].text); + edit["str1"].setText(fetch_str(mode, *str1)); } if(str2 != nullptr) { - if(*str2 >= num_s_strs[mode]) + if(*str2 >= num_strs(mode)) *str2 = -1; if(*str2 >= 0){ - if(mode == 0) - edit["str2"].setText(scenario.spec_strs[*str2]); - if(mode == 1) - edit["str2"].setText(current_terrain->spec_strs[*str2]); - if(mode == 2) - edit["str2"].setText(town->spec_strs[*str2]); - if(mode == 3) - edit["str2"].setText(scenario.journal_strs[*str2]); - if(mode == 4) - edit["str2"].setText(current_terrain->sign_locs[*str2].text); - if(mode == 5) - edit["str2"].setText(town->sign_locs[*str2].text); + edit["str2"].setText(fetch_str(mode, *str2)); } } edit.run(); } -static bool edit_dialog_text_event_filter(cDialog& me, std::string item_hit, short str_mode, short* str1){ +static bool edit_dialog_text_event_filter(cDialog& me, std::string item_hit, eStrMode str_mode, short* str1){ std::string str; short i; @@ -1134,26 +1061,7 @@ static bool edit_dialog_text_event_filter(cDialog& me, std::string item_hit, sho std::string id = "str" + std::to_string(i + 1); str = me[id].getText(); if(i == 0 && str.empty()) break; - switch(str_mode) { - case 0: - scenario.spec_strs[*str1 + i] = str; - break; - case 1: - current_terrain->spec_strs[*str1 + i] = str; - break; - case 2: - town->spec_strs[*str1 + i] = str; - break; - case 3: - scenario.journal_strs[*str1 + i] = str; - break; - case 4: - current_terrain->sign_locs[*str1 + i].text = str; - break; - case 5: - town->sign_locs[*str1 + i].text = str; - break; - } + fetch_str(str_mode, *str1 + i) = str; } me.toast(true); } else me.toast(false); @@ -1161,71 +1069,29 @@ static bool edit_dialog_text_event_filter(cDialog& me, std::string item_hit, sho } // mode 0 - scen 1 - out 2 - town -void edit_dialog_text(short mode,short *str1,cDialog* parent) { +void edit_dialog_text(eStrMode mode,short *str1,cDialog* parent) { size_t i,j; - short num_s_strs[3] = {100,90,100}; - if(*str1 >= num_s_strs[mode] - 6) + if(*str1 >= num_strs(mode) - 6) *str1 = -1; // first, assign the 6 strs for the dialog. if(*str1 < 0) { size_t n = num_strs(mode); - for(i = 160; i < n - 6; i++) { - for(j = i; j < i + 6; j++) - switch(mode) { - case 0: - if(scenario.spec_strs[j][0] != '*') - j = 500; - break; - case 1: - if(current_terrain->spec_strs[j][0] != '*') - j = 500; - break; - case 2: - if(town->spec_strs[j][0] != '*') - j = 500; - break; - case 3: - if(scenario.journal_strs[j][0] != '*') - j = 500; - break; - case 4: - if(current_terrain->sign_locs[j].text[0] != '*') - j = 500; - break; - case 5: - if(town->sign_locs[j].text[0] != '*') - j = 500; - break; - } - if(j < 500) { + for(i = 0; i < n; i++) { + for(j = i; j < i + 6 && j < n; j++) { + std::string str = fetch_str(mode, j); + if(!str.empty() && str[0] != '*') + j = 5000; + } + if(j < 5000) { *str1 = i; - i = 500; + i = 5000; } } - if(*str1 >= 0) - for(short i = *str1; i < *str1 + 6; i++) { - switch(mode) { - case 0: - scenario.spec_strs[i] = ""; - break; - case 1: - current_terrain->spec_strs[i] = ""; - break; - case 2: - town->spec_strs[i] = ""; - break; - case 3: - scenario.journal_strs[i] = ""; - break; - case 4: - current_terrain->sign_locs[i].text = ""; - break; - case 5: - town->sign_locs[i].text = ""; - break; - } - } + if(*str1 >= 0) { + for(short i = *str1; i < *str1 + 6; i++) + fetch_str(mode, i).clear(); + } } if(*str1 < 0) { giveError("To create a dialog, you need 6 consecutive unused messages. To free up 6 messages, select Edit Out/Town/Scenario Text from the menus.","",parent); @@ -1236,21 +1102,10 @@ void edit_dialog_text(short mode,short *str1,cDialog* parent) { cDialog edit("edit-dialog-text",parent); edit.attachClickHandlers(std::bind(edit_dialog_text_event_filter, _1, _2, mode, str1), {"okay", "cancel"}); - if(*str1 >= 0){ + if(*str1 >= 0) { for(i = 0; i < 6; i++) { std::string id = "str" + std::to_string(i + 1); - if(mode == 0) - edit[id].setText(scenario.spec_strs[*str1 + i]); - if(mode == 1) - edit[id].setText(current_terrain->spec_strs[*str1 + i]); - if(mode == 2) - edit[id].setText(town->spec_strs[*str1 + i]); - if(mode == 3) - edit[id].setText(scenario.journal_strs[*str1 + i]); - if(mode == 4) - edit[id].setText(current_terrain->sign_locs[*str1 + i].text); - if(mode == 5) - edit[id].setText(town->sign_locs[*str1 + i].text); + edit[id].setText(fetch_str(mode, *str1 + i)); } } diff --git a/src/scenedit/scen.keydlgs.hpp b/src/scenedit/scen.keydlgs.hpp index 42171864..ae5de839 100644 --- a/src/scenedit/scen.keydlgs.hpp +++ b/src/scenedit/scen.keydlgs.hpp @@ -23,18 +23,16 @@ pic_num_t choose_graphic(short cur_choice,ePicType g_type,cDialog* parent); short choose_background(short cur_choice, cDialog* parent); short choose_text_res(std::string res_list,short first_t,short last_t,unsigned short cur_choice,cDialog* parent,const char *title); short choose_text(eStrType list, unsigned short cur_choice, cDialog* parent,std::string title); -void edit_text_str(short which_str,short mode); +bool edit_text_str(short which_str,eStrMode mode); bool edit_spec_enc(short which_node,short mode,cDialog* parent); short get_fresh_spec(short which_mode); -void edit_spec_text(short mode,short *str1,short *str2,cDialog* parent); -void edit_dialog_text(short mode,short *str1,cDialog* parent); -void edit_spec_text(short mode,short *str1,short *str2,cDialog* parent); +void edit_spec_text(eStrMode mode,short *str1,short *str2,cDialog* parent); +void edit_dialog_text(eStrMode mode,short *str1,cDialog* parent); short edit_special_num(short mode,short what_start); void edit_scen_intro(); bool edit_area_rect_str(short which_str,short mode); void make_cursor_sword() ; -void edit_dialog_text(short mode,short *str1,cDialog* parent); -size_t num_strs(short str_mode); +size_t num_strs(eStrMode str_mode); pic_num_t choose_damage_type(short cur, cDialog* parent); short choose_field_type(short cur, cDialog* parent, bool includeSpec); diff --git a/src/scenedit/scen.main.cpp b/src/scenedit/scen.main.cpp index fc0bd344..5704b9fa 100644 --- a/src/scenedit/scen.main.cpp +++ b/src/scenedit/scen.main.cpp @@ -306,11 +306,11 @@ void handle_menu_choice(eMenu item_hit) { break; case eMenu::SCEN_TEXT: right_sbar->setPosition(0); - start_string_editing(0,0); + start_string_editing(STRS_SCEN,0); break; case eMenu::SCEN_JOURNALS: right_sbar->setPosition(0); - start_string_editing(3,0); + start_string_editing(STRS_JOURNAL,0); break; case eMenu::TOWN_IMPORT: if(change_made) { @@ -399,8 +399,8 @@ void handle_menu_choice(eMenu item_hit) { change_made = true; break; case eMenu::TOWN_AREAS: - edit_roomdescs(true); - change_made = true; + right_sbar->setPosition(0); + start_string_editing(STRS_TOWN_RECT,0); break; case eMenu::TOWN_ITEMS_RANDOM: if(cChoiceDlog("add-random-items", {"okay", "cancel"}).show() == "cancel") @@ -428,11 +428,11 @@ void handle_menu_choice(eMenu item_hit) { break; case eMenu::TOWN_TEXT: right_sbar->setPosition(0); - start_string_editing(2,0); + start_string_editing(STRS_TOWN,0); break; case eMenu::TOWN_SIGNS: right_sbar->setPosition(0); - start_string_editing(5,0); + start_string_editing(STRS_TOWN_SIGN,0); break; case eMenu::TOWN_ADVANCED: edit_advanced_town(); @@ -455,8 +455,8 @@ void handle_menu_choice(eMenu item_hit) { change_made = true; break; case eMenu::OUT_AREAS: - edit_roomdescs(false); - change_made = true; + right_sbar->setPosition(0); + start_string_editing(STRS_OUT_RECT,0); break; case eMenu::OUT_START: overall_mode = MODE_SET_OUT_START; @@ -468,11 +468,11 @@ void handle_menu_choice(eMenu item_hit) { break; case eMenu::OUT_TEXT: right_sbar->setPosition(0); - start_string_editing(1,0); + start_string_editing(STRS_OUT,0); break; case eMenu::OUT_SIGNS: right_sbar->setPosition(0); - start_string_editing(4,0); + start_string_editing(STRS_OUT_SIGN,0); break; case eMenu::ABOUT: helpDlog = "about-scened"; diff --git a/src/scenedit/scen.townout.cpp b/src/scenedit/scen.townout.cpp index 8fe9b7cb..4a939118 100644 --- a/src/scenedit/scen.townout.cpp +++ b/src/scenedit/scen.townout.cpp @@ -364,74 +364,6 @@ void edit_sign(short which_sign,short picture) { sign_dlg.run(); } -static bool save_roomdescs(cDialog& me, bool isTown, std::array str_do_delete) { - if(!me.toast(true)) return true; - int numDescs = isTown ? town->room_rect.size() : current_terrain->info_rect.size(); - for(int i = 0; i < numDescs; i++) { - std::string id = "desc" + std::to_string(i + 1); - if(isTown) { - town->room_rect[i].descr = me[id].getText().substr(0,30); - if(str_do_delete[i]) - town->room_rect[i].right = 0; - } else { - current_terrain->info_rect[i].descr = me[id].getText().substr(0,30); - if(str_do_delete[i]) - current_terrain->info_rect[i].right = 0; - } - } - return true; -} - -static void put_roomdescs_in_dlog(cDialog& me, bool isTown, std::array str_do_delete) { - int numDescs = isTown ? town->room_rect.size() : current_terrain->info_rect.size(); - for(int i = 0; i < numDescs; i++) { - std::string id = std::to_string(i + 1); - std::ostringstream str; - bool active = true; - if(isTown && town->room_rect[i].right == 0) active = false; - if(!isTown && current_terrain->info_rect[i].right == 0) active = false; - if(str_do_delete[i]) active = false; - if(!active) { - str << "Not yet placed."; - me["del" + id].hide(); - } else if(isTown) { - me["desc" + id].setText(town->room_rect[i].descr); - str << "X = " << town->room_rect[i].left << ", Y = " << town->room_rect[i].top; - } else { - me["desc" + id].setText(current_terrain->info_rect[i].descr); - str << "X = " << current_terrain->info_rect[i].left << ", Y = " << current_terrain->info_rect[i].top; - } - me["rect" + id].setText(str.str()); - } -} - -static bool delete_roomdesc(cDialog& me, std::string id, bool isTown, std::array str_do_delete) { - int item_hit = boost::lexical_cast(id.substr(3)); - me["desc" + id.substr(3)].setText(""); - str_do_delete[item_hit - 1] = true; - put_roomdescs_in_dlog(me, isTown, str_do_delete); - return true; -} - -void edit_roomdescs(bool town) { - using namespace std::placeholders; - std::array str_do_delete = {0}; - int numDescs = town ? 16 : 8; - - cDialog room_dlg(town ? "edit-town-roomdescs" : "edit-out-roomdescs"); - room_dlg["okay"].attachClickHandler(std::bind(save_roomdescs, _1, town, str_do_delete)); - room_dlg["cancel"].attachClickHandler(std::bind(&cDialog::toast, &room_dlg, false)); - for(int i = 0; i < numDescs; i++) { - std::string id = std::to_string(i + 1); - room_dlg["del" + id].attachClickHandler(std::bind(delete_roomdesc, _1, _2, town, str_do_delete)); -// room_dlg["str" + id].attachFocusHandler(check_roomdesc_len); - } - - put_roomdescs_in_dlog(room_dlg, town, str_do_delete); - - room_dlg.run(); -} - static bool save_town_num(cDialog& me, std::string, eKeyMod) { if(me.toast(true)) me.setResult(me["town"].getTextAsNum()); return true; @@ -1122,15 +1054,15 @@ static bool talk_node_branch(cDialog& me, std::stack& talk_edit_stac if(!save_talk_node(me, talk_edit_stack, false, true)) return true; int spec = -1; - for(int j = 0; j < 60; j++) + for(int j = 0; j < town->talking.talk_nodes.size(); j++) if(town->talking.talk_nodes[j].personality == -1 && strnicmp(town->talking.talk_nodes[j].link1, "xxxx", 4) == 0) { spec = j; break; } if(spec < 0) { - giveError("You have used all 60 available talk nodes. To create fresh dialogue, go back and reuse an old one.", &me); - return true; + spec = town->talking.talk_nodes.size(); + town->talking.talk_nodes.emplace_back(); } talk_edit_stack.push({spec, town->talking.talk_nodes[spec]}); @@ -1164,7 +1096,8 @@ static bool select_talk_node_value(cDialog& me, std::string item_hit, const std: return true; } -void edit_talk_node(short which_node) { +// Returns -1 if accepted, otherwise the node that was cancelled +short edit_talk_node(short which_node) { using namespace std::placeholders; std::stack talk_edit_stack; @@ -1183,6 +1116,7 @@ void edit_talk_node(short which_node) { put_talk_node_in_dlog(talk_dlg, talk_edit_stack); talk_dlg.run(); + return talk_dlg.accepted() ? -1 : talk_edit_stack.top().first; } static void put_out_loc_in_dlog(cDialog& me, location cur_loc) { diff --git a/src/scenedit/scen.townout.hpp b/src/scenedit/scen.townout.hpp index a6adc8af..db724e1e 100644 --- a/src/scenedit/scen.townout.hpp +++ b/src/scenedit/scen.townout.hpp @@ -2,7 +2,6 @@ void edit_placed_monst(short which_m); cTownperson edit_placed_monst_adv(cTownperson monst_record, short which, class cDialog& parent); void edit_sign(short which_sign,short picture); -void edit_roomdescs(bool town); short pick_town_num(std::string which_dlog,short def,cScenario& scenario); bool change_ter(short& change_from,short& change_to,short& chance); void edit_out_wand(short mode); @@ -11,7 +10,7 @@ void edit_town_details(); void edit_town_events(); void edit_advanced_town(); void edit_basic_dlog(short which_node); -void edit_talk_node(short which_node); +short edit_talk_node(short which_node); location pick_out(location default_loc); cTown* pick_import_town(short def); bool new_town(short which_town); diff --git a/src/tools/fileio_scen.cpp b/src/tools/fileio_scen.cpp index 4c824989..7ad9d63c 100644 --- a/src/tools/fileio_scen.cpp +++ b/src/tools/fileio_scen.cpp @@ -151,6 +151,9 @@ bool load_scenario_v1(fs::path file_to_load, cScenario& scenario){ scenario.append(*item_data); // TODO: Consider skipping the fread and assignment when len is 0 + scenario.special_items.resize(50); + scenario.journal_strs.resize(50); + scenario.spec_strs.resize(100); for(i = 0; i < 270; i++) { len = (long) (temp_scenario->scen_str_len[i]); n = fread(temp_str, len, 1, file_id); @@ -678,7 +681,7 @@ static void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) { // TODO: Type field (verify that it's "oboe"?) and OS field } else if(type == "game") { Iterator game; - int store_rects = 0, town_mods = 0, spec_items = 0, quests = 0, shops = 0, timers = 0, strs = 0, journals = 0; + int store_rects = 0, town_mods = 0, spec_items = 0, quests = 0, shops = 0, timers = 0, strnum; for(game = game.begin(elem.Get()); game != game.end(); game++) { game->GetValue(&type); if(type == "num-towns") { @@ -719,8 +722,7 @@ static void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) { // TODO: Make sure town is valid town_mods++; } else if(type == "special-item") { - if(spec_items >= 50) - throw xBadNode(type,game->Row(),game->Column(),fname); + scenario.special_items.emplace_back(); readSpecItemFromXml(*game, scenario.special_items[spec_items]); spec_items++; } else if(type == "quest") { @@ -737,15 +739,15 @@ static void readScenarioFromXml(ticpp::Document&& data, cScenario& scenario) { readTimerFromXml(*game, scenario.scenario_timers[timers]); timers++; } else if(type == "string") { - if(strs >= 100) - throw xBadNode(type,game->Row(),game->Column(),fname); - game->GetText(&scenario.spec_strs[strs], false); - strs++; + game->GetAttribute("id", &strnum); + if(strnum >= scenario.spec_strs.size()) + scenario.spec_strs.resize(strnum + 1); + game->GetText(&scenario.spec_strs[strnum], false); } else if(type == "journal") { - if(journals >= 50) - throw xBadNode(type,game->Row(),game->Column(),fname); - game->GetText(&scenario.journal_strs[journals], false); - journals++; + game->GetAttribute("id", &strnum); + if(strnum >= scenario.journal_strs.size()) + scenario.journal_strs.resize(strnum + 1); + game->GetText(&scenario.journal_strs[strnum], false); } else throw xBadNode(type, game->Row(), game->Column(), fname); } } else if(type == "editor") { @@ -836,6 +838,8 @@ static void readTerrainFromXml(ticpp::Document&& data, cScenario& scenario) { throw xBadNode(type, elem->Row(), elem->Column(), fname); int which_ter; elem->GetAttribute("id", &which_ter); + if(which_ter >= scenario.ter_types.size()) + scenario.ter_types.resize(which_ter + 1); cTerrain& the_ter = scenario.ter_types[which_ter]; the_ter = cTerrain(); Iterator ter; @@ -933,6 +937,8 @@ static void readItemsFromXml(ticpp::Document&& data, cScenario& scenario) { throw xBadNode(type, elem->Row(), elem->Column(), fname); int which_item; elem->GetAttribute("id", &which_item); + if(which_item >= scenario.scen_items.size()) + scenario.scen_items.resize(which_item + 1); cItem& the_item = scenario.scen_items[which_item]; the_item = cItem(); Iterator item; @@ -1160,6 +1166,8 @@ static void readMonstersFromXml(ticpp::Document&& data, cScenario& scenario) { elem->GetAttribute("id", &which_monst); if(which_monst == 0) throw xBadVal(type, "id", "0", elem->Row(), elem->Column(), fname); + if(which_monst >= scenario.scen_monsters.size()) + scenario.scen_monsters.resize(which_monst + 1); cMonster& the_mon = scenario.scen_monsters[which_monst]; the_mon = cMonster(); Iterator attr; @@ -1334,16 +1342,20 @@ static void readOutdoorsFromXml(ticpp::Document&& data, cOutdoors& out) { } else if(type == "sign") { int sign; elem->GetAttribute("id", &sign); + if(sign >= out.sign_locs.size()) + out.sign_locs.resize(sign + 1); elem->GetText(&out.sign_locs[sign].text, false); } else if(type == "area") { - if(num_rects >= 8) - throw xBadNode(type, elem->Row(), elem->Column(), fname); + if(num_rects >= out.info_rect.size()) + out.info_rect.resize(num_rects + 1); static_cast(out.info_rect[num_rects]) = readRectFromXml(*elem); elem->GetText(&out.info_rect[num_rects].descr, false); num_rects++; } else if(type == "string") { int str; elem->GetAttribute("id", &str); + if(str >= out.spec_strs.size()) + out.spec_strs.resize(str + 1); elem->GetText(&out.spec_strs[str], false); } else throw xBadNode(type, elem->Row(), elem->Column(), fname); } @@ -1452,10 +1464,14 @@ static void readTownFromXml(ticpp::Document&& data, cTown*& town, cScenario& sce } else if(type == "sign") { int sign; elem->GetAttribute("id", &sign); + if(sign >= town->sign_locs.size()) + town->sign_locs.resize(sign + 1); elem->GetText(&town->sign_locs[sign].text, false); } else if(type == "string") { int str; elem->GetAttribute("id", &str); + if(str >= town->spec_strs.size()) + town->spec_strs.resize(str + 1); elem->GetText(&town->spec_strs[str], false); } else if(type == "item") { int which_item; @@ -1525,8 +1541,8 @@ static void readTownFromXml(ticpp::Document&& data, cTown*& town, cScenario& sce } else throw xBadNode(type, monst->Row(), monst->Column(), fname); } } else if(type == "area") { - if(num_rects >= 16) - throw xBadNode(type, elem->Row(), elem->Column(), fname); + if(num_rects >= town->room_rect.size()) + town->room_rect.resize(num_rects + 1); static_cast(town->room_rect[num_rects]) = readRectFromXml(*elem); elem->GetText(&town->room_rect[num_rects].descr, false); num_rects++; @@ -1566,6 +1582,8 @@ static void readDialogueFromXml(ticpp::Document&& data, cSpeech& talk, int town_ } else throw xBadNode(type, who->Row(), who->Column(), fname); } } else if(type == "node") { + if(num_nodes >= talk.talk_nodes.size()) + talk.talk_nodes.resize(num_nodes + 1); elem->GetAttribute("for", &talk.talk_nodes[num_nodes].personality); int num_keys = 0, num_params = 0, num_strs = 0; Iterator node; @@ -1623,6 +1641,7 @@ static void loadOutMapData(map_data&& data, location which, cScenario& scen) { case eMapFeature::ENTRANCE_WEST: case eMapFeature::ITEM: case eMapFeature::CREATURE: break; case eMapFeature::TOWN: + out.city_locs.emplace_back(); out.city_locs[num_towns].x = x; out.city_locs[num_towns].y = y; out.city_locs[num_towns].spec = feat.second; @@ -1960,6 +1979,9 @@ bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy: break; } + the_town.spec_strs.resize(100); + the_town.sign_locs.resize(20); + the_town.room_rect.resize(16); for(i = 0; i < 140; i++) { len = (long) (store_town.strlens[i]); n = fread(temp_str, len, 1, file_id); @@ -1984,6 +2006,7 @@ bool load_town_v1(fs::path scen_file, short which_town, cTown& the_town, legacy: } port_talk_nodes(&store_talk); + the_town.talking.talk_nodes.resize(60); for(i = 0; i < 170; i++) { len = (long) (store_talk.strlens[i]); n = fread(temp_str, len, 1, file_id); @@ -2071,6 +2094,9 @@ bool load_outdoors_v1(fs::path scen_file, location which_out,cOutdoors& the_out, the_out.y = which_out.y; port_out(&store_out); the_out.append(store_out); + the_out.spec_strs.resize(90); + the_out.sign_locs.resize(8); + the_out.info_rect.resize(8); for(i = 0; i < 108; i++) { len = (long) (store_out.strlens[i]); n = fread(temp_str, len, 1, file_id);