Sanity pass of saved game format
This adds several fields to the saved game format that were simply missing. - Monster boolean flags (for summons) - Some missing monster ability details (for summons) - Special on talk (for creatures) - Max SP and morale (for creatures) - Source scenario (for encounter notes) It also changes the default resist to 0 instead of 100, meaning that resistances will be saved almost always, but should be loaded correctly. The target location is no longer saved for creatures. There was already code that nulled it out after loading, so now that just happens during loading instead. The town active flags (belt_present and quickfire_present) are now set during loading instead of after loading. This changes the save format, so there will be minor incompatibilities. In particular, monster health won't be loaded correctly from older saves.
This commit is contained in:
@@ -95,25 +95,7 @@ void finish_load_party(){
|
||||
build_outdoors();
|
||||
erase_out_specials();
|
||||
|
||||
if(!town_restore) {
|
||||
center = univ.party.out_loc;
|
||||
}
|
||||
else {
|
||||
for(int i = 0; i < univ.town.monst.size(); i++){
|
||||
univ.town.monst[i].targ_loc.x = 0;
|
||||
univ.town.monst[i].targ_loc.y = 0;
|
||||
}
|
||||
|
||||
// Set up field booleans
|
||||
for(int j = 0; j < univ.town->max_dim; j++)
|
||||
for(int k = 0; k < univ.town->max_dim; k++) {
|
||||
if(univ.town.is_quickfire(j,k))
|
||||
univ.town.quickfire_present = true;
|
||||
if(univ.scenario.ter_types[univ.town->terrain(j,k)].special == eTerSpec::CONVEYOR)
|
||||
univ.town.belt_present = true;
|
||||
}
|
||||
center = univ.party.town_loc;
|
||||
}
|
||||
center = town_restore ? univ.party.town_loc : univ.party.out_loc;
|
||||
|
||||
redraw_screen(REFRESH_ALL);
|
||||
univ.cur_pc = first_active_pc();
|
||||
|
@@ -791,13 +791,18 @@ void cMonster::writeTo(cTagFile_Page& page) const {
|
||||
page["RACE"] << m_type;
|
||||
page["TREASURE"] << treasure;
|
||||
page["CORPSEITEM"] << corpse_item << corpse_item_chance;
|
||||
page["IMMUNE"].encodeSparse(resist, 100);
|
||||
page["IMMUNE"].encodeSparse(resist);
|
||||
page["SIZE"] << x_width << y_width;
|
||||
page["ATTITUDE"] << default_attitude;
|
||||
page["SUMMON"] << summon_type;
|
||||
page["PORTRAIT"] << default_facial_pic;
|
||||
page["PICTURE"] << picture_num;
|
||||
page["SOUND"] << ambient_sound;
|
||||
if(mindless) page.add("MINDLESS");
|
||||
if(invuln) page.add("INVULNERABLE");
|
||||
if(invisible) page.add("INVISIBLE");
|
||||
if(guard) page.add("GUARD");
|
||||
if(amorphous) page.add("AMORPHOUS");
|
||||
}
|
||||
|
||||
bool uAbility::writeTo(eMonstAbil key, cTagFile_Page &page) const {
|
||||
@@ -825,16 +830,17 @@ bool uAbility::writeTo(eMonstAbil key, cTagFile_Page &page) const {
|
||||
page["EXTRA"] << gen.stat;
|
||||
break;
|
||||
case eMonstAbilCat::RADIATE:
|
||||
page["TYPE"] << radiate.type;
|
||||
page["TYPE"] << radiate.type << radiate.pat;
|
||||
page["CHANCE"] << radiate.chance;
|
||||
break;
|
||||
case eMonstAbilCat::SUMMON:
|
||||
page["TYPE"] << summon.type << summon.what;
|
||||
page["HOWMANY"] << summon.min << summon.max;
|
||||
page["DURATION"] << summon.len;
|
||||
page["CHANCE"] << summon.chance;
|
||||
break;
|
||||
case eMonstAbilCat::SPECIAL:
|
||||
page["EXTRA"] << special.extra1 << special.extra2;
|
||||
page["EXTRA"] << special.extra1 << special.extra2 << special.extra3;
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
@@ -845,7 +851,6 @@ void cMonster::readFrom(const cTagFile_Page& page) {
|
||||
see_spec = -1;
|
||||
page["MONSTER"] >> m_name;
|
||||
page["SIZE"] >> x_width >> y_width;
|
||||
// TODO: Isn't the default immunity supposed to be 100? Is that handled?
|
||||
page["IMMUNE"].extractSparse(resist);
|
||||
page["RACE"] >> m_type;
|
||||
page["CORPSEITEM"] >> corpse_item >> corpse_item_chance;
|
||||
@@ -862,6 +867,11 @@ void cMonster::readFrom(const cTagFile_Page& page) {
|
||||
page["PRIEST"] >> cl;
|
||||
page["TREASURE"] >> treasure;
|
||||
page["SUMMON"] >> summon_type;
|
||||
mindless = page.contains("MINDLESS");
|
||||
invuln = page.contains("INVULNERABLE");
|
||||
invisible = page.contains("INVISIBLE");
|
||||
guard = page.contains("GUARD");
|
||||
amorphous = page.contains("AMORPHOUS");
|
||||
for(int i = 0; i < page["ATTACK"].size(); i++) {
|
||||
size_t which_atk;
|
||||
auto tmp = page["ATTACK"] >> which_atk;
|
||||
@@ -898,16 +908,17 @@ eMonstAbil uAbility::readFrom(const cTagFile_Page& page) {
|
||||
page["EXTRA"] >> gen.stat;
|
||||
break;
|
||||
case eMonstAbilCat::RADIATE:
|
||||
page["TYPE"] >> radiate.type;
|
||||
page["TYPE"] >> radiate.type >> radiate.pat;
|
||||
page["CHANCE"] >> radiate.chance;
|
||||
break;
|
||||
case eMonstAbilCat::SUMMON:
|
||||
page["TYPE"] >> summon.type >> summon.what;
|
||||
page["HOWMANY"] >> summon.min >> summon.max;
|
||||
page["DURATION"] >> summon.len;
|
||||
page["CHANCE"] >> summon.chance;
|
||||
break;
|
||||
case eMonstAbilCat::SPECIAL:
|
||||
page["EXTRA"] >> special.extra1 >> special.extra2;
|
||||
page["EXTRA"] >> special.extra1 >> special.extra2 >> special.extra3;
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
|
@@ -347,18 +347,18 @@ void cCreature::writeTo(cTagFile_Page& page) const {
|
||||
page["TIME"] << monster_time;
|
||||
page["TALK"] << personality;
|
||||
page["DEATH"] << special_on_kill;
|
||||
page["TALK"] << special_on_talk;
|
||||
page["FACE"] << facial_pic;
|
||||
page["TARGET"] << target;
|
||||
page["TARGLOC"] << targ_loc.x << targ_loc.y;
|
||||
page["STATUS"].encodeSparse(status);
|
||||
page["CURHP"] << health << '\n';
|
||||
page["CURSP"] << mp << '\n';
|
||||
page["MORALE"] << morale << '\n';
|
||||
page["DIRECTION"] << direction << '\n';
|
||||
// TODO: Should we be saving "max_mp" and/or "m_morale"?
|
||||
page["HEALTH"] << health << m_health;
|
||||
page["MANA"] << mp << max_mp;
|
||||
page["MORALE"] << morale << m_morale;
|
||||
page["DIRECTION"] << direction;
|
||||
}
|
||||
|
||||
void cCreature::readFrom(const cTagFile_Page& page) {
|
||||
targ_loc = location(0,0);
|
||||
page["MONSTER"] >> number;
|
||||
page["ATTITUDE"] >> attitude;
|
||||
page["STARTATT"] >> start_attitude;
|
||||
@@ -373,12 +373,12 @@ void cCreature::readFrom(const cTagFile_Page& page) {
|
||||
page["TIME"] >> monster_time;
|
||||
page["TALK"] >> personality;
|
||||
page["DEATH"] >> special_on_kill;
|
||||
page["TALK"] >> special_on_talk;
|
||||
page["FACE"] >> facial_pic;
|
||||
page["TARGET"] >> target;
|
||||
page["TARGLOC"] >> targ_loc.x >> targ_loc.y;
|
||||
page["STATUS"].extractSparse(status);
|
||||
page["CURHP"] >> health;
|
||||
page["CURSP"] >> mp;
|
||||
page["HEALTH"] >> health >> m_health;
|
||||
page["MANA"] >> mp >> max_mp;
|
||||
page["MORALE"] >> morale;
|
||||
page["DIRECTION"] >> direction;
|
||||
}
|
||||
|
@@ -838,7 +838,7 @@ void cParty::writeTo(cTagFile& file) const {
|
||||
if(special_notes.size() > 0) {
|
||||
for(const cEncNote& note : special_notes) {
|
||||
auto& note_page = file.add();
|
||||
note_page["ENCNOTE"] << note.type << note.where;
|
||||
note_page["ENCNOTE"] << note.type << note.where << note.in_scen;
|
||||
note_page["STRING"] << note.the_str;
|
||||
}
|
||||
}
|
||||
@@ -887,7 +887,7 @@ void cParty::readFrom(const cTagFile& file) {
|
||||
page["WON"] >> scen_won;
|
||||
page["PLAYED"] >> scen_played;
|
||||
|
||||
page["STATUS"].extractSparse(status);
|
||||
page["STATUS"].extractSparse(status); // Does this do anything?
|
||||
page["EVENT"].extractSparse(key_times);
|
||||
|
||||
if(page.contains("SPLIT_LEFT_IN")) {
|
||||
@@ -1041,7 +1041,7 @@ void cParty::readFrom(const cTagFile& file) {
|
||||
journal.push_back(entry);
|
||||
} else if(page.getFirstKey() == "ENCNOTE") {
|
||||
cEncNote note;
|
||||
page["ENCNOTE"] >> note.type >> note.where;
|
||||
page["ENCNOTE"] >> note.type >> note.where >> note.in_scen;
|
||||
page["STRING"] >> note.the_str;
|
||||
special_notes.push_back(note);
|
||||
} else if(page.getFirstKey() == "TALKNOTE") {
|
||||
|
@@ -97,7 +97,6 @@ public:
|
||||
short light_level;
|
||||
location outdoor_corner;
|
||||
location i_w_c;
|
||||
// TODO: Does this duplicate cCurTown::p_loc? If not, why not?
|
||||
location out_loc, town_loc;
|
||||
location loc_in_sec;
|
||||
short town_num;
|
||||
|
@@ -844,6 +844,18 @@ void cCurTown::readFrom(const cTagFile& file){
|
||||
for(size_t x = 0; x < 64; x++) {
|
||||
for(size_t y = 0; y < 64; y++) {
|
||||
fields[x][y] = fields_tmp[x][y];
|
||||
if(is_quickfire(x, y)) {
|
||||
quickfire_present = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(size_t x = 0; x < record()->max_dim; x++) {
|
||||
for(size_t y = 0; y < record()->max_dim; y++) {
|
||||
auto ter_num = record()->terrain(x,y);
|
||||
const auto ter_info = univ.scenario.ter_types[ter_num];
|
||||
if(ter_info.special == eTerSpec::CONVEYOR) {
|
||||
belt_present = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(page.getFirstKey() == "ITEM") {
|
||||
|
Reference in New Issue
Block a user