Properly implement copying for universe and scenario

This allows a failed load to not clobber the currently-loaded save or scenario.
This commit is contained in:
2016-09-02 18:56:47 -04:00
parent e969da6fc1
commit 20f22d7952
16 changed files with 635 additions and 22 deletions

View File

@@ -67,6 +67,12 @@ void cPopulation::assign(size_t n, const cTownperson& other, const cMonster& bas
dudes[n].summon_time = 0;
}
void cPopulation::swap(cPopulation& other) {
std::swap(dudes, other.dudes);
std::swap(which_town, other.which_town);
std::swap(hostile, other.hostile);
}
void cPopulation::readFrom(std::istream& in, size_t n) {
if(n >= dudes.size()) dudes.resize(n + 1);
dudes[n].readFrom(in);

View File

@@ -35,6 +35,7 @@ public:
cPopulation() : which_town(200) {}
// Apparently Visual Studio needs this to work
cPopulation& operator=(const cPopulation& other) = default;
void swap(cPopulation& other);
};
#endif

View File

@@ -53,6 +53,144 @@ cParty::~cParty() {
}
}
cParty::cParty(const cParty& other)
: iLiving(other)
, next_pc_id(other.next_pc_id)
, age(other.age)
, gold(other.gold)
, food(other.food)
, hostiles_present(other.hostiles_present)
, easy_mode(other.easy_mode)
, less_wm(other.less_wm)
, magic_ptrs(other.magic_ptrs)
, light_level(other.light_level)
, outdoor_corner(other.outdoor_corner)
, i_w_c(other.i_w_c)
, out_loc(other.out_loc)
, town_loc(other.town_loc)
, loc_in_sec(other.loc_in_sec)
, town_num(other.town_num)
, boats(other.boats)
, horses(other.horses)
, creature_save(other.creature_save)
, in_boat(other.in_boat)
, in_horse(other.in_horse)
, out_c(other.out_c)
, magic_store_items(other.magic_store_items)
, store_limited_stock(other.store_limited_stock)
, job_banks(other.job_banks)
, imprisoned_monst(other.imprisoned_monst)
, m_noted(other.m_noted)
, m_seen(other.m_seen)
, journal(other.journal)
, special_notes(other.special_notes)
, talk_save(other.talk_save)
, status(other.status)
, quest_status(other.quest_status)
, quest_start(other.quest_start)
, quest_source(other.quest_source)
, left_at(other.left_at)
, left_in(other.left_in)
, direction(other.direction)
, at_which_save_slot(other.at_which_save_slot)
, alchemy(other.alchemy)
, key_times(other.key_times)
, party_event_timers(other.party_event_timers)
, spec_items(other.spec_items)
, total_m_killed(other.total_m_killed)
, total_dam_done(other.total_dam_done)
, total_xp_gained(other.total_xp_gained)
, total_dam_taken(other.total_dam_taken)
, scen_name(other.scen_name)
, stored_items(other.stored_items)
, summons(other.summons)
, scen_won(other.scen_won)
, scen_played(other.scen_played)
, campaign_flags(other.campaign_flags)
, pointers(other.pointers)
{
memcpy(stuff_done, other.stuff_done, sizeof(stuff_done));
memcpy(setup, other.setup, sizeof(setup));
for(int i = 0; i < 6; i++) {
adven[i] = new cPlayer(*other.adven[i]);
adven[i]->join_party(*this);
}
}
cParty::cParty(cParty&& other) : cParty() {
swap(other);
}
cParty& cParty::operator=(cParty other) {
swap(other);
return *this;
}
void cParty::swap(cParty& other) {
std::swap(next_pc_id, other.next_pc_id);
std::swap(age, other.age);
std::swap(gold, other.gold);
std::swap(food, other.food);
std::swap(hostiles_present, other.hostiles_present);
std::swap(easy_mode, other.easy_mode);
std::swap(less_wm, other.less_wm);
std::swap(magic_ptrs, other.magic_ptrs);
std::swap(light_level, other.light_level);
std::swap(outdoor_corner, other.outdoor_corner);
std::swap(i_w_c, other.i_w_c);
std::swap(out_loc, other.out_loc);
std::swap(town_loc, other.town_loc);
std::swap(loc_in_sec, other.loc_in_sec);
std::swap(town_num, other.town_num);
std::swap(boats, other.boats);
std::swap(horses, other.horses);
std::swap(creature_save, other.creature_save);
std::swap(in_boat, other.in_boat);
std::swap(in_horse, other.in_horse);
std::swap(out_c, other.out_c);
std::swap(magic_store_items, other.magic_store_items);
std::swap(store_limited_stock, other.store_limited_stock);
std::swap(job_banks, other.job_banks);
std::swap(imprisoned_monst, other.imprisoned_monst);
std::swap(m_noted, other.m_noted);
std::swap(m_seen, other.m_seen);
std::swap(journal, other.journal);
std::swap(special_notes, other.special_notes);
std::swap(talk_save, other.talk_save);
std::swap(status, other.status);
std::swap(quest_status, other.quest_status);
std::swap(quest_start, other.quest_start);
std::swap(quest_source, other.quest_source);
std::swap(left_at, other.left_at);
std::swap(left_in, other.left_in);
std::swap(direction, other.direction);
std::swap(at_which_save_slot, other.at_which_save_slot);
std::swap(alchemy, other.alchemy);
std::swap(key_times, other.key_times);
std::swap(party_event_timers, other.party_event_timers);
std::swap(spec_items, other.spec_items);
std::swap(total_m_killed, other.total_m_killed);
std::swap(total_dam_done, other.total_dam_done);
std::swap(total_xp_gained, other.total_xp_gained);
std::swap(total_dam_taken, other.total_dam_taken);
std::swap(scen_name, other.scen_name);
std::swap(adven, other.adven);
std::swap(stored_items, other.stored_items);
std::swap(summons, other.summons);
std::swap(scen_won, other.scen_won);
std::swap(scen_played, other.scen_played);
std::swap(campaign_flags, other.campaign_flags);
std::swap(pointers, other.pointers);
unsigned char temp_sdf[350][50];
memcpy(temp_sdf, stuff_done, sizeof(stuff_done));
memcpy(stuff_done, other.stuff_done, sizeof(stuff_done));
memcpy(other.stuff_done, temp_sdf, sizeof(stuff_done));
unsigned short temp_setup[4][64][64];
memcpy(temp_setup, setup, sizeof(setup));
memcpy(setup, other.setup, sizeof(setup));
memcpy(other.setup, temp_setup, sizeof(setup));
}
void cParty::import_legacy(legacy::party_record_type& old, cUniverse& univ){
age = old.age;
gold = old.gold;

View File

@@ -213,6 +213,11 @@ public:
typedef std::vector<cConvers>::iterator talkIter;
cParty(long party_preset = 'dflt');
~cParty();
// Copy-and-swap
void swap(cParty& other);
cParty(const cParty& other);
cParty(cParty&& other);
cParty& operator=(cParty other);
};
bool operator==(const cParty::cConvers& one, const cParty::cConvers& two);

View File

@@ -1099,6 +1099,65 @@ cPlayer::cPlayer(cParty& party,long key,short slot) : cPlayer(party) {
}
}
cPlayer::cPlayer(const cPlayer& other)
: iLiving(other)
, party(other.party)
, main_status(other.main_status)
, name(other.name)
, skills(other.skills)
, max_health(other.max_health)
, cur_health(other.cur_health)
, max_sp(other.max_sp)
, cur_sp(other.cur_sp)
, experience(other.experience)
, skill_pts(other.skill_pts)
, level(other.level)
, items(other.items)
, equip(other.equip)
, priest_spells(other.priest_spells)
, mage_spells(other.mage_spells)
, which_graphic(other.which_graphic)
, weap_poisoned(*this, other.weap_poisoned.slot)
, traits(other.traits)
, race(other.race)
, unique_id(party->next_pc_id++)
, last_cast(other.last_cast)
, combat_pos(other.combat_pos)
, parry(other.parry)
, last_attacked(nullptr)
{}
cPlayer::cPlayer(cPlayer&& other) : weap_poisoned(*this, other.weap_poisoned.slot) {
swap(other);
}
void cPlayer::swap(cPlayer& other) {
std::swap(party, other.party);
std::swap(main_status, other.main_status);
std::swap(name, other.name);
std::swap(skills, other.skills);
std::swap(max_health, other.max_health);
std::swap(cur_health, other.cur_health);
std::swap(max_sp, other.max_sp);
std::swap(cur_sp, other.cur_sp);
std::swap(experience, other.experience);
std::swap(skill_pts, other.skill_pts);
std::swap(level, other.level);
std::swap(items, other.items);
std::swap(equip, other.equip);
std::swap(priest_spells, other.priest_spells);
std::swap(mage_spells, other.mage_spells);
std::swap(which_graphic, other.which_graphic);
std::swap(weap_poisoned.slot, other.weap_poisoned.slot);
std::swap(traits, other.traits);
std::swap(race, other.race);
std::swap(unique_id, other.unique_id);
std::swap(last_cast, other.last_cast);
std::swap(combat_pos, other.combat_pos);
std::swap(parry, other.parry);
std::swap(last_attacked, other.last_attacked);
}
void operator += (eMainStatus& stat, eMainStatus othr){
if(othr == eMainStatus::SPLIT)
stat = (eMainStatus) (10 + (int)stat);

View File

@@ -159,6 +159,12 @@ public:
void writeTo(std::ostream& file) const;
void readFrom(std::istream& file);
virtual ~cPlayer() = default;
// Copy-and-swap
void swap(cPlayer& other);
cPlayer(const cPlayer& other);
cPlayer(cPlayer&& other);
// For now, not assignable because of an issue of how to handle the unique_id
cPlayer& operator=(cPlayer other) = delete;
};
void operator += (eMainStatus& stat, eMainStatus othr);

