From e9bf63afc7cc0a17ca6d5ff74594a5fbf2a6e290 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Sun, 21 Aug 2016 16:09:58 -0400 Subject: [PATCH] Move town-specific daved game data into the town record Als, use bitsets for item_taken and maps. --- src/boe.actions.cpp | 10 ----- src/boe.dlgutil.cpp | 4 +- src/boe.fileio.cpp | 74 +++++++++---------------------------- src/boe.items.cpp | 5 +-- src/boe.monster.cpp | 2 +- src/boe.party.cpp | 53 ++++++++++----------------- src/boe.specials.cpp | 4 +- src/boe.text.cpp | 2 +- src/boe.town.cpp | 17 ++++----- src/classes/outdoors.hpp | 2 + src/classes/party.cpp | 75 +++++++++++++++----------------------- src/classes/party.hpp | 10 ++--- src/classes/town.cpp | 2 +- src/classes/town.hpp | 7 +++- src/classes/universe.cpp | 17 ++++++--- src/classes/universe.hpp | 2 - src/pcedit/pc.main.cpp | 14 +++---- src/tools/fileio_party.cpp | 40 ++++++++++---------- 18 files changed, 133 insertions(+), 207 deletions(-) diff --git a/src/boe.actions.cpp b/src/boe.actions.cpp index c1e09094..edac543b 100644 --- a/src/boe.actions.cpp +++ b/src/boe.actions.cpp @@ -163,16 +163,6 @@ void init_screen_locs() { startup_top.left = 5; startup_top.right = startup_button[STARTBTN_JOIN].right; - for(short i = 0; i < 200; i++) - for(short j = 0; j < 8; j++) - for(short k = 0; k < 64; k++) - univ.town_maps[i][j][k] = 0; - - for(short i = 0; i < 100; i++) - for(short k = 0; k < 6; k++) - for(short l = 0; l < 48; l++) - univ.out_maps[i][k][l] = 0; - // name, use, give, drip, info, sell/id each one 13 down item_buttons[0][ITEMBTN_NAME].top = 17; item_buttons[0][ITEMBTN_NAME].bottom = item_buttons[0][ITEMBTN_NAME].top + 12; diff --git a/src/boe.dlgutil.cpp b/src/boe.dlgutil.cpp index eb9ee7d5..c5808d29 100644 --- a/src/boe.dlgutil.cpp +++ b/src/boe.dlgutil.cpp @@ -999,7 +999,7 @@ void handle_talk_event(location p) { save_talk_str2 = ""; break; case eTalkNode::BUY_TOWN_LOC: - if(univ.party.can_find_town[b]) { + if(univ.scenario.towns[b]->can_find) { // TODO: Uh, is something supposed to happen here? } else if(univ.party.gold < a) { @@ -1008,7 +1008,7 @@ void handle_talk_event(location p) { else { univ.party.gold -= a; put_pc_screen(); - univ.party.can_find_town[b] = true; + univ.scenario.towns[b]->can_find = true; } save_talk_str2 = ""; break; diff --git a/src/boe.fileio.cpp b/src/boe.fileio.cpp index f9ad1baa..630e55d2 100644 --- a/src/boe.fileio.cpp +++ b/src/boe.fileio.cpp @@ -291,71 +291,33 @@ void build_outdoors() { } -short onm(char x_sector,char y_sector) { - short i; - - i = y_sector * univ.scenario.outdoors.width() + x_sector; - return i; -} - - - // This adds the current outdoor map info to the saved outdoor map info void save_outdoor_maps() { + location corner = univ.party.outdoor_corner; for(short i = 0; i < 48; i++) for(short j = 0; j < 48; j++) { - if(univ.out.out_e[i][j] > 0) - univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y)][i / 8][j] = - univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y)][i / 8][j] | - (char) (1 << i % 8); - if(univ.party.outdoor_corner.x + 1 < univ.scenario.outdoors.width()) { - if(univ.out.out_e[i + 48][j] > 0) - univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y)][i / 8][j] = - univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y)][i / 8][j] | - (char) (1 << i % 8); - } - if(univ.party.outdoor_corner.y + 1 < univ.scenario.outdoors.height()) { - if(univ.out.out_e[i][j + 48] > 0) - univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y + 1)][i / 8][j] = - univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y + 1)][i / 8][j] | - (char) (1 << i % 8); - } - if((univ.party.outdoor_corner.y + 1 < univ.scenario.outdoors.height()) && - (univ.party.outdoor_corner.x + 1 < univ.scenario.outdoors.width())) { - if(univ.out.out_e[i + 48][j + 48] > 0) - univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y + 1)][i / 8][j] = - univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y + 1)][i / 8][j] | - (char) (1 << i % 8); - } + univ.scenario.outdoors[corner.x][corner.y]->maps[j][i] = univ.out.out_e[i][j]; + if(corner.x + 1 < univ.scenario.outdoors.width()) + univ.scenario.outdoors[corner.x + 1][corner.y]->maps[j][i] = univ.out.out_e[i + 48][j]; + if(corner.y + 1 < univ.scenario.outdoors.height()) + univ.scenario.outdoors[corner.x][corner.y + 1]->maps[j][i] = univ.out.out_e[i][j + 48]; + if(corner.y + 1 < univ.scenario.outdoors.height() && corner.x + 1 < univ.scenario.outdoors.width()) + univ.scenario.outdoors[corner.x + 1][corner.y + 1]->maps[j][i] = univ.out.out_e[i + 48][j + 48]; } } -void add_outdoor_maps() { // This takes the existing outdoor map info and supplements it with the saved map info +// This takes the existing outdoor map info and supplements it with the saved map info +void add_outdoor_maps() { + location corner = univ.party.outdoor_corner; for(short i = 0; i < 48; i++) for(short j = 0; j < 48; j++) { - if((univ.out.out_e[i][j] == 0) && - ((univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y)][i / 8][j] & - (char) (1 << i % 8)) != 0)) - univ.out.out_e[i][j] = 1; - if(univ.party.outdoor_corner.x + 1 < univ.scenario.outdoors.width()) { - if((univ.out.out_e[i + 48][j] == 0) && - ((univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y)][i / 8][j] & - (char) (1 << i % 8)) != 0)) - univ.out.out_e[i + 48][j] = 1; - } - if(univ.party.outdoor_corner.y + 1 < univ.scenario.outdoors.height()) { - if((univ.out.out_e[i][j + 48] == 0) && - ((univ.out_maps[onm(univ.party.outdoor_corner.x,univ.party.outdoor_corner.y + 1)][i / 8][j] & - (char) (1 << i % 8)) != 0)) - univ.out.out_e[i][j + 48] = 1; - } - if((univ.party.outdoor_corner.y + 1 < univ.scenario.outdoors.height()) && - (univ.party.outdoor_corner.x + 1 < univ.scenario.outdoors.width())) { - if((univ.out.out_e[i + 48][j + 48] == 0) && - ((univ.out_maps[onm(univ.party.outdoor_corner.x + 1,univ.party.outdoor_corner.y + 1)][i / 8][j] & - (char) (1 << i % 8)) != 0)) - univ.out.out_e[i + 48][j + 48] = 1; - } + univ.out.out_e[i][j] = univ.scenario.outdoors[corner.x][corner.y]->maps[j][i]; + if(corner.x + 1 < univ.scenario.outdoors.width()) + univ.out.out_e[i + 48][j] = univ.scenario.outdoors[corner.x + 1][corner.y]->maps[j][i]; + if(corner.y + 1 < univ.scenario.outdoors.height()) + univ.out.out_e[i][j + 48] = univ.scenario.outdoors[corner.x][corner.y + 1]->maps[j][i]; + if(corner.y + 1 < univ.scenario.outdoors.height() && corner.x + 1 < univ.scenario.outdoors.width()) + univ.out.out_e[i + 48][j + 48] = univ.scenario.outdoors[corner.x + 1][corner.y + 1]->maps[j][i]; } } diff --git a/src/boe.items.cpp b/src/boe.items.cpp index 7ef03a63..055c1825 100644 --- a/src/boe.items.cpp +++ b/src/boe.items.cpp @@ -251,12 +251,11 @@ short dist_from_party(location where) { return store; } -// TODO: I have no idea what is going on here, other than that it seems to have something to do items being picked up in town +// This marks the item as taken so that it won't show up again when the party returns to this town void set_item_flag(cItem* item) { if((item->is_special > 0) && (item->is_special < 65)) { item->is_special--; - univ.party.item_taken[univ.party.town_num][item->is_special / 8] = - univ.party.item_taken[univ.party.town_num][item->is_special / 8] | (1 << item->is_special % 8); + univ.town->item_taken.set(item->is_special); item->is_special = 0; } } diff --git a/src/boe.monster.cpp b/src/boe.monster.cpp index 0706dcc3..c745d71c 100644 --- a/src/boe.monster.cpp +++ b/src/boe.monster.cpp @@ -54,7 +54,7 @@ void create_wand_monst() { place_outd_wand_monst(univ.out->wandering_locs[r2], univ.out->wandering[r1],0); } } else if(!univ.town->wandering[r1].isNull() && univ.town.countMonsters() <= 50 - && !univ.town->is_cleaned_out(univ.party.m_killed[univ.party.town_num])) { + && !univ.town->is_cleaned_out()) { // won't place wandering if more than 50 monsters r2 = get_ran(1,0,univ.town->wandering.size() - 1); while(point_onscreen(univ.town->wandering_locs[r2],univ.party.town_loc) && diff --git a/src/boe.party.cpp b/src/boe.party.cpp index 87292cac..86013cc4 100644 --- a/src/boe.party.cpp +++ b/src/boe.party.cpp @@ -144,6 +144,13 @@ static void init_party_scen_data() { } } } + for(short j = 0; j < 6; j++) { + univ.party[j].status.clear(); + if(isSplit(univ.party[j].main_status)) + univ.party[j].main_status -= eMainStatus::SPLIT; + univ.party[j].cur_health = univ.party[j].max_health; + univ.party[j].cur_sp = univ.party[j].max_sp; + } univ.party.in_boat = -1; univ.party.in_horse = -1; for(auto& pop : univ.party.creature_save) @@ -153,22 +160,20 @@ static void init_party_scen_data() { for(short i = 0; i < 5; i++) for(short j = 0; j < 10; j++) univ.party.magic_store_items[i][j].variety = eItemType::NO_ITEM; -// for(short i = 0; i < 50; i++) -// univ.party.journal_str[i] = -1; -// for(short i = 0; i < 140; i++) -// for(short j = 0; j < 2; j++) -// univ.party.special_notes_str[i][j] = 0; -// for(short i = 0; i < 120; i++) -// univ.party.talk_save[i].personality = -1; - // TODO: The journal at least should persist across scenarios; the special and talk notes, maybe, maybe not + // TODO: Now uncertain if the journal should really persist +// univ.party.journal.clear(); univ.party.special_notes.clear(); univ.party.talk_save.clear(); univ.party.direction = DIR_N; univ.party.at_which_save_slot = 0; - univ.party.can_find_town.resize(univ.scenario.towns.size()); - for(short i = 0; i < univ.scenario.towns.size(); i++) - univ.party.can_find_town[i] = !univ.scenario.towns[i]->is_hidden; + for(auto town : univ.scenario.towns) { + town->can_find = !town->is_hidden; + town->m_killed = 0; + town->item_taken.reset(); + for(auto& m : town->maps) + m.reset(); + } for(short i = 0; i < 20; i++) univ.party.key_times[i] = 30000; univ.party.party_event_timers.clear(); @@ -184,13 +189,6 @@ static void init_party_scen_data() { } } - univ.party.m_killed.clear(); - univ.party.m_killed.resize(univ.scenario.towns.size()); - - for(short i = 0; i < 200; i++) - for(short j = 0; j < 8; j++) - univ.party.item_taken[i][j] = 0; - refresh_store_items(); @@ -216,10 +214,9 @@ static void init_party_scen_data() { for(short i = 0; i < 3;i++) univ.party.stored_items[i].clear(); - for(short i = 0; i < 100; i++) - for(short k = 0; k < 6; k++) - for(short l = 0; l < 48; l++) - univ.out_maps[i][k][l] = 0; + for(auto sector : univ.scenario.outdoors) + for(auto& m : sector->maps) + m.reset(); } @@ -234,14 +231,6 @@ void put_party_in_scen(std::string scen_name) { univ.ghost_mode = false; univ.node_step_through = false; - for(short j = 0; j < 6; j++) { - univ.party[j].status.clear(); - if(isSplit(univ.party[j].main_status)) - univ.party[j].main_status -= eMainStatus::SPLIT; - univ.party[j].cur_health = univ.party[j].max_health; - univ.party[j].cur_sp = univ.party[j].max_sp; - } - // TODO: The above probably belongs in init_party_scen_data for(short j = 0; j < 6; j++) for(short i = 23; i >= 0; i--) { cItem& thisItem = univ.party[j].items[i]; @@ -268,10 +257,6 @@ void put_party_in_scen(std::string scen_name) { } if(item_took) cChoiceDlog("removed-special-items").show(); - univ.party.age = 0; - univ.party.m_killed.clear(); - univ.party.m_killed.resize(univ.scenario.towns.size()); - univ.party.party_event_timers.clear(); fs::path path = locate_scenario(scen_name); if(path.empty()) { diff --git a/src/boe.specials.cpp b/src/boe.specials.cpp index 57b7d63f..b8ce45aa 100644 --- a/src/boe.specials.cpp +++ b/src/boe.specials.cpp @@ -1652,7 +1652,7 @@ void kill_monst(cCreature& which_m,short who_killed,eMainStatus type) { } if((is_town() || which_combat_type == 1) && which_m.summon_time == 0) { - univ.party.m_killed[univ.party.town_num]++; + univ.town->m_killed++; } which_m.spec1 = 0; // make sure, if this is a spec. activated monster, it won't come back @@ -2227,7 +2227,7 @@ void general_spec(eSpecCtx which_mode,cSpecial cur_node,short cur_spec_type, check_mess = true; if(spec.ex1a != minmax(0,univ.scenario.towns.size() - 1,spec.ex1a)) showError("Town out of range."); - else univ.party.can_find_town[spec.ex1a] = spec.ex2a; + else univ.scenario.towns[spec.ex1a]->can_find = spec.ex2a; *redraw = true; break; case eSpecType::MAJOR_EVENT_OCCURRED: diff --git a/src/boe.text.cpp b/src/boe.text.cpp index 8d4a45be..1ab78de5 100644 --- a/src/boe.text.cpp +++ b/src/boe.text.cpp @@ -679,7 +679,7 @@ void print_party_stats() { add_string_to_buf("PARTY STATS:"); add_string_to_buf(" Number of kills: " + std::to_string(univ.party.total_m_killed)); if((is_town()) || ((is_combat()) && (which_combat_type == 1))) { - add_string_to_buf(" Kills in this town: " + std::to_string(univ.party.m_killed[univ.party.town_num])); + add_string_to_buf(" Kills in this town: " + std::to_string(univ.town->m_killed)); } add_string_to_buf(" Total experience: " + std::to_string(univ.party.total_xp_gained)); add_string_to_buf(" Total damage done: " + std::to_string(univ.party.total_dam_done)); diff --git a/src/boe.town.cpp b/src/boe.town.cpp index 40bfe56c..7e98a6db 100644 --- a/src/boe.town.cpp +++ b/src/boe.town.cpp @@ -127,7 +127,7 @@ void start_town_mode(short which_town, short entry_dir) { // Set up map, using stored map for(short i = 0; i < univ.town->max_dim(); i++) for(short j = 0; j < univ.town->max_dim(); j++) { - if(univ.town_maps[univ.party.town_num][i / 8][j] & (char)(1 << i % 8)) + if(univ.town->maps[j][i]) make_explored(i,j); if(univ.town->terrain(i,j) == 0) @@ -218,7 +218,7 @@ void start_town_mode(short which_town, short entry_dir) { // TODO: Should these two cases be separated? if(univ.town->town_chop_time > 0 && day_reached(univ.town->town_chop_time,univ.town->town_chop_key)) univ.town.monst[j].active += 10; - else if(univ.town->is_cleaned_out(univ.party.m_killed[univ.party.town_num])) + else if(univ.town->is_cleaned_out()) univ.town.monst[j].active += 10; else univ.town.monst[j].active = 0; if(univ.town.monst[j].active >= 10) @@ -290,7 +290,7 @@ void start_town_mode(short which_town, short entry_dir) { // TODO: Should these two cases be separated? if(univ.town->town_chop_time > 0 && day_reached(univ.town->town_chop_time,univ.town->town_chop_key)) univ.town.monst[i].active += 10; - else if(univ.town->is_cleaned_out(univ.party.m_killed[univ.party.town_num])) + else if(univ.town->is_cleaned_out()) univ.town.monst[i].active += 10; else univ.town.monst[i].active = 0; break; @@ -319,7 +319,7 @@ void start_town_mode(short which_town, short entry_dir) { // Thrash town? - if(univ.town->is_cleaned_out(univ.party.m_killed[univ.party.town_num])) { + if(univ.town->is_cleaned_out()) { town_toast = true; add_string_to_buf("Area has been cleaned out."); } @@ -373,7 +373,7 @@ void start_town_mode(short which_town, short entry_dir) { for(short i = 0; i < univ.town->preset_items.size(); i++) if((univ.town->preset_items[i].code >= 0) - && (((univ.party.item_taken[univ.party.town_num][i / 8] & (1 << i % 8)) == 0) || + && (!univ.town->item_taken[i] || (univ.town->preset_items[i].always_there))) { // place the preset item, if party hasn't gotten it already univ.town.items.push_back(get_stored_item(univ.town->preset_items[i].code)); @@ -571,8 +571,7 @@ location end_town_mode(short switching_level,location destination) { // returns for(short i = 0; i < univ.town->max_dim(); i++) for(short j = 0; j < univ.town->max_dim(); j++) if(is_explored(i,j)) { - univ.town_maps[univ.party.town_num][i / 8][j] = univ.town_maps[univ.party.town_num][i / 8][j] | - (char) (1 << i % 8); + univ.town->maps[j].set(i); } to_return = univ.party.out_loc; @@ -1268,11 +1267,11 @@ void erase_out_specials() { (sector.city_locs[k].y == minmax(0,47,sector.city_locs[k].y))) { if(sector.city_locs[k].spec < 0 || sector.city_locs[k].spec >= univ.scenario.towns.size()) continue; - if(!univ.party.can_find_town[sector.city_locs[k].spec]) { + if(!univ.scenario.towns[sector.city_locs[k].spec]->can_find) { univ.out[48 * i + sector.city_locs[k].x][48 * j + sector.city_locs[k].y] = univ.scenario.ter_types[sector.terrain[sector.city_locs[k].x][sector.city_locs[k].y]].flag1; } - else if(univ.party.can_find_town[sector.city_locs[k].spec]) { + else if(univ.scenario.towns[sector.city_locs[k].spec]->can_find) { univ.out[48 * i + sector.city_locs[k].x][48 * j + sector.city_locs[k].y] = sector.terrain[sector.city_locs[k].x][sector.city_locs[k].y]; diff --git a/src/classes/outdoors.hpp b/src/classes/outdoors.hpp index ffa6df94..a780d445 100644 --- a/src/classes/outdoors.hpp +++ b/src/classes/outdoors.hpp @@ -78,6 +78,8 @@ public: eAmbientSound ambient_sound; snd_num_t out_sound; int bg_out, bg_fight, bg_town, bg_dungeon; + // Persistent data for saved games + std::array, 48> maps; explicit cOutdoors(cScenario& scenario); void append(legacy::outdoor_record_type& old); diff --git a/src/classes/party.cpp b/src/classes/party.cpp index 91016861..6dff0a79 100644 --- a/src/classes/party.cpp +++ b/src/classes/party.cpp @@ -53,16 +53,13 @@ cParty::~cParty() { } } -void cParty::append(legacy::party_record_type& old, const cScenario& scen){ +void cParty::append(legacy::party_record_type& old, cUniverse& univ){ age = old.age; gold = old.gold; food = old.food; for(short i = 0; i < 310; i++) for(short j = 0; j < 10; j++) stuff_done[i][j] = old.stuff_done[i][j]; - for(short i = 0; i < 200; i++) - for(short j = 0; j < 8; j++) - item_taken[i][j] = old.item_taken[i][j]; light_level = old.light_level; if(stuff_done[305][0] > 0) status[ePartyStatus::STEALTH] = stuff_done[305][0]; @@ -108,26 +105,18 @@ void cParty::append(legacy::party_record_type& old, const cScenario& scen){ for(short i = 0; i < 256; i++) if(old.m_seen[i]) m_noted.insert(i); - journal.reserve(50); - // The journal wasn't used before, so let's not bother converting it -// for(short i = 0; i < 50; i++){ -// cJournal j; -// j.day = old.journal_day[i]; -// journal.push_back(j); -// spec_items[i] = old.spec_items[i]; -// } if(!scen_name.empty()) { special_notes.reserve(140); for(short i = 0; i < 140; i++){ if(old.special_notes_str[i][0] <= 0) continue; cEncNote n; - n.append(old.special_notes_str[i], scen); + n.append(old.special_notes_str[i], univ.scenario); special_notes.push_back(n); } talk_save.reserve(120); for(short i = 0; i < 120; i++){ cConvers t; - t.append(old.talk_save[i], scen); + t.append(old.talk_save[i], univ.scenario); talk_save.push_back(t); } } @@ -135,11 +124,11 @@ void cParty::append(legacy::party_record_type& old, const cScenario& scen){ at_which_save_slot = old.at_which_save_slot; for(short i = 0; i < 20 ; i++) alchemy[i] = old.alchemy[i]; - can_find_town.resize(200); - m_killed.resize(200); - for(short i = 0; i < 200; i++){ - can_find_town[i] = old.can_find_town[i]; - m_killed[i] = old.m_killed[i]; + for(short i = 0; i < univ.scenario.towns.size(); i++){ + univ.scenario.towns[i]->can_find = old.can_find_town[i]; + univ.scenario.towns[i]->m_killed = old.m_killed[i]; + for(short j = 0; j < 64; j++) + univ.scenario.towns[i]->item_taken[j] = old.item_taken[i][j / 8] & (1 << j % 8); } for(short i = 0; i < 100; i++) key_times[i] = old.key_times[i]; @@ -538,7 +527,7 @@ bool cParty::start_timer(short time, short node, short type){ return(true); } -void cParty::writeTo(std::ostream& file) const { +void cParty::writeTo(std::ostream& file, const cScenario& scen) const { file << "CREATEVERSION " << std::hex << OBOE_CURRENT_VERSION << std::dec << '\n'; file << "AGE " << age << '\n'; file << "GOLD " << gold << '\n'; @@ -555,14 +544,6 @@ void cParty::writeTo(std::ostream& file) const { file << "POINTER " << iter->first << ' ' << iter->second.first << ' ' << iter->second.second << '\n'; for(int i = 0; i < magic_ptrs.size(); i++) file << "POINTER " << i << ' ' << int(magic_ptrs[i]) << '\n'; - for(int i = 0; i < 200; i++) - if(item_taken[i][0] > 0 || item_taken[i][1] > 0 || item_taken[i][2] > 0 || item_taken[i][3] > 0 || - item_taken[i][4] > 0 || item_taken[i][5] > 0 || item_taken[i][6] > 0 || item_taken[i][7] > 0) { - file << "ITEMTAKEN " << i; - for(int j = 0; j < 8; j++) - file << ' ' << unsigned(item_taken[i][j]); - file << '\n'; - } file << "LIGHT " << light_level << '\n'; file << "OUTCORNER " << outdoor_corner.x << ' ' << outdoor_corner.y << '\n'; file << "INWHICHCORNER " << i_w_c.x << ' ' << i_w_c.y << '\n'; @@ -594,16 +575,18 @@ void cParty::writeTo(std::ostream& file) const { for(int i = 0; i < alchemy.size(); i++) if(alchemy[i]) file << "ALCHEMY " << i << '\n'; - for(int i = 0; i < can_find_town.size(); i++) - if(can_find_town[i]) - file << "TOWNVISIBLE " << i << '\n'; + for(int i = 0; i < scen.towns.size(); i++) { + if(scen.towns[i]->item_taken.any()) + file << "ITEMTAKEN " << i << ' ' << scen.towns[i]->item_taken << '\n'; + if(scen.towns[i]->can_find == scen.towns[i]->is_hidden) + file << (scen.towns[i]->can_find ? "TOWNVISIBLE " : "TOWNHIDDEN ") << i << '\n'; + if(scen.towns[i]->m_killed > 0) + file << "TOWNSLAUGHTER " << i << ' ' << scen.towns[i]->m_killed << '\n'; + } for(auto key : key_times) file << "EVENT " << key.first << ' ' << key.second << '\n'; for(int i : spec_items) file << "ITEM " << i << '\n'; - for(int i = 0; i < m_killed.size(); i++) - if(m_killed[i] > 0) - file << "TOWNSLAUGHTER " << i << ' ' << m_killed[i] << '\n'; file << "KILLS " << total_m_killed << '\n'; file << "DAMAGE " << total_dam_done << '\n'; file << "WOUNDS " << total_dam_taken << '\n'; @@ -728,7 +711,7 @@ void cParty::writeTo(std::ostream& file) const { } } -void cParty::readFrom(std::istream& file){ +void cParty::readFrom(std::istream& file, cScenario& scen){ // TODO: Error-check input // TODO: Don't call this sin, it's a trig function std::istringstream bin; @@ -787,11 +770,8 @@ void cParty::readFrom(std::istream& file){ }else if(cur == "ITEMTAKEN"){ int i; sin >> i; - for(int j = 0; j < 8; j++) { - unsigned int n; - sin >> n; - item_taken[i][j] = n; - } + if(i >= 0 && i < scen.towns.size()) + sin >> scen.towns[i]->item_taken; }else if(cur == "LIGHT") sin >> light_level; else if(cur == "OUTCORNER") @@ -840,9 +820,13 @@ void cParty::readFrom(std::istream& file){ } else if(cur == "TOWNVISIBLE") { int i; sin >> i; - if(i >= can_find_town.size()) - can_find_town.resize(i + 1); - can_find_town[i] = true; + if(i >= 0 && i < scen.towns.size()) + scen.towns[i]->can_find = true; + } else if(cur == "TOWNHIDDEN") { + int i; + sin >> i; + if(i >= 0 && i < scen.towns.size()) + scen.towns[i]->can_find = false; }else if(cur == "EVENT"){ int i; sin >> i; @@ -854,9 +838,8 @@ void cParty::readFrom(std::istream& file){ }else if(cur == "TOWNSLAUGHTER"){ int i; sin >> i; - if(i >= m_killed.size()) - m_killed.resize(i + 1); - sin >> m_killed[i]; + if(i >= 0 && i < scen.towns.size()) + sin >> scen.towns[i]->m_killed; } else if(cur == "QUEST") { int i; sin >> i; diff --git a/src/classes/party.hpp b/src/classes/party.hpp index cc271b99..11aad307 100644 --- a/src/classes/party.hpp +++ b/src/classes/party.hpp @@ -45,6 +45,7 @@ struct job_bank_t { bool inited = false; }; +class cUniverse; class cItem; class cParty : public iLiving { @@ -80,7 +81,6 @@ public: bool easy_mode = false, less_wm = false; // End former magic SDFs std::array magic_ptrs; - unsigned char item_taken[200][8]; short light_level; location outdoor_corner; location i_w_c; @@ -113,11 +113,9 @@ public: eDirection direction; short at_which_save_slot; std::bitset<20> alchemy; - std::vector can_find_town; std::map key_times; std::vector party_event_timers; std::set spec_items; - std::vector m_killed; long long total_m_killed, total_dam_done, total_xp_gained, total_dam_taken; std::string scen_name; private: @@ -138,7 +136,7 @@ public: void clear_ptr(unsigned short p); unsigned char get_ptr(unsigned short p); - void append(legacy::party_record_type& old, const cScenario& scen); + void append(legacy::party_record_type& old, cUniverse& univ); void append(legacy::big_tr_type& old); void append(legacy::stored_items_list_type& old,short which_list); void append(legacy::setup_save_type& old); @@ -184,8 +182,8 @@ public: bool start_timer(short time, short node, short type); cPlayer& operator[](unsigned short n); const cPlayer& operator[](unsigned short n) const; - void writeTo(std::ostream& file) const; - void readFrom(std::istream& file); + void writeTo(std::ostream& file, const cScenario& scen) const; + void readFrom(std::istream& file, cScenario& scen); bool give_item(cItem item,int flags); bool forced_give(cItem item,eItemAbil abil,short dat = -1); diff --git a/src/classes/town.cpp b/src/classes/town.cpp index e570d593..c6332944 100644 --- a/src/classes/town.cpp +++ b/src/classes/town.cpp @@ -173,7 +173,7 @@ bool cTown::cWandering::isNull(){ return true; } -bool cTown::is_cleaned_out(long m_killed) { +bool cTown::is_cleaned_out() { if(max_num_monst < 0) return false; return m_killed >= max_num_monst; } diff --git a/src/classes/town.hpp b/src/classes/town.hpp index adc6e47e..2faa1656 100644 --- a/src/classes/town.hpp +++ b/src/classes/town.hpp @@ -91,6 +91,11 @@ public: std::array comment; std::vector spec_strs; cSpeech talking; + // Persistent data for saved games + std::array, 64> maps; + std::bitset<64> item_taken; + bool can_find; + long m_killed; virtual ~cTown(){} virtual void append(legacy::big_tr_type& old, int town_num); @@ -103,7 +108,7 @@ public: void init_start(); void set_up_lights(); short light_obscurity(short x,short y); // Obscurity function used for calculating lighting - bool is_cleaned_out(long m_killed); + bool is_cleaned_out(); explicit cTown(cScenario& scenario); void append(legacy::town_record_type& old); diff --git a/src/classes/universe.cpp b/src/classes/universe.cpp index 440f66d8..29aa2bf2 100644 --- a/src/classes/universe.cpp +++ b/src/classes/universe.cpp @@ -64,16 +64,21 @@ void cCurTown::append(legacy::town_item_list& old){ void cUniverse::append(legacy::stored_town_maps_type& old){ for(int n = 0; n < 200; n++) - for(int i = 0; i < 8; i++) + for(int i = 0; i < 64; i++) for(int j = 0; j < 64; j++) - town_maps[n][i][j] = old.town_maps[n][i][j]; + scenario.towns[n]->maps[j][i] = old.town_maps[n][i / 8][j] & (1 << (i % 8)); +} + +static short onm(char x_sector,char y_sector, char w) { + return y_sector * w + x_sector; } void cUniverse::append(legacy::stored_outdoor_maps_type& old){ - for(int n = 0; n < 100; n++) - for(int i = 0; i < 6; i++) - for(int j = 0; j < 48; j++) - out_maps[n][i][j] = old.outdoor_maps[n][i][j]; + for(int x = 0; x < scenario.outdoors.width(); x++) + for(int y = 0; y < scenario.outdoors.height(); y++) + for(int i = 0; i < 48; i++) + for(int j = 0; j < 48; j++) + scenario.outdoors[x][y]->maps[i][j] = old.outdoor_maps[onm(x,y,scenario.outdoors.width())][i / 8][j] & (1 << i % 8); } void cCurTown::append(unsigned char(& old_sfx)[64][64], unsigned char(& old_misc_i)[64][64]){ diff --git a/src/classes/universe.hpp b/src/classes/universe.hpp index 82c668bf..c3bdb4b0 100644 --- a/src/classes/universe.hpp +++ b/src/classes/universe.hpp @@ -176,9 +176,7 @@ public: cParty party; std::map stored_pcs; cCurTown town; - unsigned char town_maps[200][8][64]; // formerly stored_town_maps_type cCurOut out; - unsigned char out_maps[100][6][48]; // formerly stored_outdoor_maps_type fs::path file; bool debug_mode, ghost_mode, node_step_through; diff --git a/src/pcedit/pc.main.cpp b/src/pcedit/pc.main.cpp index fec9a98c..c87b69e2 100644 --- a/src/pcedit/pc.main.cpp +++ b/src/pcedit/pc.main.cpp @@ -285,17 +285,15 @@ void handle_menu_choice(eMenu item_hit) { break; case eMenu::ADD_OUT_MAPS: display_strings(13,15); - for(short i = 0; i < 100; i++) - for(short j = 0; j < 6; j++) - for(short k = 0; k < 48; k++) - univ.out_maps[i][j][k] = 255; + for(auto sector : univ.scenario.outdoors) + for(auto& m : sector->maps) + m.set(); break; case eMenu::ADD_TOWN_MAPS: display_strings(14,15); - for(short i = 0; i < 200; i++) - for(short j = 0; j < 8; j++) - for(short k = 0; k < 64; k++) - univ.town_maps[i][j][k] = 255; + for(auto town : univ.scenario.towns) + for(auto& m : town->maps) + m.set(); break; case eMenu::EDIT_MAGE: display_pc(current_active_pc,10,0); diff --git a/src/tools/fileio_party.cpp b/src/tools/fileio_party.cpp index 35b3dc9c..f8f94cdb 100644 --- a/src/tools/fileio_party.cpp +++ b/src/tools/fileio_party.cpp @@ -233,7 +233,7 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo univ.party.scen_name = ""; } - univ.party.append(store_party, univ.scenario); + univ.party.append(store_party, univ); univ.party.append(store_setup); univ.party.append(store_pc); if(in_scen){ @@ -280,7 +280,7 @@ bool load_party_v2(fs::path file_to_load, cUniverse& univ){ showError("Loading Blades of Exile save file failed."); return false; } - univ.party.readFrom(fin); + univ.party.readFrom(fin, univ.scenario); } { // Then the "setup" array @@ -343,10 +343,9 @@ bool load_party_v2(fs::path file_to_load, cUniverse& univ){ // Read town maps std::istream& fin2 = partyIn.getFile("save/townmaps.dat"); - for(int i = 0; i < 200; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 64; k++) - univ.town_maps[i][j][k] = fin2.get(); + for(int i = 0; i < univ.scenario.towns.size(); i++) + for(int j = 0; j < 64; j++) + fin2 >> univ.scenario.towns[i]->maps[j]; } else univ.party.town_num = 200; // Load outdoors data @@ -359,10 +358,10 @@ bool load_party_v2(fs::path file_to_load, cUniverse& univ){ // Read outdoor maps std::istream& fin2 = partyIn.getFile("save/outmaps.dat"); - for(int i = 0; i < 100; i++) - for(int j = 0; j < 6; j++) - for(int k = 0; k < 48; k++) - univ.out_maps[i][j][k] = fin2.get(); + for(int i = 0; i < univ.scenario.outdoors.height(); i++) + for(int j = 0; j < 48; j++) + for(int k = 0; k < univ.scenario.outdoors.width(); k++) + fin2 >> univ.scenario.outdoors[k][i]->maps[j]; } else univ.party.scen_name = ""; if(partyIn.hasFile("save/export.png")) { @@ -391,7 +390,7 @@ bool save_party(fs::path dest_file, const cUniverse& univ) { tarball partyOut; // First, write the main party data - univ.party.writeTo(partyOut.newFile("save/party.txt")); + univ.party.writeTo(partyOut.newFile("save/party.txt"), univ.scenario); { std::ostream& fout = partyOut.newFile("save/setup.dat"); static uint16_t magic = 0x0B0E; @@ -423,10 +422,9 @@ bool save_party(fs::path dest_file, const cUniverse& univ) { // Write the town map data std::ostream& fout = partyOut.newFile("save/townmaps.dat"); - for(int i = 0; i < 200; i++) - for(int j = 0; j < 8; j++) - for(int k = 0; k < 64; k++) - fout.put(univ.town_maps[i][j][k]); + for(int i = 0; i < univ.scenario.towns.size(); i++) + for(int j = 0; j < 64; j++) + fout << univ.scenario.towns[i]->maps[j] << '\n'; } // Write the current outdoors data @@ -434,10 +432,14 @@ bool save_party(fs::path dest_file, const cUniverse& univ) { // Write the outdoors map data std::ostream& fout = partyOut.newFile("save/outmaps.dat"); - for(int i = 0; i < 100; i++) - for(int j = 0; j < 6; j++) - for(int k = 0; k < 48; k++) - fout.put(univ.out_maps[i][j][k]); + for(int i = 0; i < univ.scenario.outdoors.height(); i++) { + for(int j = 0; j < 48; j++) { + for(int k = 0; k < univ.scenario.outdoors.width(); k++) + fout << univ.scenario.outdoors[k][i]->maps[j] << ' '; + fout << '\n'; + } + fout << '\n'; + } } if(spec_scen_g.party_sheet) {