From 78c5173cd1061f4cc2d93e0dbdb6d64bc4fa7979 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 22 Aug 2018 17:41:54 -0700 Subject: [PATCH 01/12] shop damage repair Fixes #121 Fix githib issue #121 - shopkeepers don't charge for consecutive acts of vandalism on the same square. pay_for_damage() keys its action on the 'when' field of the damage structure, and when a second type of damage gets added to existing damage, that wasn't being updated. Both bits of damage (broken door or dug wall plus trap created at same spot) get repaired together but shopkeeper wasn't challanging hero to pay for the second one (trap). The repair process had issues too. If you broke a shop door, paid off the shopkeeper, then left the level before the repair took place and came back after (or rather, catching up for lost time repaired it when you returned to the level), it didn't actually get fixed and remained a doorless doorway that was considered to have been successfully repaired (record of damage discarded). Unless there was also a trap there; then the door did get properly fixed when the trap was removed. Object scattering during wall repair was bypassed if trap removal took place. Also, trap removal while off level still gave messages when it took place after you returned. I didn't try to verify that; it's possible that vision is in a state where you can't see the repair even if you return to a spot where it would be visible. But the return value from the repair routine was one which wanted a message instead of the one to suppress messages. Not addressed: digging a pit inside a shop (aside from in doorway or breached wall) is not treated as damage which should be repaired. This includes the case of digging up a grave which converts the spot into ordinary floor (plus pit trap). --- doc/fixes36.2 | 6 ++ src/shk.c | 172 +++++++++++++++++++++++++++----------------------- 2 files changed, 100 insertions(+), 78 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ab3ee4870..3d412d2ca 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -87,6 +87,12 @@ wallifying a special level might go out of map bounds (not with 3.6.x levels) and corrupt other level data if a random grave produced during level creation included some gold, that gold was left on the ground instead of being buried with other treasure +multiple instances of shop damage at same spot (before repairs, so a broken + door or dug wall plus trap creation) only charged hero for first one +shop door repair which took place when hero was on another level only worked + correctly if a trap at the same spot was removed +object scattering during shop wall repair was skipped if a trap at the same + spot was also being removed Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/shk.c b/src/shk.c index 1b42f278c..e0b7cae8b 100644 --- a/src/shk.c +++ b/src/shk.c @@ -3303,8 +3303,8 @@ long cost; /* Don't schedule for repair unless it's a real shop entrance */ for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++) - if ((mtmp = shop_keeper(*shops)) != 0 && x == ESHK(mtmp)->shd.x - && y == ESHK(mtmp)->shd.y) + if ((mtmp = shop_keeper(*shops)) != 0 + && x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y) break; if (!*shops) return; @@ -3312,10 +3312,11 @@ long cost; for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) if (tmp_dam->place.x == x && tmp_dam->place.y == y) { tmp_dam->cost += cost; + tmp_dam->when = monstermoves; /* needed by pay_for_damage() */ return; } - tmp_dam = (struct damage *) alloc((unsigned) sizeof(struct damage)); - (void) memset((genericptr_t)tmp_dam, 0, sizeof(struct damage)); + tmp_dam = (struct damage *) alloc((unsigned) sizeof *tmp_dam); + (void) memset((genericptr_t) tmp_dam, 0, sizeof *tmp_dam); tmp_dam->when = monstermoves; tmp_dam->place.x = x; tmp_dam->place.y = y; @@ -3362,11 +3363,11 @@ boolean croaked; if (IS_DOOR(levl[x][y].typ)) old_doormask = levl[x][y].doormask; - if (croaked) + if (croaked) { disposition = (shops[1]) ? 0 : 1; - else if (stop_picking) + } else if (stop_picking) { disposition = repair_damage(shkp, tmp_dam, FALSE); - else { + } else { /* Defer the stop_occupation() until after repair msgs */ if (closed_door(x, y)) stop_picking = picking_at(x, y); @@ -3461,15 +3462,16 @@ boolean croaked; */ int repair_damage(shkp, tmp_dam, catchup) -register struct monst *shkp; -register struct damage *tmp_dam; +struct monst *shkp; +struct damage *tmp_dam; boolean catchup; /* restoring a level */ { - register xchar x, y, i; + xchar x, y; xchar litter[9]; - register struct monst *mtmp; - register struct obj *otmp; - register struct trap *ttmp; + struct monst *mtmp; + struct obj *otmp; + struct trap *ttmp; + int i, k, ix, iy, disposition = 1; if ((monstermoves - tmp_dam->when) < REPAIR_DELAY) return 0; @@ -3478,18 +3480,14 @@ boolean catchup; /* restoring a level */ x = tmp_dam->place.x; y = tmp_dam->place.y; if (!IS_ROOM(tmp_dam->typ)) { - if (x == u.ux && y == u.uy) - if (!Passes_walls) - return 0; - if (x == shkp->mx && y == shkp->my) - return 0; - if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data))) + if ((x == u.ux && y == u.uy && !Passes_walls) + || (x == shkp->mx && y == shkp->my) + || ((mtmp = m_at(x, y)) && !passes_walls(mtmp->data))) return 0; } if ((ttmp = t_at(x, y)) != 0) { - if (x == u.ux && y == u.uy) - if (!Passes_walls) - return 0; + if (x == u.ux && y == u.uy && !Passes_walls) + return 0; if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) { /* convert to an object */ otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP, @@ -3499,48 +3497,60 @@ boolean catchup; /* restoring a level */ (void) mpickobj(shkp, otmp); } deltrap(ttmp); - if (IS_DOOR(tmp_dam->typ) && !(levl[x][y].doormask & D_ISOPEN)) { - levl[x][y].doormask = D_CLOSED; - block_point(x, y); - } else if (IS_WALL(tmp_dam->typ)) { - levl[x][y].typ = tmp_dam->typ; - block_point(x, y); - } - newsym(x, y); - return 3; + if (cansee(x, y)) + newsym(x, y); + if (!catchup) + disposition = 3; } - if (IS_ROOM(tmp_dam->typ)) { - /* No messages, because player already filled trap door */ - return 1; - } - if ((tmp_dam->typ == levl[x][y].typ) - && (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN))) - /* No messages if player already replaced shop door */ - return 1; + if (IS_ROOM(tmp_dam->typ) + || (tmp_dam->typ == levl[x][y].typ + && (!IS_DOOR(tmp_dam->typ) || levl[x][y].doormask > D_BROKEN))) + /* no terrain fix necessary (trap removal or manually repaired) */ + return disposition; + + /* door or wall repair; trap, if any, is now gone; + restore original terrain type and move any items away */ levl[x][y].typ = tmp_dam->typ; - (void) memset((genericptr_t) litter, 0, sizeof(litter)); - if ((otmp = level.objects[x][y]) != 0) { -/* Scatter objects haphazardly into the shop */ + if (IS_DOOR(tmp_dam->typ)) + levl[x][y].doormask = D_CLOSED; /* arbitrary */ + + (void) memset((genericptr_t) litter, 0, sizeof litter); #define NEED_UPDATE 1 #define OPEN 2 #define INSHOP 4 #define horiz(i) ((i % 3) - 1) #define vert(i) ((i / 3) - 1) + k = 0; /* number of adjacent shop spots */ + if (level.objects[x][y] && !IS_ROOM(levl[x][y].typ)) { for (i = 0; i < 9; i++) { - if ((i == 4) || (!ZAP_POS(levl[x + horiz(i)][y + vert(i)].typ))) + ix = x + horiz(i); + iy = y + vert(i); + if (i == 4 || !isok(ix, iy) || !ZAP_POS(levl[ix][iy].typ)) continue; litter[i] = OPEN; - if (inside_shop(x + horiz(i), y + vert(i)) - == ESHK(shkp)->shoproom) + if (inside_shop(ix, iy) == ESHK(shkp)->shoproom) { litter[i] |= INSHOP; + ++k; + } } + } + /* placement below assumes there is always at least one adjacent + spot; the 'k' check guards against getting stuck in an infinite + loop if some irregularly shaped room breaks that assumption */ + if (k > 0) { + /* Scatter objects haphazardly into the shop */ if (Punished && !u.uswallow && ((uchain->ox == x && uchain->oy == y) || (uball->ox == x && uball->oy == y))) { /* * Either the ball or chain is in the repair location. - * * Take the easy way out and put ball&chain under hero. + * + * FIXME: message should be reworded; this might be the + * shop's doorway rather than a wall, there might be some + * other stuff here which isn't junk, and "your junk" has + * a slang connotation which could be applicable if hero + * has Passes_walls ability. */ if (!Deaf && !muteshk(shkp)) verbalize("Get your junk out of my wall!"); @@ -3549,40 +3559,48 @@ boolean catchup; /* restoring a level */ } while ((otmp = level.objects[x][y]) != 0) /* Don't mess w/ boulders -- just merge into wall */ - if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) { + if (otmp->otyp == BOULDER || otmp->otyp == ROCK) { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } else { - while (!(litter[i = rn2(9)] & INSHOP)) - ; + int trylimit = 50; + + /* otmp must be moved otherwise level.objects[x][y] will + never become Null and while-loop won't terminate */ + do { + i = rn2(9); + } while (--trylimit && !(litter[i] & INSHOP)); + if ((litter[i] & (OPEN | INSHOP)) != 0) { + ix = x + horiz(i); + iy = y + vert(i); + } else { + /* we know shk isn't at because repair + is deferred in that situation */ + ix = shkp->mx; + iy = shkp->my; + } remove_object(otmp); - place_object(otmp, x + horiz(i), y + vert(i)); + place_object(otmp, ix, iy); litter[i] |= NEED_UPDATE; } } if (catchup) - return 1; /* repair occurred while off level */ + return 1; /* repair occurred while off level so no messages */ block_point(x, y); - if (IS_DOOR(tmp_dam->typ)) { - levl[x][y].doormask = D_CLOSED; /* arbitrary */ - newsym(x, y); - } else { - /* don't set doormask - it is (hopefully) the same as it was - if not, perhaps save it with the damage array... */ - - if (IS_WALL(tmp_dam->typ) && cansee(x, y)) { - /* Player sees actual repair process, so they KNOW it's a wall */ + if (cansee(x, y)) { + if (IS_WALL(tmp_dam->typ)) + /* player sees actual repair process, so KNOWS it's a wall */ levl[x][y].seenv = SVALL; - newsym(x, y); - } - /* Mark this wall as "repaired". There currently is no code - to do anything about repaired walls, so don't do it. */ + newsym(x, y); } for (i = 0; i < 9; i++) if (litter[i] & NEED_UPDATE) newsym(x + horiz(i), y + vert(i)); - return 2; + + if (disposition < 3) + disposition = 2; + return disposition; #undef NEED_UPDATE #undef OPEN #undef INSHOP @@ -3595,12 +3613,12 @@ boolean catchup; /* restoring a level */ */ int shk_move(shkp) -register struct monst *shkp; +struct monst *shkp; { - register xchar gx, gy, omx, omy; - register int udist; - register schar appr; - register struct eshk *eshkp = ESHK(shkp); + xchar gx, gy, omx, omy; + int udist; + schar appr; + struct eshk *eshkp = ESHK(shkp); int z; boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv; @@ -3858,24 +3876,22 @@ boolean cant_mollify; { register struct monst *shkp = (struct monst *) 0; char shops_affected[5]; - register boolean uinshp = (*u.ushops != '\0'); + boolean uinshp = (*u.ushops != '\0'); char qbuf[80]; - register xchar x, y; + xchar x, y; boolean dugwall = (!strcmp(dmgstr, "dig into") /* wand */ || !strcmp(dmgstr, "damage")); /* pick-axe */ boolean animal, pursue; struct damage *tmp_dam, *appear_here = 0; - /* any number >= (80*80)+(24*24) would do, actually */ long cost_of_damage = 0L; - unsigned int nearest_shk = 7000, nearest_damage = 7000; + unsigned int nearest_shk = (ROWNO * ROWNO) + (COLNO * COLNO), + nearest_damage = nearest_shk; int picks = 0; - for (tmp_dam = level.damagelist; - (tmp_dam && (tmp_dam->when == monstermoves)); - tmp_dam = tmp_dam->next) { + for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) { char *shp; - if (!tmp_dam->cost) + if (tmp_dam->when != monstermoves || !tmp_dam->cost) continue; cost_of_damage += tmp_dam->cost; Strcpy(shops_affected, From 083e0904dbd017ddbdd2174ce93697c32864dc23 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Aug 2018 18:01:00 -0700 Subject: [PATCH 02/12] another fix fox "killed, while helpless" Augmented death reason with appended "while " was broken in 3.6.0 and got fixed shortly after release (too late to prevent high-score files from being corrupted). Then within a couple of weeks it got broken again, and doesn't work in 3.6.1 either (but in this case, it is omitted instead of being cloned to all following score entries). The problem is in both record and logfile, but not xlogfile, so we could create a fix up routine that would use the last to repair record (and perhaps logfile). But having two fixup routines would probably lead to confusion. The problem this time was bad logic in the fix for |alter name of monster causing hero's death if name contains | characters that could cause confusion when using record, | logfile, or xlogfile later killerformat() was going out of bounds of the input string and using up all of 'siz' so that there was never room to append the ", while helpless" suffix. --- doc/fixes36.2 | 2 ++ src/topten.c | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3d412d2ca..582b85c52 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -93,6 +93,8 @@ shop door repair which took place when hero was on another level only worked correctly if a trap at the same spot was removed object scattering during shop wall repair was skipped if a trap at the same spot was also being removed +augmented death reason for "while helpless" was broken for record and logfile + (but still correct for xlogfile) Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/topten.c b/src/topten.c index fbe6573cb..4652d42b2 100644 --- a/src/topten.c +++ b/src/topten.c @@ -130,7 +130,9 @@ boolean incl_helpless; */ while (--siz > 0) { c = *kname++; - if (c == ',') + if (!c) + break; + else if (c == ',') c = ';'; /* 'xlogfile' doesn't really need protection for '=', but fixrecord.awk for corrupted 3.6.0 'record' does (only From 6b793554949d5ad9544aa8b046a47f973298904f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Aug 2018 12:15:42 +0300 Subject: [PATCH 03/12] Make wish prompts not remember the input With EDIT_GETLIN, the wish prompt remembered the previous input, but this isn't actually useful. --- doc/fixes36.2 | 1 + src/zap.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 582b85c52..9aa0e6f36 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -95,6 +95,7 @@ object scattering during shop wall repair was skipped if a trap at the same spot was also being removed augmented death reason for "while helpless" was broken for record and logfile (but still correct for xlogfile) +prevent wish prompt input from remembering the previous wish Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/zap.c b/src/zap.c index 966ac914e..ea0f9bee4 100644 --- a/src/zap.c +++ b/src/zap.c @@ -5071,7 +5071,7 @@ int triesleft; void makewish() { - static char buf[BUFSZ] = DUMMY; + char buf[BUFSZ] = DUMMY; char promptbuf[BUFSZ]; struct obj *otmp, nothing; int tries = 0; From 43dc3bdf5f18a0e2f03f8ad45bb649acb434bd6f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Aug 2018 17:54:47 +0300 Subject: [PATCH 04/12] Hallu YAFM for stumbling onto an undetected monster Pokemon reference. Based on an idea by aosdict. --- doc/fixes36.2 | 1 + src/uhitm.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 9aa0e6f36..d2d40a267 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -144,6 +144,7 @@ status_hilite options which use comparisons may now use <= and >= in sortloot option has been enhanced to improve object ordering; primarily, items of undiscovered type come out before items of discovered type within each class or sub-class of objects +YAFM when stumbling on an undetected monster while hallucinating Code Cleanup and Reorganization diff --git a/src/uhitm.c b/src/uhitm.c index 6b41f6204..16bac15a6 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -176,7 +176,10 @@ struct obj *wep; /* uwep for attack(), null for kick_monster() */ if (!((Blind ? Blind_telepat : Unblind_telepat) || Detect_monsters)) { struct obj *obj; - if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) + if (!Blind && Hallucination) + pline("A %s %s appeared!", + mtmp->mtame ? "tame" : "wild", l_monnam(mtmp)); + else if (Blind || (is_pool(mtmp->mx, mtmp->my) && !Underwater)) pline("Wait! There's a hidden monster there!"); else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) pline("Wait! There's %s hiding under %s!", From bf10a70de0d5cd0f7925d77bfcfd320b7d58e7d8 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Aug 2018 18:43:22 +0300 Subject: [PATCH 05/12] Make it clear when a leprechaun dodges your attack It was not obvious what was happening when a leprechaun dodged your attack. Add a message to explicitly spell it out. Code by aosdict. --- doc/fixes36.2 | 1 + src/uhitm.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index d2d40a267..94d8c1394 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -145,6 +145,7 @@ sortloot option has been enhanced to improve object ordering; primarily, items of undiscovered type come out before items of discovered type within each class or sub-class of objects YAFM when stumbling on an undetected monster while hallucinating +Make it clear when a leprechaun dodges your attack Code Cleanup and Reorganization diff --git a/src/uhitm.c b/src/uhitm.c index 16bac15a6..9de48c971 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -412,8 +412,10 @@ register struct monst *mtmp; && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 /* it died */ || mtmp->mx != u.ux + u.dx - || mtmp->my != u.uy + u.dy)) /* it moved */ + || mtmp->my != u.uy + u.dy)) { /* it moved */ + You("miss wildly and stumble forwards."); return FALSE; + } if (Upolyd) (void) hmonas(mtmp); From 95b920516801678fef6e7503270a1ec05bf4a454 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 27 Aug 2018 19:13:54 -0700 Subject: [PATCH 06/12] fix #H7354 - incorrect material for parchment and vellum spellbooks. Parchment and vellum are made from animal skin rather than from plants, so classifying spellbooks with those descriptions as paper is inaccurate. Changing them to be made out of leather has a couple of side-effects: eating them while polymorphed will break vegetarian conduct and polymorphing them might result in a leather golem rather than a paper one. I left "leathery spell book" as paper since that directly refers to the cover. The composition shouldn't be changed--the pages of such a book are still made out of paper--but the effect of eating one possibly should. (That description originally was "leather" and got changed. I don't remember the details and assumed it was due to odd wishing behavior, but there's a commented-out routine in eat.c which suggests it was related to eating instead. Anyway, "leathery" is still non-leather.) --- doc/fixes36.2 | 3 +++ src/objects.c | 29 +++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 94d8c1394..92bbd1770 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -96,6 +96,9 @@ object scattering during shop wall repair was skipped if a trap at the same augmented death reason for "while helpless" was broken for record and logfile (but still correct for xlogfile) prevent wish prompt input from remembering the previous wish +parchment and vellum are made from animal skin so change material composition + and color for spellbooks with those descriptions from paper to leather; + eating those books now breaks vegetarian conduct Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/objects.c b/src/objects.c index 3a8db8d92..0809ff41a 100644 --- a/src/objects.c +++ b/src/objects.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objects.c $NHDT-Date: 1447313395 2015/11/12 07:29:55 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */ +/* NetHack 3.6 objects.c $NHDT-Date: 1535422421 2018/08/28 02:13:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.51 $ */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -883,18 +883,35 @@ SCROLL("blank paper", "unlabeled", 0, 28, 60), #undef SCROLL /* spellbooks ... */ -/* expanding beyond 52 spells would require changes in spellcasting - or imposition of a limit on number of spells hero can know because - they are currently assigned successive letters, a-zA-Z, when learned */ + /* Expanding beyond 52 spells would require changes in spellcasting + * or imposition of a limit on number of spells hero can know because + * they are currently assigned successive letters, a-zA-Z, when learned. + * [The existing spell sorting capability could conceivably be extended + * to enable moving spells from beyond Z to within it, bumping others + * out in the process, allowing more than 52 spells be known but keeping + * only 52 be castable at any given time.] + */ #define SPELL(name,desc,sub,prob,delay,level,mgc,dir,color) \ OBJECT(OBJ(name, desc), \ BITS(0, 0, 0, 0, mgc, 0, 0, 0, 0, 0, dir, sub, PAPER), \ 0, SPBOOK_CLASS, prob, delay, 50, level * 100, \ 0, 0, 0, level, 20, color) +/* Spellbook description normally refers to book covers (primarily color). + Parchment and vellum would never be used for such, but rather than + eliminate those, finagle their definitions to refer to the pages + rather than the cover. They are made from animal skin (typically of + a goat or sheep) and books using them for pages generally need heavy + covers with straps or clamps to tightly close the book in order to + keep the pages flat. (However, a wooden cover might itself be covered + by a sheet of parchment, making this become less of an exception. Also, + changing the internal composition from paper to leather makes eating a + parchment or vellum spellbook break vegetarian conduct, as it should.) */ +#define PAPER LEATHER /* override enum for use in SPELL() expansion */ SPELL("dig", "parchment", - P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_PAPER), + P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_LEATHER), SPELL("magic missile", "vellum", - P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_PAPER), + P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_LEATHER), +#undef PAPER /* revert to normal material */ SPELL("fireball", "ragged", P_ATTACK_SPELL, 20, 4, 4, 1, RAY, HI_PAPER), SPELL("cone of cold", "dog eared", From 599edde94d13a462430d94f8f6b7122826a314c2 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Aug 2018 17:41:18 +0300 Subject: [PATCH 07/12] Fix monsters not wielding digging implements My change to unify the pet and monster digging weapon choosing made monsters not actually wield the chosen weapon, even though they could still dig as if they did. Pets behaved properly. Also add an explicit check for IS_STWALL so they won't keep switching away from their current weapon until needed. --- doc/fixes36.2 | 1 + src/monmove.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 92bbd1770..0d95c8fde 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -99,6 +99,7 @@ prevent wish prompt input from remembering the previous wish parchment and vellum are made from animal skin so change material composition and color for spellbooks with those descriptions from paper to leather; eating those books now breaks vegetarian conduct +fix monsters not wielding digging implements Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/monmove.c b/src/monmove.c index cdef76f89..99efdbbbf 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -716,25 +716,25 @@ struct monst *mtmp; xchar nix,niy; { boolean can_tunnel = 0; - struct obj *mw_tmp; + struct obj *mw_tmp = MON_WEP(mtmp); if (!Is_rogue_level(&u.uz)) can_tunnel = tunnels(mtmp->data); - if (can_tunnel && needspick(mtmp->data) - && mtmp->weapon_check != NO_WEAPON_WANTED - && ((IS_ROCK(levl[nix][niy].typ) && may_dig(nix, niy)) - || closed_door(nix, niy))) { + if (can_tunnel && needspick(mtmp->data) && !mwelded(mw_tmp) + && (may_dig(nix, niy) || closed_door(nix, niy))) { + /* may_dig() is either IS_STWALL or IS_TREE */ if (closed_door(nix, niy)) { - if (!(mw_tmp = MON_WEP(mtmp)) + if (!mw_tmp || !is_pick(mw_tmp) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_PICK_OR_AXE; } else if (IS_TREE(levl[nix][niy].typ)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_AXE; - } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { - mtmp->weapon_check = NEED_PICK_AXE; + } else if (IS_STWALL(levl[nix][niy].typ)) { + if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) + mtmp->weapon_check = NEED_PICK_AXE; } if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return TRUE; From 987516cedb552b2b0c119dba77eb0a0aca0bc5c0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Aug 2018 19:52:15 +0300 Subject: [PATCH 08/12] Split string parsing and monster creation out of create_particular --- src/read.c | 266 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 150 insertions(+), 116 deletions(-) diff --git a/src/read.c b/src/read.c index f86afe04a..bedf5172a 100644 --- a/src/read.c +++ b/src/read.c @@ -2424,6 +2424,146 @@ struct obj *from_obj; return FALSE; } +struct _create_particular_data { + int which; + int fem; + char monclass; + boolean randmonst; + boolean maketame, makepeaceful, makehostile; + boolean sleeping, saddled, invisible; +}; + +boolean +create_particular_parse(str, d) +char *str; +struct _create_particular_data *d; +{ + char *bufp = str; + char *tmpp; + + d->monclass = MAXMCLASSES; + d->which = urole.malenum; /* an arbitrary index into mons[] */ + d->fem = -1; /* gender not specified */ + d->randmonst = FALSE; + d->maketame = d->makepeaceful = d->makehostile = FALSE; + d->sleeping = d->saddled = d->invisible = FALSE; + + if ((tmpp = strstri(bufp, "saddled ")) != 0) { + d->saddled = TRUE; + (void) memset(tmpp, ' ', sizeof "saddled " - 1); + } + if ((tmpp = strstri(bufp, "sleeping ")) != 0) { + d->sleeping = TRUE; + (void) memset(tmpp, ' ', sizeof "sleeping " - 1); + } + if ((tmpp = strstri(bufp, "invisible ")) != 0) { + d->invisible = TRUE; + (void) memset(tmpp, ' ', sizeof "invisible " - 1); + } + /* check "female" before "male" to avoid false hit mid-word */ + if ((tmpp = strstri(bufp, "female ")) != 0) { + d->fem = 1; + (void) memset(tmpp, ' ', sizeof "female " - 1); + } + if ((tmpp = strstri(bufp, "male ")) != 0) { + d->fem = 0; + (void) memset(tmpp, ' ', sizeof "male " - 1); + } + bufp = mungspaces(bufp); /* after potential memset(' ') */ + /* allow the initial disposition to be specified */ + if (!strncmpi(bufp, "tame ", 5)) { + bufp += 5; + d->maketame = TRUE; + } else if (!strncmpi(bufp, "peaceful ", 9)) { + bufp += 9; + d->makepeaceful = TRUE; + } else if (!strncmpi(bufp, "hostile ", 8)) { + bufp += 8; + d->makehostile = TRUE; + } + /* decide whether a valid monster was chosen */ + if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) { + d->randmonst = TRUE; + return TRUE; + } + d->which = name_to_mon(bufp); + if (d->which >= LOW_PM) + return TRUE; /* got one */ + d->monclass = name_to_monclass(bufp, &d->which); + if (d->which >= LOW_PM) { + d->monclass = MAXMCLASSES; /* matters below */ + return TRUE; + } else if (d->monclass > 0) { + d->which = urole.malenum; /* reset from NON_PM */ + return TRUE; + } + return FALSE; +} + +boolean +create_particular_creation(d) +struct _create_particular_data *d; +{ + struct permonst *whichpm = NULL; + int i, firstchoice = NON_PM; + struct monst *mtmp; + boolean madeany = FALSE; + + if (!d->randmonst) { + firstchoice = d->which; + if (cant_revive(&d->which, FALSE, (struct obj *) 0)) { + /* wizard mode can override handling of special monsters */ + char buf[BUFSZ]; + + Sprintf(buf, "Creating %s instead; force %s?", + mons[d->which].mname, mons[firstchoice].mname); + if (yn(buf) == 'y') + d->which = firstchoice; + } + whichpm = &mons[d->which]; + } + for (i = 0; i <= multi; i++) { + if (d->monclass != MAXMCLASSES) + whichpm = mkclass(d->monclass, 0); + else if (d->randmonst) + whichpm = rndmonst(); + mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); + if (!mtmp) { + /* quit trying if creation failed and is going to repeat */ + if (d->monclass == MAXMCLASSES && !d->randmonst) + break; + /* otherwise try again */ + continue; + } + /* 'is_FOO()' ought to be called 'always_FOO()' */ + if (d->fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data)) + mtmp->female = d->fem; /* ignored for is_neuter() */ + if (d->maketame) { + (void) tamedog(mtmp, (struct obj *) 0); + } else if (d->makepeaceful || d->makehostile) { + mtmp->mtame = 0; /* sanity precaution */ + mtmp->mpeaceful = d->makepeaceful ? 1 : 0; + set_malign(mtmp); + } + if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { + struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); + + put_saddle_on_mon(otmp, mtmp); + } + if (d->invisible) + mon_set_minvis(mtmp); + if (d->sleeping) + mtmp->msleeping = 1; + madeany = TRUE; + /* in case we got a doppelganger instead of what was asked + for, make it start out looking like what was asked for */ + if (mtmp->cham != NON_PM && firstchoice != NON_PM + && mtmp->cham != firstchoice) + (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE); + } + return madeany; +} + /* * Make a new monster with the type controlled by the user. * @@ -2439,135 +2579,29 @@ struct obj *from_obj; boolean create_particular() { - char buf[BUFSZ] = DUMMY, *bufp, monclass; - char *tmpp; - int which, tryct, i, firstchoice = NON_PM; - struct permonst *whichpm = NULL; - struct monst *mtmp; - boolean madeany = FALSE, randmonst = FALSE, - maketame, makepeaceful, makehostile, saddled, invisible, - sleeping; - int fem; + char buf[BUFSZ] = DUMMY, *bufp; + int tryct = 5; + struct _create_particular_data d; - tryct = 5; do { - monclass = MAXMCLASSES; - which = urole.malenum; /* an arbitrary index into mons[] */ - maketame = makepeaceful = makehostile = FALSE; - sleeping = saddled = invisible = FALSE; - fem = -1; /* gender not specified */ getlin("Create what kind of monster? [type the name or symbol]", buf); bufp = mungspaces(buf); if (*bufp == '\033') return FALSE; - if ((tmpp = strstri(bufp, "saddled ")) != 0) { - saddled = TRUE; - (void) memset(tmpp, ' ', sizeof "saddled " - 1); - } - if ((tmpp = strstri(bufp, "sleeping ")) != 0) { - sleeping = TRUE; - (void) memset(tmpp, ' ', sizeof "sleeping " - 1); - } - if ((tmpp = strstri(bufp, "invisible ")) != 0) { - invisible = TRUE; - (void) memset(tmpp, ' ', sizeof "invisible " - 1); - } - /* check "female" before "male" to avoid false hit mid-word */ - if ((tmpp = strstri(bufp, "female ")) != 0) { - fem = 1; - (void) memset(tmpp, ' ', sizeof "female " - 1); - } - if ((tmpp = strstri(bufp, "male ")) != 0) { - fem = 0; - (void) memset(tmpp, ' ', sizeof "male " - 1); - } - bufp = mungspaces(bufp); /* after potential memset(' ') */ - /* allow the initial disposition to be specified */ - if (!strncmpi(bufp, "tame ", 5)) { - bufp += 5; - maketame = TRUE; - } else if (!strncmpi(bufp, "peaceful ", 9)) { - bufp += 9; - makepeaceful = TRUE; - } else if (!strncmpi(bufp, "hostile ", 8)) { - bufp += 8; - makehostile = TRUE; - } - /* decide whether a valid monster was chosen */ - if (wizard && (!strcmp(bufp, "*") || !strcmp(bufp, "random"))) { - randmonst = TRUE; + + if (create_particular_parse(bufp, &d)) break; - } - which = name_to_mon(bufp); - if (which >= LOW_PM) - break; /* got one */ - monclass = name_to_monclass(bufp, &which); - if (which >= LOW_PM) { - monclass = MAXMCLASSES; /* matters below */ - break; - } else if (monclass > 0) { - which = urole.malenum; /* reset from NON_PM */ - break; - } + /* no good; try again... */ pline("I've never heard of such monsters."); } while (--tryct > 0); - if (!tryct) { + if (!tryct) pline1(thats_enough_tries); - } else { - if (!randmonst) { - firstchoice = which; - if (cant_revive(&which, FALSE, (struct obj *) 0)) { - /* wizard mode can override handling of special monsters */ - Sprintf(buf, "Creating %s instead; force %s?", - mons[which].mname, mons[firstchoice].mname); - if (yn(buf) == 'y') - which = firstchoice; - } - whichpm = &mons[which]; - } - for (i = 0; i <= multi; i++) { - if (monclass != MAXMCLASSES) - whichpm = mkclass(monclass, 0); - else if (randmonst) - whichpm = rndmonst(); - mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); - if (!mtmp) { - /* quit trying if creation failed and is going to repeat */ - if (monclass == MAXMCLASSES && !randmonst) - break; - /* otherwise try again */ - continue; - } - /* 'is_FOO()' ought to be called 'always_FOO()' */ - if (fem != -1 && !is_male(mtmp->data) && !is_female(mtmp->data)) - mtmp->female = fem; /* ignored for is_neuter() */ - if (maketame) { - (void) tamedog(mtmp, (struct obj *) 0); - } else if (makepeaceful || makehostile) { - mtmp->mtame = 0; /* sanity precaution */ - mtmp->mpeaceful = makepeaceful ? 1 : 0; - set_malign(mtmp); - } - if (saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { - struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); + else + return create_particular_creation(&d); - put_saddle_on_mon(otmp, mtmp); - } - if (invisible) - mon_set_minvis(mtmp); - if (sleeping) - mtmp->msleeping = 1; - madeany = TRUE; - /* in case we got a doppelganger instead of what was asked - for, make it start out looking like what was asked for */ - if (mtmp->cham != NON_PM && firstchoice != NON_PM - && mtmp->cham != firstchoice) - (void) newcham(mtmp, &mons[firstchoice], FALSE, FALSE); - } - } - return madeany; + return FALSE; } /*read.c*/ From 9457fde9fc4617ba1ee3c40477f09cdee06094b5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 29 Aug 2018 19:39:30 +0300 Subject: [PATCH 09/12] Document windowcolors option --- doc/Guidebook.mn | 17 ++++++++++++++++- doc/Guidebook.tex | 20 +++++++++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 49a854c07..e363527ef 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -3280,7 +3280,22 @@ If NetHack can, it should display this number of messages at a time in the message window. .lp windowcolors If NetHack can, it should display windows with the specified -foreground/background colors if it can. +foreground/background colors. Windows GUI only. The format is +.si +.lp "OPTION=windowcolors:wintype foreground/background" +.ei +.pg +where wintype is one of "menu", "message", "status", or "text", and +foreground and background are colors, either a hexadecimal \'#rrggbb', +one of the named colors (black, red, green, brown, +blue, magenta, cyan, orange, brightgreen, yellow, brightblue, +brightmagenta, brightcyan, white, trueblack, gray, purple, +silver, maroon, fuchsia, lime, olive, navy, teal, aqua), +or one of Windows UI colors (activeborder, activecaption, +appworkspace, background, btnface, btnshadow, btntext, +captiontext, graytext, greytext, highlight, highlighttext, +inactiveborder, inactivecaption, menu, menutext, scrollbar, +window, windowframe, windowtext). .lp wraptext If NetHack can, it should wrap long lines of text if they don't fit in the visible area of the window. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index e9a805e25..895dfe1ad 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3850,7 +3850,25 @@ in the message window. %.lp \item[\ib{windowcolors}] If {\it NetHack\/} can, it should display windows with the specified -foreground/background colors if it can. +foreground/background colors. Windows GUI only. The format is +\begin{verbatim} + OPTION=windowcolors:wintype foreground/background +\end{verbatim} + +%.pg +where wintype is one of {\it menu}, {\it message}, {\it status}, or {\it text}, and +foreground and background are colors, either a hexadecimal {\it \#rrggbb}, +one of the named colors ({\it black}, {\it red}, {\it green}, {\it brown}, +{\it blue}, {\it magenta}, {\it cyan}, {\it orange}, +{\it brightgreen}, {\it yellow}, {\it brightblue}, {\it brightmagenta}, +{\it brightcyan}, {\it white}, {\it trueblack}, {\it gray}, {\it purple}, +{\it silver}, {\it maroon}, {\it fuchsia}, {\it lime}, {\it olive}, +{\it navy}, {\it teal}, {\it aqua}), or one of Windows UI colors ({\it activeborder}, +{\it activecaption}, {\it appworkspace}, {\it background}, {\it btnface}, {\it btnshadow}, +{\it btntext}, {\it captiontext}, {\it graytext}, {\it greytext}, {\it highlight}, +{\it highlighttext}, {\it inactiveborder}, {\it inactivecaption}, {\it menu}, +{\it menutext}, {\it scrollbar}, {\it window}, {\it windowframe}, {\it windowtext}). + %.lp \item[\ib{wraptext}] If {\it NetHack\/} can, it should wrap long lines of text if they don't fit From f1d0636ba081c1f8052eaa87e9ca4ff85ad59ac9 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 29 Aug 2018 19:19:49 -0700 Subject: [PATCH 10/12] fix wiz identify bugs Fixes #124 Fix github pull request #124 which was also reported directly (but not through the contact form so #Hxxx number). Using ^I or #wizidentify displays inventory with everything ID'd for that command only and adds a menu entry "_ - use '^I' to identify" that can be chosen to make those ID's persistent. Picking underscore would work but picking the alternate '^I' wouldn't work if the platform had unsigned characters for plain 'char'. Switch the return value from magic number -1 to magic number ^I which isn't a valid inventory letter and isn't subject to sign conversion. Casting -1 to '(char) -1' would have worked too despite some confusion expressed in discussion of the pull request. If ^I has been bound to some other command and #wizidentify hasn't been bound to any keystroke, temporary ID didn't disclose any extra information (ie, acted like ordinary inventory display) and the extra menu entry to make temporary ID become persistent wasn't available. This fixes that too. --- doc/fixes36.2 | 4 ++++ src/cmd.c | 44 +++++++++++++++++++++++++++----------------- src/end.c | 2 +- src/invent.c | 14 ++++++++++++-- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 0d95c8fde..576701c53 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -100,6 +100,10 @@ parchment and vellum are made from animal skin so change material composition and color for spellbooks with those descriptions from paper to leather; eating those books now breaks vegetarian conduct fix monsters not wielding digging implements +wizard mode ^I^I didn't make temporary identifications become persistent if + the build configuration makes plain 'char' unsigned +wizard mode #wizidentify didn't disclose extra information for unID'd items if + key bindings took away ^I and didn't bind #wizidentify to another key Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/cmd.c b/src/cmd.c index d7303ec18..3afa198b0 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -7,6 +7,22 @@ #include "lev.h" #include "func_tab.h" +/* Macros for meta and ctrl modifiers: + * M and C return the meta/ctrl code for the given character; + * e.g., (C('c') is ctrl-c + */ +#ifndef M +#ifndef NHSTDC +#define M(c) (0x80 | (c)) +#else +#define M(c) ((c) - 128) +#endif /* NHSTDC */ +#endif + +#ifndef C +#define C(c) (0x1f & (c)) +#endif + #ifdef ALTMETA STATIC_VAR boolean alt_esc = FALSE; #endif @@ -625,8 +641,18 @@ wiz_identify(VOID_ARGS) { if (wizard) { iflags.override_ID = (int) cmd_from_func(wiz_identify); - if (display_inventory((char *) 0, TRUE) == -1) + /* command remapping might leave #wizidentify as the only way + to invoke us, in which case cmd_from_func() will yield NUL; + it won't matter to display_inventory()/display_pickinv() + if ^I invokes some other command--what matters is that it + is never an inventory letter */ + if (!iflags.override_ID) + iflags.override_ID = C('I'); + /* C('I') == ^I == default keystroke for wiz_identify; + it doesn't matter whether the command has been remapped */ + if (display_inventory((char *) 0, TRUE) == C('I')) identify_pack(0, FALSE); + /* [TODO? if player picks a specific inventory item, ID it] */ iflags.override_ID = 0; } else pline("Unavailable command '%s'.", @@ -2859,22 +2885,6 @@ int final; en_win = WIN_ERR; } -/* Macros for meta and ctrl modifiers: - * M and C return the meta/ctrl code for the given character; - * e.g., (C('c') is ctrl-c - */ -#ifndef M -#ifndef NHSTDC -#define M(c) (0x80 | (c)) -#else -#define M(c) ((c) - 128) -#endif /* NHSTDC */ -#endif - -#ifndef C -#define C(c) (0x1f & (c)) -#endif - /* ordered by command name */ struct ext_func_tab extcmdlist[] = { { '#', "#", "perform an extended command", diff --git a/src/end.c b/src/end.c index 589733078..4d176323b 100644 --- a/src/end.c +++ b/src/end.c @@ -748,7 +748,7 @@ time_t when; /* date+time at end of game */ dump_plines(); putstr(0, 0, ""); putstr(0, 0, "Inventory:"); - display_inventory((char *) 0, TRUE); + (void) display_inventory((char *) 0, TRUE); container_contents(invent, TRUE, TRUE, FALSE); enlightenment((BASICENLIGHTENMENT | MAGICENLIGHTENMENT), (how >= PANICKED) ? ENL_GAMEOVERALIVE : ENL_GAMEOVERDEAD); diff --git a/src/invent.c b/src/invent.c index 9ea974698..6355a255a 100644 --- a/src/invent.c +++ b/src/invent.c @@ -5,6 +5,10 @@ #include "hack.h" +#ifndef C /* same as cmd.c */ +#define C(c) (0x1f & (c)) +#endif + #define NOINVSYM '#' #define CONTAINED_SYM '>' /* designator for inside a container */ #define HANDS_SYM '-' @@ -2580,9 +2584,15 @@ long *out_cnt; if (wizard && iflags.override_ID) { char prompt[QBUFSZ]; - any.a_char = -1; + /* C('I') == ^I == default keystroke for wiz_identify; + it is guaranteed not to be in use as an inventory letter + (wiz_identify might be remapped to an ordinary letter, + making iflags.override_ID ambiguous as a return value) */ + any.a_char = C('I'); /* wiz_identify stuffed the wiz_identify command character (^I) - into iflags.override_ID for our use as an accelerator */ + into iflags.override_ID for our use as an accelerator; + it could be ambiguous as a selector but the only time it + is wanted is in case where no item is being selected */ Sprintf(prompt, "Debug Identify (%s to permanently identify)", visctrl(iflags.override_ID)); add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, From d2eba695c858347ea09fca8047db8e6779861d6d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 30 Aug 2018 20:05:18 +0300 Subject: [PATCH 11/12] Use DEADMONSTER instead of checking mhp --- src/apply.c | 2 +- src/dogmove.c | 6 +++--- src/dokick.c | 8 ++++---- src/eat.c | 4 ++-- src/explode.c | 4 ++-- src/makemon.c | 2 +- src/mhitm.c | 36 ++++++++++++++++++------------------ src/mhitu.c | 12 ++++++------ src/mkobj.c | 2 +- src/mon.c | 28 ++++++++++++++-------------- src/monmove.c | 10 +++++----- src/mthrowu.c | 8 ++++---- src/muse.c | 18 +++++++++--------- src/music.c | 4 ++-- src/polyself.c | 4 ++-- src/potion.c | 8 ++++---- src/read.c | 2 +- src/region.c | 6 +++--- src/steal.c | 2 +- src/steed.c | 4 ++-- src/trap.c | 24 ++++++++++++------------ src/uhitm.c | 34 +++++++++++++++++----------------- src/vault.c | 6 +++--- src/zap.c | 16 ++++++++-------- 24 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/apply.c b/src/apply.c index d8cbb7a87..d7b770f4d 100644 --- a/src/apply.c +++ b/src/apply.c @@ -767,7 +767,7 @@ register xchar x, y; corpse less likely to remain tame after revival */ xkilled(mtmp, XKILL_NOMSG); /* life-saving doesn't ordinarily reset this */ - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) u.uconduct.killer = save_pacifism; } else { pline("%s is choked by the leash!", Monnam(mtmp)); diff --git a/src/dogmove.c b/src/dogmove.c index 614eef794..2ec72551e 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -326,7 +326,7 @@ boolean devour; /* turning into slime might be cureable */ if (slimer && munslime(mtmp, FALSE)) { /* but the cure (fire directed at self) might be fatal */ - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) return 2; slimer = FALSE; /* sliming is avoided, skip polymorph */ } @@ -370,7 +370,7 @@ struct edog *edog; mtmp->mhpmax = newmhpmax; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) goto dog_died; if (cansee(mtmp->mx, mtmp->my)) pline("%s is confused from hunger.", Monnam(mtmp)); @@ -379,7 +379,7 @@ struct edog *edog; else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); - } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { + } else if (monstermoves > edog->hungrytime + 750 || DEADMONSTER(mtmp)) { dog_died: if (mtmp->mleashed && mtmp != u.usteed) Your("leash goes slack."); diff --git a/src/dokick.c b/src/dokick.c index 363a13894..950d03553 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -97,7 +97,7 @@ register boolean clumsy; dmg += u.udaminc; /* add ring(s) of increase damage */ if (dmg > 0) mon->mhp -= dmg; - if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) + if (!DEADMONSTER(mon) && martial() && !bigmonst(mon->data) && !rn2(3) && mon->mcanmove && mon != u.ustuck && !mon->mtrapped) { /* see if the monster has a place to move into */ mdx = mon->mx + u.dx; @@ -116,8 +116,8 @@ register boolean clumsy; } } - (void) passive(mon, uarmf, TRUE, mon->mhp > 0, AT_KICK, FALSE); - if (mon->mhp <= 0 && !trapkilled) + (void) passive(mon, uarmf, TRUE, !DEADMONSTER(mon), AT_KICK, FALSE); + if (DEADMONSTER(mon) && !trapkilled) killed(mon); /* may bring up a dialog, so put this after all messages */ @@ -914,7 +914,7 @@ dokick() kick_monster(mtmp, x, y); glyph = glyph_at(x, y); /* see comment in attack_checks() */ - if (mtmp->mhp <= 0) { /* DEADMONSTER() */ + if (DEADMONSTER(mtmp)) { /* DEADMONSTER() */ /* if we mapped an invisible monster and immediately killed it, we don't want to forget what we thought was there before the kick */ diff --git a/src/eat.c b/src/eat.c index f398c8cc5..895cdf2a6 100644 --- a/src/eat.c +++ b/src/eat.c @@ -525,7 +525,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ if (visflag && canseemon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) { + if (!DEADMONSTER(magr)) { /* life-saved; don't continue eating the brains */ return MM_MISS; } else { @@ -612,7 +612,7 @@ int *dmg_p; /* for dishing out extra damage in lieu of Int loss */ return MM_MISS; } else if (is_rider(pd)) { mondied(magr); - if (magr->mhp <= 0) + if (DEADMONSTER(magr)) result = MM_AGR_DIED; /* Rider takes extra damage regardless of whether attacker dies */ *dmg_p += xtra_dmg; diff --git a/src/explode.c b/src/explode.c index fcda5f956..c48f9ffb1 100644 --- a/src/explode.c +++ b/src/explode.c @@ -208,7 +208,7 @@ int expltype; if (!mtmp && i + x - 1 == u.ux && j + y - 1 == u.uy) mtmp = u.usteed; if (mtmp) { - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) explmask[i][j] = 2; else switch (adtyp) { @@ -444,7 +444,7 @@ int expltype; mtmp->mhp -= mdam; mtmp->mhp -= (idamres + idamnonres); } - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { int xkflg = ((adtyp == AD_FIRE && completelyburns(mtmp->data)) ? XKILL_NOCORPSE : 0); diff --git a/src/makemon.c b/src/makemon.c index a40121e0a..0ba833def 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1751,7 +1751,7 @@ struct monst *mtmp, *victim; /* monster died after killing enemy but before calling this function */ /* currently possible if killing a gas spore */ - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) return (struct permonst *) 0; /* note: none of the monsters with special hit point calculations diff --git a/src/mhitm.c b/src/mhitm.c index 44a7ecc32..3b0f11855 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -247,7 +247,7 @@ boolean quietly; if (!quietly && canspotmon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -633,7 +633,7 @@ struct attack *mattk; if (canseemon(magr)) pline("%s is turned to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_MISS; return MM_AGR_DIED; } @@ -782,7 +782,7 @@ struct attack *mattk; /* Kill off aggressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { mondead(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return result; /* life saved */ result |= MM_AGR_DIED; } @@ -826,7 +826,7 @@ register struct attack *mattk; if (vis && canspotmon(magr)) pline("%s turns to stone!", Monnam(magr)); monstone(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return MM_HIT; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -850,7 +850,7 @@ register struct attack *mattk; ? "coughs spasmodically and collapses" : "vomits violently and drops dead"); mondied(magr); - if (magr->mhp > 0) + if (!DEADMONSTER(magr)) return 0; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "queasy"); @@ -864,7 +864,7 @@ register struct attack *mattk; m_useup(mdef, obj); /* Is a corpse for nutrition possible? It may kill magr */ - if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1) + if (!corpse_chance(mdef, magr, TRUE) || DEADMONSTER(magr)) break; /* Pets get nutrition from swallowing monster whole. @@ -924,7 +924,7 @@ register struct attack *mattk; tmp = 1; if (otmp->oartifact) { (void) artifact_hit(magr, mdef, otmp, &tmp, dieroll); - if (mdef->mhp <= 0) + if (DEADMONSTER(mdef)) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); } @@ -951,7 +951,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s burns completely!", Monnam(mdef)); mondead(mdef); /* was mondied() but that dropped paper scrolls */ - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s roast in peace.", mon_nam(mdef)); @@ -1029,7 +1029,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s rust in peace.", mon_nam(mdef)); @@ -1053,7 +1053,7 @@ register struct attack *mattk; if (vis && canseemon(mdef)) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) pline("May %s rot in peace.", mon_nam(mdef)); @@ -1080,7 +1080,7 @@ register struct attack *mattk; pline("%s turns to stone!", Monnam(mdef)); monstone(mdef); post_stone: - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "peculiarly sad"); @@ -1184,7 +1184,7 @@ register struct attack *mattk; pline("%s is destroyed!", Monnam(mdef)); } mondied(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "strangely sad"); @@ -1280,7 +1280,7 @@ register struct attack *mattk; possibly_unwield(mdef, FALSE); mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *) 0, FALSE); - if (mdef->mhp <= 0) + if (DEADMONSTER(mdef)) return (MM_DEF_DIED | (grow_up(magr, mdef) ? 0 : MM_AGR_DIED)); if (pa->mlet == S_NYMPH && !tele_restrict(magr)) { @@ -1343,7 +1343,7 @@ register struct attack *mattk; if (cancelled) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { - if (!munslime(mdef, FALSE) && mdef->mhp > 0) { + if (!munslime(mdef, FALSE) && !DEADMONSTER(mdef)) { if (newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis && canseemon(mdef))) pd = mdef->data; mdef->mstrategy &= ~STRAT_WAITFORU; @@ -1351,9 +1351,9 @@ register struct attack *mattk; } /* munslime attempt could have been fatal, potentially to multiple monsters (SCR_FIRE) */ - if (magr->mhp < 1) + if (DEADMONSTER(magr)) res |= MM_AGR_DIED; - if (mdef->mhp < 1) + if (DEADMONSTER(mdef)) res |= MM_DEF_DIED; tmp = 0; } @@ -1385,7 +1385,7 @@ register struct attack *mattk; mdef->mhp = 0; } monkilled(mdef, "", (int) mattk->adtyp); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return res; /* mdef lifesaved */ else if (res == MM_AGR_DIED) return (MM_DEF_DIED | MM_AGR_DIED); @@ -1400,7 +1400,7 @@ register struct attack *mattk; } else if (pd == &mons[PM_WRAITH]) { (void) grow_up(magr, (struct monst *) 0); /* don't grow up twice */ - return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED)); + return (MM_DEF_DIED | (!DEADMONSTER(magr) ? 0 : MM_AGR_DIED)); } else if (pd == &mons[PM_NURSE]) { magr->mhp = magr->mhpmax; } diff --git a/src/mhitu.c b/src/mhitu.c index 12a6d3212..c429a0241 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -365,7 +365,7 @@ register struct monst *mtmp; if (!ranged) nomul(0); - if (mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data))) + if (DEADMONSTER(mtmp) || (Underwater && !is_swimmer(mtmp->data))) return 0; /* If swallowed, can only be affected by u.ustuck */ @@ -1796,7 +1796,7 @@ struct attack *mattk; if (Punished) placebc(); u.ustuck = 0; - return (mtmp->mhp > 0) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? 0 : 2; } display_nhwindow(WIN_MESSAGE, FALSE); @@ -2066,7 +2066,7 @@ boolean ufound; if (kill_agr) mondead(mtmp); wake_nearto(mtmp->mx, mtmp->my, 7 * 7); - return (mtmp->mhp > 0) ? 0 : 2; + return (!DEADMONSTER(mtmp)) ? 0 : 2; } /* monster gazes at you */ @@ -2132,7 +2132,7 @@ struct attack *mattk; stoned = TRUE; killed(mtmp); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) break; return 2; } @@ -2768,7 +2768,7 @@ struct attack *mattk; pline("%s turns to stone!", Monnam(mtmp)); stoned = 1; xkilled(mtmp, XKILL_NOMSG); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return 1; return 2; } @@ -2879,7 +2879,7 @@ assess_dmg: if ((mtmp->mhp -= tmp) <= 0) { pline("%s dies!", Monnam(mtmp)); xkilled(mtmp, XKILL_NOMSG); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return 1; return 2; } diff --git a/src/mkobj.c b/src/mkobj.c index 1724cded5..cf7a77233 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -1861,7 +1861,7 @@ discard_minvent(mtmp) struct monst *mtmp; { struct obj *otmp, *mwep = MON_WEP(mtmp); - boolean keeping_mon = (mtmp->mhp > 0); + boolean keeping_mon = (!DEADMONSTER(mtmp)); while ((otmp = mtmp->minvent) != 0) { /* this has now become very similar to m_useupall()... */ diff --git a/src/mon.c b/src/mon.c index 2ccb585cb..39e777a26 100644 --- a/src/mon.c +++ b/src/mon.c @@ -509,9 +509,9 @@ register struct monst *mtmp; mtmp->mhp -= dam; if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { mondead(mtmp); - if (mtmp->mhp < 1) + if (DEADMONSTER(mtmp)) return 1; } water_damage_chain(mtmp->minvent, FALSE); @@ -538,14 +538,14 @@ register struct monst *mtmp; mondead(mtmp); } else { mtmp->mhp -= 1; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s surrenders to the fire.", Monnam(mtmp)); mondead(mtmp); } else if (cansee(mtmp->mx, mtmp->my)) pline("%s burns slightly.", Monnam(mtmp)); } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { (void) fire_damage_chain(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); (void) rloc(mtmp, FALSE); @@ -570,7 +570,7 @@ register struct monst *mtmp; Monnam(mtmp), hliquid("water")); } mondead(mtmp); - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { water_damage_chain(mtmp->minvent, FALSE); (void) rloc(mtmp, FALSE); return 0; @@ -708,7 +708,7 @@ movemon() nmtmp = mtmp->nmon; /* one dead monster needs to perform a move after death: vault guard whose temporary corridor is still on the map */ - if (mtmp->isgd && !mtmp->mx && mtmp->mhp <= 0) + if (mtmp->isgd && !mtmp->mx && DEADMONSTER(mtmp)) (void) gd_move(mtmp); if (DEADMONSTER(mtmp)) continue; @@ -1536,7 +1536,7 @@ dmonsfree() for (mtmp = &fmon; *mtmp;) { freetmp = *mtmp; - if (freetmp->mhp <= 0 && !freetmp->isgd) { + if (DEADMONSTER(freetmp) && !freetmp->isgd) { *mtmp = freetmp->nmon; freetmp->nmon = NULL; dealloc_monst(freetmp); @@ -1825,7 +1825,7 @@ register struct monst *mtmp; mtmp->mhp = 0; /* in case caller hasn't done this */ lifesaved_monster(mtmp); - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) return; if (is_vampshifter(mtmp)) { @@ -1993,9 +1993,9 @@ boolean was_swallowed; /* digestion */ } else { You_hear("an explosion."); magr->mhp -= tmp; - if (magr->mhp < 1) + if (DEADMONSTER(magr)) mondied(magr); - if (magr->mhp < 1) { /* maybe lifesaved */ + if (DEADMONSTER(magr)) { /* maybe lifesaved */ if (canspotmon(magr)) pline("%s rips open!", Monnam(magr)); } else if (canseemon(magr)) @@ -2033,7 +2033,7 @@ mondied(mdef) register struct monst *mdef; { mondead(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return; /* lifesaved */ if (corpse_chance(mdef, (struct monst *) 0, FALSE) @@ -2083,7 +2083,7 @@ struct monst *mdef; */ mdef->mhp = 0; /* in case caller hasn't done this */ lifesaved_monster(mdef); - if (mdef->mhp > 0) + if (!DEADMONSTER(mdef)) return; mdef->mtrapped = 0; /* (see m_detach) */ @@ -2176,7 +2176,7 @@ int how; else mondied(mdef); - if (be_sad && mdef->mhp <= 0) + if (be_sad && DEADMONSTER(mdef)) You("have a sad feeling for a moment, then it passes."); } @@ -2276,7 +2276,7 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ mondead(mtmp); disintegested = FALSE; /* reset */ - if (mtmp->mhp > 0) { /* monster lifesaved */ + if (!DEADMONSTER(mtmp)) { /* monster lifesaved */ /* Cannot put the non-visible lifesaving message in * lifesaved_monster() since the message appears only when _you_ * kill it (as opposed to visible lifesaving which always appears). diff --git a/src/monmove.c b/src/monmove.c index 99efdbbbf..0abf63b6d 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -31,9 +31,9 @@ struct monst *mtmp; wake_nearto(mtmp->mx, mtmp->my, 7 * 7); mtmp->mstun = 1; mtmp->mhp -= rnd(15); - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { mondied(mtmp); - if (mtmp->mhp > 0) /* lifesaved */ + if (!DEADMONSTER(mtmp)) /* lifesaved */ return FALSE; else return TRUE; @@ -413,7 +413,7 @@ register struct monst *mtmp; m_respond(mtmp); if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) m_respond(mtmp); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) return 1; /* m_respond gaze can kill medusa */ /* fleeing monsters might regain courage */ @@ -518,7 +518,7 @@ register struct monst *mtmp; if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); m2->mhp -= rnd(15); - if (m2->mhp <= 0) + if (DEADMONSTER(m2)) monkilled(m2, "", AD_DRIN); else m2->msleeping = 0; @@ -590,7 +590,7 @@ toofar: case 0: /* no movement, but it can still attack you */ case 3: /* absolutely no movement */ /* vault guard might have vanished */ - if (mtmp->isgd && (mtmp->mhp < 1 || mtmp->mx == 0)) + if (mtmp->isgd && (DEADMONSTER(mtmp) || mtmp->mx == 0)) return 1; /* behave as if it died */ /* During hallucination, monster appearance should * still change - even if it doesn't move. diff --git a/src/mthrowu.c b/src/mthrowu.c index ed5dec975..e2ec346aa 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -285,7 +285,7 @@ struct obj *otmp, *mwep; if mtmp gets killed (shot kills adjacent gas spore and triggers explosion, perhaps), inventory will be dropped and otmp might go away via merging into another stack */ - if (mtmp->mhp <= 0 && m_shot.i < m_shot.n) + if (DEADMONSTER(mtmp) && m_shot.i < m_shot.n) /* cancel pending shots (perhaps ought to give a message here since we gave one above about throwing/shooting N missiles) */ break; /* endmultishot(FALSE); */ @@ -404,9 +404,9 @@ boolean verbose; /* give message(s) even when you can't see what happened */ damage = 0; } - if (mtmp->mhp > 0) { /* might already be dead (if petrified) */ + if (!DEADMONSTER(mtmp)) { /* might already be dead (if petrified) */ mtmp->mhp -= damage; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (vis || (verbose && !target)) pline("%s is %s!", Monnam(mtmp), (nonliving(mtmp->data) || is_vampshifter(mtmp) @@ -422,7 +422,7 @@ boolean verbose; /* give message(s) even when you can't see what happened */ /* blinding venom and cream pie do 0 damage, but verify that the target is still alive anyway */ - if (mtmp->mhp > 0 + if (!DEADMONSTER(mtmp) && can_blnd((struct monst *) 0, mtmp, (uchar) ((otmp->otyp == BLINDING_VENOM) ? AT_SPIT : AT_WEAP), diff --git a/src/muse.c b/src/muse.c index 402f7250f..e0403003b 100644 --- a/src/muse.c +++ b/src/muse.c @@ -155,7 +155,7 @@ struct obj *obj; } m_useup(mon, obj); mon->mhp -= dam; - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { monkilled(mon, "", AD_RBRE); return 1; } @@ -1273,7 +1273,7 @@ register struct obj *otmp; break; } if (reveal_invis) { - if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) + if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } @@ -1406,7 +1406,7 @@ struct monst *mtmp; (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; case MUSE_FIRE_HORN: case MUSE_FROST_HORN: if (oseen) { @@ -1420,7 +1420,7 @@ struct monst *mtmp; rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my)); m_using = FALSE; - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; case MUSE_WAN_TELEPORTATION: case MUSE_WAN_STRIKING: zap_oseen = oseen; @@ -1473,7 +1473,7 @@ struct monst *mtmp; drop_boulder_on_player(confused, !is_cursed, FALSE, TRUE); } - return (mtmp->mhp <= 0) ? 1 : 2; + return (DEADMONSTER(mtmp)) ? 1 : 2; } #if 0 case MUSE_SCR_FIRE: { @@ -1513,7 +1513,7 @@ struct monst *mtmp; mtmp2->mhp -= num; if (resists_cold(mtmp2)) mtmp2->mhp -= 3 * num; - if (mtmp2->mhp < 1) { + if (DEADMONSTER(mtmp2)) { mondied(mtmp2); break; } @@ -2260,7 +2260,7 @@ boolean stoning; /* True: stop petrification, False: cure stun && confusion */ mon->mhp -= rnd(15); if (vis) pline("%s has a very bad case of stomach acid.", Monnam(mon)); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { pline("%s dies!", Monnam(mon)); if (by_you) /* hero gets credit (experience) and blame (possible loss @@ -2502,7 +2502,7 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */ for fire breath, dmg is going to be 0 (fire breathers are immune to fire damage) but for wand of fire or fire horn, 'mon' could have taken damage so might die */ - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { if (by_you) { /* mon killed self but hero gets credit and blame (except for pacifist conduct); xkilled()'s message would say @@ -2520,7 +2520,7 @@ boolean by_you; /* true: if mon kills itself, hero gets credit/blame */ } } if (vis) { - if (res && mon->mhp > 0) + if (res && !DEADMONSTER(mon)) pline("%s slime is burned away!", s_suffix(Monnam(mon))); if (otyp != STRANGE_OBJECT) makeknown(otyp); diff --git a/src/music.c b/src/music.c index 071d33635..24e1c559e 100644 --- a/src/music.c +++ b/src/music.c @@ -354,9 +354,9 @@ int force; /* Falling is okay for falling down within a pit from jostling too */ mselftouch(mtmp, "Falling, ", TRUE); - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { mtmp->mhp -= rnd(m_already_trapped ? 4 : 6); - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (!cansee(x, y)) { pline("It is destroyed!"); } else { diff --git a/src/polyself.c b/src/polyself.c index 5111ec41e..c7f9c538d 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1355,7 +1355,7 @@ dogaze() (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); if (dmg) mtmp->mhp -= dmg; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } /* For consistency with passive() in uhitm.c, this only @@ -1517,7 +1517,7 @@ domindblast() u_sen ? "telepathy" : telepathic(mtmp->data) ? "latent telepathy" : "mind"); mtmp->mhp -= rnd(15); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } } diff --git a/src/potion.c b/src/potion.c index d90beb898..6904bc315 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1464,7 +1464,7 @@ int how; wake_nearto(tx, ty, mon->data->mlevel * 10); mon->mhp -= d(2, 6); /* should only be by you */ - if (mon->mhp < 1) + if (DEADMONSTER(mon)) killed(mon); else if (is_were(mon->data) && !is_human(mon->data)) new_were(mon); /* revert to human */ @@ -1487,7 +1487,7 @@ int how; pline("%s rusts.", Monnam(mon)); mon->mhp -= d(1, 6); /* should only be by you */ - if (mon->mhp < 1) + if (DEADMONSTER(mon)) killed(mon); } break; @@ -1502,7 +1502,7 @@ int how; if (!is_silent(mon->data)) wake_nearto(tx, ty, mon->data->mlevel * 10); mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); - if (mon->mhp < 1) { + if (DEADMONSTER(mon)) { if (your_fault) killed(mon); else @@ -1523,7 +1523,7 @@ int how; */ } /* target might have been killed */ - if (mon->mhp > 0) { + if (!DEADMONSTER(mon)) { if (angermon) wakeup(mon, TRUE); else diff --git a/src/read.c b/src/read.c index bedf5172a..c4cf716e9 100644 --- a/src/read.c +++ b/src/read.c @@ -1814,7 +1814,7 @@ boolean confused, byu; } } mtmp->mhp -= mdmg; - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (byu) { killed(mtmp); } else { diff --git a/src/region.c b/src/region.c index d91b9fa39..258dab98a 100644 --- a/src/region.c +++ b/src/region.c @@ -408,7 +408,7 @@ run_regions() struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); - if (!mtmp || mtmp->mhp <= 0 + if (!mtmp || DEADMONSTER(mtmp) || (*callbacks[f_indx])(regions[i], mtmp)) { /* The monster died, remove it from list */ k = (regions[i]->n_monst -= 1); @@ -989,12 +989,12 @@ genericptr_t p2; if (resists_poison(mtmp)) return FALSE; mtmp->mhp -= rnd(dam) + 5; - if (mtmp->mhp <= 0) { + if (DEADMONSTER(mtmp)) { if (heros_fault(reg)) killed(mtmp); else monkilled(mtmp, "gas cloud", AD_DRST); - if (mtmp->mhp <= 0) { /* not lifesaved */ + if (DEADMONSTER(mtmp)) { /* not lifesaved */ return TRUE; } } diff --git a/src/steal.c b/src/steal.c index 1c30b7733..2f746ce6e 100644 --- a/src/steal.c +++ b/src/steal.c @@ -645,7 +645,7 @@ boolean verbosely; if (obj->owornmask) { /* perform worn item handling if the monster is still alive */ - if (mon->mhp > 0) { + if (!DEADMONSTER(mon)) { mon->misc_worn_check &= ~obj->owornmask; update_mon = TRUE; diff --git a/src/steed.c b/src/steed.c index 0fc14296c..aa2beb300 100644 --- a/src/steed.c +++ b/src/steed.c @@ -551,7 +551,7 @@ int reason; /* Player was thrown off etc. */ (void) rloc(mtmp, FALSE); return; } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { place_monster(mtmp, u.ux, u.uy); if (!u.uswallow && !u.ustuck && have_spot) { struct permonst *mdat = mtmp->data; @@ -594,7 +594,7 @@ int reason; /* Player was thrown off etc. */ * falling into the hole). */ /* [ALI] No need to move the player if the steed died. */ - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { /* Keep steed here, move the player to cc; * teleds() clears u.utrap */ diff --git a/src/trap.c b/src/trap.c index 1c106890b..6e7e3ed78 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1568,7 +1568,7 @@ struct obj *otmp; break; case PIT: case SPIKED_PIT: - trapkilled = (steed->mhp <= 0 + trapkilled = (DEADMONSTER(steed) || thitm(0, steed, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)); steedhit = TRUE; @@ -2311,7 +2311,7 @@ register struct monst *mtmp; else if (mtmp->mtame) pline("May %s rust in peace.", mon_nam(mtmp)); mondied(mtmp); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { (void) split_mon(mtmp, (struct monst *) 0); @@ -2408,7 +2408,7 @@ register struct monst *mtmp; seetrap(trap); } mselftouch(mtmp, "Falling, ", FALSE); - if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *) 0, + if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; break; @@ -2555,13 +2555,13 @@ register struct monst *mtmp; if (in_sight) seetrap(trap); mtmp->mhp -= dmgval2; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) monkilled(mtmp, in_sight ? "compression from an anti-magic field" : (const char *) 0, -AD_MAGM); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; if (see_it) newsym(trap->tx, trap->ty); @@ -2596,7 +2596,7 @@ register struct monst *mtmp; blow_up_landmine(trap); /* explosion might have destroyed a drawbridge; don't dish out more damage if monster is already dead */ - if (mtmp->mhp <= 0 + if (DEADMONSTER(mtmp) || thitm(0, mtmp, (struct obj *) 0, rnd(16), FALSE)) { trapkilled = TRUE; } else { @@ -2606,7 +2606,7 @@ register struct monst *mtmp; } /* a boulder may fill the new pit, crushing monster */ fill_pit(trap->tx, trap->ty); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; if (unconscious()) { multi = -1; @@ -2636,7 +2636,7 @@ register struct monst *mtmp; trap->launch2.x, trap->launch2.y, style)) { if (in_sight) trap->tseen = TRUE; - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) trapkilled = TRUE; } else { deltrap(trap); @@ -2753,7 +2753,7 @@ boolean byplayer; } minstapetrify(mon, byplayer); /* if life-saved, might not be able to continue wielding */ - if (mon->mhp > 0 && !which_armor(mon, W_ARMG) && !resists_ston(mon)) + if (!DEADMONSTER(mon) && !which_armor(mon, W_ARMG) && !resists_ston(mon)) mwepgone(mon); } } @@ -3976,7 +3976,7 @@ boolean force_failure; if (mtmp->mtame) abuse_dog(mtmp); mtmp->mhp -= rnd(4); - if (mtmp->mhp <= 0) + if (DEADMONSTER(mtmp)) killed(mtmp); } else if (ttype == WEB) { if (!webmaker(youmonst.data)) { @@ -5063,11 +5063,11 @@ boolean nocorpse; dam = 1; } mon->mhp -= dam; - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { int xx = mon->mx, yy = mon->my; monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { newsym(xx, yy); trapkilled = TRUE; } diff --git a/src/uhitm.c b/src/uhitm.c index 9de48c971..0e482d6ec 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -429,7 +429,7 @@ atk_done: * and it returned 0 (it's okay to attack), and the monster didn't * evade. */ - if (context.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) + if (context.forcefight && !DEADMONSTER(mtmp) && !canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux + u.dx][u.uy + u.dy].glyph) && !(u.uswallow && mtmp == u.ustuck)) map_invisible(u.ux + u.dx, u.uy + u.dy); @@ -792,7 +792,7 @@ int dieroll; if (obj->oartifact && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) { - if (mon->mhp <= 0) /* artifact killed monster */ + if (DEADMONSTER(mon)) /* artifact killed monster */ return FALSE; if (tmp == 0) return TRUE; @@ -835,7 +835,7 @@ int dieroll; freeinv(obj); potionhit(mon, obj, hand_to_hand ? POTHIT_HERO_BASH : POTHIT_HERO_THROW); - if (mon->mhp <= 0) + if (DEADMONSTER(mon)) return FALSE; /* killed */ hittxt = TRUE; /* in case potion effect causes transformation */ @@ -884,7 +884,7 @@ int dieroll; if (resists_ston(mon)) break; /* note: hp may be <= 0 even if munstoned==TRUE */ - return (boolean) (mon->mhp > 0); + return (boolean) (!DEADMONSTER(mon)); #if 0 } else if (touch_petrifies(mdat)) { ; /* maybe turn the corpse into a statue? */ @@ -933,7 +933,7 @@ int dieroll; minstapetrify(mon, TRUE); if (resists_ston(mon)) break; - return (boolean) (mon->mhp > 0); + return (boolean) (!DEADMONSTER(mon)); } else { /* ordinary egg(s) */ const char *eggp = (obj->corpsenm != NON_PM && obj->known) @@ -1176,7 +1176,7 @@ int dieroll; a level draining artifact has already done to max HP */ if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; - if (mon->mhp < 1) + if (DEADMONSTER(mon)) destroyed = TRUE; if (mon->mtame && tmp > 0) { /* do this even if the pet is being killed (affects revival) */ @@ -1501,7 +1501,7 @@ struct attack *mattk; possibly_unwield(mdef, FALSE); } else if (unwornmask & W_ARMG) { /* stole worn gloves */ mselftouch(mdef, (const char *) 0, TRUE); - if (mdef->mhp <= 0) /* it's now a statue */ + if (DEADMONSTER(mdef)) /* it's now a statue */ return; /* can't continue stealing */ } @@ -1724,7 +1724,7 @@ register struct attack *mattk; mdef->mhp -= xtmp; /* !m_lev: level 0 monster is killed regardless of hit points rather than drop to level -1 */ - if (mdef->mhp <= 0 || !mdef->m_lev) { + if (DEADMONSTER(mdef) || !mdef->m_lev) { pline("%s dies!", Monnam(mdef)); xkilled(mdef, XKILL_NOMSG); } else @@ -1848,7 +1848,7 @@ register struct attack *mattk; if (negated) break; /* physical damage only */ if (!rn2(4) && !slimeproof(pd)) { - if (!munslime(mdef, TRUE) && mdef->mhp > 0) { + if (!munslime(mdef, TRUE) && !DEADMONSTER(mdef)) { /* this assumes newcham() won't fail; since hero has a slime attack, green slimes haven't been geno'd */ You("turn %s into slime.", mon_nam(mdef)); @@ -1856,7 +1856,7 @@ register struct attack *mattk; pd = mdef->data; } /* munslime attempt could have been fatal */ - if (mdef->mhp < 1) + if (DEADMONSTER(mdef)) return 2; /* skip death message */ tmp = 0; } @@ -1888,7 +1888,7 @@ register struct attack *mattk; mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ mdef->mhp -= tmp; - if (mdef->mhp < 1) { + if (DEADMONSTER(mdef)) { if (mdef->mtame && !cansee(mdef->mx, mdef->my)) { You_feel("embarrassed for a moment."); if (tmp) @@ -1940,7 +1940,7 @@ register struct attack *mattk; if (!resistance) { pline("%s gets blasted!", Monnam(mdef)); mdef->mhp -= tmp; - if (mdef->mhp <= 0) { + if (DEADMONSTER(mdef)) { killed(mdef); return 2; } @@ -2074,7 +2074,7 @@ register struct attack *mattk; several turns) but the level-gain message seems out of order if the kill message is left implicit */ xkilled(mdef, XKILL_GIVEMSG | XKILL_NOCORPSE); - if (mdef->mhp > 0) { /* monster lifesaved */ + if (!DEADMONSTER(mdef)) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", body_part(STOMACH)); } else { @@ -2183,9 +2183,9 @@ register struct attack *mattk; } end_engulf(); mdef->mhp -= dam; - if (mdef->mhp <= 0) { + if (DEADMONSTER(mdef)) { killed(mdef); - if (mdef->mhp <= 0) /* not lifesaved */ + if (DEADMONSTER(mdef)) /* not lifesaved */ return 2; } You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel", @@ -2832,7 +2832,7 @@ struct obj *otmp; /* source of flash */ : rn2(min(mtmp->mhp, 4)); light_hits_gremlin(mtmp, amt); } - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { if (!context.mon_moving) setmangry(mtmp, TRUE); if (tmp < 9 && !mtmp->isshk && rn2(4)) @@ -2854,7 +2854,7 @@ int dmg; (dmg > mon->mhp / 2) ? "wails in agony" : "cries out in pain"); mon->mhp -= dmg; wake_nearto(mon->mx, mon->my, 30); - if (mon->mhp <= 0) { + if (DEADMONSTER(mon)) { if (context.mon_moving) monkilled(mon, (char *) 0, AD_BLND); else diff --git a/src/vault.c b/src/vault.c index 0f5724925..22bf15e9c 100644 --- a/src/vault.c +++ b/src/vault.c @@ -55,9 +55,9 @@ boolean forceshow; while ((fcbeg = egrd->fcbeg) < egrd->fcend) { fcx = egrd->fakecorr[fcbeg].fx; fcy = egrd->fakecorr[fcbeg].fy; - if ((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) + if ((DEADMONSTER(grd) || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) forceshow = TRUE; - if ((u.ux == fcx && u.uy == fcy && grd->mhp > 0) + if ((u.ux == fcx && u.uy == fcy && !DEADMONSTER(grd)) || (!forceshow && couldsee(fcx, fcy)) || (Punished && !carried(uball) && uball->ox == fcx && uball->oy == fcy)) @@ -592,7 +592,7 @@ register struct monst *grd; boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ? TRUE : FALSE; - boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); + boolean disappear_msg_seen = FALSE, semi_dead = (DEADMONSTER(grd)); long umoney = money_cnt(invent); register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); boolean see_guard, newspot = FALSE; diff --git a/src/zap.c b/src/zap.c index ea0f9bee4..8c4458347 100644 --- a/src/zap.c +++ b/src/zap.c @@ -214,7 +214,7 @@ struct obj *otmp; dmg = spell_damage_bonus(dmg); context.bypasses = TRUE; /* for make_corpse() */ if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { - if (mtmp->mhp > 0) + if (!DEADMONSTER(mtmp)) monflee(mtmp, 0, FALSE, TRUE); } } @@ -412,11 +412,11 @@ struct obj *otmp; dmg = spell_damage_bonus(dmg); if (resists_drli(mtmp)) { shieldeff(mtmp->mx, mtmp->my); - } else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && mtmp->mhp > 0) { + } else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && !DEADMONSTER(mtmp)) { mtmp->mhp -= dmg; mtmp->mhpmax -= dmg; /* die if already level 0, regardless of hit points */ - if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) { + if (DEADMONSTER(mtmp) || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) { killed(mtmp); } else { mtmp->m_lev--; @@ -433,7 +433,7 @@ struct obj *otmp; break; } if (wake) { - if (mtmp->mhp > 0) { + if (!DEADMONSTER(mtmp)) { wakeup(mtmp, helpful_gesture ? FALSE : TRUE); m_respond(mtmp); if (mtmp->isshk && !*u.ushops) @@ -446,7 +446,7 @@ struct obj *otmp; * might be an invisible worm hit on the tail. */ if (reveal_invis) { - if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) + if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } @@ -3956,7 +3956,7 @@ boolean say; /* Announce out of sight hit/miss events if true */ /* Using disintegration from the inside only makes a hole... */ if (tmp == MAGIC_COOKIE) u.ustuck->mhp = 0; - if (u.ustuck->mhp < 1) + if (DEADMONSTER(u.ustuck)) killed(u.ustuck); return; } @@ -4044,7 +4044,7 @@ boolean say; /* Announce out of sight hit/miss events if true */ if (tmp == MAGIC_COOKIE) { /* disintegration */ disintegrate_mon(mon, type, fltxt); - } else if (mon->mhp < 1) { + } else if (DEADMONSTER(mon)) { if (type < 0) { /* mon has just been killed by another monster */ monkilled(mon, fltxt, AD_RBRE); @@ -4998,7 +4998,7 @@ int damage, tell; if (damage) { mtmp->mhp -= damage; - if (mtmp->mhp < 1) { + if (DEADMONSTER(mtmp)) { if (m_using) monkilled(mtmp, "", AD_RBRE); else From 111cfa0ff46181bb785cc5a989ffbabef316b06d Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 30 Aug 2018 15:42:06 -0700 Subject: [PATCH 12/12] Guidebook update I noticed that the description of ^O still referred to the 3.6.0 behavior (either #wizwhere or #overview depending upon play mode) rather than the 3.6.1 behavior (unconditional #overview). While updating that I changed a bunch of "Wizard-mode" references to "Debug mode" which is the proper end-user name. I slightly expanded the descriptions of #wizdetect, #wizgenesis, \#wizintrinsic, WIZKIT, and Debug mode, and removed at least one out of date reference to debug mode being a conditional feature. And for most of the stuff I was looking at, I changed the nroff source to honor the roff guideline of having each sentence start on its own line (and also the latex source to use those same line breaks even though they don't need it). Not done: a lot of quoted single characters use 'c' instead of `c' (pair of ticks rather than back-tick and normal tick). One form or the other should be changed so that they're all consistent. I'm pretty this was mentioned the last time it was formatted for the web site. Guidebook.mn has been tested, Guidebook.tex has not. --- doc/Guidebook.mn | 147 ++++++++++++++++++++++++++++++++-------------- doc/Guidebook.tex | 147 +++++++++++++++++++++++++++++++++------------- 2 files changed, 207 insertions(+), 87 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e363527ef..e1db1cd85 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.264 $ $NHDT-Date: 1524690677 2018/04/25 21:11:17 $ +.\" $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.271 $ $NHDT-Date: 1535668900 2018/08/30 22:41:40 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\" NetHack's Guidebook.mn currently does *not* adhere to these guidelines. @@ -21,7 +21,7 @@ .ds vr "NetHack 3.6 .ds f0 "\*(vr .ds f1 -.ds f2 "May 28, 2018 +.ds f2 "August 30, 2018 . .\" labeled paragraph start (should be part of tmac.n, but I don't want to .\" make changes to that file) @@ -782,13 +782,13 @@ The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `O' command; see the section on options below. .lp ^O -Show overview or show dungeon layout +Show overview. .lp "" -In normal play and in explore mode, a shortcut for the ``#overview'' -extended command to list interesting dungeon levels visited. +Shortcut for ``#overview'': list interesting dungeon levels visited. .lp "" -In debug mode, an extra command which lists the placement of all special -levels. +(Prior to 3.6.0, `^O' was a debug mode command which listed +the placement of all special levels. +Use ``#wizwhere'' to run that command.) .lp p Pay your shopping bill. .lp P @@ -1098,13 +1098,19 @@ Default key is '^D', and 'k' if .op number_pad is on. .lp #known -Show what object types have been discovered. Default key is '\\'. +Show what object types have been discovered. +Default key is '\\'. .lp #knownclass -Show discovered types for one class of objects. Default key is '`'. +Show discovered types for one class of objects. +Default key is '`'. .lp #levelchange -Change your experience level. Autocompletes. Wizard-mode only. +Change your experience level. +Autocompletes. +Debug mode only. .lp #lightsources -Show mobile light sources. Autocompletes. Wizard-mode only. +Show mobile light sources. +Autocompletes. +Debug mode only. .lp #look Look at what is here, under you. Default key is ':'. .lp #loot @@ -1116,7 +1122,9 @@ Default key is 'M-l', and 'l' if .op number_pad is on. .lp #monpolycontrol -Control monster polymorphs. Autocompletes. Wizard-mode only. +Control monster polymorphs. +Autocompletes. +Debug mode only. .lp #monster Use a monster's special ability (when polymorphed into monster form). Autocompletes. Default key is 'M-m'. @@ -1142,14 +1150,19 @@ If dungeon overview is chosen during end-of-game disclosure, every visited level will be included regardless of annotations. Autocompletes. Default keys are '^O', and 'M-O'. .lp #panic -Test the panic routine. Autocompletes. Wizard-mode only. +Test the panic routine. +Terminates the current game. +Autocompletes. +Debug mode only. .lp "#pay " Pay your shopping bill. Default key is 'p'. .lp #pickup Pick up things at the current location. Default key is ','. The `m' prefix forces use of a menu. .lp #polyself -Polymorph self. Autocompletes. Wizard-mode only. +Polymorph self. +Autocompletes. +Debug mode only. .lp #pray Pray to the gods for help. Autocompletes. Default key is 'M-p'. .lp "" @@ -1203,7 +1216,9 @@ Show the armor currently worn. Default key is '['. .lp #seegold Count your gold. Default key is '$'. .lp #seenv -Show seen vectors. Autocompletes. Wizard-mode only. +Show seen vectors. +Autocompletes. +Debug mode only. .lp #seerings Show the ring(s) currently worn. Default key is '='. .lp #seespells @@ -1220,7 +1235,9 @@ Do a shell escape. Default key is '!'. .lp "#sit " Sit down. Autocompletes. Default key is 'M-s'. .lp #stats -Show memory statistics. Autocompletes. Wizard-mode only. +Show memory statistics. +Autocompletes. +Debug mode only. .lp #suspend Suspend the game. Default key is '^Z'. .lp #swap @@ -1239,7 +1256,9 @@ Show a menu of possible actions in a location next to you. .lp #throw Throw something. Default key is 't'. .lp #timeout -Look at the timeout queue. Autocompletes. Wizard-mode only. +Look at the timeout queue. +Autocompletes. +Debug mode only. .lp "#tip " Tip over a container (bag or box) to pour out its contents. Autocompletes. Default key is 'M-T'. @@ -1271,16 +1290,21 @@ In some circumstances it can also be used to rescue trapped monsters. .lp "#up " Go up a staircase. Default key is '<'. .lp #vanquished -List vanquished monsters. Autocompletes. Wizard-mode only. +List vanquished monsters. +Autocompletes. +Debug mode only. .lp #version Print compile time options for this version of NetHack. Autocompletes. Default key is 'M-v'. .lp #versionshort Show version string. Default key is 'v'. .lp #vision -Show vision array. Autocompletes. Wizard-mode only. +Show vision array. +Autocompletes. +Debug mode only. .lp #wait -Rest one move while doing nothing. Default key is '.', and ' ' if +Rest one move while doing nothing. +Default key is '.', and also ' ' if rest_on_space is on. .lp #wear Wear a piece of armor. Default key is 'W'. @@ -1293,35 +1317,65 @@ Wield a weapon. Default key is 'w'. .lp #wipe Wipe off your face. Autocompletes. Default key is 'M-w'. .lp #wizdebug_bury -Bury objects under and around you. Autocompletes. Wizard-mode only. +Bury objects under and around you. +Autocompletes. +Debug mode only. .lp #wizdebug_traveldisplay -Toggle travel display. Autocompletes. Wizard-mode only. +Toggle travel display. +Autocompletes. +Debug mode only. .lp #wizdetect -Search a room. Autocompletes. Wizard-mode only. Default key is '^E'. +Search for hidden things (secret doors or traps or unseen monsters) +within a modest radius. +Autocompletes. +Debug mode only. +Default key is '^E'. .lp #wizgenesis -Create a monster. Autocompletes. Wizard-mode only. Default key is '^G'. +Create a monster. +May be prefixed by a count to create more than one. +Autocompletes. +Debug mode only. +Default key is '^G'. .lp #wizidentify -Identify all items in inventory. Autocompletes. Wizard-mode only. +Identify all items in inventory. +Autocompletes. +Debug mode only. Default key is '^I'. .lp #wizintrinsic -Set intrinsic. Autocompletes. Wizard-mode only. +Set one or more intrinsic attributes. +Autocompletes. +Debug mode only. .lp #wizlevelport Teleport to another level. Autocompletes. -Wizard-mode only. +Debug mode only. Default key is '^V'. .lp #wizmap -Map the level. Autocompletes. Wizard-mode only. Default key is '^F'. +Map the level. +Autocompletes. +Debug mode only. +Default key is '^F'. .lp #wizrumorcheck -Verify rumor boundaries. Autocompletes. Wizard-mode only. +Verify rumor boundaries. +Autocompletes. +Debug mode only. .lp #wizsmell -Smell monster. Autocompletes. Wizard-mode only. +Smell monster. +Autocompletes. +Debug mode only. .lp #wizwhere -Show locations of special levels. Autocompletes. Wizard-mode only. +Show locations of special levels. +Autocompletes. +Debug mode only. .lp #wizwish -Wish for something. Autocompletes. Wizard-mode only. Default key is '^W'. +Wish for something. +Autocompletes. +Debug mode only. +Default key is '^W'. .lp #wmode -Show wall modes. Autocompletes. Wizard-mode only. +Show wall modes. +Autocompletes. +Debug mode only. .lp "#zap " Zap a wand. Default key is 'z'. .lp "#? " @@ -2476,9 +2530,10 @@ Example: \fBSYMBOLS=S_boulder:0\fP .ed .lp WIZKIT -Wizard-mode extra items, in a text file containing item names, -one per line, up to a maximum of 128 lines. Each line is processed -by the function that handles wishing. +Debug mode only: extra items to add to initial inventory. +Value is the name of a text file containing a list of item names, +one per line, up to a maximum of 128 lines. +Each line is processed by the function that handles wishing. .pg Example: .sd @@ -4145,15 +4200,15 @@ system). .\" as filling and justifying are concerned .lp WIZARDS\ =\ A space-separated list of user names who are allowed to -play in wizard -mode (the debugging mode, not the magic-using role). A value of a single -asterisk (*) allows anyone to start a game in wizard mode. +play in debug mode (commonly referred to as wizard mode). +A value of a single +asterisk (*) allows anyone to start a game in debug mode. .lp SHELLERS\ =\ A list of users who are allowed to use the shell escape command (!). The syntax is the same as WIZARDS. .lp -EXPLORERS\ =\ A list of users who are allowed to use the explore mode. The -syntax is the same as WIZARDS. +EXPLORERS\ =\ A list of users who are allowed to use the explore mode. +The syntax is the same as WIZARDS. .lp MAXPLAYERS\ =\ Limit the maximum number of games that can be running at the same time. @@ -4261,10 +4316,13 @@ the trepid reader to discover. Debug mode .pg Debug mode, also known as wizard mode, is undocumented aside from this -brief description. It is intended for tracking down problems within the +brief description and the various ``debug mode only'' commands listed +among the command descriptions. +It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it -themselves. It is initiated by starting the game with the +themselves. +It is initiated by starting the game with the .op \-D command-line switch or with the .op playmode:debug @@ -4274,8 +4332,7 @@ For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the Wizard role). -And on any system, the program might have been configured to omit debug -mode entirely. Attempting to start a game in debug mode when not allowed +Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. . .hn diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 895dfe1ad..7cc9b7de6 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -45,7 +45,7 @@ %.au \author{Original version - Eric S. Raymond\\ (Edited and expanded for 3.6 by Mike Stephenson and others)} -\date{May 28, 2018} +\date{August 30, 2018} \maketitle @@ -852,13 +852,14 @@ are listed later in this Guidebook. Options are usually set before the game rather than with the `{\tt O}' command; see the section on options below. %.lp \item[\tb{\^{}O}] -Show overview or show dungeon layout\\ +Show overview.\\ %.lp "" -In normal play and in explore mode, a shortcut for the ``{\tt \#overview}'' -extended command to list interesting dungeon levels visited.\\ +Shortcut for the ``{\tt \#overview}'': +list interesting dungeon levels visited.\\ %.lp "" -In debug mode, an extra command which lists the placement of all special -levels. +(Prior to 3.6.0, `{\tt \^{}O}' was a debug mode command which listed +the placement of all special levels. +Use ``{\tt \#wizwhere}'' to run that command.) %.lp \item[\tb{p}] Pay your shopping bill. @@ -1216,16 +1217,22 @@ Jump to another location. Autocompletes. Default key is '{\tt M-j}', and '{\tt j Kick something. Default key is '{\tt \^{}D}', and '{\tt k}' if {\it number\verb+_+pad\/} is on. %.lp \item[\tb{\#known}] -Show what object types have been discovered. Default key is '{\tt $\backslash$}'. +Show what object types have been discovered. +Default key is '{\tt $\backslash$}'. %.lp \item[\tb{\#knownclass}] -Show discovered types for one class of objects. Default key is '{\tt `}'. +Show discovered types for one class of objects. +Default key is '{\tt `}'. %.lp \item[\tb{\#levelchange}] -Change your experience level. Autocompletes. Wizard-mode only. +Change your experience level. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#lightsources}] -Show mobile light sources. Autocompletes. Wizard-mode only. +Show mobile light sources. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#look}] Look at what is here, under you. Default key is '{\tt :}'. @@ -1238,7 +1245,9 @@ Precede with the `{\tt m}' prefix to skip containers at your location and go directly to removing a saddle. %.lp \item[\tb{\#monpolycontrol}] -Control monster polymorphs. Autocompletes. Wizard-mode only. +Control monster polymorphs. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#monster}] Use a monster's special ability (when polymorphed into monster form). @@ -1271,7 +1280,10 @@ level will be included regardless of annotations. Autocompletes. Default keys are '{\tt \^{}O}', and '{\tt M-O}'. %.lp \item[\tb{\#panic}] -Test the panic routine. Autocompletes. Wizard-mode only. +Test the panic routine. +Terminates the current game. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#pay}] Pay your shopping bill. Default key is '{\tt p}'. @@ -1281,7 +1293,9 @@ Pick up things at the current location. Default key is '{\tt ,}'. The `{\tt m}' prefix forces use of a menu. %.lp \item[\tb{\#polyself}] -Polymorph self. Autocompletes. Wizard-mode only. +Polymorph self. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#pray}] Pray to the gods for help. Autocompletes. Default key is '{\tt M-p}'.\\ @@ -1352,7 +1366,9 @@ Show the armor currently worn. Default key is '{\tt [}'. Count your gold. Default key is '{\tt \$}'. %.lp \item[\tb{\#seenv}] -Show seen vectors. Autocompletes. Wizard-mode only. +Show seen vectors. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#seerings}] Show the ring(s) currently worn. Default key is '{\tt =}'. @@ -1376,7 +1392,9 @@ Do a shell escape. Default key is '{\tt !}'. Sit down. Autocompletes. Default key is '{\tt M-s}'. %.lp \item[\tb{\#stats}] -Show memory statistics. Autocompletes. Wizard-mode only. +Show memory statistics. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#suspend}] Suspend the game. Default key is '{\tt \^{}Z}'. @@ -1404,7 +1422,9 @@ Show a menu of possible actions in a location next to you. Throw something. Default key is '{\tt t}'. %.lp \item[\tb{\#timeout}] -Look at the timeout queue. Autocompletes. Wizard-mode only. +Look at the timeout queue. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#tip}] Tip over a container (bag or box) to pour out its contents. @@ -1438,7 +1458,9 @@ In some circumstancs it can also be used to rescue trapped monsters. Go up a staircase. Default key is '{\tt <}'. %.lp \item[\tb{\#vanquished}] -List vanquished monsters. Autocompletes. Wizard-mode only. +List vanquished monsters. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#version}] Print compile time options for this version of {\it NetHack\/}. @@ -1448,10 +1470,14 @@ Autocompletes. Default key is '{\tt M-v}'. Show version string. Default key is '{\tt v}'. %.lp \item[\tb{\#vision}] -Show vision array. Autocompletes. Wizard-mode only. +Show vision array. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wait}] -Rest one move while doing nothing. Default key is '{\tt .}', and '{\tt{ }}' if {\it rest\verb+_+on\verb+_+space\/} is on. +Rest one move while doing nothing. +Default key is '{\tt .}', and also '{\tt{ }}' if +{\it rest\verb+_+on\verb+_+space\/} is on. %.lp \item[\tb{\#wear}] Wear a piece of armor. Default key is '{\tt W}'. @@ -1469,44 +1495,77 @@ Wield a weapon. Default key is '{\tt w}'. Wipe off your face. Autocompletes. Default key is '{\tt M-w}'. %.lp \item[\tb{\#wizdebug\verb+_+bury}] -Bury objects under and around you. Autocompletes. Wizard-mode only. +Bury objects under and around you. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizdebug\verb+_+traveldisplay}] -Toggle travel display. Autocompletes. Wizard-mode only. +Toggle travel display. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizdetect}] -Search a room. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}E}'. +Search for hidden things (secret doors or traps or unseen monsters) +within a modest radius. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}E}'. %.lp \item[\tb{\#wizgenesis}] -Create a monster. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}G}'. +Create a monster. +May be prefixed by a count to create more than one. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}G}'. %.lp \item[\tb{\#wizidentify}] -Identify all items in inventory. Autocompletes. Wizard-mode only. +Identify all items in inventory. +Autocompletes. +Debug mode only. Default key is '{\tt \^{}I}'. %.lp \item[\tb{\#wizintrinsic}] -Set intrinsic. Autocompletes. Wizard-mode only. +Set one or more intrinsic attributes. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizlevelport}] -Teleport to another level. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}V}'. +Teleport to another level. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}V}'. %.lp \item[\tb{\#wizmap}] -Map the level. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}F}'. +Map the level. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}F}'. %.lp \item[\tb{\#wizrumorcheck}] -Verify rumor boundaries. Autocompletes. Wizard-mode only. +Verify rumor boundaries. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizsmell}] -Smell monster. Autocompletes. Wizard-mode only. +Smell monster. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizwhere}] -Show locations of special levels. Autocompletes. Wizard-mode only. +Show locations of special levels. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#wizwish}] -Wish for something. Autocompletes. Wizard-mode only. Default key is '{\tt \^{}W}'. +Wish for something. +Autocompletes. +Debug mode only. +Default key is '{\tt \^{}W}'. %.lp \item[\tb{\#wmode}] -Show wall modes. Autocompletes. Wizard-mode only. +Show wall modes. +Autocompletes. +Debug mode only. %.lp \item[\tb{\#zap}] Zap a wand. Default key is '{\tt z}'. @@ -2882,9 +2941,10 @@ Example: %.lp \item[\bb{WIZKIT}] -Wizard-mode extra items, in a text file containing item names, -one per line, up to a maximum of 128 lines. Each line is processed -by the function that handles wishing. +Debug mode only: extra items to add to initial inventory. +Value is the name of a text file containing a list of item names, +one per line, up to a maximum of 128 lines. +Each line is processed by the function that handles wishing. %.pg Example: %.sd @@ -4811,9 +4871,10 @@ system). \blist{} %.lp \item[\ib{WIZARDS}] -A space-separated list of user name who are allowed to play in wizard -mode (the debugging mode, not the magic-useing role). A value of a single -asterisk (*) allows anyone to start a game in wizard mode. +A space-separated list of user name who are allowed to +play in debug mode (commonly referred to as wizard mode). +A value of a single +asterisk (*) allows anyone to start a game in debug mode. %.lp \item[\ib{SHELLERS}] A list of users who are allowed to use the shell escape command (`{\tt !}'). @@ -4939,10 +5000,13 @@ the trepid reader to discover. %.pg Debug mode, also known as wizard mode, is undocumented aside from this -brief description. It is intended for tracking down problems within the +brief description and the various ``debug mode only'' commands listed +among the command descriptions. +It is intended for tracking down problems within the program rather than to provide god-like powers to your character, and players who attempt debugging are expected to figure out how to use it -themselves. It is initiated by starting the game with the +themselves. +It is initiated by starting the game with the {\tt -D} command-line switch or with the {\it playmode:debug\/} @@ -4953,8 +5017,7 @@ For some systems, the player must be logged in under a particular user name to be allowed to use debug mode; for others, the hero must be given a particular character name (but may be any role; there's no connection between ``wizard mode'' and the {\it Wizard\/} role). -And on any system, the program might have been configured to omit debug -mode entirely. Attempting to start a game in debug mode when not allowed +Attempting to start a game in debug mode when not allowed or not available will result in falling back to explore mode instead. %.hn