// 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 removed_cells; void slow_delete_cell(cell *c) { while(c->mpdist < BARLEV) degrade(c); for(int i=0; itype; 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; itype; i++) if(c->move(i)) slow_delete_cell(c->move(i)); } slow_delete_cell(c); for(int i=0; imove(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; imove(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.at) { if(unsafeLand(recallCell.at)) return; heptagon *at2 = recallCell.at->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; jmove(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; imove(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; } }