View File

@@ -390,6 +390,84 @@ cTinyTown::cTinyTown(cScenario& scenario) : cTown(scenario) {
init_start();
}
cBigTown::cBigTown(const cBigTown& other) : cTown(other) {
memcpy(ter, other.ter, sizeof(ter));
memcpy(light, other.light, sizeof(light));
}
cBigTown::cBigTown(cBigTown&& other) : cTown(*other.scenario) {
swap(other);
}
cMedTown::cMedTown(const cMedTown& other) : cTown(other) {
memcpy(ter, other.ter, sizeof(ter));
memcpy(light, other.light, sizeof(light));
}
cMedTown::cMedTown(cMedTown&& other) : cTown(*other.scenario) {
swap(other);
}
cTinyTown::cTinyTown(const cTinyTown& other) : cTown(other) {
memcpy(ter, other.ter, sizeof(ter));
memcpy(light, other.light, sizeof(light));
}
cTinyTown::cTinyTown(cTinyTown&& other) : cTown(*other.scenario) {
swap(other);
}
void cBigTown::swap(cTown& with) {
cTown::swap(with);
cBigTown& other = dynamic_cast<cBigTown&>(with);
ter_num_t temp_ter[64][64];
memcpy(temp_ter, ter, sizeof(ter));
memcpy(ter, other.ter, sizeof(ter));
memcpy(other.ter, temp_ter, sizeof(ter));
unsigned char temp_light[8][64];
memcpy(temp_light, light, sizeof(light));
memcpy(light, other.light, sizeof(light));
memcpy(other.light, temp_light, sizeof(light));
}
void cMedTown::swap(cTown& with) {
cTown::swap(with);
cMedTown& other = dynamic_cast<cMedTown&>(with);
ter_num_t temp_ter[48][48];
memcpy(temp_ter, ter, sizeof(ter));
memcpy(ter, other.ter, sizeof(ter));
memcpy(other.ter, temp_ter, sizeof(ter));
unsigned char temp_light[6][48];
memcpy(temp_light, light, sizeof(light));
memcpy(light, other.light, sizeof(light));
memcpy(other.light, temp_light, sizeof(light));
}
void cTinyTown::swap(cTown& with) {
cTown::swap(with);
cTinyTown& other = dynamic_cast<cTinyTown&>(with);
ter_num_t temp_ter[32][32];
memcpy(temp_ter, ter, sizeof(ter));
memcpy(ter, other.ter, sizeof(ter));
memcpy(other.ter, temp_ter, sizeof(ter));
unsigned char temp_light[4][32];
memcpy(temp_light, light, sizeof(light));
memcpy(light, other.light, sizeof(light));
memcpy(other.light, temp_light, sizeof(light));
}
cBigTown* cBigTown::clone() {
return new cBigTown(*this);
}
cMedTown* cMedTown::clone() {
return new cMedTown(*this);
}
cTinyTown* cTinyTown::clone() {
return new cTinyTown(*this);
}
size_t cBigTown::max_dim() const {
return 64;
}

