leash sanity checking
I still haven't found any explanation for the report by a hardfought player recently that going down some stairs with a pair of leashed pets got one into a confused state where it was flagged as leashed but the corresponding leash was no longer in use. This adds some new object and monster sanity checks regarding leashes, and it changes o_unleash(obj) to clear obj->leashmon even if/when the monster can't be found. It also changes behavior for dipping an attached leash into a potion of polymorph when that happens to yield another leash--now the new one will end up being pre-attached.
This commit is contained in:
@@ -702,10 +702,10 @@ o_unleash(struct obj *otmp)
|
||||
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
|
||||
if (mtmp->m_id == (unsigned) otmp->leashmon) {
|
||||
mtmp->mleashed = 0;
|
||||
otmp->leashmon = 0;
|
||||
update_inventory();
|
||||
break;
|
||||
}
|
||||
otmp->leashmon = 0;
|
||||
update_inventory();
|
||||
}
|
||||
|
||||
/* mtmp is about to die, or become untame */
|
||||
|
||||
37
src/mkobj.c
37
src/mkobj.c
@@ -2907,6 +2907,8 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
||||
insane_object(obj, ofmt0, mesg, (struct monst *) 0);
|
||||
if (obj->where == OBJ_INVENT && obj->how_lost != LOST_NONE) {
|
||||
char lostbuf[40];
|
||||
|
||||
/* %d: bitfield is unsigned but narrow, so promotes to int */
|
||||
Sprintf(lostbuf, "how_lost=%d obj in inventory!", obj->how_lost);
|
||||
insane_object(obj, ofmt0, lostbuf, (struct monst *) 0);
|
||||
}
|
||||
@@ -2948,6 +2950,37 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (obj->otyp == LEASH && obj->leashmon) {
|
||||
char buf[BUFSZ];
|
||||
struct monst *mtmp = find_mid(obj->leashmon, FM_FMON);
|
||||
|
||||
if (obj->where == OBJ_INVENT) {
|
||||
if (!mtmp) { /* found leash with phantom mon */
|
||||
Sprintf(buf, "leashmon=%u no monst,",
|
||||
(unsigned) obj->leashmon);
|
||||
insane_object(obj, ofmt0, buf, (struct monst *) 0);
|
||||
} else if (!mtmp->mleashed) { /* found leashed mon
|
||||
* not flagged as leashed */
|
||||
Sprintf(buf, "leashmon=%u %s not leashed,",
|
||||
(unsigned) obj->leashmon, mon_pmname(mtmp));
|
||||
insane_object(obj, ofmt0, buf, (struct monst *) 0);
|
||||
}
|
||||
} else {
|
||||
struct monst *mtmp2 = (obj->where == OBJ_MINVENT)
|
||||
? obj->ocarry : (struct monst *) 0;
|
||||
|
||||
if (mtmp) { /* found monst leashed by non-invent leash */
|
||||
Sprintf(buf, "leashmon:%u %s leashed by %s leash,",
|
||||
(unsigned) obj->leashmon,
|
||||
mon_pmname(mtmp), where_name(obj));
|
||||
insane_object(obj, ofmt0, buf, mtmp2);
|
||||
} else { /* found non-invent leash with m_id of phantom mon */
|
||||
Sprintf(buf, "leashmon:%u no monst for %s leash,",
|
||||
(unsigned) obj->leashmon, where_name(obj));
|
||||
insane_object(obj, ofmt0, buf, mtmp2);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (obj->globby)
|
||||
check_glob(obj, mesg);
|
||||
/* temporary flags that might have been set but which should
|
||||
@@ -3165,11 +3198,13 @@ init_dummyobj(struct obj *obj, short otyp, long oquan)
|
||||
/* obj->dknown = 0; */
|
||||
/* suppress known except for amulets (needed for fakes & real AoY) */
|
||||
obj->known = (obj->oclass == AMULET_CLASS)
|
||||
? obj->known
|
||||
? obj->known
|
||||
/* default is "on" for types which don't use it */
|
||||
: !objects[otyp].oc_uses_known;
|
||||
obj->quan = oquan ? oquan : 1L;
|
||||
obj->corpsenm = NON_PM; /* suppress statue and figurine details */
|
||||
if (obj->otyp == LEASH)
|
||||
obj->leashmon = 0; /* overloads corpsenm, avoid NON_PM */
|
||||
if (obj->otyp == BOULDER)
|
||||
obj->next_boulder = 0; /* overloads corpsenm, avoid NON_PM */
|
||||
/* but suppressing fruit details leads to "bad fruit #0" */
|
||||
|
||||
18
src/mon.c
18
src/mon.c
@@ -214,6 +214,24 @@ sanity_check_single_mon(
|
||||
impossible("mimic%s concealed in inaccessible location: %s (%s)",
|
||||
is_mimic ? "" : "ker", typnam, msg);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (mtmp->mleashed) {
|
||||
if (!get_mleash(mtmp))
|
||||
impossible("monst %u: leashed but no leash for %s",
|
||||
mtmp->m_id, mon_pmname(mtmp));
|
||||
else if (!mtmp->mtame)
|
||||
impossible("monst %u: leashed but not tame %s",
|
||||
mtmp->m_id, mon_pmname(mtmp));
|
||||
#if 0
|
||||
/* after hero moves, leashed mon won't necessarily pass 'm_next2u()'
|
||||
test; 90 is farthest observed distance with expert jumping spell
|
||||
when very slow mon is already several steps away and hero jumps in
|
||||
opposite direction (if hero teleports, leashed mon moves adjacent
|
||||
immediately; knockback has shorter range than magical jumping) */
|
||||
else if (distu(mtmp->mx, mtmp->my) > 90) /*if (!m_next2u(mtmp))*/
|
||||
impossible("monst %u: leashed but not next to you (%d)",
|
||||
mtmp->m_id, distu(mtmp->mx, mtmp->my));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
13
src/objnam.c
13
src/objnam.c
@@ -1407,11 +1407,16 @@ doname_base(
|
||||
if (obj->otyp == LEASH && obj->leashmon != 0) {
|
||||
struct monst *mlsh = find_mid(obj->leashmon, FM_FMON);
|
||||
|
||||
if (!mlsh) {
|
||||
impossible("leashed monster not on this level");
|
||||
obj->leashmon = 0;
|
||||
} else {
|
||||
if (mlsh && !DEADMONSTER(mlsh)) {
|
||||
ConcatF1(bp, 0, " (attached to %s)", noit_mon_nam(mlsh));
|
||||
} else {
|
||||
if (mlsh) /*&& DEADMONSTER(mlsh)*/
|
||||
impossible("leashed %s #%u is dead",
|
||||
mon_pmname(mlsh), (unsigned) obj->leashmon);
|
||||
else
|
||||
impossible("leashed monster #%u not found",
|
||||
(unsigned) obj->leashmon);
|
||||
obj->leashmon = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
10
src/zap.c
10
src/zap.c
@@ -1769,6 +1769,16 @@ poly_obj(struct obj *obj, int id)
|
||||
otmp->cursed = FALSE;
|
||||
}
|
||||
}
|
||||
if (obj->otyp == LEASH && obj->leashmon != 0) {
|
||||
if (otmp->otyp == LEASH) {
|
||||
otmp->leashmon = obj->leashmon;
|
||||
/* clear m_id before delobj(), to avoid o_unleash() by obfree() */
|
||||
obj->leashmon = 0;
|
||||
} else {
|
||||
/* obfree() would do this if we didn't do it here */
|
||||
o_unleash(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/* no box contents --KAA */
|
||||
if (Has_contents(otmp))
|
||||
|
||||
Reference in New Issue
Block a user