From 6b371a70423e0c0c4cf15a7e25b7c588c2b2a83d Mon Sep 17 00:00:00 2001 From: "nethack.rankin" Date: Sun, 22 Oct 2006 02:53:31 +0000 Subject: [PATCH] unhiding during level change From the newsgroup: if a pet was hiding under an object next to you when you changed levels, it could arrive hidden at the destination if there was something available to hide under there too, and sometimes you'd start the new level with a hidden monster glyph at its location. I was able to reproduce that once with current trunk code, but while trying to figure out what is actually happening I've been unable to make it happen again. However, it doesn't make sense for a monster to be able to remain in hiding during the level change in the first place, so this patch prevents that. (I'd still like to know how/why map_invisible() is sometimes getting called. [The test character was a level 1 tourist without auto-search capability.] I'm reasonably sure that it won't happen any more once this fix in place.) This also brings adjacent pets out of hiding when they accompany you during ascension or dungeon escape, but it seems that that wasn't actually necessary. The end of game disclosure already lists such by name rather than as "it", contrary to my expectations. (I had forgotten that end-of- game forces true names so that blindness and hallucination don't interfere with disclosure; obviously that ends up handling hidden monsters too.) --- doc/fixes34.4 | 1 + include/extern.h | 2 +- src/dog.c | 12 +++--------- src/mon.c | 48 +++++++++++++++++++++++++++++++++++++----------- 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/doc/fixes34.4 b/doc/fixes34.4 index e2cda30c0..2e0c416fc 100644 --- a/doc/fixes34.4 +++ b/doc/fixes34.4 @@ -263,6 +263,7 @@ try harder to keep dragged chain between ball and hero fireproof containers should not burn in lava fix invalid pointer dereference after applying a wielded cream pie avoid drowned in a drowning and burned by burning if life-saving is inadequate +hidden monsters who change levels come out of hiding in the process Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 585159854..ea4cd3193 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1247,7 +1247,7 @@ E void NDECL(dmonsfree); E int FDECL(mcalcmove, (struct monst*)); E void NDECL(mcalcdistress); E void FDECL(replmon, (struct monst *,struct monst *)); -E void FDECL(relmon, (struct monst *)); +E void FDECL(relmon, (struct monst *,struct monst **)); E struct obj *FDECL(mlifesaver, (struct monst *)); E boolean FDECL(corpse_chance,(struct monst *,struct monst *,BOOLEAN_P)); E void FDECL(mondead, (struct monst *)); diff --git a/src/dog.c b/src/dog.c index 037c12659..cc7e81ead 100644 --- a/src/dog.c +++ b/src/dog.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dog.c 3.5 2006/06/11 */ +/* SCCS Id: @(#)dog.c 3.5 2006/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -604,13 +604,10 @@ boolean pets_only; /* true for ascension or final escape */ obj->no_charge = 0; } - relmon(mtmp); - newsym(mtmp->mx,mtmp->my); + relmon(mtmp, &mydogs); /* move it from map to mydogs */ mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */ mtmp->wormno = num_segs; mtmp->mlstmv = monstermoves; - mtmp->nmon = mydogs; - mydogs = mtmp; } else if (mtmp->iswiz) { /* we want to be able to find him when his next resurrection chance comes up, but have him resume his present location @@ -660,10 +657,7 @@ migrate_to_level(mtmp, tolev, xyloc, cc) mtmp->mtame--; m_unleash(mtmp, TRUE); } - relmon(mtmp); - mtmp->nmon = migrating_mons; - migrating_mons = mtmp; - newsym(mtmp->mx,mtmp->my); + relmon(mtmp, &migrating_mons); /* move it from map to migrating_mons */ new_lev.dnum = ledger_to_dnum((xchar)tolev); new_lev.dlevel = ledger_to_dlev((xchar)tolev); diff --git a/src/mon.c b/src/mon.c index 0642fcc67..b205d1f26 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)mon.c 3.5 2006/09/06 */ +/* SCCS Id: @(#)mon.c 3.5 2006/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1297,7 +1297,7 @@ register struct monst *mtmp, *mtmp2; mtmp->minvent = 0; /* remove the old monster from the map and from `fmon' list */ - relmon(mtmp); + relmon(mtmp, (struct monst **)0); /* finish adding its replacement */ #ifdef STEED @@ -1326,22 +1326,48 @@ register struct monst *mtmp, *mtmp2; dealloc_monst(mtmp); } -/* release mon from display and monster list */ +/* release mon from the display and the map's monster list, + maybe transfer it to one of the other monster lists */ void -relmon(mon) +relmon(mon, monst_list) register struct monst *mon; +struct monst **monst_list; /* &migrating_mons or &mydogs or null */ { register struct monst *mtmp; + boolean unhide = (monst_list != 0); + int mx = mon->mx, my = mon->my; - if (fmon == (struct monst *)0) panic ("relmon: no fmon available."); + if (!fmon) panic("relmon: no fmon available."); - remove_monster(mon->mx, mon->my); + if (unhide) { + /* can't remain hidden across level changes (exception: wizard + clone can continue imitating some other monster form); also, + might be imitating a boulder so need line-of-sight unblocking */ + mon->mundetected = 0; + if (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER) + seemimic(mon); + } - if(mon == fmon) fmon = fmon->nmon; - else { - for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ; - if(mtmp) mtmp->nmon = mon->nmon; - else panic("relmon: mon not in list."); + remove_monster(mx, my); + + if (mon == fmon) { + fmon = fmon->nmon; + } else { + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) + if (mtmp->nmon == mon) break; + + if (mtmp) mtmp->nmon = mon->nmon; + else panic("relmon: mon not in list."); + } + + if (unhide) { + newsym(mx, my); + /* insert into mydogs or migrating_mons */ + mon->nmon = *monst_list; + *monst_list = mon; + } else { + /* orphan has no next monster */ + mon->nmon = 0; } }