shmup:: replaced monsters_at with content lists

This commit is contained in:
Zeno Rogue
2026-04-16 19:11:17 +02:00
parent 72c89959e5
commit 4c2d53251f
6 changed files with 104 additions and 127 deletions
+1
View File
@@ -249,6 +249,7 @@ EX int dirdiff(int dd, int t) {
EX int cellcount = 0;
EX void destroy_cell(cell *c) {
while(c->contents) c->contents->unlist_and_unref();
tailored_delete(c);
cellcount--;
}
+1 -2
View File
@@ -57,7 +57,6 @@ struct celldrawer {
void draw();
bool cell_clipped();
void draw_fallanims();
bool draw_shmup_monster();
void draw_gravity_particles();
void set_land_floor(const shiftmatrix& Vf);
@@ -2975,7 +2974,7 @@ void celldrawer::draw() {
Vboat = Vd;
draw_shmup_monster();
FOR_LIST(li, c->contents) li->draw(self);
poly_outline = OUTLINE_DEFAULT;
+43 -1
View File
@@ -22,6 +22,45 @@ extern int cellcount, heptacount;
#define NOBARRIERS 127
#define NOBARRIERS2 125
using cell_content_list = struct cell_content*;
namespace shmup { struct monster; }
struct cell_content {
cell_content *next;
cell_content_list *last;
virtual shmup::monster *as_monster() { return nullptr; }
void remove_from_list() {
if(last) { last[0] = next; next->last = last; next = nullptr; last = nullptr; }
}
void add_to_list(cell_content_list& l) {
remove_from_list();
last = &l;
next = l;
next->last = &next;
l = this;
}
int refs;
cell_content() { refs = 1; }
virtual ~cell_content() {
remove_from_list();
}
void unref() {
refs--;
if(!refs) delete this;
}
void unlist_and_unref() { remove_from_list(); unref(); }
virtual void draw(struct celldrawer& cd) {}
};
#define FOR_LIST(it, ml) for(cell_content *it = (ml); it; it = ml->next)
/** \brief Cell information for the game. struct cell builds on this */
struct gcell {
@@ -98,11 +137,14 @@ struct gcell {
#ifdef CELLID
int cellid;
#endif
cell_content_list contents;
gcell() {
#ifdef CELLID
cellid = cellcount;
cellid = cellcount;
#endif
contents = nullptr;
}
};
+1 -5
View File
@@ -67,12 +67,8 @@ EX void addradar(const shiftpoint h1, const shiftpoint h2, color_t col) {
void celldrawer::drawcell_in_radar() {
#if CAP_SHMUP
if(shmup::on) {
pair<shmup::mit, shmup::mit> p =
shmup::monstersAt.equal_range(c);
for(shmup::mit it = p.first; it != p.second; it++) {
shmup::monster* m = it->second;
FOR_LIST(it, c->contents) if(shmup::monster *m = it->as_monster())
addradar(V*m->at, minf[m->type].glyph, minf[m->type].color, 0xFF0000FF);
}
}
#endif
if(c->monst)
+58 -118
View File
@@ -33,9 +33,13 @@ ld sqdist(shiftpoint a, shiftpoint b) {
EX namespace shmup {
EX hookset<void(struct monster*)> hooks_destroy_monster;
#if HDR
struct monster : dim_listener {
extern struct monster *mousetarget, *lmousetarget;
struct monster : cell_content, dim_listener {
eMonster type;
cell *base; ///< on which base cell this monster currently is
cell *torigin; ///< tortoises: origin, butterflies: last position
@@ -60,18 +64,19 @@ struct monster : dim_listener {
bool isVirtual; ///< off the screen: gmatrix is unknown, and pat equals at
hyperpoint inertia;///< for frictionless lands
int refs; ///< +1 for every reference (parent, lists of active monsters)
int split_owner; ///< in splitscreen mode, which player handles this
int split_tick; ///< in which tick was split_owner computed
void reset();
monster *as_monster() override { return this; }
void draw(celldrawer &cd) override;
monster() {
reset();
refs = 1; split_tick = -1; split_owner = -1;
split_tick = -1; split_owner = -1;
no_targetting = false;
dead = false; inBoat = false; parent = NULL;
dead = false; inBoat = false; parent = nullptr;
}
eMonster get_parenttype() { return parent ? parent->type : moNone; }
@@ -84,11 +89,15 @@ struct monster : dim_listener {
void rebasePat(const shiftmatrix& new_pat, cell *tgt);
void remove_reference();
~monster() {
if(mousetarget == this) mousetarget = nullptr;
if(lmousetarget == this) lmousetarget = nullptr;
callhooks(hooks_destroy_monster, this);
if(parent) parent->unref();
}
void set_parent(monster *par) {
if(parent == par) return;
if(parent) parent->remove_reference();
if(parent) parent->unref();
parent = par;
parent->refs++;
}
@@ -117,22 +126,9 @@ EX eLand delayed_safety_land;
bool lastdead = false;
EX multimap<cell*, monster*> monstersAt;
EX cell_content_list active;
#if HDR
typedef multimap<cell*, monster*>::iterator mit;
#endif
EX vector<monster*> active, nonvirtual, additional;
void monster::remove_reference() {
refs--;
if(!refs) {
if(parent) parent->remove_reference();
nonvirtual.erase(std::remove(nonvirtual.begin(), nonvirtual.end(), this), nonvirtual.end());
delete this;
}
}
EX vector<monster*> nonvirtual, additional;
cell *findbaseAround(shiftpoint p, cell *around, int maxsteps) {
@@ -170,9 +166,7 @@ cell *findbaseAround(const shiftmatrix& H, cell *around, int maxsteps) {
return asinh(h[2]);
} */
void monster::store() {
monstersAt.insert(make_pair(base, this));
}
void monster::store() { add_to_list(base->contents); }
void monster::findpat() {
isVirtual = !gmatrix.count(base) || invalid_matrix(gmatrix[base].T);
@@ -1565,8 +1559,10 @@ EX bool verifyTeleport() {
return true;
}
#define FOR_MONSTERS_IN_LIST(it, m, ml) FOR_LIST(it, ml) if(monster *m = it->as_monster())
void destroyMimics() {
for(monster *m: active)
FOR_MONSTERS_IN_LIST(it, m, active)
if(isMimic(m->type))
m->dead = true;
}
@@ -2568,15 +2564,11 @@ void moveMonster(monster *m, int delta) {
}
}
void activateMonstersAt(cell *c) {
pair<mit, mit> p =
monstersAt.equal_range(c);
for(mit it = p.first; it != p.second;) {
mit itplus = it;
itplus++;
active.push_back(it->second);
monstersAt.erase(it);
it = itplus;
void activate_monsters_at(cell *c) {
auto p = &c->contents;
while(*p) {
if(monster *m = (*p)->as_monster()) m->add_to_list(active);
else p = &((*p)->next);
}
if(c->monst && isMimic(c->monst)) c->monst = moNone;
// mimics are awakened by awakenMimics
@@ -2596,22 +2588,10 @@ void activateMonstersAt(cell *c) {
enemy->inertia = random_spin() * point2(SCALE/3000., 0);
}
c->monst = moNone;
active.push_back(enemy);
enemy->add_to_list(active);
}
}
EX void fixStorage() {
vector<monster*> restore;
for(auto it = monstersAt.begin(); it != monstersAt.end(); it++)
restore.push_back(it->second);
monstersAt.clear();
for(monster *m: restore) m->store();
}
EX hookset<bool(int)> hooks_turn;
/** the amount of time chars are disabled in PvP */
@@ -2687,28 +2667,24 @@ EX void turn(int delta) {
// detect active monsters
if(doall)
for(cell *c: currentmap->allcells()) activateMonstersAt(c);
for(cell *c: currentmap->allcells()) activate_monsters_at(c);
else
for(auto& p: gmatrix)
activateMonstersAt(p.first);
/* printf("size: gmatrix = %ld, active = %ld, monstersAt = %ld, delta = %d\n",
gmatrix.size(), active.size(), monstersAt.size(),
delta); */
activate_monsters_at(p.first);
bool exists[motypes];
for(int i=0; i<motypes; i++) exists[i] = false;
nonvirtual.clear();
for(monster *m: active) {
nonvirtual.clear();
FOR_MONSTERS_IN_LIST(it, m, active) {
m->findpat();
if(m->isVirtual) continue;
else nonvirtual.push_back(m);
exists[movegroup(m->type)] = true;
}
for(monster *m: active) {
FOR_MONSTERS_IN_LIST(it, m, active) {
switch(m->type) {
case moPlayer:
@@ -2724,7 +2700,7 @@ EX void turn(int delta) {
}
}
for(monster *m: active) {
FOR_MONSTERS_IN_LIST(it, m, active) {
if(isMimic(m->type))
moveMimic(m);
}
@@ -2886,8 +2862,7 @@ EX void turn(int delta) {
}
}
for(monster *m: additional)
active.push_back(m);
for(monster *m: additional) m->add_to_list(active);
additional.clear();
if(delayed_safety) {
@@ -2895,18 +2870,13 @@ EX void turn(int delta) {
delayed_safety = false;
}
// deactivate all monsters
for(monster *m: active)
if(m->dead && m->type != moPlayer) {
if(m == mousetarget) mousetarget = NULL;
if(m == lmousetarget) lmousetarget = NULL;
m->remove_reference();
}
else {
while(active) {
auto *m = (monster*) active;
if(m->dead && m->type != moPlayer)
m->unlist_and_unref();
else
m->store();
}
active.clear();
}
}
EX void recall() {
@@ -2954,29 +2924,13 @@ EX void init() {
}
EX bool boatAt(cell *c) {
pair<mit, mit> p =
monstersAt.equal_range(c);
for(mit it = p.first; it != p.second; it++) {
monster* m = it->second;
if(m->inBoat) return true;
}
FOR_MONSTERS_IN_LIST(it, m, c->contents) if(m->inBoat) return true;
return false;
}
EX hookset<bool(const shiftmatrix&, cell*, shmup::monster*)> hooks_draw;
EX void clearMonsters() {
for(mit it = monstersAt.begin(); it != monstersAt.end(); it++)
delete(it->second);
for(monster *m: active) m->remove_reference();
mousetarget = NULL;
lmousetarget = NULL;
monstersAt.clear();
active.clear();
}
EX void clearMemory() {
clearMonsters();
while(!traplist.empty()) traplist.pop();
curtime = 0;
speed_saving = 0;
@@ -2995,7 +2949,6 @@ void gamedata(hr::gamedata* gd) {
gd->store(nextdragon);
gd->store(visibleAt);
gd->store(traplist);
gd->store(monstersAt);
gd->store(active);
gd->store(mousetarget);
gd->store(lmousetarget);
@@ -3018,7 +2971,7 @@ EX bool playerInBoat(int i) {
}
EX void destroyBoats(cell *c) {
for(monster *m: active)
FOR_MONSTERS_IN_LIST(it, m, active)
if(m->base == c && m->inBoat)
m->inBoat = false;
}
@@ -3039,17 +2992,7 @@ EX void addShmupHelp(string& out) {
}
auto hooks = addHook(hooks_clearmemory, 0, shmup::clearMemory) +
addHook(hooks_gamedata, 0, shmup::gamedata) +
addHook(hooks_removecells, 0, [] () {
for(mit it = monstersAt.begin(); it != monstersAt.end();) {
if(is_cell_removed(it->first)) {
monstersAt.insert(make_pair(nullptr, it->second));
auto it0 = it; it++;
monstersAt.erase(it0);
}
else it++;
}
});
addHook(hooks_gamedata, 0, shmup::gamedata);
EX void switch_shmup() {
stop_game();
@@ -3071,21 +3014,19 @@ EX void draw_collision_debug() {
EX }
bool celldrawer::draw_shmup_monster() {
using namespace shmup;
void shmup::monster::draw(struct hr::celldrawer& cd) {
#if CAP_SHAPES
using namespace shmup;
auto m = this;
cell *c = cd.c;
auto& Vd = cd.Vd;
auto& V = cd.V;
auto& Vboat = cd.Vboat;
pair<mit, mit> p =
monstersAt.equal_range(c);
if(p.first == p.second) return false;
ld zlev = -geom3::factor_to_lev(zlevel(tC0(Vd.T)));
vector<monster*> monsters;
for(mit it = p.first; it != p.second; it++) {
monster* m = it->second;
if(c != m->base) continue; // may happen in RogueViz Collatz
if(1) {
m->pat = ggmatrix(m->base) * m->at;
shiftmatrix view = V * m->at;
@@ -3097,7 +3038,7 @@ bool celldrawer::draw_shmup_monster() {
bool half_elliptic = elliptic && GDIM == 3 && WDIM == 2;
bool mirrored = det(view.T) > 0;
if(half_elliptic && mirrored) continue;
if(half_elliptic && mirrored) return;
if(!mouseout()) {
if(m->no_targetting) ; else
@@ -3133,7 +3074,7 @@ bool celldrawer::draw_shmup_monster() {
int q = isize(ptds);
if(q != isize(ptds) && !m->inBoat) pushdown(c, q, view, zlev, true, false);
if(callhandlers(false, hooks_draw, V, c, m)) continue;
if(callhandlers(false, hooks_draw, V, c, m)) return;
switch(m->type) {
case moPlayer: {
@@ -3284,7 +3225,6 @@ bool celldrawer::draw_shmup_monster() {
}
#endif
return false;
}
}
-1
View File
@@ -1106,7 +1106,6 @@ EX slide default_slides[] = {
resetview();
}
if(mode == 3) {
shmup::clearMonsters();
gamestack::pop();
}
}