View File

@@ -34,6 +34,11 @@ public:
explicit cBigTown(cScenario& scenario);
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
// Copy-and-swap
cBigTown* clone() override;
void swap(cTown& other) override;
cBigTown(const cBigTown& other);
cBigTown(cBigTown&& other);
};
class cMedTown : public virtual cTown { // formerly ave_tr_type
@@ -48,6 +53,11 @@ public:
explicit cMedTown(cScenario& scenario);
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
// Copy-and-swap
cMedTown* clone() override;
void swap(cTown& other) override;
cMedTown(const cMedTown& other);
cMedTown(cMedTown&& other);
};
class cTinyTown : public virtual cTown { // formerly tiny_tr_type
@@ -62,6 +72,11 @@ public:
explicit cTinyTown(cScenario& scenario);
void writeTerrainTo(std::ostream& file);
void readTerrainFrom(std::istream& file);
// Copy-and-swap
cTinyTown* clone() override;
void swap(cTown& other) override;
cTinyTown(const cTinyTown& other);
cTinyTown(cTinyTown&& other);
};
#endif

View File

@@ -46,18 +46,6 @@ void cScenario::destroy_terrain() {
}
}
cScenario& cScenario::operator=(cScenario&& other) {
// If self-assignment, do nothing.
if(this == &other) return *this;
// First, free any held pointers.
destroy_terrain();
// Resize the outdoors to ensure the assigned outdoors fits
outdoors.resize(other.outdoors.width(), other.outdoors.height());
// Then forward to the default assignment operator.
// Use const_cast to ensure the right overload is selected.
return *this = const_cast<const cScenario&>(other);
}
cScenario::cScenario() {
std::string temp_str;
@@ -94,6 +82,122 @@ cScenario::cScenario() {
contact_info[1] = "Contact info";
}
cScenario::cScenario(const cScenario& other)
: difficulty(other.difficulty)
, intro_pic(other.intro_pic)
, default_ground(other.default_ground)
, bg_out(other.bg_out)
, bg_fight(other.bg_fight)
, bg_town(other.bg_town)
, bg_dungeon(other.bg_dungeon)
, intro_mess_pic(other.intro_mess_pic)
, where_start(other.where_start)
, out_sec_start(other.out_sec_start)
, out_start(other.out_start)
, which_town_start(other.which_town_start)
, init_spec(other.init_spec)
, town_mods(other.town_mods)
, store_item_rects(other.store_item_rects)
, store_item_towns(other.store_item_towns)
, special_items(other.special_items)
, quests(other.quests)
, shops(other.shops)
, uses_custom_graphics(other.uses_custom_graphics)
, rating(other.rating)
, custom_graphics(other.custom_graphics)
, scen_monsters(other.scen_monsters)
, boats(other.boats)
, horses(other.horses)
, ter_types(other.ter_types)
, scenario_timers(other.scenario_timers)
, scen_specials(other.scen_specials)
, storage_shortcuts(other.storage_shortcuts)
, last_out_edited(other.last_out_edited)
, last_town_edited(other.last_town_edited)
, format(other.format)
, campaign_id(other.campaign_id)
, scen_items(other.scen_items)
, scen_name(other.scen_name)
, who_wrote{other.who_wrote[0], other.who_wrote[1]}
, contact_info{other.contact_info[0], other.contact_info[1]}
, intro_strs(other.intro_strs)
, journal_strs(other.journal_strs)
, spec_strs(other.spec_strs)
, snd_names(other.snd_names)
, adjust_diff(other.adjust_diff)
, is_legacy(other.is_legacy)
, scen_file(other.scen_file)
, towns(other.towns.size())
, outdoors(other.outdoors.width(), other.outdoors.height())
{
// Copy towns and sectors
for(size_t i = 0; i < towns.size(); i++)
towns[i] = other.towns[i]->clone();
for(size_t i = 0; i < outdoors.width(); i++)
for(size_t j = 0; j < outdoors.height(); j++)
outdoors[i][j] = new cOutdoors(*other.outdoors[i][j]);
}
cScenario::cScenario(cScenario&& other) {
swap(other);
}
cScenario& cScenario::operator=(cScenario other) {
swap(other);
return *this;
}
void cScenario::swap(cScenario& other) {
std::swap(difficulty, other.difficulty);
std::swap(intro_pic, other.intro_pic);
std::swap(default_ground, other.default_ground);
std::swap(bg_out, other.bg_out);
std::swap(bg_fight, other.bg_fight);
std::swap(bg_town, other.bg_town);
std::swap(bg_dungeon, other.bg_dungeon);
std::swap(intro_mess_pic, other.intro_mess_pic);
std::swap(where_start, other.where_start);
std::swap(out_sec_start, other.out_sec_start);
std::swap(out_start, other.out_start);
std::swap(which_town_start, other.which_town_start);
std::swap(init_spec, other.init_spec);
std::swap(town_mods, other.town_mods);
std::swap(store_item_rects, other.store_item_rects);
std::swap(store_item_towns, other.store_item_towns);
std::swap(special_items, other.special_items);
std::swap(quests, other.quests);
std::swap(shops, other.shops);
std::swap(uses_custom_graphics, other.uses_custom_graphics);
std::swap(rating, other.rating);
std::swap(custom_graphics, other.custom_graphics);
std::swap(scen_monsters, other.scen_monsters);
std::swap(boats, other.boats);
std::swap(horses, other.horses);
std::swap(ter_types, other.ter_types);
std::swap(scenario_timers, other.scenario_timers);
std::swap(scen_specials, other.scen_specials);
std::swap(storage_shortcuts, other.storage_shortcuts);
std::swap(last_out_edited, other.last_out_edited);
std::swap(last_town_edited, other.last_town_edited);
std::swap(format, other.format);
std::swap(campaign_id, other.campaign_id);
std::swap(scen_items, other.scen_items);
std::swap(scen_name, other.scen_name);
std::swap(who_wrote[0], other.who_wrote[0]);
std::swap(who_wrote[1], other.who_wrote[1]);
std::swap(contact_info[0], other.contact_info[0]);
std::swap(contact_info[1], other.contact_info[1]);
std::swap(intro_strs, other.intro_strs);
std::swap(journal_strs, other.journal_strs);
std::swap(spec_strs, other.spec_strs);
std::swap(snd_names, other.snd_names);
std::swap(adjust_diff, other.adjust_diff);
std::swap(is_legacy, other.is_legacy);
std::swap(scen_file, other.scen_file);
std::swap(outdoors, other.outdoors);
std::swap(towns, other.towns);
}
cScenario::cItemStorage::cItemStorage() : ter_type(-1), property(0) {
for(int i = 0; i < 10; i++)
item_num[i] = -1;

View File

@@ -57,7 +57,6 @@ public:
cItemStorage();
cItemStorage& operator = (legacy::item_storage_shortcut_type& old);
};
cScenario& operator=(const cScenario& other) = default;
void destroy_terrain();
public:
unsigned short difficulty,intro_pic,default_ground;
@@ -120,10 +119,13 @@ public:
cItem pull_item_of_type(unsigned int loot_max,short min_val,short max_val,const std::vector<eItemType>& types,bool allow_junk_treasure=false);
void reset_version();
cScenario& operator=(cScenario&& other);
cScenario(cScenario&) = delete;
explicit cScenario();
~cScenario();
// Copy-and-swap
void swap(cScenario& other);
cScenario(const cScenario& other);
cScenario(cScenario&& other);
cScenario& operator=(cScenario other);
};
std::istream& operator>> (std::istream& in, eContentRating& rating);

