Migration-safe monster movement iteration

The monster knockback could mess with the monster linked list while
the code was going through it for monster movements. (For example,
a monster knocked back another into a level teleport trap)

Add iter_mons_safe, which first grabs all the monster pointers in
the list into an array, and goes over that array instead of relying
on the "next monster" pointer. This is possible because dead monsters
are not removed from the linked list until after all the monsters
have moved.

Testing is very minimal, and I'm not sure the vault guard check
for migration is correct - it should probably check for more states?

Also the iterator could be improved by not continually allocating
and freeing the monster pointer array.
This commit is contained in:
Pasi Kallinen
2022-08-10 10:53:43 +03:00
parent e9ec89a903
commit d91915dba3
4 changed files with 143 additions and 118 deletions

View File

@@ -1033,6 +1033,7 @@ struct instance_globals {
boolean zombify;
short *animal_list; /* list of PM values for animal monsters */
int animal_list_count;
boolean somebody_can_move;
/* mthrowu.c */
int mesg_given; /* for m_throw()/thitu() 'miss' message */

View File

@@ -1525,6 +1525,7 @@ extern int undead_to_corpse(int);
extern int genus(int, int);
extern int pm_to_cham(int);
extern int minliquid(struct monst *);
extern boolean movemon_singlemon(struct monst *);
extern int movemon(void);
extern int meatmetal(struct monst *);
extern int meatobj(struct monst *);
@@ -1570,6 +1571,7 @@ extern void wake_nearby(void);
extern void wake_nearto(coordxy, coordxy, int);
extern void seemimic(struct monst *);
extern void normal_shape(struct monst *);
extern void iter_mons_safe(boolean (*)(struct monst *));
extern void iter_mons(void (*)(struct monst *));
extern struct monst *get_iter_mons(boolean (*)(struct monst *));
extern struct monst *get_iter_mons_xy(boolean (*)(struct monst *,