1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-25 09:30:35 +00:00
hyperrogue/savemem.cpp
2019-09-12 22:50:00 +02:00

174 lines
4.2 KiB
C++

// Hyperbolic Rogue -- smart memory cleaner
// Copyright (C) 2011-2018 Zeno Rogue, see 'hyper.cpp' for details
namespace hr {
bool memory_saving_mode = true;
static const int LIM = 150;
heptagon *last_cleared;
void destroycellcontents(cell *c) {
c->land = laMemory;
c->wall = waChasm;
c->item = itNone;
if(!isMultitile(c->monst) && c->monst != moPair)
c->monst = moNone;
}
void degrade(cell *c) {
c->mpdist++;
forCellEx(c2, c)
if(c2->mpdist < c->mpdist - 1)
degrade(c2);
destroycellcontents(c);
}
vector<cell*> removed_cells;
void slow_delete_cell(cell *c) {
while(c->mpdist < BARLEV)
degrade(c);
for(int i=0; i<c->type; i++)
if(c->move(i))
c->move(i)->move(c->c.spin(i)) = NULL;
removed_cells.push_back(c);
delete c;
}
void delete_heptagon(heptagon *h2) {
cell *c = h2->c7;
if(BITRUNCATED) {
for(int i=0; i<c->type; i++)
if(c->move(i))
slow_delete_cell(c->move(i));
}
slow_delete_cell(c);
for(int i=0; i<S7; i++)
if(h2->move(i))
h2->move(i)->move(h2->c.spin(i)) = NULL;
delete h2;
}
void recursive_delete(heptagon *h, int i) {
heptagon *h2 = h->move(i);
{ for(int i=1; i<S7; i++)
if(h2->move(i) && h2->move(i)->move(0) == h2)
recursive_delete(h2, i); }
if(h2->alt && h2->alt->alt == h2->alt) {
DEBB(DF_MEMORY, ("destroying alternate map ", h2->alt));
for(hrmap *& hm: allmaps) {
if(hm->getOrigin() == h2->alt) {
delete hm;
hm = allmaps.back();
allmaps.pop_back();
DEBB(DF_MEMORY, ("map found (", isize(allmaps), " altmaps total)"));
break;
}
}
}
if(h2->alt) {
h2->alt->cdata = NULL;
}
delete_heptagon(h2);
h->move(i) = NULL;
}
bool unsafeLand(cell *c) {
return
isCyclic(c->land) || isGravityLand(c->land) || isHaunted(c->land) ||
among(c->land, laCaribbean, laOcean, laGraveyard, laPrincessQuest);
}
void save_memory() {
if(quotient || !hyperbolic || NONSTDVAR) return;
if(!memory_saving_mode) return;
if(unsafeLand(cwt.at)) return;
int d = celldist(cwt.at);
if(d < LIM+10) return;
heptagon *at = cwt.at->master;
heptagon *orig = currentmap->gamestart()->master;
if(recallCell) {
if(unsafeLand(recallCell)) return;
heptagon *at2 = recallCell->master;
int t = 0;
while(at != at2) {
t++; if(t > 10000) return;
if(celldist(at->c7) > celldist(at2->c7))
at = at->move(0);
else
at2 = at2->move(0);
}
}
while(celldist(at->c7) > d-LIM) at = at->move(0);
// go back to such a point X that all the heptagons adjacent to the current 'at'
// are the children of X. This X becomes the new 'at'
if(true) {
heptagon *allh[9];
int hcount = 0;
allh[hcount++] = at;
for(int j=0; j<S7; j++)
if(allh[0]->move(j))
allh[hcount++] = at->move(j);
int deuniq_steps = 0;
int i = 1;
while(i < hcount) {
if(allh[i] == allh[0])
allh[i] = allh[hcount-1], hcount--;
else if(celldist(allh[i]->c7) > celldist(allh[0]->c7))
allh[i] = allh[i]->move(0);
else {
if(allh[0] == orig) return;
allh[0] = allh[0]->move(0);
i = 1;
deuniq_steps++;
if(deuniq_steps == 10) return;
}
}
at = allh[0];
}
if(last_cleared && celldist(at->c7) < celldist(last_cleared->c7))
return;
DEBB(DF_MEMORY, ("celldist = ", make_pair(celldist(cwt.at), celldist(at->c7))));
heptagon *at1 = at;
while(at != last_cleared && at != orig) {
heptagon *atn = at;
at = at->move(0);
for(int i=1; i<S7; i++)
if(at->move(i) && at->move(i) != atn)
recursive_delete(at, i);
}
last_cleared = at1;
DEBB(DF_MEMORY, ("current cellcount = ", cellcount));
sort(removed_cells.begin(), removed_cells.end());
callhooks(hooks_removecells);
removed_cells.clear();
}
purehookset hooks_removecells;
bool is_cell_removed(cell *c) {
return binary_search(removed_cells.begin(), removed_cells.end(), c);
}
void set_if_removed(cell*& c, cell *val) {
if(is_cell_removed(c)) c = val;
}
}