View File

@@ -112,6 +112,88 @@ cTown::cTown(cScenario& scenario) : scenario(&scenario) {
}
}
cTown::cTown(const cTown& other)
: town_chop_time(other.town_chop_time)
, town_chop_key(other.town_chop_key)
, bg_town(other.bg_town)
, bg_fight(other.bg_fight)
, wandering(other.wandering)
, wandering_locs(other.wandering_locs)
, special_locs(other.special_locs)
, sign_locs(other.sign_locs)
, lighting_type(other.lighting_type)
, start_locs(other.start_locs)
, exits(other.exits)
, in_town_rect(other.in_town_rect)
, preset_items(other.preset_items)
, creatures(other.creatures)
, max_num_monst(other.max_num_monst)
, preset_fields(other.preset_fields)
, spec_on_entry(other.spec_on_entry)
, spec_on_entry_if_dead(other.spec_on_entry_if_dead)
, spec_on_hostile(other.spec_on_hostile)
, timers(other.timers)
, specials(other.specials)
, strong_barriers(other.strong_barriers)
, defy_mapping(other.defy_mapping)
, defy_scrying(other.defy_scrying)
, is_hidden(other.is_hidden)
, has_tavern(other.has_tavern)
, difficulty(other.difficulty)
, town_name(other.town_name)
, room_rect(other.room_rect)
, comment(other.comment)
, spec_strs(other.spec_strs)
, talking(other.talking)
, maps(other.maps)
, item_taken(other.item_taken)
, can_find(other.can_find)
, m_killed(other.m_killed)
{}
cTown::cTown(cTown&& other) {
swap(other);
}
void cTown::swap(cTown& other) {
std::swap(town_chop_time, other.town_chop_time);
std::swap(town_chop_key, other.town_chop_key);
std::swap(bg_town, other.bg_town);
std::swap(bg_fight, other.bg_fight);
std::swap(wandering, other.wandering);
std::swap(wandering_locs, other.wandering_locs);
std::swap(special_locs, other.special_locs);
std::swap(sign_locs, other.sign_locs);
std::swap(lighting_type, other.lighting_type);
std::swap(start_locs, other.start_locs);
std::swap(exits, other.exits);
std::swap(in_town_rect, other.in_town_rect);
std::swap(preset_items, other.preset_items);
std::swap(creatures, other.creatures);
std::swap(max_num_monst, other.max_num_monst);
std::swap(preset_fields, other.preset_fields);
std::swap(spec_on_entry, other.spec_on_entry);
std::swap(spec_on_entry_if_dead, other.spec_on_entry_if_dead);
std::swap(spec_on_hostile, other.spec_on_hostile);
std::swap(timers, other.timers);
std::swap(specials, other.specials);
std::swap(strong_barriers, other.strong_barriers);
std::swap(defy_mapping, other.defy_mapping);
std::swap(defy_scrying, other.defy_scrying);
std::swap(is_hidden, other.is_hidden);
std::swap(has_tavern, other.has_tavern);
std::swap(difficulty, other.difficulty);
std::swap(town_name, other.town_name);
std::swap(room_rect, other.room_rect);
std::swap(comment, other.comment);
std::swap(spec_strs, other.spec_strs);
std::swap(talking, other.talking);
std::swap(maps, other.maps);
std::swap(item_taken, other.item_taken);
std::swap(can_find, other.can_find);
std::swap(m_killed, other.m_killed);
}
void cTown::init_start() {
short s = this->max_dim();
start_locs[0].x = s / 2;

View File

@@ -115,6 +115,13 @@ public:
void reattach(cScenario& to);
virtual void writeTerrainTo(std::ostream& file) = 0;
virtual void readTerrainFrom(std::istream& file) = 0;
virtual cTown* clone() = 0;
// Copy-and-swap
// However, it's protected so that it can only be used by the clone implementations
protected:
virtual void swap(cTown& other);
cTown(const cTown& other);
cTown(cTown&& other);
};
std::ostream& operator<< (std::ostream& out, eLighting light);

