mirror of
https://codeberg.org/noisytoot/notnotdnethack.git
synced 2025-07-27 07:52:25 +01:00
More fixes
Split relink into mx/ox versions that can be called on single mons/objs, to cover cases where we may need to fix up pointers that weren't done during restore (eg, mon_traits). At the moment, this isn't needed -- only ESUM needs any fixups at all, and the only way to reach montraits is for the mon to die, which quite intentionally severs the connection between mon and summoner. But this may be needed for future features! Futureproofing, yay! Save youmonst, so we can use &youmonst->summonpwr and not have it reset to 0 over save/restore. Revived petrified statues of summons crumble into dust (instead of creating a summon unlinked from its summoner and with no desummoning timer).
This commit is contained in:
parent
93e2e0f3d9
commit
a76396c29c
11 changed files with 92 additions and 45 deletions
|
@ -132,6 +132,8 @@ struct esum {
|
|||
struct monst * summoner; /* monster responsible for this mon/obj -- can be null */
|
||||
unsigned sm_id; /* m_id of summoner */
|
||||
int summonstr; /* tax on summoner, who may maintain up to its own HD of summons at a time. */
|
||||
Bitfield(staleptr, 1); /* denotes if `summoner` is a stale pointer and needs to be updated */
|
||||
Bitfield(unused,7);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1316,6 +1316,7 @@ E void * FDECL(bundle_mextra, (struct monst *, long *));
|
|||
E void FDECL(unbundle_mextra, (struct monst *, void *));
|
||||
E void FDECL(save_mextra, (struct monst *, int, int));
|
||||
E void FDECL(rest_mextra, (struct monst *, int, boolean));
|
||||
E void FDECL(relink_mx, (struct monst *));
|
||||
|
||||
/* out of order, but it makes sense to directly follow mextra */
|
||||
/* ### oextra.c ### */
|
||||
|
@ -1332,6 +1333,7 @@ E void * FDECL(bundle_oextra, (struct obj *, long *));
|
|||
E void FDECL(unbundle_oextra, (struct obj *, void *));
|
||||
E void FDECL(save_oextra, (struct obj *, int, int));
|
||||
E void FDECL(rest_oextra, (struct obj *, int, boolean));
|
||||
E void FDECL(relink_ox, (struct obj *));
|
||||
|
||||
/* ### minion.c ### */
|
||||
|
||||
|
|
26
src/mextra.c
26
src/mextra.c
|
@ -230,8 +230,13 @@ long * len_p;
|
|||
for (i = 0; i < NUM_MX; i++) {
|
||||
if (!(towrite & (1 << i)))
|
||||
continue;
|
||||
/* special handling when we need to mark something as having a stale pointer */
|
||||
if (i == MX_ESUM) mtmp->mextra_p->esum_p->staleptr = 1;
|
||||
/* copy memory */
|
||||
memcpy(output_ptr,mtmp->mextra_p->eindex[i],siz_mx(mtmp, i));
|
||||
/* and remove markers after saving */
|
||||
if (i == MX_ESUM) mtmp->mextra_p->esum_p->staleptr = 0;
|
||||
|
||||
/* increment output_ptr (char is 1 byte) */
|
||||
output_ptr = ((char *)output_ptr) + siz_mx(mtmp, i);
|
||||
}
|
||||
|
@ -377,8 +382,29 @@ boolean ghostly;
|
|||
assign_level(&(mtmp->mextra_p->epri_p->shrlevel), &u.uz);
|
||||
}
|
||||
}
|
||||
/* cannot handle esum here -- it needs all monsters to have been restored first -- done in relink_mx() below */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* relinks mx. If called with a specific mtmp, only does so for that one, otherwise does all on fmon */
|
||||
void
|
||||
relink_mx(specific_mtmp)
|
||||
struct monst * specific_mtmp;
|
||||
{
|
||||
unsigned nid;
|
||||
struct monst * mtmp = (specific_mtmp ? specific_mtmp : fmon);
|
||||
/* only checking fmon because MX_ESUM cannot be on migratingmons */
|
||||
for (; mtmp && (mtmp == specific_mtmp || !specific_mtmp); mtmp = mtmp->nmon) {
|
||||
if (get_mx(mtmp, MX_ESUM)) {
|
||||
if (mtmp->mextra_p->esum_p->staleptr) {
|
||||
mtmp->mextra_p->esum_p->staleptr = 0;
|
||||
/* restore stale pointer -- id==0 is assumed to be player */
|
||||
nid = mtmp->mextra_p->esum_p->sm_id;
|
||||
mtmp->mextra_p->esum_p->summoner = (genericptr_t) (nid ? find_mid(nid, FM_FMON) : &youmonst);
|
||||
if (!mtmp->mextra_p->esum_p->summoner) panic("cant find m_id %d", nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*mextra.c*/
|
||||
|
|
|
@ -2552,6 +2552,8 @@ boolean copyof;
|
|||
if (mnew->mextra_p) {
|
||||
void * mextra_bundle = mtmp+1;
|
||||
unbundle_mextra(mnew, mextra_bundle);
|
||||
/* relink any stale pointers */
|
||||
relink_mx(mnew);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -230,6 +230,7 @@ STATIC_VAR int cham_to_pm[] = {
|
|||
is_reviver((mon)->data) || \
|
||||
((mon)->mfaction) || \
|
||||
(templated(mon)) || \
|
||||
(get_mx((mon), MX_ESUM)) || \
|
||||
((mon)->ispolyp) || \
|
||||
((mon)->zombify) || \
|
||||
((mon)->mtyp == PM_UNDEAD_KNIGHT) || \
|
||||
|
|
33
src/oextra.c
33
src/oextra.c
|
@ -226,8 +226,13 @@ long * len_p;
|
|||
for (i = 0; i < NUM_OX; i++) {
|
||||
if (!(towrite & (1 << i)))
|
||||
continue;
|
||||
/* special handling when we need to mark something as having a stale pointer */
|
||||
if (i == OX_ESUM) otmp->oextra_p->esum_p->staleptr = 1;
|
||||
/* copy memory */
|
||||
memcpy(output_ptr,otmp->oextra_p->eindex[i],siz_ox(otmp, i));
|
||||
/* and remove markers after saving */
|
||||
if (i == OX_ESUM) otmp->oextra_p->esum_p->staleptr = 0;
|
||||
|
||||
/* increment output_ptr (char is 1 byte) */
|
||||
output_ptr = ((char *)output_ptr) + siz_ox(otmp, i);
|
||||
}
|
||||
|
@ -355,4 +360,32 @@ boolean ghostly;
|
|||
return;
|
||||
}
|
||||
|
||||
/* relinks ox. If called with a specific otmp, only does so for that one, otherwise does all */
|
||||
void
|
||||
relink_ox(specific_otmp)
|
||||
struct obj * specific_otmp;
|
||||
{
|
||||
unsigned nid;
|
||||
int owhere = ((1 << OBJ_FLOOR) |
|
||||
(1 << OBJ_INVENT) |
|
||||
(1 << OBJ_MINVENT) |
|
||||
(1 << OBJ_MIGRATING) |
|
||||
(1 << OBJ_BURIED) |
|
||||
(1 << OBJ_CONTAINED) |
|
||||
(1 << OBJ_MAGIC_CHEST) |
|
||||
(1 << OBJ_INTRAP));
|
||||
struct obj * otmp = specific_otmp ? specific_otmp : start_all_items(&owhere);
|
||||
|
||||
for (; otmp && (otmp == specific_otmp || !specific_otmp); otmp = (specific_otmp ? (struct obj *)0 : next_all_items(&owhere))) {
|
||||
if (get_ox(otmp, OX_ESUM)) {
|
||||
if (otmp->oextra_p->esum_p->staleptr) {
|
||||
otmp->oextra_p->esum_p->staleptr = 0;
|
||||
/* restore stale pointer -- id==0 is assumed to be player */
|
||||
nid = otmp->oextra_p->esum_p->sm_id;
|
||||
otmp->oextra_p->esum_p->summoner = (genericptr_t) (nid ? find_mid(nid, FM_FMON) : &youmonst);
|
||||
if (!otmp->oextra_p->esum_p->summoner) panic("cant find m_id %d", nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*oextra.c*/
|
||||
|
|
|
@ -30,7 +30,6 @@ STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
|
|||
STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
|
||||
STATIC_DCL int FDECL(restlevelfile, (int,int));
|
||||
STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
|
||||
STATIC_DCL void NDECL(relink);
|
||||
|
||||
/*
|
||||
* Save a mapping of IDs from ghost levels to the current level. This
|
||||
|
@ -432,6 +431,7 @@ unsigned int *stuckid, *steedid; /* STEED */
|
|||
amii_setpens(amii_numcolors); /* use colors from save file */
|
||||
#endif
|
||||
mread(fd, (genericptr_t) &u, sizeof(struct you));
|
||||
mread(fd, (genericptr_t) &youmonst, sizeof(struct monst));
|
||||
mread(fd, (genericptr_t) &god_list, sizeof(struct god_details)*MAX_GOD);
|
||||
init_uasmon();
|
||||
#ifdef CLIPPING
|
||||
|
@ -544,7 +544,8 @@ unsigned int *stuckid, *steedid; /* STEED */
|
|||
sizeof realtime_data.realtime);
|
||||
#endif
|
||||
/* must come after all mons & objs are restored */
|
||||
relink();
|
||||
relink_mx((struct monst *)0);
|
||||
relink_ox((struct obj *)0);
|
||||
#ifdef WHEREIS_FILE
|
||||
touch_whereis();
|
||||
#endif
|
||||
|
@ -1013,7 +1014,8 @@ boolean ghostly;
|
|||
}
|
||||
|
||||
/* must come after all mons & objs are restored */
|
||||
relink();
|
||||
relink_mx((struct monst *)0);
|
||||
relink_ox((struct obj *)0);
|
||||
reset_oattached_mids(ghostly);
|
||||
|
||||
/* regenerate animals while on another level */
|
||||
|
@ -1129,44 +1131,6 @@ boolean ghostly;
|
|||
}
|
||||
}
|
||||
|
||||
/* relink (o/m)extras as needed */
|
||||
void
|
||||
relink()
|
||||
{
|
||||
unsigned nid;
|
||||
/* objects first */
|
||||
struct obj * otmp;
|
||||
int owhere = ((1 << OBJ_FLOOR) |
|
||||
(1 << OBJ_INVENT) |
|
||||
(1 << OBJ_MINVENT) |
|
||||
(1 << OBJ_MIGRATING) |
|
||||
(1 << OBJ_BURIED) |
|
||||
(1 << OBJ_CONTAINED) |
|
||||
(1 << OBJ_MAGIC_CHEST) |
|
||||
(1 << OBJ_INTRAP));
|
||||
|
||||
for (otmp = start_all_items(&owhere); otmp; otmp = next_all_items(&owhere)) {
|
||||
if (get_ox(otmp, OX_ESUM)) {
|
||||
nid = otmp->oextra_p->esum_p->sm_id;
|
||||
if (nid) {
|
||||
otmp->oextra_p->esum_p->summoner = (genericptr_t) find_mid(nid, FM_FMON);
|
||||
if (!otmp->oextra_p->esum_p->summoner) panic("cant find m_id %d", nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* then monsters -- only checking fmon because MX_ESUM cannot be on migratingmons */
|
||||
struct monst * mtmp;
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
|
||||
if (get_mx(mtmp, MX_ESUM)) {
|
||||
nid = mtmp->mextra_p->esum_p->sm_id;
|
||||
if (nid) {
|
||||
mtmp->mextra_p->esum_p->summoner = (genericptr_t) find_mid(nid, FM_FMON);
|
||||
if (!mtmp->mextra_p->esum_p->summoner) panic("cant find m_id %d", nid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ZEROCOMP
|
||||
#define RLESC '\0' /* Leading character for run of RLESC's */
|
||||
|
||||
|
|
|
@ -305,6 +305,7 @@ register int fd, mode;
|
|||
flags.end_around = has_loaded_bones;
|
||||
bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
|
||||
bwrite(fd, (genericptr_t) &u, sizeof(struct you));
|
||||
bwrite(fd, (genericptr_t) &youmonst, sizeof(struct monst));
|
||||
bwrite(fd, (genericptr_t) &god_list, sizeof(struct god_details)*MAX_GOD);
|
||||
|
||||
/* save random monsters*/
|
||||
|
|
|
@ -2455,6 +2455,8 @@ long timeout;
|
|||
struct monst * mon = (struct monst *)arg;
|
||||
if (get_mx(mon, MX_ESUM) && mon->mextra_p->esum_p->summoner) {
|
||||
mon->mextra_p->esum_p->summoner->summonpwr -= mon->mextra_p->esum_p->summonstr;
|
||||
mon->mextra_p->esum_p->summoner = (struct monst *)0;
|
||||
mon->mextra_p->esum_p->sm_id = 0;
|
||||
}
|
||||
|
||||
/* special case for vexing orbs -- awful */
|
||||
|
@ -2478,8 +2480,11 @@ genericptr_t arg;
|
|||
long timeout;
|
||||
{
|
||||
struct monst * mon = (struct monst *)arg;
|
||||
if (get_mx(mon, MX_ESUM) && mon->mextra_p->esum_p->summoner) {
|
||||
/* if we are stopping the timer because mon died or vanished, reduce tax on summoner */
|
||||
if (get_mx(mon, MX_ESUM) && DEADMONSTER(mon) && mon->mextra_p->esum_p->summoner) {
|
||||
mon->mextra_p->esum_p->summoner->summonpwr -= mon->mextra_p->esum_p->summonstr;
|
||||
mon->mextra_p->esum_p->summoner = (struct monst *)0;
|
||||
mon->mextra_p->esum_p->sm_id = 0;
|
||||
}
|
||||
}
|
||||
void
|
||||
|
|
|
@ -633,7 +633,11 @@ int *fail_reason;
|
|||
/* mimic statue becomes seen mimic; other hiders won't be hidden */
|
||||
if (mon->m_ap_type) seemimic(mon);
|
||||
else mon->mundetected = FALSE;
|
||||
if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
|
||||
if (get_mx(mon, MX_ESUM)) {
|
||||
if (cansee(x,y))
|
||||
pline_The("statue crumbles to dust.");
|
||||
}
|
||||
else if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) {
|
||||
const char *comes_to_life = nonliving(mon->data) ?
|
||||
"moves" : "comes to life";
|
||||
if (cause == ANIMATE_SPELL){
|
||||
|
|
11
src/zap.c
11
src/zap.c
|
@ -2098,8 +2098,8 @@ struct obj *obj, *otmp;
|
|||
obj = poly_obj(obj, MEATBALL);
|
||||
goto smell;
|
||||
}
|
||||
if (!animate_statue(obj, oox, ooy,
|
||||
ANIMATE_SPELL, (int *)0)) {
|
||||
struct monst * mtmp;
|
||||
if (!(mtmp = animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *)0))) {
|
||||
struct obj *item;
|
||||
makecorpse: if (mons[obj->corpsenm].geno &
|
||||
(G_NOCORPSE|G_UNIQ)) {
|
||||
|
@ -2117,6 +2117,13 @@ makecorpse: if (mons[obj->corpsenm].geno &
|
|||
obj = poly_obj(obj, CORPSE);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
/* creature was created */
|
||||
if (get_mx(mtmp, MX_ESUM)) {
|
||||
/* vanish it */
|
||||
monvanished(mtmp);
|
||||
}
|
||||
}
|
||||
} else if (obj->otyp == FOSSIL) {
|
||||
int corpsetype = obj->corpsenm;
|
||||
xchar oox, ooy;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue