Fix fields array not matching the size of the town
The fields array was fixed at 64x64, which is fine for all towns supported in legacy BoE. However, we intend to support even larger towns in the future, and also it seems silly to hold so much extra space for a smaller town. So now, the fields array is a 2D vector that matches the size of the terrain vector. The setup array is similarly a list of 2D vectors. This radically changes the format used to store the setup array in a saved game. Older saves won't crash the game, but fields will be messed up or missing. Resetting towns is recommended.
This commit is contained in:
@@ -92,6 +92,7 @@ cParty::cParty(const cParty& other)
|
||||
, total_xp_gained(other.total_xp_gained)
|
||||
, total_dam_taken(other.total_dam_taken)
|
||||
, scen_name(other.scen_name)
|
||||
, setup(other.setup)
|
||||
, stored_items(other.stored_items)
|
||||
, summons(other.summons)
|
||||
, scen_won(other.scen_won)
|
||||
@@ -100,7 +101,6 @@ cParty::cParty(const cParty& other)
|
||||
, 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].reset(new cPlayer(*this, *other.adven[i]));
|
||||
}
|
||||
@@ -162,6 +162,7 @@ void cParty::swap(cParty& other) {
|
||||
std::swap(total_dam_taken, other.total_dam_taken);
|
||||
std::swap(scen_name, other.scen_name);
|
||||
std::swap(adven, other.adven);
|
||||
std::swap(setup, other.setup);
|
||||
std::swap(stored_items, other.stored_items);
|
||||
std::swap(summons, other.summons);
|
||||
std::swap(scen_won, other.scen_won);
|
||||
@@ -173,9 +174,6 @@ void cParty::swap(cParty& other) {
|
||||
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));
|
||||
for(size_t i = 0; i < adven.size(); i++) {
|
||||
std::swap(adven[i], other.adven[i]);
|
||||
}
|
||||
|
@@ -129,7 +129,7 @@ public:
|
||||
private:
|
||||
std::array<std::unique_ptr<cPlayer>,6> adven;
|
||||
public:
|
||||
unsigned short setup[4][64][64]; // formerly setup_save_type
|
||||
std::array<vector2d<unsigned short>, 4> setup; // formerly setup_save_type
|
||||
std::array<std::vector<cItem>,3> stored_items; // formerly stored_items_list_type
|
||||
|
||||
std::vector<cMonster> summons; // an array of monsters which can be summoned by the party's items yet don't originate from this scenario
|
||||
|
@@ -108,10 +108,8 @@ cTown& cCurTown::operator * (){
|
||||
|
||||
void cCurTown::place_preset_fields() {
|
||||
// Initialize barriers, etc. Note non-sfx gets forgotten if this is a town recently visited.
|
||||
for(int i = 0; i < 64; i++)
|
||||
for(int j = 0; j < 64; j++) {
|
||||
fields[i][j] = 0;
|
||||
}
|
||||
fields.resize(record()->max_dim, record()->max_dim);
|
||||
fields.fill(0);
|
||||
for(size_t i = 0; i < record()->preset_fields.size(); i++) {
|
||||
switch(record()->preset_fields[i].type){
|
||||
case OBJECT_BLOCK:
|
||||
@@ -176,6 +174,26 @@ void cCurTown::place_preset_fields() {
|
||||
}
|
||||
}
|
||||
|
||||
void cCurTown::update_fields(const vector2d<unsigned short>& setup) {
|
||||
for(short i = 0; i < record()->max_dim && i < setup.width(); i++) {
|
||||
for(short j = 0; j < record()->max_dim && j < setup.height(); j++) {
|
||||
// except that pushable things restore to orig locs
|
||||
unsigned short temp = setup[i][j] << 8;
|
||||
temp &= ~(OBJECT_CRATE | OBJECT_BARREL | OBJECT_BLOCK);
|
||||
univ.town.fields[i][j] |= temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cCurTown::save_setup(vector2d<unsigned short>& setup) const {
|
||||
setup.resize(record()->max_dim, record()->max_dim);
|
||||
for(short i = 0; i < record()->max_dim; i++) {
|
||||
for(short j = 0; j < record()->max_dim; j++) {
|
||||
setup[i][j] = fields[i][j] >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cSpeech& cCurTown::cur_talk() {
|
||||
// Make sure we actually have a valid speech stored
|
||||
return univ.scenario.towns[cur_talk_loaded]->talking;
|
||||
@@ -190,6 +208,8 @@ bool cCurTown::prep_talk(short which) {
|
||||
void cCurTown::prep_arena() {
|
||||
if(arena != nullptr) delete arena;
|
||||
arena = new cTown(univ.scenario, AREA_MEDIUM);
|
||||
fields.resize(AREA_MEDIUM, AREA_MEDIUM);
|
||||
fields.fill(0);
|
||||
}
|
||||
|
||||
cCurTown::~cCurTown() {
|
||||
@@ -201,6 +221,13 @@ cTown*const cCurTown::record() const {
|
||||
return univ.scenario.towns[univ.party.town_num];
|
||||
}
|
||||
|
||||
bool cCurTown::is_summon_safe(short x, short y) const {
|
||||
if(x > record()->max_dim || y > record()->max_dim) return false;
|
||||
// Here 254 indicates the low byte of the town fields, minus explored spaces (which is lowest bit).
|
||||
static const unsigned long blocking_fields = SPECIAL_SPOT | OBJECT_CRATE | OBJECT_BARREL | OBJECT_BLOCK | FIELD_QUICKFIRE | 254;
|
||||
return fields[x][y] & blocking_fields;
|
||||
}
|
||||
|
||||
bool cCurTown::is_explored(short x, short y) const{
|
||||
if(x > record()->max_dim || y > record()->max_dim) return false;
|
||||
return fields[x][y] & SPECIAL_EXPLORED;
|
||||
@@ -817,14 +844,7 @@ void cCurTown::writeTo(cTagFile& file) const {
|
||||
}
|
||||
}
|
||||
auto& fields_page = file.add();
|
||||
vector2d<as_hex<unsigned long>> fields_tmp;
|
||||
fields_tmp.resize(64, 64);
|
||||
for(size_t x = 0; x < 64; x++) {
|
||||
for(size_t y = 0; y < 64; y++) {
|
||||
fields_tmp[x][y] = fields[x][y];
|
||||
}
|
||||
}
|
||||
fields_page["FIELDS"].encode(fields_tmp);
|
||||
fields_page["FIELDS"].encode(fields);
|
||||
fields_page["TERRAIN"].encode(record()->terrain);
|
||||
// TODO: Do we need to save special_spot?
|
||||
}
|
||||
@@ -837,13 +857,11 @@ void cCurTown::readFrom(const cTagFile& file){
|
||||
monst.hostile = page.contains("HOSTILE");
|
||||
page["AT"] >> univ.party.town_loc.x >> univ.party.town_loc.y;
|
||||
} else if(page.getFirstKey() == "FIELDS" || page.getFirstKey() == "TERRAIN") {
|
||||
vector2d<as_hex<unsigned long>> fields_tmp;
|
||||
page["FIELDS"].extract(fields_tmp);
|
||||
page["FIELDS"].extract(fields);
|
||||
page["TERRAIN"].extract(record()->terrain);
|
||||
fields_tmp.resize(64, 64);
|
||||
for(size_t x = 0; x < 64; x++) {
|
||||
for(size_t y = 0; y < 64; y++) {
|
||||
fields[x][y] = fields_tmp[x][y];
|
||||
fields.resize(record()->max_dim, record()->max_dim);
|
||||
for(size_t x = 0; x < record()->max_dim; x++) {
|
||||
for(size_t y = 0; y < record()->max_dim; y++) {
|
||||
if(is_quickfire(x, y)) {
|
||||
quickfire_present = true;
|
||||
}
|
||||
@@ -876,9 +894,6 @@ void cCurTown::readFrom(const cTagFile& file){
|
||||
cCurTown::cCurTown(cUniverse& univ) : univ(univ) {
|
||||
arena = nullptr;
|
||||
univ.party.town_num = 200;
|
||||
for(int i = 0; i < 64; i++)
|
||||
for(int j = 0; j < 64; j++)
|
||||
fields[i][j] = 0L;
|
||||
}
|
||||
|
||||
cCurOut::cCurOut(cUniverse& univ) : univ(univ) {}
|
||||
@@ -973,7 +988,7 @@ void cCurTown::copy(const cCurTown& other) {
|
||||
difficulty = other.difficulty;
|
||||
monst = other.monst;
|
||||
items = other.items;
|
||||
memcpy(fields, other.fields, sizeof(fields));
|
||||
fields = other.fields;
|
||||
}
|
||||
|
||||
void cCurTown::swap(cCurTown& other) {
|
||||
@@ -983,10 +998,7 @@ void cCurTown::swap(cCurTown& other) {
|
||||
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));
|
||||
fields.swap(other.fields);
|
||||
}
|
||||
|
||||
void cUniverse::check_monst(cMonster& monst) {
|
||||
|
@@ -39,6 +39,7 @@ class cCurTown {
|
||||
cUniverse& univ;
|
||||
cTown* arena;
|
||||
cTown*const record() const;
|
||||
vector2d<unsigned long> fields;
|
||||
public:
|
||||
bool quickfire_present = false, belt_present = false;
|
||||
// formerly current_town_type
|
||||
@@ -47,8 +48,6 @@ public:
|
||||
|
||||
std::vector<cItem> items; // formerly town_item_list type
|
||||
|
||||
unsigned long fields[64][64];
|
||||
|
||||
void import_legacy(legacy::current_town_type& old);
|
||||
void import_legacy(legacy::town_item_list& old);
|
||||
void import_legacy(unsigned char(& old_sfx)[64][64], unsigned char(& old_misc_i)[64][64]);
|
||||
@@ -62,6 +61,9 @@ public:
|
||||
bool prep_talk(short which); // Prepare for loading specified speech, returning true if already loaded
|
||||
void prep_arena(); // Set up for a combat arena
|
||||
void place_preset_fields();
|
||||
void update_fields(const vector2d<unsigned short>& setup);
|
||||
void save_setup(vector2d<unsigned short>& setup) const;
|
||||
bool is_summon_safe(short x, short y) const;
|
||||
|
||||
bool is_explored(short x, short y) const;
|
||||
bool is_force_wall(short x, short y) const;
|
||||
|
Reference in New Issue
Block a user