View File

@@ -899,6 +899,87 @@ bool cCurOut::is_road(int x, int y) {
cUniverse::cUniverse(long party_type) : party(party_type), out(*this), town(*this) {}
cUniverse::cUniverse(const cUniverse& other)
: strbuf(other.strbuf)
, extrabufs(other.extrabufs)
, cur_pc(other.cur_pc)
, scenario(other.scenario)
, party(other.party)
, stored_pcs(other.stored_pcs)
, town(*this)
, out(*this)
, file(other.file)
, debug_mode(other.debug_mode)
, ghost_mode(other.ghost_mode)
, node_step_through(other.node_step_through)
{
for(auto& p : stored_pcs) {
p.second = new cPlayer(*p.second);
}
town.copy(other.town);
out.copy(other.out);
}
cUniverse::cUniverse(cUniverse&& other) : town(*this), out(*this) {
swap(other);
}
cUniverse& cUniverse::operator=(cUniverse other) {
swap(other);
return *this;
}
void cUniverse::swap(cUniverse& other) {
party.swap(other.party);
town.swap(other.town);
out.swap(other.out);
scenario.swap(other.scenario);
std::swap(stored_pcs, other.stored_pcs);
std::swap(file, other.file);
std::swap(debug_mode, other.debug_mode);
std::swap(ghost_mode, other.ghost_mode);
std::swap(node_step_through, other.node_step_through);
std::swap(cur_pc, other.cur_pc);
std::swap(strbuf, other.strbuf);
std::swap(extrabufs, other.extrabufs);
}
void cCurOut::copy(const cCurOut& other) {
memcpy(expl, other.expl, sizeof(expl));
memcpy(out, other.out, sizeof(out));
memcpy(out_e, other.out_e, sizeof(out_e));
}
void cCurOut::swap(cCurOut& other) {
cCurOut temp(univ);
temp.copy(other);
other.copy(*this);
copy(temp);
}
void cCurTown::copy(const cCurTown& other) {
cur_talk_loaded = other.cur_talk_loaded;
quickfire_present = other.quickfire_present;
belt_present = other.belt_present;
difficulty = other.difficulty;
monst = other.monst;
items = other.items;
memcpy(fields, other.fields, sizeof(fields));
}
void cCurTown::swap(cCurTown& other) {
std::swap(cur_talk_loaded, other.cur_talk_loaded);
std::swap(quickfire_present, other.quickfire_present);
std::swap(belt_present, other.belt_present);
std::swap(difficulty, other.difficulty);
monst.swap(other.monst);
std::swap(items, other.items);
unsigned long temp[64][64];
memcpy(temp, other.fields, sizeof(fields));
memcpy(other.fields, fields, sizeof(fields));
memcpy(fields, temp, sizeof(fields));
}
void cUniverse::check_monst(cMonster& monst) {
if(monst.see_spec == -2) return; // Avoid infinite recursion
monst.see_spec = -2;

View File

@@ -121,6 +121,16 @@ public:
void readFrom(std::istream& file);
~cCurTown();
// It's not directly copyable due to the cUniverse reference, which must always point to the cUniverse that contains it.
// The cUniverse copy constructor is thus responsible for performing the copy.
cCurTown(const cCurTown&) = delete;
cCurTown& operator=(const cCurTown&) = delete;
// Not movable for similar reasons
cCurTown(const cCurTown&& other) = delete;
cCurTown& operator=(const cCurTown&& other) = delete;
// This implements the actual copy/move.
void copy(const cCurTown& other);
void swap(cCurTown& other);
};
class cCurOut {
@@ -143,12 +153,23 @@ public:
void readFrom(std::istream& file);
cOutdoors* operator->();
explicit cCurOut(cUniverse& univ);
// It's not directly copyable due to the cUniverse reference, which must always point to the cUniverse that contains it.
// The cUniverse copy constructor is thus responsible for performing the copy.
cCurOut(const cCurOut&) = delete;
cCurOut& operator=(const cCurOut&) = delete;
// Not movable for similar reasons
cCurOut(const cCurOut&& other) = delete;
cCurOut& operator=(const cCurOut&& other) = delete;
// This implements the actual copy/move.
void copy(const cCurOut& other);
void swap(cCurOut& other);
};
enum eTargetType {TARG_ANY, TARG_PC, TARG_MONST};
class cUniverse{
template<typename T> using update_info = std::set<T*>;
// All these maps are transient data that doesn't need to be saved
std::map<pic_num_t, update_info<cItem>> update_items;
std::map<pic_num_t, update_info<cMonster>> update_monsters;
std::map<pic_num_t, update_info<cPlayer>> update_pcs;
@@ -157,6 +178,7 @@ class cUniverse{
pic_num_t addGraphic(pic_num_t pic, ePicType type);
void check_monst(cMonster& monst);
void check_item(cItem& item);
// The string buffer currently isn't saved
std::string strbuf;
std::map<int,std::string> extrabufs;
cItem get_random_store_item(int loot_type, bool allow_junk_treasure);
@@ -193,6 +215,11 @@ public:
short difficulty_adjust() const;
explicit cUniverse(long party_type = 'dflt');
~cUniverse();
// Copy-and-swap
void swap(cUniverse& other);
cUniverse(const cUniverse& other);
cUniverse(cUniverse&& other);
cUniverse& operator=(cUniverse other);
static void(* print_result)(std::string);
};

View File

@@ -131,7 +131,7 @@ bool load_party(fs::path file_to_load, cUniverse& univ){
return true;
}
bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bool in_scen, bool maps_there, bool must_port){
bool load_party_v1(fs::path file_to_load, cUniverse& real_univ, bool town_restore, bool in_scen, bool maps_there, bool must_port){
std::ifstream fin(file_to_load.c_str(), std::ios_base::binary);
fin.seekg(3*sizeof(short),std::ios_base::beg); // skip the header, which is 6 bytes in the old format
@@ -192,7 +192,7 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
len = (long) sizeof(legacy::town_item_list);
fin.read((char*)&t_i, len);
}else univ.party.town_num = 200;
}
// LOAD STORED ITEMS
for(int i = 0; i < 3; i++) {
@@ -219,8 +219,7 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
fin.close();
univ.~cUniverse();
new(&univ) cUniverse(' ');
cUniverse univ;
if(in_scen){
fs::path path;
@@ -248,6 +247,7 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
univ.import_legacy(town_maps);
univ.import_legacy(o_maps);
univ.town.import_legacy(sfx, misc_i);
if(!town_restore) univ.party.town_num = 200;
// Check items in crates/barrels
for(int i = 0; i < univ.town->max_dim(); i++) {
for(int j = 0; j < univ.town->max_dim(); j++) {
@@ -261,18 +261,18 @@ bool load_party_v1(fs::path file_to_load, cUniverse& univ, bool town_restore, bo
}
}
real_univ = std::move(univ);
return true;
}
extern fs::path scenDir;
bool load_party_v2(fs::path file_to_load, cUniverse& univ){
bool load_party_v2(fs::path file_to_load, cUniverse& real_univ){
igzstream zin(file_to_load.string().c_str());
tarball partyIn;
partyIn.readFrom(zin);
zin.close();
univ.~cUniverse();
new(&univ) cUniverse(' ');
cUniverse univ;
{ // Load main party data first
std::istream& fin = partyIn.getFile("save/party.txt");
@@ -375,6 +375,7 @@ bool load_party_v2(fs::path file_to_load, cUniverse& univ){
} else showWarning("There was an error loading the party custom graphics.");
}
real_univ = std::move(univ);
return true;
}

View File

@@ -162,6 +162,7 @@ public:
return data.empty();
}
vector2d() : w(0), h(0) {}
vector2d(size_t w, size_t h) : w(w), h(h) {}
};
#endif