]> granicus.if.org Git - nethack/commitdiff
populate insight.c
authorPatR <rankin@nethack.org>
Fri, 7 Feb 2020 01:42:15 +0000 (17:42 -0800)
committerPatR <rankin@nethack.org>
Fri, 7 Feb 2020 01:42:15 +0000 (17:42 -0800)
Move enlightenment and conduct from cmd.c to insight.c.  Also move
vanquished monsters plus genocided and/or extinct monsters from end.c
to there.  And move the one-line stethoscope/probing feedback for
self and for monsters from priest.c to there.

Achievement feedback has been overhauled a bit.  When no achievements
have been recorded, the header for them (after conducts) won't be
shown, and when at least one has been recorded, make the prompt for
asking whether to disclose conduct be about disclosing conduct and
achievements.  Also, describe achievements in the Guidebook.

I ran out of gas before updating Guidebook.tex; it will catch up to
Guidebook.mn eventually.

Some of the MS-DOS Makefiles haven't been updated yet so linking
without insight.{o,obj} will break there.

doc/Guidebook.mn
include/extern.h
src/cmd.c
src/end.c
src/insight.c
src/priest.c

index e189cd8a99cb5acd30e2a502b3393bc04da11b15..fd906d9c82cf32e561a9a8eaf0a21bb66fa15e75 100644 (file)
@@ -1084,6 +1084,9 @@ Close a door.
 Default key is \(oqc\(cq.
 .lp "#conduct "
 List voluntary challenges you have maintained.
+.\" [only in wizard mode:]
+.\" Also lists various achievements representing progress toward ultimate
+.\" ascension if any have been attained.
 Autocompletes.
 Default key is \(oqM-C\(cq.
 .lp ""
@@ -2726,6 +2729,71 @@ wish for any items is a challenge, as is a game without wishing for
 an artifact (even if the artifact immediately disappears).
 When the game offers you an opportunity to make a wish for an item,
 you may choose \(lqnothing\(rq if you want to decline.
+.hn 2
+Achievements
+.pg
+End of game disclosure will also display various achievements
+representing progress toward ultimate ascension, if any have been
+attained.
+They aren't directly related to \fIconduct\fP but are grouped with
+it because they fall into the same category of \(lqbragging rights\(rq
+and to limit the number of questions during disclosure.
+.pg
+The first two are also conducts, the rest are listed roughly in order
+of difficulty and not necessarily in the order in which you might
+accomplish them.
+.lp "Blind   "
+Blind from birth.
+.lp "Nudist  "
+Never wore any armor.
+.lp "Mines' End"
+Explored to the bottom of the Gnomish Mines and found a special item there.
+.lp "Sokoban "
+Explored to the top of Sokoban and found a special item there.
+.lp "Medusa  "
+Defeated Medusa.
+.lp "Bell    "
+Acquired the Bell of Opening.
+.lp "Gehennom"
+Entered Gehennom proper (beyond the Valley).
+.lp "Candle  "
+Acquired the Candelabrum of Invocation.
+.lp "Book    "
+Acquired the Book of the Dead.
+.lp Invocation
+Gained access to the bottommost level of Gehennom.
+.lp "Amulet  "
+Acquired the fabled Amulet of Yendor.
+.lp "Endgame "
+Reached the Elemental Planes.
+.lp "Astral  "
+Reached the Astral Plane level.
+.lp "Ascended"
+Delivered the Amulet to its final destination.
+.lp ""
+.lp "Notes:  "
+.pg
+\fIBlind\fP and \fINudist\fP are also conducts, and they can only be
+enabled by setting the correspondingly named option in NETHACKOPTIONS
+or run-time configuration file prior to game start.
+In the case of \fIBlind\fP, the option also enforces the conduct.
+They aren't really significant accomplishments unless/until you make
+substantial progress into the dungeon but they are treated as
+Achievements as long as the conduct is enabled and hasn't been broken.
+.pg
+The \(lqspecial items\(rq hidden in \fIMines\~End\fP and \fISokoban\fP
+are not unique but are considered to be prizes or rewards
+for exploring those levels since doing so is not necessary to complete
+the game.
+Finding other instances of the same objects doesn't record the
+corresponding achievement.
+.pg
+The \fIMedusa\fP achievement is recorded if she dies for any reason,
+even if you are not directly responsible.
+.pg
+The \fIValley of the Dead\fP is part of \fIGehennom\fP but the
+\fIGehennom\fP achievement doesn't get recorded until you make it past
+that level.
 .
 .hn 1
 Options
@@ -3106,7 +3174,7 @@ The possibilities are:
 .CC a "disclose your attributes;"
 .CC v "summarize monsters that have been vanquished;"
 .CC g "list monster species that have been genocided;"
-.CC c "display your conduct;"
+.CC c "display your conduct; also achievements, if any;"
 .CC o "display dungeon overview."
 .ei
 .ed
index f08f922dfc884ed4a8b0c09218350b7992a5cd69..c19f8df64de47d94d1913171939f0f4c2fcacbfc 100644 (file)
@@ -198,7 +198,6 @@ E boolean NDECL(status_hilite_menu);
 E char NDECL(randomkey);
 E void FDECL(random_response, (char *, int));
 E int NDECL(rnd_extcmd_idx);
-E int NDECL(doconduct);
 E int NDECL(domonability);
 E char FDECL(cmd_from_func, (int NDECL((*))));
 E boolean FDECL(redraw_cmd, (CHAR_P));
@@ -231,10 +230,6 @@ E void FDECL(rhack, (char *));
 E int NDECL(doextlist);
 E int NDECL(extcmd_via_menu);
 E int NDECL(enter_explore_mode);
-E char *FDECL(trap_predicament, (char *, int, BOOLEAN_P));
-E void FDECL(enlightenment, (int, int));
-E void FDECL(youhiding, (BOOLEAN_P, int));
-E void FDECL(show_conduct, (int));
 E boolean FDECL(bind_key, (UCHAR_P, const char *));
 E void NDECL(dokeylist);
 E int FDECL(xytod, (SCHAR_P, SCHAR_P));
@@ -724,8 +719,6 @@ E void FDECL(done, (int));
 E void FDECL(container_contents, (struct obj *, BOOLEAN_P,
                                   BOOLEAN_P, BOOLEAN_P));
 E void FDECL(nh_terminate, (int)) NORETURN;
-E int NDECL(dovanquished);
-E int NDECL(num_genocides);
 E void FDECL(delayed_killer, (int, int, const char *));
 E struct kinfo *FDECL(find_delayed_killer, (int));
 E void FDECL(dealloc_killer, (struct kinfo *));
@@ -986,6 +979,24 @@ E void FDECL(strbuf_empty, (strbuf_t *));
 E void FDECL(strbuf_nl_to_crlf, (strbuf_t *));
 E char *FDECL(nonconst, (const char *, char *));
 
+/* ### insight.c ### */
+
+E int NDECL(doattributes);
+E void FDECL(enlightenment, (int, int));
+E void FDECL(youhiding, (BOOLEAN_P, int));
+E char *FDECL(trap_predicament, (char *, int, BOOLEAN_P));
+E int NDECL(doconduct);
+E void FDECL(show_conduct, (int));
+E int NDECL(count_uachieve);
+E int NDECL(dovanquished);
+E void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
+E int NDECL(num_genocides);
+E void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
+E const char *FDECL(align_str, (ALIGNTYP_P));
+E char *FDECL(piousness, (BOOLEAN_P, const char *));
+E void FDECL(mstatusline, (struct monst *));
+E void NDECL(ustatusline);
+
 /* ### invent.c ### */
 
 E Loot *FDECL(sortloot, (struct obj **, unsigned, BOOLEAN_P,
@@ -2095,10 +2106,6 @@ E void NDECL(clearpriests);
 E void FDECL(restpriest, (struct monst *, BOOLEAN_P));
 E void FDECL(newepri, (struct monst *));
 E void FDECL(free_epri, (struct monst *));
-E const char *FDECL(align_str, (ALIGNTYP_P));
-E char *FDECL(piousness, (BOOLEAN_P, const char *));
-E void FDECL(mstatusline, (struct monst *));
-E void NDECL(ustatusline);
 
 /* ### quest.c ### */
 
index df02c6e4f491429239c5e32dd1218f95c905c1e7..a619b42a460bb2fa1f4a40c506c43501acde23f7 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -29,9 +29,6 @@
 static boolean alt_esc = FALSE;
 #endif
 
-extern const char *hu_stat[];  /* hunger status from eat.c */
-extern const char *enc_stat[]; /* encumbrance status from botl.c */
-
 #ifdef UNIX
 /*
  * Some systems may have getchar() return EOF for various reasons, and
@@ -178,23 +175,6 @@ static void FDECL(misc_stats, (winid, long *, long *));
 static int NDECL(wiz_show_stats);
 static boolean FDECL(accept_menu_prefix, (int NDECL((*))));
 static int NDECL(wiz_rumor_check);
-static int NDECL(doattributes);
-
-static void FDECL(enlght_out, (const char *));
-static void FDECL(enlght_line, (const char *, const char *, const char *,
-                                    const char *));
-static char *FDECL(enlght_combatinc, (const char *, int, int, char *));
-static void FDECL(enlght_halfdmg, (int, int));
-static boolean NDECL(walking_on_water);
-static boolean FDECL(cause_known, (int));
-static char *FDECL(attrval, (int, int, char *));
-static void FDECL(background_enlightenment, (int, int));
-static void FDECL(basics_enlightenment, (int, int));
-static void FDECL(characteristics_enlightenment, (int, int));
-static void FDECL(one_characteristic, (int, int, int));
-static void FDECL(status_enlightenment, (int, int));
-static void FDECL(attributes_enlightenment, (int, int));
-static void FDECL(show_achievements, (int));
 
 static void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)),
                                              const char *));
@@ -419,7 +399,7 @@ doextlist(VOID_ARGS)
             any.a_int = 4;
             add_menu(menuwin, NO_GLYPH, &any, 'z', 0, ATR_NONE,
                      onelist ? "Show debugging commands in separate section"
-                     : "Show all alphabetically, including debugging commands",
+                    : "Show all alphabetically, including debugging commands",
                      MENU_ITEMFLAGS_NONE);
         }
         any = cg.zeroany;
@@ -997,7 +977,8 @@ wiz_load_splua(VOID_ARGS)
             strcat(buf, ".lua");
         makemap_prepost(TRUE, was_in_W_tower);
 
-        /* TODO: need to split some of this out of mklev(), makelevel(), makemaz() */
+        /* TODO: need to split some of this out of mklev(), makelevel(),
+           makemaz() */
         g.in_mklev = TRUE;
         oinit(); /* assign level dependent obj probabilities */
         clear_level_structures();
@@ -1019,8 +1000,8 @@ wiz_load_splua(VOID_ARGS)
 #endif
         }
         set_wall_state();
-        /* for many room types, g.rooms[].rtype is zeroed once the room has been
-           entered; g.rooms[].orig_rtype always retains original rtype value */
+        /* for many room types, rooms[].rtype is zeroed once the room has been
+           entered; rooms[].orig_rtype always retains original rtype value */
         for (ridx = 0; ridx < SIZE(g.rooms); ridx++)
             g.rooms[ridx].orig_rtype = g.rooms[ridx].rtype;
 
@@ -1584,7 +1565,7 @@ wiz_intrinsic(VOID_ARGS)
                 if (!Warn_of_mon) {
                     g.context.warntype.speciesidx = PM_GRID_BUG;
                     g.context.warntype.species
-                                         = &mons[g.context.warntype.speciesidx];
+                                       = &mons[g.context.warntype.speciesidx];
                 }
                 goto def_feedback;
             case GLIB:
@@ -1714,1746 +1695,6 @@ doterrain(VOID_ARGS)
     return 0; /* no time elapses */
 }
 
-/* -enlightenment and conduct- */
-static const char You_[] = "You ", are[] = "are ", were[] = "were ",
-                  have[] = "have ", had[] = "had ", can[] = "can ",
-                  could[] = "could ";
-static const char have_been[] = "have been ", have_never[] = "have never ",
-                  never[] = "never ";
-
-#define enl_msg(prefix, present, past, suffix, ps) \
-    enlght_line(prefix, final ? past : present, suffix, ps)
-#define you_are(attr, ps) enl_msg(You_, are, were, attr, ps)
-#define you_have(attr, ps) enl_msg(You_, have, had, attr, ps)
-#define you_can(attr, ps) enl_msg(You_, can, could, attr, ps)
-#define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "")
-#define you_have_never(badthing) \
-    enl_msg(You_, have_never, never, badthing, "")
-#define you_have_X(something) \
-    enl_msg(You_, have, (const char *) "", something, "")
-
-static void
-enlght_out(buf)
-const char *buf;
-{
-    if (g.en_via_menu) {
-        anything any;
-
-        any = cg.zeroany;
-        add_menu(g.en_win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
-                 MENU_ITEMFLAGS_NONE);
-    } else
-        putstr(g.en_win, 0, buf);
-}
-
-static void
-enlght_line(start, middle, end, ps)
-const char *start, *middle, *end, *ps;
-{
-    char buf[BUFSZ];
-
-    Sprintf(buf, " %s%s%s%s.", start, middle, end, ps);
-    enlght_out(buf);
-}
-
-/* format increased chance to hit or damage or defense (Protection) */
-static char *
-enlght_combatinc(inctyp, incamt, final, outbuf)
-const char *inctyp;
-int incamt, final;
-char *outbuf;
-{
-    const char *modif, *bonus;
-    boolean invrt;
-    int absamt;
-
-    absamt = abs(incamt);
-    /* Protection amount is typically larger than damage or to-hit;
-       reduce magnitude by a third in order to stretch modifier ranges
-       (small:1..5, moderate:6..10, large:11..19, huge:20+) */
-    if (!strcmp(inctyp, "defense"))
-        absamt = (absamt * 2) / 3;
-
-    if (absamt <= 3)
-        modif = "small";
-    else if (absamt <= 6)
-        modif = "moderate";
-    else if (absamt <= 12)
-        modif = "large";
-    else
-        modif = "huge";
-
-    modif = !incamt ? "no" : an(modif); /* ("no" case shouldn't happen) */
-    bonus = (incamt >= 0) ? "bonus" : "penalty";
-    /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
-    invrt = strcmp(inctyp, "to hit") ? TRUE : FALSE;
-
-    Sprintf(outbuf, "%s %s %s", modif, invrt ? inctyp : bonus,
-            invrt ? bonus : inctyp);
-    if (final || wizard)
-        Sprintf(eos(outbuf), " (%s%d)", (incamt > 0) ? "+" : "", incamt);
-
-    return outbuf;
-}
-
-/* report half physical or half spell damage */
-static void
-enlght_halfdmg(category, final)
-int category;
-int final;
-{
-    const char *category_name;
-    char buf[BUFSZ];
-
-    switch (category) {
-    case HALF_PHDAM:
-        category_name = "physical";
-        break;
-    case HALF_SPDAM:
-        category_name = "spell";
-        break;
-    default:
-        category_name = "unknown";
-        break;
-    }
-    Sprintf(buf, " %s %s damage", (final || wizard) ? "half" : "reduced",
-            category_name);
-    enl_msg(You_, "take", "took", buf, from_what(category));
-}
-
-/* is hero actively using water walking capability on water (or lava)? */
-static boolean
-walking_on_water()
-{
-    if (u.uinwater || Levitation || Flying)
-        return FALSE;
-    return (boolean) (Wwalking
-                      && (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)));
-}
-
-/* describe u.utraptype; used by status_enlightenment() and self_lookat() */
-char *
-trap_predicament(outbuf, final, wizxtra)
-char *outbuf;
-int final;
-boolean wizxtra;
-{
-    struct trap *t;
-
-    /* caller has verified u.utrap */
-    *outbuf = '\0';
-    switch (u.utraptype) {
-    case TT_BURIEDBALL:
-        Strcpy(outbuf, "tethered to something buried");
-        break;
-    case TT_LAVA:
-        Sprintf(outbuf, "sinking into %s", final ? "lava" : hliquid("lava"));
-        break;
-    case TT_INFLOOR:
-        Sprintf(outbuf, "stuck in %s", the(surface(u.ux, u.uy)));
-        break;
-    default: /* TT_BEARTRAP, TT_PIT, or TT_WEB */
-        Strcpy(outbuf, "trapped");
-        if ((t = t_at(u.ux, u.uy)) != 0) /* should never be null */
-            Sprintf(eos(outbuf), " in %s", an(trapname(t->ttyp, FALSE)));
-        break;
-    }
-    if (wizxtra) { /* give extra information for wizard mode enlightenment */
-        /* curly braces: u.utrap is an escape attempt counter rather than a
-           turn timer so use different ornamentation than usual parentheses */
-        Sprintf(eos(outbuf), " {%u}", u.utrap);
-    }
-    return outbuf;
-}
-
-/* check whether hero is wearing something that player definitely knows
-   confers the target property; item must have been seen and its type
-   discovered but it doesn't necessarily have to be fully identified */
-static boolean
-cause_known(propindx)
-int propindx; /* index of a property which can be conveyed by worn item */
-{
-    register struct obj *o;
-    long mask = W_ARMOR | W_AMUL | W_RING | W_TOOL;
-
-    /* simpler than from_what()/what_gives(); we don't attempt to
-       handle artifacts and we deliberately ignore wielded items */
-    for (o = g.invent; o; o = o->nobj) {
-        if (!(o->owornmask & mask))
-            continue;
-        if ((int) objects[o->otyp].oc_oprop == propindx
-            && objects[o->otyp].oc_name_known && o->dknown)
-            return TRUE;
-    }
-    return FALSE;
-}
-
-/* format a characteristic value, accommodating Strength's strangeness */
-static char *
-attrval(attrindx, attrvalue, resultbuf)
-int attrindx, attrvalue;
-char resultbuf[]; /* should be at least [7] to hold "18/100\0" */
-{
-    if (attrindx != A_STR || attrvalue <= 18)
-        Sprintf(resultbuf, "%d", attrvalue);
-    else if (attrvalue > STR18(100)) /* 19 to 25 */
-        Sprintf(resultbuf, "%d", attrvalue - 100);
-    else /* simplify "18/ **" to be "18/100" */
-        Sprintf(resultbuf, "18/%02d", attrvalue - 18);
-    return resultbuf;
-}
-
-void
-enlightenment(mode, final)
-int mode;  /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */
-int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
-{
-    char buf[BUFSZ], tmpbuf[BUFSZ];
-
-    g.en_win = create_nhwindow(NHW_MENU);
-    g.en_via_menu = !final;
-    if (g.en_via_menu)
-        start_menu(g.en_win);
-
-    Strcpy(tmpbuf, g.plname);
-    *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */
-    /* as in background_enlightenment, when poly'd we need to use the saved
-       gender in u.mfemale rather than the current you-as-monster gender */
-    Sprintf(buf, "%s the %s's attributes:", tmpbuf,
-            ((Upolyd ? u.mfemale : flags.female) && g.urole.name.f)
-                ? g.urole.name.f
-                : g.urole.name.m);
-
-    /* title */
-    enlght_out(buf); /* "Conan the Archeologist's attributes:" */
-    /* background and characteristics; ^X or end-of-game disclosure */
-    if (mode & BASICENLIGHTENMENT) {
-        /* role, race, alignment, deities, dungeon level, time, experience */
-        background_enlightenment(mode, final);
-        /* hit points, energy points, armor class, gold */
-        basics_enlightenment(mode, final);
-        /* strength, dexterity, &c */
-        characteristics_enlightenment(mode, final);
-    }
-    /* expanded status line information, including things which aren't
-       included there due to space considerations--such as obvious
-       alternative movement indicators (riding, levitation, &c), and
-       various troubles (turning to stone, trapped, confusion, &c);
-       shown for both basic and magic enlightenment */
-    status_enlightenment(mode, final);
-    /* remaining attributes; shown for potion,&c or wizard mode and
-       explore mode ^X or end of game disclosure */
-    if (mode & MAGICENLIGHTENMENT) {
-        /* intrinsics and other traditional enlightenment feedback */
-        attributes_enlightenment(mode, final);
-    }
-
-    if (!g.en_via_menu) {
-        display_nhwindow(g.en_win, TRUE);
-    } else {
-        menu_item *selected = 0;
-
-        end_menu(g.en_win, (char *) 0);
-        if (select_menu(g.en_win, PICK_NONE, &selected) > 0)
-            free((genericptr_t) selected);
-        g.en_via_menu = FALSE;
-    }
-    destroy_nhwindow(g.en_win);
-    g.en_win = WIN_ERR;
-}
-
-/*ARGSUSED*/
-/* display role, race, alignment and such to en_win */
-static void
-background_enlightenment(unused_mode, final)
-int unused_mode UNUSED;
-int final;
-{
-    const char *role_titl, *rank_titl;
-    int innategend, difgend, difalgn;
-    char buf[BUFSZ], tmpbuf[BUFSZ];
-
-    /* note that if poly'd, we need to use u.mfemale instead of flags.female
-       to access hero's saved gender-as-human/elf/&c rather than current one */
-    innategend = (Upolyd ? u.mfemale : flags.female) ? 1 : 0;
-    role_titl = (innategend && g.urole.name.f) ? g.urole.name.f
-                                               : g.urole.name.m;
-    rank_titl = rank_of(u.ulevel, Role_switch, innategend);
-
-    enlght_out(""); /* separator after title */
-    enlght_out("Background:");
-
-    /* if polymorphed, report current shape before underlying role;
-       will be repeated as first status: "you are transformed" and also
-       among various attributes: "you are in beast form" (after being
-       told about lycanthropy) or "you are polymorphed into <a foo>"
-       (with countdown timer appended for wizard mode); we really want
-       the player to know he's not a samurai at the moment... */
-    if (Upolyd) {
-        char anbuf[20]; /* includes trailing space; [4] suffices */
-        struct permonst *uasmon = g.youmonst.data;
-        boolean altphrasing = vampshifted(&g.youmonst);
-
-        tmpbuf[0] = '\0';
-        /* here we always use current gender, not saved role gender */
-        if (!is_male(uasmon) && !is_female(uasmon) && !is_neuter(uasmon))
-            Sprintf(tmpbuf, "%s ", genders[flags.female ? 1 : 0].adj);
-        if (altphrasing)
-            Sprintf(eos(tmpbuf), "%s in ", mons[g.youmonst.cham].mname);
-        Sprintf(buf, "%s%s%s%s form", !final ? "currently " : "",
-                altphrasing ? just_an(anbuf, tmpbuf) : "in ",
-                tmpbuf, uasmon->mname);
-        you_are(buf, "");
-    }
-
-    /* report role; omit gender if it's redundant (eg, "female priestess") */
-    tmpbuf[0] = '\0';
-    if (!g.urole.name.f
-        && ((g.urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
-            || innategend != flags.initgend))
-        Sprintf(tmpbuf, "%s ", genders[innategend].adj);
-    buf[0] = '\0';
-    if (Upolyd)
-        Strcpy(buf, "actually "); /* "You are actually a ..." */
-    if (!strcmpi(rank_titl, role_titl)) {
-        /* omit role when rank title matches it */
-        Sprintf(eos(buf), "%s, level %d %s%s", an(rank_titl), u.ulevel,
-                tmpbuf, g.urace.noun);
-    } else {
-        Sprintf(eos(buf), "%s, a level %d %s%s %s", an(rank_titl), u.ulevel,
-                tmpbuf, g.urace.adj, role_titl);
-    }
-    you_are(buf, "");
-
-    /* report alignment (bypass you_are() in order to omit ending period);
-       adverb is used to distinguish between temporary change (helm of opp.
-       alignment), permanent change (one-time conversion), and original */
-    Sprintf(buf, " %s%s%s, %son a mission for %s",
-            You_, !final ? are : were,
-            align_str(u.ualign.type),
-            /* helm of opposite alignment (might hide conversion) */
-            (u.ualign.type != u.ualignbase[A_CURRENT])
-               /* what's the past tense of "currently"? if we used "formerly"
-                  it would sound like a reference to the original alignment */
-               ? (!final ? "currently " : "temporarily ")
-               /* permanent conversion */
-               : (u.ualign.type != u.ualignbase[A_ORIGINAL])
-                  /* and what's the past tense of "now"? certainly not "then"
-                     in a context like this...; "belatedly" == weren't that
-                     way sooner (in other words, didn't start that way) */
-                  ? (!final ? "now " : "belatedly ")
-                  /* atheist (ignored in very early game) */
-                  : (!u.uconduct.gnostic && g.moves > 1000L)
-                     ? "nominally "
-                     /* lastly, normal case */
-                     : "",
-            u_gname());
-    enlght_out(buf);
-    /* show the rest of this game's pantheon (finishes previous sentence)
-       [appending "also Moloch" at the end would allow for straightforward
-       trailing "and" on all three aligned entries but looks too verbose] */
-    Sprintf(buf, " who %s opposed by", !final ? "is" : "was");
-    if (u.ualign.type != A_LAWFUL)
-        Sprintf(eos(buf), " %s (%s) and", align_gname(A_LAWFUL),
-                align_str(A_LAWFUL));
-    if (u.ualign.type != A_NEUTRAL)
-        Sprintf(eos(buf), " %s (%s)%s", align_gname(A_NEUTRAL),
-                align_str(A_NEUTRAL),
-                (u.ualign.type != A_CHAOTIC) ? " and" : "");
-    if (u.ualign.type != A_CHAOTIC)
-        Sprintf(eos(buf), " %s (%s)", align_gname(A_CHAOTIC),
-                align_str(A_CHAOTIC));
-    Strcat(buf, "."); /* terminate sentence */
-    enlght_out(buf);
-
-    /* show original alignment,gender,race,role if any have been changed;
-       giving separate message for temporary alignment change bypasses need
-       for tricky phrasing otherwise necessitated by possibility of having
-       helm of opposite alignment mask a permanent alignment conversion */
-    difgend = (innategend != flags.initgend);
-    difalgn = (((u.ualign.type != u.ualignbase[A_CURRENT]) ? 1 : 0)
-               + ((u.ualignbase[A_CURRENT] != u.ualignbase[A_ORIGINAL])
-                  ? 2 : 0));
-    if (difalgn & 1) { /* have temporary alignment so report permanent one */
-        Sprintf(buf, "actually %s", align_str(u.ualignbase[A_CURRENT]));
-        you_are(buf, "");
-        difalgn &= ~1; /* suppress helm from "started out <foo>" message */
-    }
-    if (difgend || difalgn) { /* sex change or perm align change or both */
-        Sprintf(buf, " You started out %s%s%s.",
-                difgend ? genders[flags.initgend].adj : "",
-                (difgend && difalgn) ? " and " : "",
-                difalgn ? align_str(u.ualignbase[A_ORIGINAL]) : "");
-        enlght_out(buf);
-    }
-
-    /* As of 3.6.2: dungeon level, so that ^X really has all status info as
-       claimed by the comment below; this reveals more information than
-       the basic status display, but that's one of the purposes of ^X;
-       similar information is revealed by #overview; the "You died in
-       <location>" given by really_done() is more rudimentary than this */
-    *buf = *tmpbuf = '\0';
-    if (In_endgame(&u.uz)) {
-        int egdepth = observable_depth(&u.uz);
-
-        (void) endgamelevelname(tmpbuf, egdepth);
-        Sprintf(buf, "in the endgame, on the %s%s",
-                !strncmp(tmpbuf, "Plane", 5) ? "Elemental " : "", tmpbuf);
-    } else if (Is_knox(&u.uz)) {
-        /* this gives away the fact that the knox branch is only 1 level */
-        Sprintf(buf, "on the %s level", g.dungeons[u.uz.dnum].dname);
-        /* TODO? maybe phrase it differently when actually inside the fort,
-           if we're able to determine that (not trivial) */
-    } else {
-        char dgnbuf[QBUFSZ];
-
-        Strcpy(dgnbuf, g.dungeons[u.uz.dnum].dname);
-        if (!strncmpi(dgnbuf, "The ", 4))
-            *dgnbuf = lowc(*dgnbuf);
-        Sprintf(tmpbuf, "level %d",
-                In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
-        /* TODO? maybe extend this bit to include various other automatic
-           annotations from the dungeon overview code */
-        if (Is_rogue_level(&u.uz))
-            Strcat(tmpbuf, ", a primitive area");
-        else if (Is_bigroom(&u.uz) && !Blind)
-            Strcat(tmpbuf, ", a very big room");
-        Sprintf(buf, "in %s, on %s", dgnbuf, tmpbuf);
-    }
-    you_are(buf, "");
-
-    /* this is shown even if the 'time' option is off */
-    if (g.moves == 1L) {
-        you_have("just started your adventure", "");
-    } else {
-        /* 'turns' grates on the nerves in this context... */
-        Sprintf(buf, "the dungeon %ld turn%s ago", g.moves, plur(g.moves));
-        /* same phrasing for current and final: "entered" is unconditional */
-        enlght_line(You_, "entered ", buf, "");
-    }
-
-    /* for gameover, these have been obtained in really_done() so that they
-       won't vary if user leaves a disclosure prompt or --More-- unanswered
-       long enough for the dynamic value to change between then and now */
-    if (final ? iflags.at_midnight : midnight()) {
-        enl_msg("It ", "is ", "was ", "the midnight hour", "");
-    } else if (final ? iflags.at_night : night()) {
-        enl_msg("It ", "is ", "was ", "nighttime", "");
-    }
-    /* other environmental factors */
-    if (flags.moonphase == FULL_MOON || flags.moonphase == NEW_MOON) {
-        /* [This had "tonight" but has been changed to "in effect".
-           There is a similar issue to Friday the 13th--it's the value
-           at the start of the current session but that session might
-           have dragged on for an arbitrary amount of time.  We want to
-           report the values that currently affect play--or affected
-           play when game ended--rather than actual outside situation.] */
-        Sprintf(buf, "a %s moon in effect%s",
-                (flags.moonphase == FULL_MOON) ? "full"
-                : (flags.moonphase == NEW_MOON) ? "new"
-                  /* showing these would probably just lead to confusion
-                     since they have no effect on game play... */
-                  : (flags.moonphase < FULL_MOON) ? "first quarter"
-                    : "last quarter",
-                /* we don't have access to 'how' here--aside from survived
-                   vs died--so settle for general platitude */
-                final ? " when your adventure ended" : "");
-        enl_msg("There ", "is ", "was ", buf, "");
-    }
-    if (flags.friday13) {
-        /* let player know that friday13 penalty is/was in effect;
-           we don't say "it is/was Friday the 13th" because that was at
-           the start of the session and it might be past midnight (or
-           days later if the game has been paused without save/restore),
-           so phrase this similar to the start up message */
-        Sprintf(buf, " Bad things %s on Friday the 13th.",
-                !final ? "can happen"
-                : (final == ENL_GAMEOVERALIVE) ? "could have happened"
-                  /* there's no may to tell whether -1 Luck made a
-                     difference but hero has died... */
-                  : "happened");
-        enlght_out(buf);
-    }
-
-    if (!Upolyd) {
-        int ulvl = (int) u.ulevel;
-        /* [flags.showexp currently does not matter; should it?] */
-
-        /* experience level is already shown above */
-        Sprintf(buf, "%-1ld experience point%s", u.uexp, plur(u.uexp));
-        /* TODO?
-         *  Remove wizard-mode restriction since patient players can
-         *  determine the numbers needed without resorting to spoilers
-         *  (even before this started being disclosed for 'final';
-         *  just enable 'showexp' and look at normal status lines
-         *  after drinking gain level potions or eating wraith corpses
-         *  or being level-drained by vampires).
-         */
-        if (ulvl < 30 && (final || wizard)) {
-            long nxtlvl = newuexp(ulvl), delta = nxtlvl - u.uexp;
-
-            Sprintf(eos(buf), ", %ld %s%sneeded %s level %d",
-                    delta, (u.uexp > 0) ? "more " : "",
-                    /* present tense=="needed", past tense=="were needed" */
-                    !final ? "" : (delta == 1L) ? "was " : "were ",
-                    /* "for": grammatically iffy but less likely to wrap */
-                    (ulvl < 18) ? "to attain" : "for", (ulvl + 1));
-        }
-        you_have(buf, "");
-    }
-#ifdef SCORE_ON_BOTL
-    if (flags.showscore) {
-        /* describes what's shown on status line, which is an approximation;
-           only show it here if player has the 'showscore' option enabled */
-        Sprintf(buf, "%ld%s", botl_score(),
-                !final ? "" : " before end-of-game adjustments");
-        enl_msg("Your score ", "is ", "was ", buf, "");
-    }
-#endif
-}
-
-/* hit points, energy points, armor class -- essential information which
-   doesn't fit very well in other categories */
-/*ARGSUSED*/
-static void
-basics_enlightenment(mode, final)
-int mode UNUSED;
-int final;
-{
-    static char Power[] = "energy points (spell power)";
-    char buf[BUFSZ];
-    int pw = u.uen, hp = (Upolyd ? u.mh : u.uhp),
-        pwmax = u.uenmax, hpmax = (Upolyd ? u.mhmax : u.uhpmax);
-
-    enlght_out(""); /* separator after background */
-    enlght_out("Basics:");
-
-    if (hp < 0)
-        hp = 0;
-    /* "1 out of 1" rather than "all" if max is only 1; should never happen */
-    if (hp == hpmax && hpmax > 1)
-        Sprintf(buf, "all %d hit points", hpmax);
-    else
-        Sprintf(buf, "%d out of %d hit point%s", hp, hpmax, plur(hpmax));
-    you_have(buf, "");
-
-    /* low max energy is feasible, so handle couple of extra special cases */
-    if (pwmax == 0 || (pw == pwmax && pwmax == 2)) /* both: "all 2" is silly */
-        Sprintf(buf, "%s %s", !pwmax ? "no" : "both", Power);
-    else if (pw == pwmax && pwmax > 2)
-        Sprintf(buf, "all %d %s", pwmax, Power);
-    else
-        Sprintf(buf, "%d out of %d %s", pw, pwmax, Power);
-    you_have(buf, "");
-
-    if (Upolyd) {
-        switch (mons[u.umonnum].mlevel) {
-        case 0:
-            /* status line currently being explained shows "HD:0" */
-            Strcpy(buf, "0 hit dice (actually 1/2)");
-            break;
-        case 1:
-            Strcpy(buf, "1 hit die");
-            break;
-        default:
-            Sprintf(buf, "%d hit dice", mons[u.umonnum].mlevel);
-            break;
-        }
-        you_have(buf, "");
-    }
-
-    Sprintf(buf, "%d", u.uac);
-    enl_msg("Your armor class ", "is ", "was ", buf, "");
-
-    /* gold; similar to doprgold(#seegold) but without shop billing info;
-       same amount as shown on status line which ignores container contents */
-    {
-        static const char Your_wallet[] = "Your wallet ";
-        long umoney = money_cnt(g.invent);
-
-        if (!umoney) {
-            enl_msg(Your_wallet, "is ", "was ", "empty", "");
-        } else {
-            Sprintf(buf, "%ld %s", umoney, currency(umoney));
-            enl_msg(Your_wallet, "contains ", "contained ", buf, "");
-        }
-    }
-
-    if (flags.pickup) {
-        char ocl[MAXOCLASSES + 1];
-
-        Strcpy(buf, "on");
-        oc_to_str(flags.pickup_types, ocl);
-        Sprintf(eos(buf), " for %s%s%s",
-                *ocl ? "'" : "", *ocl ? ocl : "all types", *ocl ? "'" : "");
-        if (flags.pickup_thrown && *ocl) /* *ocl: don't show if 'all types' */
-            Strcat(buf, " plus thrown");
-        if (g.apelist)
-            Strcat(buf, ", with exceptions");
-    } else
-        Strcpy(buf, "off");
-    enl_msg("Autopickup ", "is ", "was ", buf, "");
-}
-
-/* characteristics: expanded version of bottom line strength, dexterity, &c */
-static void
-characteristics_enlightenment(mode, final)
-int mode;
-int final;
-{
-    char buf[BUFSZ];
-
-    enlght_out("");
-    Sprintf(buf, "%s Characteristics:", !final ? "Current" : "Final");
-    enlght_out(buf);
-
-    /* bottom line order */
-    one_characteristic(mode, final, A_STR); /* strength */
-    one_characteristic(mode, final, A_DEX); /* dexterity */
-    one_characteristic(mode, final, A_CON); /* constitution */
-    one_characteristic(mode, final, A_INT); /* intelligence */
-    one_characteristic(mode, final, A_WIS); /* wisdom */
-    one_characteristic(mode, final, A_CHA); /* charisma */
-}
-
-/* display one attribute value for characteristics_enlightenment() */
-static void
-one_characteristic(mode, final, attrindx)
-int mode, final, attrindx;
-{
-    extern const char *const attrname[]; /* attrib.c */
-    boolean hide_innate_value = FALSE, interesting_alimit;
-    int acurrent, abase, apeak, alimit;
-    const char *paren_pfx;
-    char subjbuf[BUFSZ], valubuf[BUFSZ], valstring[32];
-
-    /* being polymorphed or wearing certain cursed items prevents
-       hero from reliably tracking changes to characteristics so
-       we don't show base & peak values then; when the items aren't
-       cursed, hero could take them off to check underlying values
-       and we show those in such case so that player doesn't need
-       to actually resort to doing that */
-    if (Upolyd) {
-        hide_innate_value = TRUE;
-    } else if (Fixed_abil) {
-        if (stuck_ring(uleft, RIN_SUSTAIN_ABILITY)
-            || stuck_ring(uright, RIN_SUSTAIN_ABILITY))
-            hide_innate_value = TRUE;
-    }
-    switch (attrindx) {
-    case A_STR:
-        if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER && uarmg->cursed)
-            hide_innate_value = TRUE;
-        break;
-    case A_DEX:
-        break;
-    case A_CON:
-        if (uwep && uwep->oartifact == ART_OGRESMASHER && uwep->cursed)
-            hide_innate_value = TRUE;
-        break;
-    case A_INT:
-        if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed)
-            hide_innate_value = TRUE;
-        break;
-    case A_WIS:
-        if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed)
-            hide_innate_value = TRUE;
-        break;
-    case A_CHA:
-        break;
-    default:
-        return; /* impossible */
-    };
-    /* note: final disclosure includes MAGICENLIGHTENTMENT */
-    if ((mode & MAGICENLIGHTENMENT) && !Upolyd)
-        hide_innate_value = FALSE;
-
-    acurrent = ACURR(attrindx);
-    (void) attrval(attrindx, acurrent, valubuf); /* Sprintf(valubuf,"%d",) */
-    Sprintf(subjbuf, "Your %s ", attrname[attrindx]);
-
-    if (!hide_innate_value) {
-        /* show abase, amax, and/or attrmax if acurr doesn't match abase
-           (a magic bonus or penalty is in effect) or abase doesn't match
-           amax (some points have been lost to poison or exercise abuse
-           and are restorable) or attrmax is different from normal human
-           (while game is in progress; trying to reduce dependency on
-           spoilers to keep track of such stuff) or attrmax was different
-           from abase (at end of game; this attribute wasn't maxed out) */
-        abase = ABASE(attrindx);
-        apeak = AMAX(attrindx);
-        alimit = ATTRMAX(attrindx);
-        /* criterium for whether the limit is interesting varies */
-        interesting_alimit =
-            final ? TRUE /* was originally `(abase != alimit)' */
-                  : (alimit != (attrindx != A_STR ? 18 : STR18(100)));
-        paren_pfx = final ? " (" : " (current; ";
-        if (acurrent != abase) {
-            Sprintf(eos(valubuf), "%sbase:%s", paren_pfx,
-                    attrval(attrindx, abase, valstring));
-            paren_pfx = ", ";
-        }
-        if (abase != apeak) {
-            Sprintf(eos(valubuf), "%speak:%s", paren_pfx,
-                    attrval(attrindx, apeak, valstring));
-            paren_pfx = ", ";
-        }
-        if (interesting_alimit) {
-            Sprintf(eos(valubuf), "%s%slimit:%s", paren_pfx,
-                    /* more verbose if exceeding 'limit' due to magic bonus */
-                    (acurrent > alimit) ? "innate " : "",
-                    attrval(attrindx, alimit, valstring));
-            /* paren_pfx = ", "; */
-        }
-        if (acurrent != abase || abase != apeak || interesting_alimit)
-            Strcat(valubuf, ")");
-    }
-    enl_msg(subjbuf, "is ", "was ", valubuf, "");
-}
-
-/* status: selected obvious capabilities, assorted troubles */
-static void
-status_enlightenment(mode, final)
-int mode;
-int final;
-{
-    boolean magic = (mode & MAGICENLIGHTENMENT) ? TRUE : FALSE;
-    int cap, wtype;
-    char buf[BUFSZ], youtoo[BUFSZ];
-    boolean Riding = (u.usteed
-                      /* if hero dies while dismounting, u.usteed will still
-                         be set; we want to ignore steed in that situation */
-                      && !(final == ENL_GAMEOVERDEAD
-                           && !strcmp(g.killer.name, "riding accident")));
-    const char *steedname = (!Riding ? (char *) 0
-                      : x_monnam(u.usteed,
-                                 u.usteed->mtame ? ARTICLE_YOUR : ARTICLE_THE,
-                                 (char *) 0,
-                                 (SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION),
-                                 FALSE));
-
-    /*\
-     * Status (many are abbreviated on bottom line; others are or
-     *     should be discernible to the hero hence to the player)
-    \*/
-    enlght_out(""); /* separator after title or characteristics */
-    enlght_out(final ? "Final Status:" : "Current Status:");
-
-    Strcpy(youtoo, You_);
-    /* not a traditional status but inherently obvious to player; more
-       detail given below (attributes section) for magic enlightenment */
-    if (Upolyd) {
-        Strcpy(buf, "transformed");
-        if (ugenocided())
-            Sprintf(eos(buf), " and %s %s inside",
-                    final ? "felt" : "feel", udeadinside());
-        you_are(buf, "");
-    }
-    /* not a trouble, but we want to display riding status before maybe
-       reporting steed as trapped or hero stuck to cursed saddle */
-    if (Riding) {
-        Sprintf(buf, "riding %s", steedname);
-        you_are(buf, "");
-        Sprintf(eos(youtoo), "and %s ", steedname);
-    }
-    /* other movement situations that hero should always know */
-    if (Levitation) {
-        if (Lev_at_will && magic)
-            you_are("levitating, at will", "");
-        else
-            enl_msg(youtoo, are, were, "levitating", from_what(LEVITATION));
-    } else if (Flying) { /* can only fly when not levitating */
-        enl_msg(youtoo, are, were, "flying", from_what(FLYING));
-    }
-    if (Underwater) {
-        you_are("underwater", "");
-    } else if (u.uinwater) {
-        you_are(Swimming ? "swimming" : "in water", from_what(SWIMMING));
-    } else if (walking_on_water()) {
-        /* show active Wwalking here, potential Wwalking elsewhere */
-        Sprintf(buf, "walking on %s",
-                is_pool(u.ux, u.uy) ? "water"
-                : is_lava(u.ux, u.uy) ? "lava"
-                  : surface(u.ux, u.uy)); /* catchall; shouldn't happen */
-        you_are(buf, from_what(WWALKING));
-    }
-    if (Upolyd && (u.uundetected || U_AP_TYPE != M_AP_NOTHING))
-        youhiding(TRUE, final);
-
-    /* internal troubles, mostly in the order that prayer ranks them */
-    if (Stoned) {
-        if (final && (Stoned & I_SPECIAL))
-            enlght_out(" You turned into stone.");
-        else
-            you_are("turning to stone", "");
-    }
-    if (Slimed) {
-        if (final && (Slimed & I_SPECIAL))
-            enlght_out(" You turned into slime.");
-        else
-            you_are("turning into slime", "");
-    }
-    if (Strangled) {
-        if (u.uburied) {
-            you_are("buried", "");
-        } else {
-            if (final && (Strangled & I_SPECIAL)) {
-                enlght_out(" You died from strangulation.");
-            } else {
-                Strcpy(buf, "being strangled");
-                if (wizard)
-                    Sprintf(eos(buf), " (%ld)", (Strangled & TIMEOUT));
-                you_are(buf, from_what(STRANGLED));
-            }
-        }
-    }
-    if (Sick) {
-        /* the two types of sickness are lumped together; hero can be
-           afflicted by both but there is only one timeout; botl status
-           puts TermIll before FoodPois and death due to timeout reports
-           terminal illness if both are in effect, so do the same here */
-        if (final && (Sick & I_SPECIAL)) {
-            Sprintf(buf, " %sdied from %s.", You_, /* has trailing space */
-                    (u.usick_type & SICK_NONVOMITABLE)
-                    ? "terminal illness" : "food poisoning");
-            enlght_out(buf);
-        } else {
-            /* unlike death due to sickness, report the two cases separately
-               because it is possible to cure one without curing the other */
-            if (u.usick_type & SICK_NONVOMITABLE)
-                you_are("terminally sick from illness", "");
-            if (u.usick_type & SICK_VOMITABLE)
-                you_are("terminally sick from food poisoning", "");
-        }
-    }
-    if (Vomiting)
-        you_are("nauseated", "");
-    if (Stunned)
-        you_are("stunned", "");
-    if (Confusion)
-        you_are("confused", "");
-    if (Hallucination)
-        you_are("hallucinating", "");
-    if (Blind) {
-        /* from_what() (currently wizard-mode only) checks !haseyes()
-           before u.uroleplay.blind, so we should too */
-        Sprintf(buf, "%s blind",
-                !haseyes(g.youmonst.data) ? "innately"
-                : u.uroleplay.blind ? "permanently"
-                  /* better phrasing desperately wanted... */
-                  : Blindfolded_only ? "deliberately"
-                    : "temporarily");
-        if (wizard && (Blinded & TIMEOUT) != 0L
-            && !u.uroleplay.blind && haseyes(g.youmonst.data))
-            Sprintf(eos(buf), " (%ld)", (Blinded & TIMEOUT));
-        /* !haseyes: avoid "you are innately blind innately" */
-        you_are(buf, !haseyes(g.youmonst.data) ? "" : from_what(BLINDED));
-    }
-    if (Deaf)
-        you_are("deaf", from_what(DEAF));
-
-    /* external troubles, more or less */
-    if (Punished) {
-        if (uball) {
-            Sprintf(buf, "chained to %s", ansimpleoname(uball));
-        } else {
-            impossible("Punished without uball?");
-            Strcpy(buf, "punished");
-        }
-        you_are(buf, "");
-    }
-    if (u.utrap) {
-        char predicament[BUFSZ];
-        boolean anchored = (u.utraptype == TT_BURIEDBALL);
-
-        (void) trap_predicament(predicament, final, wizard);
-        if (u.usteed) { /* not `Riding' here */
-            Sprintf(buf, "%s%s ", anchored ? "you and " : "", steedname);
-            *buf = highc(*buf);
-            enl_msg(buf, (anchored ? "are " : "is "),
-                    (anchored ? "were " : "was "), predicament, "");
-        } else
-            you_are(predicament, "");
-    } /* (u.utrap) */
-    if (u.uswallow) {
-        Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
-        if (wizard)
-            Sprintf(eos(buf), " (%u)", u.uswldtim);
-        you_are(buf, "");
-    } else if (u.ustuck) {
-        Sprintf(buf, "%s %s",
-                (Upolyd && sticks(g.youmonst.data)) ? "holding" : "held by",
-                a_monnam(u.ustuck));
-        you_are(buf, "");
-    }
-    if (Riding) {
-        struct obj *saddle = which_armor(u.usteed, W_SADDLE);
-
-        if (saddle && saddle->cursed) {
-            Sprintf(buf, "stuck to %s %s", s_suffix(steedname),
-                    simpleonames(saddle));
-            you_are(buf, "");
-        }
-    }
-    if (Wounded_legs) {
-        /* when mounted, Wounded_legs applies to steed rather than to
-           hero; we only report steed's wounded legs in wizard mode */
-        if (u.usteed) { /* not `Riding' here */
-            if (wizard && steedname) {
-                Strcpy(buf, steedname);
-                *buf = highc(*buf);
-                enl_msg(buf, " has", " had", " wounded legs", "");
-            }
-        } else {
-            Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
-            you_have(buf, "");
-        }
-    }
-    if (Glib) {
-        Sprintf(buf, "slippery %s", fingers_or_gloves(TRUE));
-        if (wizard)
-            Sprintf(eos(buf), " (%ld)", (Glib & TIMEOUT));
-        you_have(buf, "");
-    }
-    if (Fumbling) {
-        if (magic || cause_known(FUMBLING))
-            enl_msg(You_, "fumble", "fumbled", "", from_what(FUMBLING));
-    }
-    if (Sleepy) {
-        if (magic || cause_known(SLEEPY)) {
-            Strcpy(buf, from_what(SLEEPY));
-            if (wizard)
-                Sprintf(eos(buf), " (%ld)", (HSleepy & TIMEOUT));
-            enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf);
-        }
-    }
-    /* hunger/nutrition */
-    if (Hunger) {
-        if (magic || cause_known(HUNGER))
-            enl_msg(You_, "hunger", "hungered", " rapidly",
-                    from_what(HUNGER));
-    }
-    Strcpy(buf, hu_stat[u.uhs]); /* hunger status; omitted if "normal" */
-    mungspaces(buf);             /* strip trailing spaces */
-    if (*buf) {
-        *buf = lowc(*buf); /* override capitalization */
-        if (!strcmp(buf, "weak"))
-            Strcat(buf, " from severe hunger");
-        else if (!strncmp(buf, "faint", 5)) /* fainting, fainted */
-            Strcat(buf, " due to starvation");
-        you_are(buf, "");
-    }
-    /* encumbrance */
-    if ((cap = near_capacity()) > UNENCUMBERED) {
-        const char *adj = "?_?"; /* (should always get overridden) */
-
-        Strcpy(buf, enc_stat[cap]);
-        *buf = lowc(*buf);
-        switch (cap) {
-        case SLT_ENCUMBER:
-            adj = "slightly";
-            break; /* burdened */
-        case MOD_ENCUMBER:
-            adj = "moderately";
-            break; /* stressed */
-        case HVY_ENCUMBER:
-            adj = "very";
-            break; /* strained */
-        case EXT_ENCUMBER:
-            adj = "extremely";
-            break; /* overtaxed */
-        case OVERLOADED:
-            adj = "not possible";
-            break;
-        }
-        Sprintf(eos(buf), "; movement %s %s%s", !final ? "is" : "was", adj,
-                (cap < OVERLOADED) ? " slowed" : "");
-        you_are(buf, "");
-    } else {
-        /* last resort entry, guarantees Status section is non-empty
-           (no longer needed for that purpose since weapon status added;
-           still useful though) */
-        you_are("unencumbered", "");
-    }
-
-    /* report being weaponless; distinguish whether gloves are worn */
-    if (!uwep) {
-        you_are(uarmg ? "empty handed" /* gloves imply hands */
-                      : humanoid(g.youmonst.data)
-                         /* hands but no weapon and no gloves */
-                         ? "bare handed"
-                         /* alternate phrasing for paws or lack of hands */
-                         : "not wielding anything",
-                "");
-    /* two-weaponing implies hands (can't be polymorphed) and
-       a weapon or wep-tool (not other odd stuff) in each hand */
-    } else if (u.twoweap) {
-        you_are("wielding two weapons at once", "");
-    /* report most weapons by their skill class (so a katana will be
-       described as a long sword, for instance; mattock and hook are
-       exceptions), or wielded non-weapon item by its object class */
-    } else {
-        const char *what = weapon_descr(uwep);
-
-        if (!strcmpi(what, "armor") || !strcmpi(what, "food")
-            || !strcmpi(what, "venom"))
-            Sprintf(buf, "wielding some %s", what);
-        else
-            Sprintf(buf, "wielding %s",
-                    (uwep->quan == 1L) ? an(what) : makeplural(what));
-        you_are(buf, "");
-    }
-    /*
-     * Skill with current weapon.  Might help players who've never
-     * noticed #enhance or decided that it was pointless.
-     *
-     * TODO?  Maybe merge wielding line and skill line into one sentence.
-     */
-    if ((wtype = uwep_skill_type()) != P_NONE) {
-        char sklvlbuf[20];
-        int sklvl = P_SKILL(wtype);
-        boolean hav = (sklvl != P_UNSKILLED && sklvl != P_SKILLED);
-
-        if (sklvl == P_ISRESTRICTED)
-            Strcpy(sklvlbuf, "no");
-        else
-            (void) lcase(skill_level_name(wtype, sklvlbuf));
-        /* "you have no/basic/expert/master/grand-master skill with <skill>"
-           or "you are unskilled/skilled in <skill>" */
-        Sprintf(buf, "%s %s %s", sklvlbuf,
-                hav ? "skill with" : "in", skill_name(wtype));
-        if (can_advance(wtype, FALSE))
-            Sprintf(eos(buf), " and %s that",
-                    !final ? "can enhance" : "could have enhanced");
-        if (hav)
-            you_have(buf, "");
-        else
-            you_are(buf, "");
-    }
-    /* report 'nudity' */
-    if (!uarm && !uarmu && !uarmc && !uarms && !uarmg && !uarmf && !uarmh) {
-        if (u.uroleplay.nudist)
-            enl_msg(You_, "do", "did", " not wear any armor", "");
-        else
-            you_are("not wearing any armor", "");
-    }
-}
-
-/* attributes: intrinsics and the like, other non-obvious capabilities */
-static void
-attributes_enlightenment(unused_mode, final)
-int unused_mode UNUSED;
-int final;
-{
-    static NEARDATA const char if_surroundings_permitted[] =
-        " if surroundings permitted";
-    int ltmp, armpro;
-    char buf[BUFSZ];
-
-    /*\
-     *  Attributes
-    \*/
-    enlght_out("");
-    enlght_out(final ? "Final Attributes:" : "Current Attributes:");
-
-    if (u.uevent.uhand_of_elbereth) {
-        static const char *const hofe_titles[3] = { "the Hand of Elbereth",
-                                                    "the Envoy of Balance",
-                                                    "the Glory of Arioch" };
-        you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1], "");
-    }
-
-    Sprintf(buf, "%s", piousness(TRUE, "aligned"));
-    if (u.ualign.record >= 0)
-        you_are(buf, "");
-    else
-        you_have(buf, "");
-
-    if (wizard) {
-        Sprintf(buf, " %d", u.ualign.record);
-        enl_msg("Your alignment ", "is", "was", buf, "");
-    }
-
-    /*** Resistances to troubles ***/
-    if (Invulnerable)
-        you_are("invulnerable", from_what(INVULNERABLE));
-    if (Antimagic)
-        you_are("magic-protected", from_what(ANTIMAGIC));
-    if (Fire_resistance)
-        you_are("fire resistant", from_what(FIRE_RES));
-    if (Cold_resistance)
-        you_are("cold resistant", from_what(COLD_RES));
-    if (Sleep_resistance)
-        you_are("sleep resistant", from_what(SLEEP_RES));
-    if (Disint_resistance)
-        you_are("disintegration-resistant", from_what(DISINT_RES));
-    if (Shock_resistance)
-        you_are("shock resistant", from_what(SHOCK_RES));
-    if (Poison_resistance)
-        you_are("poison resistant", from_what(POISON_RES));
-    if (Acid_resistance)
-        you_are("acid resistant", from_what(ACID_RES));
-    if (Drain_resistance)
-        you_are("level-drain resistant", from_what(DRAIN_RES));
-    if (Sick_resistance)
-        you_are("immune to sickness", from_what(SICK_RES));
-    if (Stone_resistance)
-        you_are("petrification resistant", from_what(STONE_RES));
-    if (Halluc_resistance)
-        enl_msg(You_, "resist", "resisted", " hallucinations",
-                from_what(HALLUC_RES));
-    if (u.uedibility)
-        you_can("recognize detrimental food", "");
-
-    /*** Vision and senses ***/
-    if (!Blind && (Blinded || !haseyes(g.youmonst.data)))
-        you_can("see", from_what(-BLINDED)); /* Eyes of the Overworld */
-    if (See_invisible) {
-        if (!Blind)
-            enl_msg(You_, "see", "saw", " invisible", from_what(SEE_INVIS));
-        else
-            enl_msg(You_, "will see", "would have seen",
-                    " invisible when not blind", from_what(SEE_INVIS));
-    }
-    if (Blind_telepat)
-        you_are("telepathic", from_what(TELEPAT));
-    if (Warning)
-        you_are("warned", from_what(WARNING));
-    if (Warn_of_mon && g.context.warntype.obj) {
-        Sprintf(buf, "aware of the presence of %s",
-                (g.context.warntype.obj & M2_ORC) ? "orcs"
-                : (g.context.warntype.obj & M2_ELF) ? "elves"
-                : (g.context.warntype.obj & M2_DEMON) ? "demons" : something);
-        you_are(buf, from_what(WARN_OF_MON));
-    }
-    if (Warn_of_mon && g.context.warntype.polyd) {
-        Sprintf(buf, "aware of the presence of %s",
-                ((g.context.warntype.polyd & (M2_HUMAN | M2_ELF))
-                 == (M2_HUMAN | M2_ELF))
-                    ? "humans and elves"
-                    : (g.context.warntype.polyd & M2_HUMAN)
-                          ? "humans"
-                          : (g.context.warntype.polyd & M2_ELF)
-                                ? "elves"
-                                : (g.context.warntype.polyd & M2_ORC)
-                                      ? "orcs"
-                                      : (g.context.warntype.polyd & M2_DEMON)
-                                            ? "demons"
-                                            : "certain monsters");
-        you_are(buf, "");
-    }
-    if (Warn_of_mon && g.context.warntype.speciesidx >= LOW_PM) {
-        Sprintf(buf, "aware of the presence of %s",
-                makeplural(mons[g.context.warntype.speciesidx].mname));
-        you_are(buf, from_what(WARN_OF_MON));
-    }
-    if (Undead_warning)
-        you_are("warned of undead", from_what(WARN_UNDEAD));
-    if (Searching)
-        you_have("automatic searching", from_what(SEARCHING));
-    if (Clairvoyant)
-        you_are("clairvoyant", from_what(CLAIRVOYANT));
-    else if ((HClairvoyant || EClairvoyant) && BClairvoyant) {
-        Strcpy(buf, from_what(-CLAIRVOYANT));
-        if (!strncmp(buf, " because of ", 12))
-            /* overwrite substring; strncpy doesn't add terminator */
-            (void) strncpy(buf, " if not for ", 12);
-        enl_msg(You_, "could be", "could have been", " clairvoyant", buf);
-    }
-    if (Infravision)
-        you_have("infravision", from_what(INFRAVISION));
-    if (Detect_monsters)
-        you_are("sensing the presence of monsters", "");
-    if (u.umconf)
-        you_are("going to confuse monsters", "");
-
-    /*** Appearance and behavior ***/
-    if (Adornment) {
-        int adorn = 0;
-
-        if (uleft && uleft->otyp == RIN_ADORNMENT)
-            adorn += uleft->spe;
-        if (uright && uright->otyp == RIN_ADORNMENT)
-            adorn += uright->spe;
-        /* the sum might be 0 (+0 ring or two which negate each other);
-           that yields "you are charismatic" (which isn't pointless
-           because it potentially impacts seduction attacks) */
-        Sprintf(buf, "%scharismatic",
-                (adorn > 0) ? "more " : (adorn < 0) ? "less " : "");
-        you_are(buf, from_what(ADORNED));
-    }
-    if (Invisible)
-        you_are("invisible", from_what(INVIS));
-    else if (Invis)
-        you_are("invisible to others", from_what(INVIS));
-    /* ordinarily "visible" is redundant; this is a special case for
-       the situation when invisibility would be an expected attribute */
-    else if ((HInvis || EInvis) && BInvis)
-        you_are("visible", from_what(-INVIS));
-    if (Displaced)
-        you_are("displaced", from_what(DISPLACED));
-    if (Stealth)
-        you_are("stealthy", from_what(STEALTH));
-    if (Aggravate_monster)
-        enl_msg("You aggravate", "", "d", " monsters",
-                from_what(AGGRAVATE_MONSTER));
-    if (Conflict)
-        enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT));
-
-    /*** Transportation ***/
-    if (Jumping)
-        you_can("jump", from_what(JUMPING));
-    if (Teleportation)
-        you_can("teleport", from_what(TELEPORT));
-    if (Teleport_control)
-        you_have("teleport control", from_what(TELEPORT_CONTROL));
-    /* actively levitating handled earlier as a status condition */
-    if (BLevitation) { /* levitation is blocked */
-        long save_BLev = BLevitation;
-
-        BLevitation = 0L;
-        if (Levitation) {
-            /* either trapped in the floor or inside solid rock
-               (or both if chained to buried iron ball and have
-               moved one step into solid rock somehow) */
-            boolean trapped = (save_BLev & I_SPECIAL) != 0L,
-                    terrain = (save_BLev & FROMOUTSIDE) != 0L;
-
-            Sprintf(buf, "%s%s%s",
-                    trapped ? " if not trapped" : "",
-                    (trapped && terrain) ? " and" : "",
-                    terrain ? if_surroundings_permitted : "");
-            enl_msg(You_, "would levitate", "would have levitated", buf, "");
-        }
-        BLevitation = save_BLev;
-    }
-    /* actively flying handled earlier as a status condition */
-    if (BFlying) { /* flight is blocked */
-        long save_BFly = BFlying;
-
-        BFlying = 0L;
-        if (Flying) {
-            enl_msg(You_, "would fly", "would have flown",
-                    /* wording quibble: for past tense, "hadn't been"
-                       would sound better than "weren't" (and
-                       "had permitted" better than "permitted"), but
-                       "weren't" and "permitted" are adequate so the
-                       extra complexity to handle that isn't worth it */
-                    Levitation
-                       ? " if you weren't levitating"
-                       : (save_BFly == I_SPECIAL)
-                          /* this is an oversimpliction; being trapped
-                             might also be blocking levitation so flight
-                             would still be blocked after escaping trap */
-                          ? " if you weren't trapped"
-                          : (save_BFly == FROMOUTSIDE)
-                             ? if_surroundings_permitted
-                             /* two or more of levitation, surroundings,
-                                and being trapped in the floor */
-                             : " if circumstances permitted",
-                    "");
-        }
-        BFlying = save_BFly;
-    }
-    /* actively walking on water handled earlier as a status condition */
-    if (Wwalking && !walking_on_water())
-        you_can("walk on water", from_what(WWALKING));
-    /* actively swimming (in water but not under it) handled earlier */
-    if (Swimming && (Underwater || !u.uinwater))
-        you_can("swim", from_what(SWIMMING));
-    if (Breathless)
-        you_can("survive without air", from_what(MAGICAL_BREATHING));
-    else if (Amphibious)
-        you_can("breathe water", from_what(MAGICAL_BREATHING));
-    if (Passes_walls)
-        you_can("walk through walls", from_what(PASSES_WALLS));
-
-    /*** Physical attributes ***/
-    if (Regeneration)
-        enl_msg("You regenerate", "", "d", "", from_what(REGENERATION));
-    if (Slow_digestion)
-        you_have("slower digestion", from_what(SLOW_DIGESTION));
-    if (u.uhitinc)
-        you_have(enlght_combatinc("to hit", u.uhitinc, final, buf), "");
-    if (u.udaminc)
-        you_have(enlght_combatinc("damage", u.udaminc, final, buf), "");
-    if (u.uspellprot || Protection) {
-        int prot = 0;
-
-        if (uleft && uleft->otyp == RIN_PROTECTION)
-            prot += uleft->spe;
-        if (uright && uright->otyp == RIN_PROTECTION)
-            prot += uright->spe;
-        if (HProtection & INTRINSIC)
-            prot += u.ublessed;
-        prot += u.uspellprot;
-        if (prot)
-            you_have(enlght_combatinc("defense", prot, final, buf), "");
-    }
-    if ((armpro = magic_negation(&g.youmonst)) > 0) {
-        /* magic cancellation factor, conferred by worn armor */
-        static const char *const mc_types[] = {
-            "" /*ordinary*/, "warded", "guarded", "protected",
-        };
-        /* sanity check */
-        if (armpro >= SIZE(mc_types))
-            armpro = SIZE(mc_types) - 1;
-        you_are(mc_types[armpro], "");
-    }
-    if (Half_physical_damage)
-        enlght_halfdmg(HALF_PHDAM, final);
-    if (Half_spell_damage)
-        enlght_halfdmg(HALF_SPDAM, final);
-    if (Half_gas_damage)
-        enl_msg(You_, "take", "took", " reduced poison gas damage", "");
-    /* polymorph and other shape change */
-    if (Protection_from_shape_changers)
-        you_are("protected from shape changers",
-                from_what(PROT_FROM_SHAPE_CHANGERS));
-    if (Unchanging) {
-        const char *what = 0;
-
-        if (!Upolyd) /* Upolyd handled below after current form */
-            you_can("not change from your current form",
-                    from_what(UNCHANGING));
-        /* blocked shape changes */
-        if (Polymorph)
-            what = !final ? "polymorph" : "have polymorphed";
-        else if (u.ulycn >= LOW_PM)
-            what = !final ? "change shape" : "have changed shape";
-        if (what) {
-            Sprintf(buf, "would %s periodically", what);
-            /* omit from_what(UNCHANGING); too verbose */
-            enl_msg(You_, buf, buf, " if not locked into your current form",
-                    "");
-        }
-    } else if (Polymorph) {
-        you_are("polymorphing periodically", from_what(POLYMORPH));
-    }
-    if (Polymorph_control)
-        you_have("polymorph control", from_what(POLYMORPH_CONTROL));
-    if (Upolyd && u.umonnum != u.ulycn
-        /* if we've died from turning into slime, we're polymorphed
-           right now but don't want to list it as a temporary attribute
-           [we need a more reliable way to detect this situation] */
-        && !(final == ENL_GAMEOVERDEAD
-             && u.umonnum == PM_GREEN_SLIME && !Unchanging)) {
-        /* foreign shape (except were-form which is handled below) */
-        if (!vampshifted(&g.youmonst))
-            Sprintf(buf, "polymorphed into %s", an(g.youmonst.data->mname));
-        else
-            Sprintf(buf, "polymorphed into %s in %s form",
-                    an(mons[g.youmonst.cham].mname), g.youmonst.data->mname);
-        if (wizard)
-            Sprintf(eos(buf), " (%d)", u.mtimedone);
-        you_are(buf, "");
-    }
-    if (lays_eggs(g.youmonst.data) && flags.female) /* Upolyd */
-        you_can("lay eggs", "");
-    if (u.ulycn >= LOW_PM) {
-        /* "you are a werecreature [in beast form]" */
-        Strcpy(buf, an(mons[u.ulycn].mname));
-        if (u.umonnum == u.ulycn) {
-            Strcat(buf, " in beast form");
-            if (wizard)
-                Sprintf(eos(buf), " (%d)", u.mtimedone);
-        }
-        you_are(buf, "");
-    }
-    if (Unchanging && Upolyd) /* !Upolyd handled above */
-        you_can("not change from your current form", from_what(UNCHANGING));
-    if (Hate_silver)
-        you_are("harmed by silver", "");
-    /* movement and non-armor-based protection */
-    if (Fast)
-        you_are(Very_fast ? "very fast" : "fast", from_what(FAST));
-    if (Reflecting)
-        you_have("reflection", from_what(REFLECTING));
-    if (Free_action)
-        you_have("free action", from_what(FREE_ACTION));
-    if (Fixed_abil)
-        you_have("fixed abilities", from_what(FIXED_ABIL));
-    if (Lifesaved)
-        enl_msg("Your life ", "will be", "would have been", " saved", "");
-
-    /*** Miscellany ***/
-    if (Luck) {
-        ltmp = abs((int) Luck);
-        Sprintf(buf, "%s%slucky",
-                ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
-                Luck < 0 ? "un" : "");
-        if (wizard)
-            Sprintf(eos(buf), " (%d)", Luck);
-        you_are(buf, "");
-    } else if (wizard)
-        enl_msg("Your luck ", "is", "was", " zero", "");
-    if (u.moreluck > 0)
-        you_have("extra luck", "");
-    else if (u.moreluck < 0)
-        you_have("reduced luck", "");
-    if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
-        ltmp = stone_luck(FALSE);
-        if (ltmp <= 0)
-            enl_msg("Bad luck ", "does", "did", " not time out for you", "");
-        if (ltmp >= 0)
-            enl_msg("Good luck ", "does", "did", " not time out for you", "");
-    }
-
-    if (u.ugangr) {
-        Sprintf(buf, " %sangry with you",
-                u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
-        if (wizard)
-            Sprintf(eos(buf), " (%d)", u.ugangr);
-        enl_msg(u_gname(), " is", " was", buf, "");
-    } else {
-        /*
-         * We need to suppress this when the game is over, because death
-         * can change the value calculated by can_pray(), potentially
-         * resulting in a false claim that you could have prayed safely.
-         */
-        if (!final) {
-#if 0
-            /* "can [not] safely pray" vs "could [not] have safely prayed" */
-            Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
-                    final ? "have " : "", final ? "ed" : "");
-#else
-            Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
-#endif
-            if (wizard)
-                Sprintf(eos(buf), " (%d)", u.ublesscnt);
-            you_can(buf, "");
-        }
-    }
-
-#ifdef DEBUG
-    /* named fruit debugging (doesn't really belong here...); to enable,
-       include 'fruit' in DEBUGFILES list (even though it isn't a file...) */
-    if (wizard && explicitdebug("fruit")) {
-        struct fruit *f;
-
-        reorder_fruit(TRUE); /* sort by fruit index, from low to high;
-                              * this modifies the g.ffruit chain, so could
-                              * possibly mask or even introduce a problem,
-                              * but it does useful sanity checking */
-        for (f = g.ffruit; f; f = f->nextf) {
-            Sprintf(buf, "Fruit #%d ", f->fid);
-            enl_msg(buf, "is ", "was ", f->fname, "");
-        }
-        enl_msg("The current fruit ", "is ", "was ", g.pl_fruit, "");
-        Sprintf(buf, "%d", flags.made_fruit);
-        enl_msg("The made fruit flag ", "is ", "was ", buf, "");
-    }
-#endif
-
-    {
-        const char *p;
-
-        buf[0] = '\0';
-        if (final < 2) { /* still in progress, or quit/escaped/ascended */
-            p = "survived after being killed ";
-            switch (u.umortality) {
-            case 0:
-                p = !final ? (char *) 0 : "survived";
-                break;
-            case 1:
-                Strcpy(buf, "once");
-                break;
-            case 2:
-                Strcpy(buf, "twice");
-                break;
-            case 3:
-                Strcpy(buf, "thrice");
-                break;
-            default:
-                Sprintf(buf, "%d times", u.umortality);
-                break;
-            }
-        } else { /* game ended in character's death */
-            p = "are dead";
-            switch (u.umortality) {
-            case 0:
-                impossible("dead without dying?");
-            case 1:
-                break; /* just "are dead" */
-            default:
-                Sprintf(buf, " (%d%s time!)", u.umortality,
-                        ordin(u.umortality));
-                break;
-            }
-        }
-        if (p)
-            enl_msg(You_, "have been killed ", p, buf, "");
-    }
-}
-
-/* ^X command */
-static int
-doattributes(VOID_ARGS)
-{
-    int mode = BASICENLIGHTENMENT;
-
-    /* show more--as if final disclosure--for wizard and explore modes */
-    if (wizard || discover)
-        mode |= MAGICENLIGHTENMENT;
-
-    enlightenment(mode, ENL_GAMEINPROGRESS);
-    return 0;
-}
-
-void
-youhiding(via_enlghtmt, msgflag)
-boolean via_enlghtmt; /* englightment line vs topl message */
-int msgflag;          /* for variant message phrasing */
-{
-    char *bp, buf[BUFSZ];
-
-    Strcpy(buf, "hiding");
-    if (U_AP_TYPE != M_AP_NOTHING) {
-        /* mimic; hero is only able to mimic a strange object or gold
-           or hallucinatory alternative to gold, so we skip the details
-           for the hypothetical furniture and monster cases */
-        bp = eos(strcpy(buf, "mimicking"));
-        if (U_AP_TYPE == M_AP_OBJECT) {
-            Sprintf(bp, " %s", an(simple_typename(g.youmonst.mappearance)));
-        } else if (U_AP_TYPE == M_AP_FURNITURE) {
-            Strcpy(bp, " something");
-        } else if (U_AP_TYPE == M_AP_MONSTER) {
-            Strcpy(bp, " someone");
-        } else {
-            ; /* something unexpected; leave 'buf' as-is */
-        }
-    } else if (u.uundetected) {
-        bp = eos(buf); /* points past "hiding" */
-        if (g.youmonst.data->mlet == S_EEL) {
-            if (is_pool(u.ux, u.uy))
-                Sprintf(bp, " in the %s", waterbody_name(u.ux, u.uy));
-        } else if (hides_under(g.youmonst.data)) {
-            struct obj *o = g.level.objects[u.ux][u.uy];
-
-            if (o)
-                Sprintf(bp, " underneath %s", ansimpleoname(o));
-        } else if (is_clinger(g.youmonst.data) || Flying) {
-            /* Flying: 'lurker above' hides on ceiling but doesn't cling */
-            Sprintf(bp, " on the %s", ceiling(u.ux, u.uy));
-        } else {
-            /* on floor; is_hider() but otherwise not special: 'trapper' */
-            if (u.utrap && u.utraptype == TT_PIT) {
-                struct trap *t = t_at(u.ux, u.uy);
-
-                Sprintf(bp, " in a %spit",
-                        (t && t->ttyp == SPIKED_PIT) ? "spiked " : "");
-            } else
-                Sprintf(bp, " on the %s", surface(u.ux, u.uy));
-        }
-    } else {
-        ; /* shouldn't happen; will result in generic "you are hiding" */
-    }
-
-    if (via_enlghtmt) {
-        int final = msgflag; /* 'final' is used by you_are() macro */
-
-        you_are(buf, "");
-    } else {
-        /* for dohide(), when player uses '#monster' command */
-        You("are %s %s.", msgflag ? "already" : "now", buf);
-    }
-}
-
-/* KMH, #conduct
- * (shares enlightenment's tense handling)
- */
-int
-doconduct(VOID_ARGS)
-{
-    show_conduct(0);
-    return 0;
-}
-
-void
-show_conduct(final)
-int final;
-{
-    char buf[BUFSZ];
-    int ngenocided;
-
-    /* Create the conduct window */
-    g.en_win = create_nhwindow(NHW_MENU);
-    putstr(g.en_win, 0, "Voluntary challenges:");
-
-    if (u.uroleplay.blind)
-        you_have_been("blind from birth");
-    if (u.uroleplay.nudist)
-        you_have_been("faithfully nudist");
-
-    if (!u.uconduct.food)
-        enl_msg(You_, "have gone", "went", " without food", "");
-        /* but beverages are okay */
-    else if (!u.uconduct.unvegan)
-        you_have_X("followed a strict vegan diet");
-    else if (!u.uconduct.unvegetarian)
-        you_have_been("vegetarian");
-
-    if (!u.uconduct.gnostic)
-        you_have_been("an atheist");
-
-    if (!u.uconduct.weaphit) {
-        you_have_never("hit with a wielded weapon");
-    } else if (wizard) {
-        Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit,
-                plur(u.uconduct.weaphit));
-        you_have_X(buf);
-    }
-    if (!u.uconduct.killer)
-        you_have_been("a pacifist");
-
-    if (!u.uconduct.literate) {
-        you_have_been("illiterate");
-    } else if (wizard) {
-        Sprintf(buf, "read items or engraved %ld time%s", u.uconduct.literate,
-                plur(u.uconduct.literate));
-        you_have_X(buf);
-    }
-
-    ngenocided = num_genocides();
-    if (ngenocided == 0) {
-        you_have_never("genocided any monsters");
-    } else {
-        Sprintf(buf, "genocided %d type%s of monster%s", ngenocided,
-                plur(ngenocided), plur(ngenocided));
-        you_have_X(buf);
-    }
-
-    if (!u.uconduct.polypiles) {
-        you_have_never("polymorphed an object");
-    } else if (wizard) {
-        Sprintf(buf, "polymorphed %ld item%s", u.uconduct.polypiles,
-                plur(u.uconduct.polypiles));
-        you_have_X(buf);
-    }
-
-    if (!u.uconduct.polyselfs) {
-        you_have_never("changed form");
-    } else if (wizard) {
-        Sprintf(buf, "changed form %ld time%s", u.uconduct.polyselfs,
-                plur(u.uconduct.polyselfs));
-        you_have_X(buf);
-    }
-
-    if (!u.uconduct.wishes) {
-        you_have_X("used no wishes");
-    } else {
-        Sprintf(buf, "used %ld wish%s", u.uconduct.wishes,
-                (u.uconduct.wishes > 1L) ? "es" : "");
-        if (u.uconduct.wisharti) {
-            /* if wisharti == wishes
-             *  1 wish (for an artifact)
-             *  2 wishes (both for artifacts)
-             *  N wishes (all for artifacts)
-             * else (N is at least 2 in order to get here; M < N)
-             *  N wishes (1 for an artifact)
-             *  N wishes (M for artifacts)
-             */
-            if (u.uconduct.wisharti == u.uconduct.wishes)
-                Sprintf(eos(buf), " (%s",
-                        (u.uconduct.wisharti > 2L) ? "all "
-                          : (u.uconduct.wisharti == 2L) ? "both " : "");
-            else
-                Sprintf(eos(buf), " (%ld ", u.uconduct.wisharti);
-
-            Sprintf(eos(buf), "for %s)",
-                    (u.uconduct.wisharti == 1L) ? "an artifact"
-                                                : "artifacts");
-        }
-        you_have_X(buf);
-
-        if (!u.uconduct.wisharti)
-            enl_msg(You_, "have not wished", "did not wish",
-                    " for any artifacts", "");
-    }
-
-    show_achievements(final);
-
-    /* Pop up the window and wait for a key */
-    display_nhwindow(g.en_win, TRUE);
-    destroy_nhwindow(g.en_win);
-    g.en_win = WIN_ERR;
-}
-
-static void
-show_achievements(final)
-int final;
-{
-    winid awin = WIN_ERR;
-    int acnt = 0;
-
-    /* unfortunately we can't show the achievements (at least not all of
-       them) while the game is in progress because it would give away the
-       ID of luckstone (at Mine's End) and of real Amulet of Yendor */
-    if (!final && !wizard)
-        return;
-
-    if (g.en_win != WIN_ERR) {
-        awin = g.en_win;
-        putstr(awin, 0, "");
-    } else {
-        awin = create_nhwindow(NHW_MENU);
-    }
-    putstr(awin, 0, "Achievements:");
-    /* arranged in approximate order of difficulty */
-    if (u.uachieve.mines_luckstone)
-        enl_msg(You_, "have ", "",
-                "completed the Gnomish Mines", ""), ++acnt;
-    if (u.uachieve.finish_sokoban)
-        enl_msg(You_, "have ", "",
-                "completed Sokoban", ""), ++acnt;
-    if (u.uachieve.killed_medusa)
-        enl_msg(You_, "have ", "",
-                "defeated Medusa", ""), ++acnt;
-    if (u.uachieve.bell)
-        enl_msg(You_, "have ", "",
-                "handled the Bell of Opening", ""), ++acnt;
-    if (u.uachieve.enter_gehennom)
-        enl_msg(You_, "have ", "",
-                "passed the Valley of the Dead", ""), ++acnt;
-    if (u.uachieve.menorah)
-        enl_msg(You_, "have ", "",
-                "handled the Candelabrum of Invocation", ""), ++acnt;
-    if (u.uachieve.book)
-        enl_msg(You_, "have ", "",
-                "handled the Book of the Dead", ""), ++acnt;
-    if (u.uevent.invoked)
-        enl_msg(You_, "have ", "",
-                "gained access to Moloch's Sanctum", ""), ++acnt;
-    if (u.uachieve.amulet)
-        enl_msg(You_, "have ", "",
-                "obtained the Amulet of Yendor", ""), ++acnt;
-    if (In_endgame(&u.uz))
-        enl_msg(You_, "have ", "",
-                "reached the Elemental Planes", ""), ++acnt;
-    if (Is_astralevel(&u.uz))
-        enl_msg(You_, "have ", "",
-                "reached the Astral Plane", ""), ++acnt;
-    if (u.uachieve.ascended)
-        enlght_out(" You ascended!"), ++acnt;
-    if (u.uroleplay.blind || u.uroleplay.nudist) {
-        if (acnt)
-            putstr(awin, 0, "");
-        if (u.uroleplay.blind)
-            enl_msg(You_, "are exploring", "explored",
-                    " without being able to see", ""), ++acnt;
-        if (u.uroleplay.nudist)
-            enl_msg(You_, "have gone", "went",
-                    " without any armor", ""), ++acnt;
-    }
-    if (!acnt)
-        enlght_out(" []");
-
-    if (awin != g.en_win) {
-        display_nhwindow(awin, TRUE);
-        destroy_nhwindow(awin);
-    }
-}
-
 /* ordered by command name */
 struct ext_func_tab extcmdlist[] = {
     { '#', "#", "perform an extended command",
@@ -3868,7 +2109,7 @@ dokeylist(VOID_ARGS)
     /* directional keys */
     putstr(datawin, 0, "");
     putstr(datawin, 0, "Directional keys:");
-    show_direction_keys(datawin, '.', FALSE); /* '.'==self in direction grid */
+    show_direction_keys(datawin, '.', FALSE); /* '.'==self in direct'n grid */
 
     keys_used[(uchar) g.Cmd.move_NW] = keys_used[(uchar) g.Cmd.move_N]
         = keys_used[(uchar) g.Cmd.move_NE] = keys_used[(uchar) g.Cmd.move_W]
@@ -4126,7 +2367,7 @@ long *total_size;
     char buf[BUFSZ];
     long count, size;
     struct monst *mon;
-    /* mon->wormno means something different for g.migrating_mons and g.mydogs */
+    /* mon->wormno means something different for migrating_mons and mydogs */
     boolean incl_wsegs = !strcmpi(src, "fmon");
 
     count = size = 0L;
@@ -4281,7 +2522,8 @@ wiz_show_stats()
     putstr(win, 0, stats_hdr);
     Sprintf(buf, "  Objects, base size %ld", (long) sizeof (struct obj));
     putstr(win, 0, buf);
-    obj_chain(win, "invent", g.invent, TRUE, &total_obj_count, &total_obj_size);
+    obj_chain(win, "invent", g.invent, TRUE,
+              &total_obj_count, &total_obj_size);
     obj_chain(win, "fobj", fobj, TRUE, &total_obj_count, &total_obj_size);
     obj_chain(win, "buried", g.level.buriedobjlist, FALSE,
               &total_obj_count, &total_obj_size);
@@ -4595,10 +2837,10 @@ boolean initial;
         'y', 'Y', C('y'), M('y'), M('Y'), M(C('y'))
     };
     static struct ext_func_tab *back_dir_cmd[8];
+    static boolean backed_dir_cmd = FALSE;
     const struct ext_func_tab *cmdtmp;
     boolean flagtemp;
     int c, i, updated = 0;
-    static boolean backed_dir_cmd = FALSE;
 
     if (initial) {
         updated = 1;
@@ -4608,7 +2850,6 @@ boolean initial;
             g.Cmd.spkeys[spkeys_binds[i].nhkf] = spkeys_binds[i].key;
         commands_init();
     } else {
-
         if (backed_dir_cmd) {
             for (i = 0; i < 8; i++) {
                 g.Cmd.commands[(uchar) g.Cmd.dirchars[i]] = back_dir_cmd[i];
@@ -4686,9 +2927,10 @@ boolean initial;
 
     if (!initial) {
         for (i = 0; i < 8; i++) {
-            back_dir_cmd[i] =
-                (struct ext_func_tab *) g.Cmd.commands[(uchar) g.Cmd.dirchars[i]];
-            g.Cmd.commands[(uchar) g.Cmd.dirchars[i]] = (struct ext_func_tab *) 0;
+            uchar di = (uchar) g.Cmd.dirchars[i];
+
+            back_dir_cmd[i] = (struct ext_func_tab *) g.Cmd.commands[di];
+            g.Cmd.commands[di] = (struct ext_func_tab *) 0;
         }
         backed_dir_cmd = TRUE;
         for (i = 0; i < 8; i++)
@@ -5096,7 +3338,7 @@ dxdy_moveok()
     return u.dx || u.dy;
 }
 
-/* decide whether character (user input keystroke) requests screen repaint */
+/* decide whether character (user input keystroke) requests screen repaint */
 boolean
 redraw_cmd(c)
 char c;
@@ -5515,7 +3757,8 @@ int x, y;
     if ((ttmp = t_at(x, y)) != 0 && ttmp->tseen) {
         add_herecmd_menuitem(win, doidtrap, "Examine trap"), ++K;
         if (ttmp->ttyp != VIBRATING_SQUARE)
-            add_herecmd_menuitem(win, dountrap, "Attempt to disarm trap"), ++K;
+            add_herecmd_menuitem(win, dountrap,
+                                 "Attempt to disarm trap"), ++K;
     }
 
     mtmp = m_at(x, y);
@@ -5675,9 +3918,11 @@ const char *
 click_to_cmd(x, y, mod)
 int x, y, mod;
 {
-    int dir;
     static char cmd[4];
-    cmd[1] = 0;
+    struct obj *o;
+    int dir;
+
+    cmd[1] = '\0';
 
     if (iflags.clicklook && mod == CLICK_2) {
         g.clicklook_cc.x = x;
@@ -5725,9 +3970,8 @@ int x, y, mod;
                        || (u.ux == xdnladder && u.uy == ydnladder)) {
                 cmd[0] = cmd_from_func(dodown);
                 return cmd;
-            } else if (OBJ_AT(u.ux, u.uy)) {
-                cmd[0] = cmd_from_func(Is_container(g.level.objects[u.ux][u.uy])
-                                       ? doloot : dopickup);
+            } else if ((o = vobj_at(u.ux, u.uy)) != 0) {
+                cmd[0] = cmd_from_func(Is_container(o) ? doloot : dopickup);
                 return cmd;
             } else {
                 cmd[0] = cmd_from_func(donull); /* just rest */
@@ -5751,8 +3995,7 @@ int x, y, mod;
             }
 
             if (IS_DOOR(levl[u.ux + x][u.uy + y].typ)) {
-                /* slight assistance to the player: choose kick/open for them
-                 */
+                /* slight assistance to player: choose kick/open for them */
                 if (levl[u.ux + x][u.uy + y].doormask & D_LOCKED) {
                     cmd[0] = cmd_from_func(dokick);
                     return cmd;
index 0f601cc9996791a99d3697dcb3ad29597afaa266..f10e0f42452d42ff287b0b0d06b1c041b071cfff 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -32,17 +32,11 @@ static void NDECL(done_object_cleanup);
 static void FDECL(artifact_score, (struct obj *, BOOLEAN_P, winid));
 static void FDECL(really_done, (int)) NORETURN;
 static void FDECL(savelife, (int));
-static int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
-                                               const genericptr));
-static int NDECL(set_vanq_order);
-static void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
-static void FDECL(list_genocided, (CHAR_P, BOOLEAN_P));
 static boolean FDECL(should_query_disclose_option, (int, char *));
 #ifdef DUMPLOG
 static void NDECL(dump_plines);
 #endif
 static void FDECL(dump_everything, (int, time_t));
-static int NDECL(num_extinct);
 
 #if defined(__BEOS__) || defined(MICRO) || defined(OS2) || defined(WIN32)
 extern void FDECL(nethack_exit, (int));
@@ -817,10 +811,16 @@ boolean taken;
     }
 
     if (!done_stopprint) {
-        ask = should_query_disclose_option('c', &defquery);
-        c = ask ? yn_function("Do you want to see your conduct?", ynqchars,
-                              defquery)
-                : defquery;
+        if (should_query_disclose_option('c', &defquery)) {
+            int acnt = count_uachieve();
+
+            Sprintf(qbuf, "Do you want to see your conduct%s%s?",
+                    (acnt > 0) ? " and achievement" : "",
+                    (acnt > 1) ? "s" : "");
+            c = yn_function(qbuf, ynqchars, defquery);
+        } else {
+            c = defquery;
+        }
         if (c == 'y')
             show_conduct((how >= PANICKED) ? 1 : 2);
         if (c == 'q')
@@ -1711,382 +1711,6 @@ int status;
     nethack_exit(status);
 }
 
-static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
-    "traditional: by monster level, by internal monster index",
-    "by monster toughness, by internal monster index",
-    "alphabetically, first unique monsters, then others",
-    "alphabetically, unique monsters and others intermixed",
-    "by monster class, high to low level within class",
-    "by monster class, low to high level within class",
-    "by count, high to low, by internal index within tied count",
-    "by count, low to high, by internal index within tied count",
-};
-
-static int CFDECLSPEC
-vanqsort_cmp(vptr1, vptr2)
-const genericptr vptr1;
-const genericptr vptr2;
-{
-    int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
-        mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
-    const char *name1, *name2, *punct;
-    schar mcls1, mcls2;
-
-    switch (g.vanq_sortmode) {
-    default:
-    case VANQ_MLVL_MNDX:
-        /* sort by monster level */
-        mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
-        res = mlev2 - mlev1; /* mlevel high to low */
-        break;
-    case VANQ_MSTR_MNDX:
-        /* sort by monster toughness */
-        mstr1 = mons[indx1].difficulty, mstr2 = mons[indx2].difficulty;
-        res = mstr2 - mstr1; /* monstr high to low */
-        break;
-    case VANQ_ALPHA_SEP:
-        uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
-        uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
-        if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
-            res = uniq2 - uniq1;
-            break;
-        } /* else both unique or neither unique */
-        /*FALLTHRU*/
-    case VANQ_ALPHA_MIX:
-        name1 = mons[indx1].mname, name2 = mons[indx2].mname;
-        res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
-        break;
-    case VANQ_MCLS_HTOL:
-    case VANQ_MCLS_LTOH:
-        /* mons[].mlet is a small integer, 1..N, of type plain char;
-           if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
-           an inappropriate result when mlet2 is greater than mlet1,
-           so force our copies (mcls1, mcls2) to be signed */
-        mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
-        /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
-           S_ANGEL through S_ZOMBIE correspond to uppercase, and various
-           punctuation characters are used for classes beyond those */
-        if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
-            /* force a specific order to the punctuation classes that's
-               different from the internal order;
-               internal order is ok if neither or just one is punctuation
-               since letters have lower values so come out before punct */
-            static const char punctclasses[] = {
-                S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
-            };
-
-            if ((punct = index(punctclasses, mcls1)) != 0)
-                mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
-            if ((punct = index(punctclasses, mcls2)) != 0)
-                mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
-        }
-        res = mcls1 - mcls2; /* class */
-        if (res == 0) {
-            mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
-            res = mlev1 - mlev2; /* mlevel low to high */
-            if (g.vanq_sortmode == VANQ_MCLS_HTOL)
-                res = -res; /* mlevel high to low */
-        }
-        break;
-    case VANQ_COUNT_H_L:
-    case VANQ_COUNT_L_H:
-        died1 = g.mvitals[indx1].died, died2 = g.mvitals[indx2].died;
-        res = died2 - died1; /* dead count high to low */
-        if (g.vanq_sortmode == VANQ_COUNT_L_H)
-            res = -res; /* dead count low to high */
-        break;
-    }
-    /* tiebreaker: internal mons[] index */
-    if (res == 0)
-        res = indx1 - indx2; /* mndx low to high */
-    return res;
-}
-
-/* returns -1 if cancelled via ESC */
-static int
-set_vanq_order()
-{
-    winid tmpwin;
-    menu_item *selected;
-    anything any;
-    int i, n, choice;
-
-    tmpwin = create_nhwindow(NHW_MENU);
-    start_menu(tmpwin);
-    any = cg.zeroany; /* zero out all bits */
-    for (i = 0; i < SIZE(vanqorders); i++) {
-        if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
-            continue;
-        any.a_int = i + 1;
-        add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
-                 (i == g.vanq_sortmode)
-                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
-    }
-    end_menu(tmpwin, "Sort order for vanquished monster counts");
-
-    n = select_menu(tmpwin, PICK_ONE, &selected);
-    destroy_nhwindow(tmpwin);
-    if (n > 0) {
-        choice = selected[0].item.a_int - 1;
-        /* skip preselected entry if we have more than one item chosen */
-        if (n > 1 && choice == g.vanq_sortmode)
-            choice = selected[1].item.a_int - 1;
-        free((genericptr_t) selected);
-        g.vanq_sortmode = choice;
-    }
-    return (n < 0) ? -1 : g.vanq_sortmode;
-}
-
-/* #vanquished command */
-int
-dovanquished()
-{
-    list_vanquished('a', FALSE);
-    return 0;
-}
-
-/* high priests aren't unique but are flagged as such to simplify something */
-#define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
-                               && mndx != PM_HIGH_PRIEST)
-
-static void
-list_vanquished(defquery, ask)
-char defquery;
-boolean ask;
-{
-    register int i;
-    int pfx, nkilled;
-    unsigned ntypes, ni;
-    long total_killed = 0L;
-    winid klwin;
-    short mindx[NUMMONS];
-    char c, buf[BUFSZ], buftoo[BUFSZ];
-    boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
-
-    dumping = (defquery == 'd');
-    if (dumping)
-        defquery = 'y';
-
-    /* get totals first */
-    ntypes = 0;
-    for (i = LOW_PM; i < NUMMONS; i++) {
-        if ((nkilled = (int) g.mvitals[i].died) == 0)
-            continue;
-        mindx[ntypes++] = i;
-        total_killed += (long) nkilled;
-    }
-
-    /* vanquished creatures list;
-     * includes all dead monsters, not just those killed by the player
-     */
-    if (ntypes != 0) {
-        char mlet, prev_mlet = 0; /* used as small integer, not character */
-        boolean class_header, uniq_header, was_uniq = FALSE;
-
-        c = ask ? yn_function(
-                            "Do you want an account of creatures vanquished?",
-                              ynaqchars, defquery)
-                : defquery;
-        if (c == 'q')
-            done_stopprint++;
-        if (c == 'y' || c == 'a') {
-            if (c == 'a') { /* ask player to choose sort order */
-                /* choose value for vanq_sortmode via menu; ESC cancels list
-                   of vanquished monsters but does not set 'done_stopprint' */
-                if (set_vanq_order() < 0)
-                    return;
-            }
-            uniq_header = (g.vanq_sortmode == VANQ_ALPHA_SEP);
-            class_header = (g.vanq_sortmode == VANQ_MCLS_LTOH
-                            || g.vanq_sortmode == VANQ_MCLS_HTOL);
-
-            klwin = create_nhwindow(NHW_MENU);
-            putstr(klwin, 0, "Vanquished creatures:");
-            if (!dumping)
-                putstr(klwin, 0, "");
-
-            qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
-            for (ni = 0; ni < ntypes; ni++) {
-                i = mindx[ni];
-                nkilled = g.mvitals[i].died;
-                mlet = mons[i].mlet;
-                if (class_header && mlet != prev_mlet) {
-                    Strcpy(buf, def_monsyms[(int) mlet].explain);
-                    putstr(klwin, ask ? 0 : iflags.menu_headings,
-                           upstart(buf));
-                    prev_mlet = mlet;
-                }
-                if (UniqCritterIndx(i)) {
-                    Sprintf(buf, "%s%s",
-                            !type_is_pname(&mons[i]) ? "the " : "",
-                            mons[i].mname);
-                    if (nkilled > 1) {
-                        switch (nkilled) {
-                        case 2:
-                            Sprintf(eos(buf), " (twice)");
-                            break;
-                        case 3:
-                            Sprintf(eos(buf), " (thrice)");
-                            break;
-                        default:
-                            Sprintf(eos(buf), " (%d times)", nkilled);
-                            break;
-                        }
-                    }
-                    was_uniq = TRUE;
-                } else {
-                    if (uniq_header && was_uniq) {
-                        putstr(klwin, 0, "");
-                        was_uniq = FALSE;
-                    }
-                    /* trolls or undead might have come back,
-                       but we don't keep track of that */
-                    if (nkilled == 1)
-                        Strcpy(buf, an(mons[i].mname));
-                    else
-                        Sprintf(buf, "%3d %s", nkilled,
-                                makeplural(mons[i].mname));
-                }
-                /* number of leading spaces to match 3 digit prefix */
-                pfx = !strncmpi(buf, "the ", 3) ? 0
-                      : !strncmpi(buf, "an ", 3) ? 1
-                        : !strncmpi(buf, "a ", 2) ? 2
-                          : !digit(buf[2]) ? 4 : 0;
-                if (class_header)
-                    ++pfx;
-                Sprintf(buftoo, "%*s%s", pfx, "", buf);
-                putstr(klwin, 0, buftoo);
-            }
-            /*
-             * if (Hallucination)
-             *     putstr(klwin, 0, "and a partridge in a pear tree");
-             */
-            if (ntypes > 1) {
-                if (!dumping)
-                    putstr(klwin, 0, "");
-                Sprintf(buf, "%ld creatures vanquished.", total_killed);
-                putstr(klwin, 0, buf);
-            }
-            display_nhwindow(klwin, TRUE);
-            destroy_nhwindow(klwin);
-        }
-    } else if (defquery == 'a') {
-        /* #dovanquished rather than final disclosure, so pline() is ok */
-        pline("No creatures have been vanquished.");
-#ifdef DUMPLOG
-    } else if (dumping) {
-        putstr(0, 0, "No creatures were vanquished."); /* not pline() */
-#endif
-    }
-}
-
-/* number of monster species which have been genocided */
-int
-num_genocides()
-{
-    int i, n = 0;
-
-    for (i = LOW_PM; i < NUMMONS; ++i) {
-        if (g.mvitals[i].mvflags & G_GENOD) {
-            ++n;
-            if (UniqCritterIndx(i))
-                impossible("unique creature '%d: %s' genocided?",
-                           i, mons[i].mname);
-        }
-    }
-    return n;
-}
-
-static int
-num_extinct()
-{
-    int i, n = 0;
-
-    for (i = LOW_PM; i < NUMMONS; ++i) {
-        if (UniqCritterIndx(i))
-            continue;
-        if ((g.mvitals[i].mvflags & G_GONE) == G_EXTINCT)
-            ++n;
-    }
-    return n;
-}
-
-static void
-list_genocided(defquery, ask)
-char defquery;
-boolean ask;
-{
-    register int i;
-    int ngenocided, nextinct;
-    char c;
-    winid klwin;
-    char buf[BUFSZ];
-    boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
-
-    dumping = (defquery == 'd');
-    if (dumping)
-        defquery = 'y';
-
-    ngenocided = num_genocides();
-    nextinct = num_extinct();
-
-    /* genocided or extinct species list */
-    if (ngenocided != 0 || nextinct != 0) {
-        Sprintf(buf, "Do you want a list of %sspecies%s%s?",
-                (nextinct && !ngenocided) ? "extinct " : "",
-                (ngenocided) ? " genocided" : "",
-                (nextinct && ngenocided) ? " and extinct" : "");
-        c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
-        if (c == 'q')
-            done_stopprint++;
-        if (c == 'y') {
-            klwin = create_nhwindow(NHW_MENU);
-            Sprintf(buf, "%s%s species:",
-                    (ngenocided) ? "Genocided" : "Extinct",
-                    (nextinct && ngenocided) ? " or extinct" : "");
-            putstr(klwin, 0, buf);
-            if (!dumping)
-                putstr(klwin, 0, "");
-
-            for (i = LOW_PM; i < NUMMONS; i++) {
-                /* uniques can't be genocided but can become extinct;
-                   however, they're never reported as extinct, so skip them */
-                if (UniqCritterIndx(i))
-                    continue;
-                if (g.mvitals[i].mvflags & G_GONE) {
-                    Sprintf(buf, " %s", makeplural(mons[i].mname));
-                    /*
-                     * "Extinct" is unfortunate terminology.  A species
-                     * is marked extinct when its birth limit is reached,
-                     * but there might be members of the species still
-                     * alive, contradicting the meaning of the word.
-                     */
-                    if ((g.mvitals[i].mvflags & G_GONE) == G_EXTINCT)
-                        Strcat(buf, " (extinct)");
-                    putstr(klwin, 0, buf);
-                }
-            }
-            if (!dumping)
-                putstr(klwin, 0, "");
-            if (ngenocided > 0) {
-                Sprintf(buf, "%d species genocided.", ngenocided);
-                putstr(klwin, 0, buf);
-            }
-            if (nextinct > 0) {
-                Sprintf(buf, "%d species extinct.", nextinct);
-                putstr(klwin, 0, buf);
-            }
-
-            display_nhwindow(klwin, TRUE);
-            destroy_nhwindow(klwin);
-        }
-#ifdef DUMPLOG
-    } else if (dumping) {
-        putstr(0, 0, "No species were genocided or became extinct.");
-#endif
-    }
-}
-
 /* set a delayed killer, ensure non-delayed killer is cleared out */
 void
 delayed_killer(id, format, killername)
index 2d0b43cdd987ccfd6887e0969bb2fa256edfb5ad..62ee93607a309a65553e37d55a44f9c345d4e122 100644 (file)
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
+/*
+ * Enlightenment and Conduct+Achievements and Vanquished+Extinct+Geno'd
+ * and stethoscope/probing feedback.
+ *
+ * Most code used to reside in cmd.c, presumeably because ^X was originally
+ * a wizard mode command and the majority of those are in that file.
+ * Some came from end.c where it is used during end of game disclosure.
+ * And some came from priest.c that had once been in pline.c.
+ */
+
 #include "hack.h"
 
-/* temporary, until Makefiles and IDE project files are all updated */
-int insight_dummy = 0;
+static void FDECL(enlght_out, (const char *));
+static void FDECL(enlght_line, (const char *, const char *, const char *,
+                                const char *));
+static char *FDECL(enlght_combatinc, (const char *, int, int, char *));
+static void FDECL(enlght_halfdmg, (int, int));
+static boolean NDECL(walking_on_water);
+static boolean FDECL(cause_known, (int));
+static char *FDECL(attrval, (int, int, char *));
+static void FDECL(background_enlightenment, (int, int));
+static void FDECL(basics_enlightenment, (int, int));
+static void FDECL(characteristics_enlightenment, (int, int));
+static void FDECL(one_characteristic, (int, int, int));
+static void FDECL(status_enlightenment, (int, int));
+static void FDECL(attributes_enlightenment, (int, int));
+static void FDECL(show_achievements, (int));
+static int FDECL(CFDECLSPEC vanqsort_cmp, (const genericptr,
+                                           const genericptr));
+static int NDECL(set_vanq_order);
+static int NDECL(num_extinct);
+
+extern const char *hu_stat[];  /* hunger status from eat.c */
+extern const char *enc_stat[]; /* encumbrance status from botl.c */
+
+static const char You_[] = "You ", are[] = "are ", were[] = "were ",
+                  have[] = "have ", had[] = "had ", can[] = "can ",
+                  could[] = "could ";
+static const char have_been[] = "have been ", have_never[] = "have never ",
+                  never[] = "never ";
+
+#define enl_msg(prefix, present, past, suffix, ps) \
+    enlght_line(prefix, final ? past : present, suffix, ps)
+#define you_are(attr, ps) enl_msg(You_, are, were, attr, ps)
+#define you_have(attr, ps) enl_msg(You_, have, had, attr, ps)
+#define you_can(attr, ps) enl_msg(You_, can, could, attr, ps)
+#define you_have_been(goodthing) enl_msg(You_, have_been, were, goodthing, "")
+#define you_have_never(badthing) \
+    enl_msg(You_, have_never, never, badthing, "")
+#define you_have_X(something) \
+    enl_msg(You_, have, (const char *) "", something, "")
+
+static void
+enlght_out(buf)
+const char *buf;
+{
+    if (g.en_via_menu) {
+        anything any;
+
+        any = cg.zeroany;
+        add_menu(g.en_win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf,
+                 MENU_ITEMFLAGS_NONE);
+    } else
+        putstr(g.en_win, 0, buf);
+}
+
+static void
+enlght_line(start, middle, end, ps)
+const char *start, *middle, *end, *ps;
+{
+    char buf[BUFSZ];
+
+    Sprintf(buf, " %s%s%s%s.", start, middle, end, ps);
+    enlght_out(buf);
+}
+
+/* format increased chance to hit or damage or defense (Protection) */
+static char *
+enlght_combatinc(inctyp, incamt, final, outbuf)
+const char *inctyp;
+int incamt, final;
+char *outbuf;
+{
+    const char *modif, *bonus;
+    boolean invrt;
+    int absamt;
+
+    absamt = abs(incamt);
+    /* Protection amount is typically larger than damage or to-hit;
+       reduce magnitude by a third in order to stretch modifier ranges
+       (small:1..5, moderate:6..10, large:11..19, huge:20+) */
+    if (!strcmp(inctyp, "defense"))
+        absamt = (absamt * 2) / 3;
+
+    if (absamt <= 3)
+        modif = "small";
+    else if (absamt <= 6)
+        modif = "moderate";
+    else if (absamt <= 12)
+        modif = "large";
+    else
+        modif = "huge";
+
+    modif = !incamt ? "no" : an(modif); /* ("no" case shouldn't happen) */
+    bonus = (incamt >= 0) ? "bonus" : "penalty";
+    /* "bonus <foo>" (to hit) vs "<bar> bonus" (damage, defense) */
+    invrt = strcmp(inctyp, "to hit") ? TRUE : FALSE;
+
+    Sprintf(outbuf, "%s %s %s", modif, invrt ? inctyp : bonus,
+            invrt ? bonus : inctyp);
+    if (final || wizard)
+        Sprintf(eos(outbuf), " (%s%d)", (incamt > 0) ? "+" : "", incamt);
+
+    return outbuf;
+}
+
+/* report half physical or half spell damage */
+static void
+enlght_halfdmg(category, final)
+int category;
+int final;
+{
+    const char *category_name;
+    char buf[BUFSZ];
+
+    switch (category) {
+    case HALF_PHDAM:
+        category_name = "physical";
+        break;
+    case HALF_SPDAM:
+        category_name = "spell";
+        break;
+    default:
+        category_name = "unknown";
+        break;
+    }
+    Sprintf(buf, " %s %s damage", (final || wizard) ? "half" : "reduced",
+            category_name);
+    enl_msg(You_, "take", "took", buf, from_what(category));
+}
+
+/* is hero actively using water walking capability on water (or lava)? */
+static boolean
+walking_on_water()
+{
+    if (u.uinwater || Levitation || Flying)
+        return FALSE;
+    return (boolean) (Wwalking
+                      && (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)));
+}
+
+/* describe u.utraptype; used by status_enlightenment() and self_lookat() */
+char *
+trap_predicament(outbuf, final, wizxtra)
+char *outbuf;
+int final;
+boolean wizxtra;
+{
+    struct trap *t;
+
+    /* caller has verified u.utrap */
+    *outbuf = '\0';
+    switch (u.utraptype) {
+    case TT_BURIEDBALL:
+        Strcpy(outbuf, "tethered to something buried");
+        break;
+    case TT_LAVA:
+        Sprintf(outbuf, "sinking into %s", final ? "lava" : hliquid("lava"));
+        break;
+    case TT_INFLOOR:
+        Sprintf(outbuf, "stuck in %s", the(surface(u.ux, u.uy)));
+        break;
+    default: /* TT_BEARTRAP, TT_PIT, or TT_WEB */
+        Strcpy(outbuf, "trapped");
+        if ((t = t_at(u.ux, u.uy)) != 0) /* should never be null */
+            Sprintf(eos(outbuf), " in %s", an(trapname(t->ttyp, FALSE)));
+        break;
+    }
+    if (wizxtra) { /* give extra information for wizard mode enlightenment */
+        /* curly braces: u.utrap is an escape attempt counter rather than a
+           turn timer so use different ornamentation than usual parentheses */
+        Sprintf(eos(outbuf), " {%u}", u.utrap);
+    }
+    return outbuf;
+}
+
+/* check whether hero is wearing something that player definitely knows
+   confers the target property; item must have been seen and its type
+   discovered but it doesn't necessarily have to be fully identified */
+static boolean
+cause_known(propindx)
+int propindx; /* index of a property which can be conveyed by worn item */
+{
+    register struct obj *o;
+    long mask = W_ARMOR | W_AMUL | W_RING | W_TOOL;
+
+    /* simpler than from_what()/what_gives(); we don't attempt to
+       handle artifacts and we deliberately ignore wielded items */
+    for (o = g.invent; o; o = o->nobj) {
+        if (!(o->owornmask & mask))
+            continue;
+        if ((int) objects[o->otyp].oc_oprop == propindx
+            && objects[o->otyp].oc_name_known && o->dknown)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+/* format a characteristic value, accommodating Strength's strangeness */
+static char *
+attrval(attrindx, attrvalue, resultbuf)
+int attrindx, attrvalue;
+char resultbuf[]; /* should be at least [7] to hold "18/100\0" */
+{
+    if (attrindx != A_STR || attrvalue <= 18)
+        Sprintf(resultbuf, "%d", attrvalue);
+    else if (attrvalue > STR18(100)) /* 19 to 25 */
+        Sprintf(resultbuf, "%d", attrvalue - 100);
+    else /* simplify "18/ **" to be "18/100" */
+        Sprintf(resultbuf, "18/%02d", attrvalue - 18);
+    return resultbuf;
+}
+
+void
+enlightenment(mode, final)
+int mode;  /* BASICENLIGHTENMENT | MAGICENLIGHTENMENT (| both) */
+int final; /* ENL_GAMEINPROGRESS:0, ENL_GAMEOVERALIVE, ENL_GAMEOVERDEAD */
+{
+    char buf[BUFSZ], tmpbuf[BUFSZ];
+
+    g.en_win = create_nhwindow(NHW_MENU);
+    g.en_via_menu = !final;
+    if (g.en_via_menu)
+        start_menu(g.en_win);
+
+    Strcpy(tmpbuf, g.plname);
+    *tmpbuf = highc(*tmpbuf); /* same adjustment as bottom line */
+    /* as in background_enlightenment, when poly'd we need to use the saved
+       gender in u.mfemale rather than the current you-as-monster gender */
+    Sprintf(buf, "%s the %s's attributes:", tmpbuf,
+            ((Upolyd ? u.mfemale : flags.female) && g.urole.name.f)
+                ? g.urole.name.f
+                : g.urole.name.m);
+
+    /* title */
+    enlght_out(buf); /* "Conan the Archeologist's attributes:" */
+    /* background and characteristics; ^X or end-of-game disclosure */
+    if (mode & BASICENLIGHTENMENT) {
+        /* role, race, alignment, deities, dungeon level, time, experience */
+        background_enlightenment(mode, final);
+        /* hit points, energy points, armor class, gold */
+        basics_enlightenment(mode, final);
+        /* strength, dexterity, &c */
+        characteristics_enlightenment(mode, final);
+    }
+    /* expanded status line information, including things which aren't
+       included there due to space considerations--such as obvious
+       alternative movement indicators (riding, levitation, &c), and
+       various troubles (turning to stone, trapped, confusion, &c);
+       shown for both basic and magic enlightenment */
+    status_enlightenment(mode, final);
+    /* remaining attributes; shown for potion,&c or wizard mode and
+       explore mode ^X or end of game disclosure */
+    if (mode & MAGICENLIGHTENMENT) {
+        /* intrinsics and other traditional enlightenment feedback */
+        attributes_enlightenment(mode, final);
+    }
+
+    if (!g.en_via_menu) {
+        display_nhwindow(g.en_win, TRUE);
+    } else {
+        menu_item *selected = 0;
+
+        end_menu(g.en_win, (char *) 0);
+        if (select_menu(g.en_win, PICK_NONE, &selected) > 0)
+            free((genericptr_t) selected);
+        g.en_via_menu = FALSE;
+    }
+    destroy_nhwindow(g.en_win);
+    g.en_win = WIN_ERR;
+}
+
+/*ARGSUSED*/
+/* display role, race, alignment and such to en_win */
+static void
+background_enlightenment(unused_mode, final)
+int unused_mode UNUSED;
+int final;
+{
+    const char *role_titl, *rank_titl;
+    int innategend, difgend, difalgn;
+    char buf[BUFSZ], tmpbuf[BUFSZ];
+
+    /* note that if poly'd, we need to use u.mfemale instead of flags.female
+       to access hero's saved gender-as-human/elf/&c rather than current */
+    innategend = (Upolyd ? u.mfemale : flags.female) ? 1 : 0;
+    role_titl = (innategend && g.urole.name.f) ? g.urole.name.f
+                                               : g.urole.name.m;
+    rank_titl = rank_of(u.ulevel, Role_switch, innategend);
+
+    enlght_out(""); /* separator after title */
+    enlght_out("Background:");
+
+    /* if polymorphed, report current shape before underlying role;
+       will be repeated as first status: "you are transformed" and also
+       among various attributes: "you are in beast form" (after being
+       told about lycanthropy) or "you are polymorphed into <a foo>"
+       (with countdown timer appended for wizard mode); we really want
+       the player to know he's not a samurai at the moment... */
+    if (Upolyd) {
+        char anbuf[20]; /* includes trailing space; [4] suffices */
+        struct permonst *uasmon = g.youmonst.data;
+        boolean altphrasing = vampshifted(&g.youmonst);
+
+        tmpbuf[0] = '\0';
+        /* here we always use current gender, not saved role gender */
+        if (!is_male(uasmon) && !is_female(uasmon) && !is_neuter(uasmon))
+            Sprintf(tmpbuf, "%s ", genders[flags.female ? 1 : 0].adj);
+        if (altphrasing)
+            Sprintf(eos(tmpbuf), "%s in ", mons[g.youmonst.cham].mname);
+        Sprintf(buf, "%s%s%s%s form", !final ? "currently " : "",
+                altphrasing ? just_an(anbuf, tmpbuf) : "in ",
+                tmpbuf, uasmon->mname);
+        you_are(buf, "");
+    }
+
+    /* report role; omit gender if it's redundant (eg, "female priestess") */
+    tmpbuf[0] = '\0';
+    if (!g.urole.name.f
+        && ((g.urole.allow & ROLE_GENDMASK) == (ROLE_MALE | ROLE_FEMALE)
+            || innategend != flags.initgend))
+        Sprintf(tmpbuf, "%s ", genders[innategend].adj);
+    buf[0] = '\0';
+    if (Upolyd)
+        Strcpy(buf, "actually "); /* "You are actually a ..." */
+    if (!strcmpi(rank_titl, role_titl)) {
+        /* omit role when rank title matches it */
+        Sprintf(eos(buf), "%s, level %d %s%s", an(rank_titl), u.ulevel,
+                tmpbuf, g.urace.noun);
+    } else {
+        Sprintf(eos(buf), "%s, a level %d %s%s %s", an(rank_titl), u.ulevel,
+                tmpbuf, g.urace.adj, role_titl);
+    }
+    you_are(buf, "");
+
+    /* report alignment (bypass you_are() in order to omit ending period);
+       adverb is used to distinguish between temporary change (helm of opp.
+       alignment), permanent change (one-time conversion), and original */
+    Sprintf(buf, " %s%s%s, %son a mission for %s",
+            You_, !final ? are : were,
+            align_str(u.ualign.type),
+            /* helm of opposite alignment (might hide conversion) */
+            (u.ualign.type != u.ualignbase[A_CURRENT])
+               /* what's the past tense of "currently"? if we used "formerly"
+                  it would sound like a reference to the original alignment */
+               ? (!final ? "currently " : "temporarily ")
+               /* permanent conversion */
+               : (u.ualign.type != u.ualignbase[A_ORIGINAL])
+                  /* and what's the past tense of "now"? certainly not "then"
+                     in a context like this...; "belatedly" == weren't that
+                     way sooner (in other words, didn't start that way) */
+                  ? (!final ? "now " : "belatedly ")
+                  /* atheist (ignored in very early game) */
+                  : (!u.uconduct.gnostic && g.moves > 1000L)
+                     ? "nominally "
+                     /* lastly, normal case */
+                     : "",
+            u_gname());
+    enlght_out(buf);
+    /* show the rest of this game's pantheon (finishes previous sentence)
+       [appending "also Moloch" at the end would allow for straightforward
+       trailing "and" on all three aligned entries but looks too verbose] */
+    Sprintf(buf, " who %s opposed by", !final ? "is" : "was");
+    if (u.ualign.type != A_LAWFUL)
+        Sprintf(eos(buf), " %s (%s) and", align_gname(A_LAWFUL),
+                align_str(A_LAWFUL));
+    if (u.ualign.type != A_NEUTRAL)
+        Sprintf(eos(buf), " %s (%s)%s", align_gname(A_NEUTRAL),
+                align_str(A_NEUTRAL),
+                (u.ualign.type != A_CHAOTIC) ? " and" : "");
+    if (u.ualign.type != A_CHAOTIC)
+        Sprintf(eos(buf), " %s (%s)", align_gname(A_CHAOTIC),
+                align_str(A_CHAOTIC));
+    Strcat(buf, "."); /* terminate sentence */
+    enlght_out(buf);
+
+    /* show original alignment,gender,race,role if any have been changed;
+       giving separate message for temporary alignment change bypasses need
+       for tricky phrasing otherwise necessitated by possibility of having
+       helm of opposite alignment mask a permanent alignment conversion */
+    difgend = (innategend != flags.initgend);
+    difalgn = (((u.ualign.type != u.ualignbase[A_CURRENT]) ? 1 : 0)
+               + ((u.ualignbase[A_CURRENT] != u.ualignbase[A_ORIGINAL])
+                  ? 2 : 0));
+    if (difalgn & 1) { /* have temporary alignment so report permanent one */
+        Sprintf(buf, "actually %s", align_str(u.ualignbase[A_CURRENT]));
+        you_are(buf, "");
+        difalgn &= ~1; /* suppress helm from "started out <foo>" message */
+    }
+    if (difgend || difalgn) { /* sex change or perm align change or both */
+        Sprintf(buf, " You started out %s%s%s.",
+                difgend ? genders[flags.initgend].adj : "",
+                (difgend && difalgn) ? " and " : "",
+                difalgn ? align_str(u.ualignbase[A_ORIGINAL]) : "");
+        enlght_out(buf);
+    }
+
+    /* As of 3.6.2: dungeon level, so that ^X really has all status info as
+       claimed by the comment below; this reveals more information than
+       the basic status display, but that's one of the purposes of ^X;
+       similar information is revealed by #overview; the "You died in
+       <location>" given by really_done() is more rudimentary than this */
+    *buf = *tmpbuf = '\0';
+    if (In_endgame(&u.uz)) {
+        int egdepth = observable_depth(&u.uz);
+
+        (void) endgamelevelname(tmpbuf, egdepth);
+        Sprintf(buf, "in the endgame, on the %s%s",
+                !strncmp(tmpbuf, "Plane", 5) ? "Elemental " : "", tmpbuf);
+    } else if (Is_knox(&u.uz)) {
+        /* this gives away the fact that the knox branch is only 1 level */
+        Sprintf(buf, "on the %s level", g.dungeons[u.uz.dnum].dname);
+        /* TODO? maybe phrase it differently when actually inside the fort,
+           if we're able to determine that (not trivial) */
+    } else {
+        char dgnbuf[QBUFSZ];
+
+        Strcpy(dgnbuf, g.dungeons[u.uz.dnum].dname);
+        if (!strncmpi(dgnbuf, "The ", 4))
+            *dgnbuf = lowc(*dgnbuf);
+        Sprintf(tmpbuf, "level %d",
+                In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz));
+        /* TODO? maybe extend this bit to include various other automatic
+           annotations from the dungeon overview code */
+        if (Is_rogue_level(&u.uz))
+            Strcat(tmpbuf, ", a primitive area");
+        else if (Is_bigroom(&u.uz) && !Blind)
+            Strcat(tmpbuf, ", a very big room");
+        Sprintf(buf, "in %s, on %s", dgnbuf, tmpbuf);
+    }
+    you_are(buf, "");
+
+    /* this is shown even if the 'time' option is off */
+    if (g.moves == 1L) {
+        you_have("just started your adventure", "");
+    } else {
+        /* 'turns' grates on the nerves in this context... */
+        Sprintf(buf, "the dungeon %ld turn%s ago", g.moves, plur(g.moves));
+        /* same phrasing for current and final: "entered" is unconditional */
+        enlght_line(You_, "entered ", buf, "");
+    }
+
+    /* for gameover, these have been obtained in really_done() so that they
+       won't vary if user leaves a disclosure prompt or --More-- unanswered
+       long enough for the dynamic value to change between then and now */
+    if (final ? iflags.at_midnight : midnight()) {
+        enl_msg("It ", "is ", "was ", "the midnight hour", "");
+    } else if (final ? iflags.at_night : night()) {
+        enl_msg("It ", "is ", "was ", "nighttime", "");
+    }
+    /* other environmental factors */
+    if (flags.moonphase == FULL_MOON || flags.moonphase == NEW_MOON) {
+        /* [This had "tonight" but has been changed to "in effect".
+           There is a similar issue to Friday the 13th--it's the value
+           at the start of the current session but that session might
+           have dragged on for an arbitrary amount of time.  We want to
+           report the values that currently affect play--or affected
+           play when game ended--rather than actual outside situation.] */
+        Sprintf(buf, "a %s moon in effect%s",
+                (flags.moonphase == FULL_MOON) ? "full"
+                : (flags.moonphase == NEW_MOON) ? "new"
+                  /* showing these would probably just lead to confusion
+                     since they have no effect on game play... */
+                  : (flags.moonphase < FULL_MOON) ? "first quarter"
+                    : "last quarter",
+                /* we don't have access to 'how' here--aside from survived
+                   vs died--so settle for general platitude */
+                final ? " when your adventure ended" : "");
+        enl_msg("There ", "is ", "was ", buf, "");
+    }
+    if (flags.friday13) {
+        /* let player know that friday13 penalty is/was in effect;
+           we don't say "it is/was Friday the 13th" because that was at
+           the start of the session and it might be past midnight (or
+           days later if the game has been paused without save/restore),
+           so phrase this similar to the start up message */
+        Sprintf(buf, " Bad things %s on Friday the 13th.",
+                !final ? "can happen"
+                : (final == ENL_GAMEOVERALIVE) ? "could have happened"
+                  /* there's no may to tell whether -1 Luck made a
+                     difference but hero has died... */
+                  : "happened");
+        enlght_out(buf);
+    }
+
+    if (!Upolyd) {
+        int ulvl = (int) u.ulevel;
+        /* [flags.showexp currently does not matter; should it?] */
+
+        /* experience level is already shown above */
+        Sprintf(buf, "%-1ld experience point%s", u.uexp, plur(u.uexp));
+        /* TODO?
+         *  Remove wizard-mode restriction since patient players can
+         *  determine the numbers needed without resorting to spoilers
+         *  (even before this started being disclosed for 'final';
+         *  just enable 'showexp' and look at normal status lines
+         *  after drinking gain level potions or eating wraith corpses
+         *  or being level-drained by vampires).
+         */
+        if (ulvl < 30 && (final || wizard)) {
+            long nxtlvl = newuexp(ulvl), delta = nxtlvl - u.uexp;
+
+            Sprintf(eos(buf), ", %ld %s%sneeded %s level %d",
+                    delta, (u.uexp > 0) ? "more " : "",
+                    /* present tense=="needed", past tense=="were needed" */
+                    !final ? "" : (delta == 1L) ? "was " : "were ",
+                    /* "for": grammatically iffy but less likely to wrap */
+                    (ulvl < 18) ? "to attain" : "for", (ulvl + 1));
+        }
+        you_have(buf, "");
+    }
+#ifdef SCORE_ON_BOTL
+    if (flags.showscore) {
+        /* describes what's shown on status line, which is an approximation;
+           only show it here if player has the 'showscore' option enabled */
+        Sprintf(buf, "%ld%s", botl_score(),
+                !final ? "" : " before end-of-game adjustments");
+        enl_msg("Your score ", "is ", "was ", buf, "");
+    }
+#endif
+}
+
+/* hit points, energy points, armor class -- essential information which
+   doesn't fit very well in other categories */
+/*ARGSUSED*/
+static void
+basics_enlightenment(mode, final)
+int mode UNUSED;
+int final;
+{
+    static char Power[] = "energy points (spell power)";
+    char buf[BUFSZ];
+    int pw = u.uen, hp = (Upolyd ? u.mh : u.uhp),
+        pwmax = u.uenmax, hpmax = (Upolyd ? u.mhmax : u.uhpmax);
+
+    enlght_out(""); /* separator after background */
+    enlght_out("Basics:");
+
+    if (hp < 0)
+        hp = 0;
+    /* "1 out of 1" rather than "all" if max is only 1; should never happen */
+    if (hp == hpmax && hpmax > 1)
+        Sprintf(buf, "all %d hit points", hpmax);
+    else
+        Sprintf(buf, "%d out of %d hit point%s", hp, hpmax, plur(hpmax));
+    you_have(buf, "");
+
+    /* low max energy is feasible, so handle couple of extra special cases */
+    if (pwmax == 0 || (pw == pwmax && pwmax == 2)) /* both: not "all 2" */
+        Sprintf(buf, "%s %s", !pwmax ? "no" : "both", Power);
+    else if (pw == pwmax && pwmax > 2)
+        Sprintf(buf, "all %d %s", pwmax, Power);
+    else
+        Sprintf(buf, "%d out of %d %s", pw, pwmax, Power);
+    you_have(buf, "");
+
+    if (Upolyd) {
+        switch (mons[u.umonnum].mlevel) {
+        case 0:
+            /* status line currently being explained shows "HD:0" */
+            Strcpy(buf, "0 hit dice (actually 1/2)");
+            break;
+        case 1:
+            Strcpy(buf, "1 hit die");
+            break;
+        default:
+            Sprintf(buf, "%d hit dice", mons[u.umonnum].mlevel);
+            break;
+        }
+        you_have(buf, "");
+    }
+
+    Sprintf(buf, "%d", u.uac);
+    enl_msg("Your armor class ", "is ", "was ", buf, "");
+
+    /* gold; similar to doprgold(#seegold) but without shop billing info;
+       same amount as shown on status line which ignores container contents */
+    {
+        static const char Your_wallet[] = "Your wallet ";
+        long umoney = money_cnt(g.invent);
+
+        if (!umoney) {
+            enl_msg(Your_wallet, "is ", "was ", "empty", "");
+        } else {
+            Sprintf(buf, "%ld %s", umoney, currency(umoney));
+            enl_msg(Your_wallet, "contains ", "contained ", buf, "");
+        }
+    }
+
+    if (flags.pickup) {
+        char ocl[MAXOCLASSES + 1];
+
+        Strcpy(buf, "on");
+        oc_to_str(flags.pickup_types, ocl);
+        Sprintf(eos(buf), " for %s%s%s",
+                *ocl ? "'" : "", *ocl ? ocl : "all types", *ocl ? "'" : "");
+        if (flags.pickup_thrown && *ocl) /* *ocl: don't show if 'all types' */
+            Strcat(buf, " plus thrown");
+        if (g.apelist)
+            Strcat(buf, ", with exceptions");
+    } else
+        Strcpy(buf, "off");
+    enl_msg("Autopickup ", "is ", "was ", buf, "");
+}
+
+/* characteristics: expanded version of bottom line strength, dexterity, &c */
+static void
+characteristics_enlightenment(mode, final)
+int mode;
+int final;
+{
+    char buf[BUFSZ];
+
+    enlght_out("");
+    Sprintf(buf, "%s Characteristics:", !final ? "Current" : "Final");
+    enlght_out(buf);
+
+    /* bottom line order */
+    one_characteristic(mode, final, A_STR); /* strength */
+    one_characteristic(mode, final, A_DEX); /* dexterity */
+    one_characteristic(mode, final, A_CON); /* constitution */
+    one_characteristic(mode, final, A_INT); /* intelligence */
+    one_characteristic(mode, final, A_WIS); /* wisdom */
+    one_characteristic(mode, final, A_CHA); /* charisma */
+}
+
+/* display one attribute value for characteristics_enlightenment() */
+static void
+one_characteristic(mode, final, attrindx)
+int mode, final, attrindx;
+{
+    extern const char *const attrname[]; /* attrib.c */
+    boolean hide_innate_value = FALSE, interesting_alimit;
+    int acurrent, abase, apeak, alimit;
+    const char *paren_pfx;
+    char subjbuf[BUFSZ], valubuf[BUFSZ], valstring[32];
+
+    /* being polymorphed or wearing certain cursed items prevents
+       hero from reliably tracking changes to characteristics so
+       we don't show base & peak values then; when the items aren't
+       cursed, hero could take them off to check underlying values
+       and we show those in such case so that player doesn't need
+       to actually resort to doing that */
+    if (Upolyd) {
+        hide_innate_value = TRUE;
+    } else if (Fixed_abil) {
+        if (stuck_ring(uleft, RIN_SUSTAIN_ABILITY)
+            || stuck_ring(uright, RIN_SUSTAIN_ABILITY))
+            hide_innate_value = TRUE;
+    }
+    switch (attrindx) {
+    case A_STR:
+        if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER && uarmg->cursed)
+            hide_innate_value = TRUE;
+        break;
+    case A_DEX:
+        break;
+    case A_CON:
+        if (uwep && uwep->oartifact == ART_OGRESMASHER && uwep->cursed)
+            hide_innate_value = TRUE;
+        break;
+    case A_INT:
+        if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed)
+            hide_innate_value = TRUE;
+        break;
+    case A_WIS:
+        if (uarmh && uarmh->otyp == DUNCE_CAP && uarmh->cursed)
+            hide_innate_value = TRUE;
+        break;
+    case A_CHA:
+        break;
+    default:
+        return; /* impossible */
+    };
+    /* note: final disclosure includes MAGICENLIGHTENTMENT */
+    if ((mode & MAGICENLIGHTENMENT) && !Upolyd)
+        hide_innate_value = FALSE;
+
+    acurrent = ACURR(attrindx);
+    (void) attrval(attrindx, acurrent, valubuf); /* Sprintf(valubuf,"%d",) */
+    Sprintf(subjbuf, "Your %s ", attrname[attrindx]);
+
+    if (!hide_innate_value) {
+        /* show abase, amax, and/or attrmax if acurr doesn't match abase
+           (a magic bonus or penalty is in effect) or abase doesn't match
+           amax (some points have been lost to poison or exercise abuse
+           and are restorable) or attrmax is different from normal human
+           (while game is in progress; trying to reduce dependency on
+           spoilers to keep track of such stuff) or attrmax was different
+           from abase (at end of game; this attribute wasn't maxed out) */
+        abase = ABASE(attrindx);
+        apeak = AMAX(attrindx);
+        alimit = ATTRMAX(attrindx);
+        /* criterium for whether the limit is interesting varies */
+        interesting_alimit =
+            final ? TRUE /* was originally `(abase != alimit)' */
+                  : (alimit != (attrindx != A_STR ? 18 : STR18(100)));
+        paren_pfx = final ? " (" : " (current; ";
+        if (acurrent != abase) {
+            Sprintf(eos(valubuf), "%sbase:%s", paren_pfx,
+                    attrval(attrindx, abase, valstring));
+            paren_pfx = ", ";
+        }
+        if (abase != apeak) {
+            Sprintf(eos(valubuf), "%speak:%s", paren_pfx,
+                    attrval(attrindx, apeak, valstring));
+            paren_pfx = ", ";
+        }
+        if (interesting_alimit) {
+            Sprintf(eos(valubuf), "%s%slimit:%s", paren_pfx,
+                    /* more verbose if exceeding 'limit' due to magic bonus */
+                    (acurrent > alimit) ? "innate " : "",
+                    attrval(attrindx, alimit, valstring));
+            /* paren_pfx = ", "; */
+        }
+        if (acurrent != abase || abase != apeak || interesting_alimit)
+            Strcat(valubuf, ")");
+    }
+    enl_msg(subjbuf, "is ", "was ", valubuf, "");
+}
+
+/* status: selected obvious capabilities, assorted troubles */
+static void
+status_enlightenment(mode, final)
+int mode;
+int final;
+{
+    boolean magic = (mode & MAGICENLIGHTENMENT) ? TRUE : FALSE;
+    int cap, wtype;
+    char buf[BUFSZ], youtoo[BUFSZ];
+    boolean Riding = (u.usteed
+                      /* if hero dies while dismounting, u.usteed will still
+                         be set; we want to ignore steed in that situation */
+                      && !(final == ENL_GAMEOVERDEAD
+                           && !strcmp(g.killer.name, "riding accident")));
+    const char *steedname = (!Riding ? (char *) 0
+                      : x_monnam(u.usteed,
+                                 u.usteed->mtame ? ARTICLE_YOUR : ARTICLE_THE,
+                                 (char *) 0,
+                                 (SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION),
+                                 FALSE));
+
+    /*\
+     * Status (many are abbreviated on bottom line; others are or
+     *     should be discernible to the hero hence to the player)
+    \*/
+    enlght_out(""); /* separator after title or characteristics */
+    enlght_out(final ? "Final Status:" : "Current Status:");
+
+    Strcpy(youtoo, You_);
+    /* not a traditional status but inherently obvious to player; more
+       detail given below (attributes section) for magic enlightenment */
+    if (Upolyd) {
+        Strcpy(buf, "transformed");
+        if (ugenocided())
+            Sprintf(eos(buf), " and %s %s inside",
+                    final ? "felt" : "feel", udeadinside());
+        you_are(buf, "");
+    }
+    /* not a trouble, but we want to display riding status before maybe
+       reporting steed as trapped or hero stuck to cursed saddle */
+    if (Riding) {
+        Sprintf(buf, "riding %s", steedname);
+        you_are(buf, "");
+        Sprintf(eos(youtoo), "and %s ", steedname);
+    }
+    /* other movement situations that hero should always know */
+    if (Levitation) {
+        if (Lev_at_will && magic)
+            you_are("levitating, at will", "");
+        else
+            enl_msg(youtoo, are, were, "levitating", from_what(LEVITATION));
+    } else if (Flying) { /* can only fly when not levitating */
+        enl_msg(youtoo, are, were, "flying", from_what(FLYING));
+    }
+    if (Underwater) {
+        you_are("underwater", "");
+    } else if (u.uinwater) {
+        you_are(Swimming ? "swimming" : "in water", from_what(SWIMMING));
+    } else if (walking_on_water()) {
+        /* show active Wwalking here, potential Wwalking elsewhere */
+        Sprintf(buf, "walking on %s",
+                is_pool(u.ux, u.uy) ? "water"
+                : is_lava(u.ux, u.uy) ? "lava"
+                  : surface(u.ux, u.uy)); /* catchall; shouldn't happen */
+        you_are(buf, from_what(WWALKING));
+    }
+    if (Upolyd && (u.uundetected || U_AP_TYPE != M_AP_NOTHING))
+        youhiding(TRUE, final);
+
+    /* internal troubles, mostly in the order that prayer ranks them */
+    if (Stoned) {
+        if (final && (Stoned & I_SPECIAL))
+            enlght_out(" You turned into stone.");
+        else
+            you_are("turning to stone", "");
+    }
+    if (Slimed) {
+        if (final && (Slimed & I_SPECIAL))
+            enlght_out(" You turned into slime.");
+        else
+            you_are("turning into slime", "");
+    }
+    if (Strangled) {
+        if (u.uburied) {
+            you_are("buried", "");
+        } else {
+            if (final && (Strangled & I_SPECIAL)) {
+                enlght_out(" You died from strangulation.");
+            } else {
+                Strcpy(buf, "being strangled");
+                if (wizard)
+                    Sprintf(eos(buf), " (%ld)", (Strangled & TIMEOUT));
+                you_are(buf, from_what(STRANGLED));
+            }
+        }
+    }
+    if (Sick) {
+        /* the two types of sickness are lumped together; hero can be
+           afflicted by both but there is only one timeout; botl status
+           puts TermIll before FoodPois and death due to timeout reports
+           terminal illness if both are in effect, so do the same here */
+        if (final && (Sick & I_SPECIAL)) {
+            Sprintf(buf, " %sdied from %s.", You_, /* has trailing space */
+                    (u.usick_type & SICK_NONVOMITABLE)
+                    ? "terminal illness" : "food poisoning");
+            enlght_out(buf);
+        } else {
+            /* unlike death due to sickness, report the two cases separately
+               because it is possible to cure one without curing the other */
+            if (u.usick_type & SICK_NONVOMITABLE)
+                you_are("terminally sick from illness", "");
+            if (u.usick_type & SICK_VOMITABLE)
+                you_are("terminally sick from food poisoning", "");
+        }
+    }
+    if (Vomiting)
+        you_are("nauseated", "");
+    if (Stunned)
+        you_are("stunned", "");
+    if (Confusion)
+        you_are("confused", "");
+    if (Hallucination)
+        you_are("hallucinating", "");
+    if (Blind) {
+        /* from_what() (currently wizard-mode only) checks !haseyes()
+           before u.uroleplay.blind, so we should too */
+        Sprintf(buf, "%s blind",
+                !haseyes(g.youmonst.data) ? "innately"
+                : u.uroleplay.blind ? "permanently"
+                  /* better phrasing desperately wanted... */
+                  : Blindfolded_only ? "deliberately"
+                    : "temporarily");
+        if (wizard && (Blinded & TIMEOUT) != 0L
+            && !u.uroleplay.blind && haseyes(g.youmonst.data))
+            Sprintf(eos(buf), " (%ld)", (Blinded & TIMEOUT));
+        /* !haseyes: avoid "you are innately blind innately" */
+        you_are(buf, !haseyes(g.youmonst.data) ? "" : from_what(BLINDED));
+    }
+    if (Deaf)
+        you_are("deaf", from_what(DEAF));
+
+    /* external troubles, more or less */
+    if (Punished) {
+        if (uball) {
+            Sprintf(buf, "chained to %s", ansimpleoname(uball));
+        } else {
+            impossible("Punished without uball?");
+            Strcpy(buf, "punished");
+        }
+        you_are(buf, "");
+    }
+    if (u.utrap) {
+        char predicament[BUFSZ];
+        boolean anchored = (u.utraptype == TT_BURIEDBALL);
+
+        (void) trap_predicament(predicament, final, wizard);
+        if (u.usteed) { /* not `Riding' here */
+            Sprintf(buf, "%s%s ", anchored ? "you and " : "", steedname);
+            *buf = highc(*buf);
+            enl_msg(buf, (anchored ? "are " : "is "),
+                    (anchored ? "were " : "was "), predicament, "");
+        } else
+            you_are(predicament, "");
+    } /* (u.utrap) */
+    if (u.uswallow) {
+        Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck));
+        if (wizard)
+            Sprintf(eos(buf), " (%u)", u.uswldtim);
+        you_are(buf, "");
+    } else if (u.ustuck) {
+        Sprintf(buf, "%s %s",
+                (Upolyd && sticks(g.youmonst.data)) ? "holding" : "held by",
+                a_monnam(u.ustuck));
+        you_are(buf, "");
+    }
+    if (Riding) {
+        struct obj *saddle = which_armor(u.usteed, W_SADDLE);
+
+        if (saddle && saddle->cursed) {
+            Sprintf(buf, "stuck to %s %s", s_suffix(steedname),
+                    simpleonames(saddle));
+            you_are(buf, "");
+        }
+    }
+    if (Wounded_legs) {
+        /* when mounted, Wounded_legs applies to steed rather than to
+           hero; we only report steed's wounded legs in wizard mode */
+        if (u.usteed) { /* not `Riding' here */
+            if (wizard && steedname) {
+                Strcpy(buf, steedname);
+                *buf = highc(*buf);
+                enl_msg(buf, " has", " had", " wounded legs", "");
+            }
+        } else {
+            Sprintf(buf, "wounded %s", makeplural(body_part(LEG)));
+            you_have(buf, "");
+        }
+    }
+    if (Glib) {
+        Sprintf(buf, "slippery %s", fingers_or_gloves(TRUE));
+        if (wizard)
+            Sprintf(eos(buf), " (%ld)", (Glib & TIMEOUT));
+        you_have(buf, "");
+    }
+    if (Fumbling) {
+        if (magic || cause_known(FUMBLING))
+            enl_msg(You_, "fumble", "fumbled", "", from_what(FUMBLING));
+    }
+    if (Sleepy) {
+        if (magic || cause_known(SLEEPY)) {
+            Strcpy(buf, from_what(SLEEPY));
+            if (wizard)
+                Sprintf(eos(buf), " (%ld)", (HSleepy & TIMEOUT));
+            enl_msg("You ", "fall", "fell", " asleep uncontrollably", buf);
+        }
+    }
+    /* hunger/nutrition */
+    if (Hunger) {
+        if (magic || cause_known(HUNGER))
+            enl_msg(You_, "hunger", "hungered", " rapidly",
+                    from_what(HUNGER));
+    }
+    Strcpy(buf, hu_stat[u.uhs]); /* hunger status; omitted if "normal" */
+    mungspaces(buf);             /* strip trailing spaces */
+    if (*buf) {
+        *buf = lowc(*buf); /* override capitalization */
+        if (!strcmp(buf, "weak"))
+            Strcat(buf, " from severe hunger");
+        else if (!strncmp(buf, "faint", 5)) /* fainting, fainted */
+            Strcat(buf, " due to starvation");
+        you_are(buf, "");
+    }
+    /* encumbrance */
+    if ((cap = near_capacity()) > UNENCUMBERED) {
+        const char *adj = "?_?"; /* (should always get overridden) */
+
+        Strcpy(buf, enc_stat[cap]);
+        *buf = lowc(*buf);
+        switch (cap) {
+        case SLT_ENCUMBER:
+            adj = "slightly";
+            break; /* burdened */
+        case MOD_ENCUMBER:
+            adj = "moderately";
+            break; /* stressed */
+        case HVY_ENCUMBER:
+            adj = "very";
+            break; /* strained */
+        case EXT_ENCUMBER:
+            adj = "extremely";
+            break; /* overtaxed */
+        case OVERLOADED:
+            adj = "not possible";
+            break;
+        }
+        Sprintf(eos(buf), "; movement %s %s%s", !final ? "is" : "was", adj,
+                (cap < OVERLOADED) ? " slowed" : "");
+        you_are(buf, "");
+    } else {
+        /* last resort entry, guarantees Status section is non-empty
+           (no longer needed for that purpose since weapon status added;
+           still useful though) */
+        you_are("unencumbered", "");
+    }
+
+    /* report being weaponless; distinguish whether gloves are worn */
+    if (!uwep) {
+        you_are(uarmg ? "empty handed" /* gloves imply hands */
+                      : humanoid(g.youmonst.data)
+                         /* hands but no weapon and no gloves */
+                         ? "bare handed"
+                         /* alternate phrasing for paws or lack of hands */
+                         : "not wielding anything",
+                "");
+    /* two-weaponing implies hands (can't be polymorphed) and
+       a weapon or wep-tool (not other odd stuff) in each hand */
+    } else if (u.twoweap) {
+        you_are("wielding two weapons at once", "");
+    /* report most weapons by their skill class (so a katana will be
+       described as a long sword, for instance; mattock and hook are
+       exceptions), or wielded non-weapon item by its object class */
+    } else {
+        const char *what = weapon_descr(uwep);
+
+        if (!strcmpi(what, "armor") || !strcmpi(what, "food")
+            || !strcmpi(what, "venom"))
+            Sprintf(buf, "wielding some %s", what);
+        else
+            Sprintf(buf, "wielding %s",
+                    (uwep->quan == 1L) ? an(what) : makeplural(what));
+        you_are(buf, "");
+    }
+    /*
+     * Skill with current weapon.  Might help players who've never
+     * noticed #enhance or decided that it was pointless.
+     */
+    if ((wtype = uwep_skill_type()) != P_NONE) {
+        char sklvlbuf[20];
+        int sklvl = P_SKILL(wtype);
+        boolean hav = (sklvl != P_UNSKILLED && sklvl != P_SKILLED);
+
+        if (sklvl == P_ISRESTRICTED)
+            Strcpy(sklvlbuf, "no");
+        else
+            (void) lcase(skill_level_name(wtype, sklvlbuf));
+        /* "you have no/basic/expert/master/grand-master skill with <skill>"
+           or "you are unskilled/skilled in <skill>" */
+        Sprintf(buf, "%s %s %s", sklvlbuf,
+                hav ? "skill with" : "in", skill_name(wtype));
+        if (can_advance(wtype, FALSE))
+            Sprintf(eos(buf), " and %s that",
+                    !final ? "can enhance" : "could have enhanced");
+        if (hav)
+            you_have(buf, "");
+        else
+            you_are(buf, "");
+    }
+    /* report 'nudity' */
+    if (!uarm && !uarmu && !uarmc && !uarms && !uarmg && !uarmf && !uarmh) {
+        if (u.uroleplay.nudist)
+            enl_msg(You_, "do", "did", " not wear any armor", "");
+        else
+            you_are("not wearing any armor", "");
+    }
+}
+
+/* attributes: intrinsics and the like, other non-obvious capabilities */
+static void
+attributes_enlightenment(unused_mode, final)
+int unused_mode UNUSED;
+int final;
+{
+    static NEARDATA const char if_surroundings_permitted[] =
+        " if surroundings permitted";
+    int ltmp, armpro;
+    char buf[BUFSZ];
+
+    /*\
+     *  Attributes
+    \*/
+    enlght_out("");
+    enlght_out(final ? "Final Attributes:" : "Current Attributes:");
+
+    if (u.uevent.uhand_of_elbereth) {
+        static const char *const hofe_titles[3] = { "the Hand of Elbereth",
+                                                    "the Envoy of Balance",
+                                                    "the Glory of Arioch" };
+        you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1], "");
+    }
+
+    Sprintf(buf, "%s", piousness(TRUE, "aligned"));
+    if (u.ualign.record >= 0)
+        you_are(buf, "");
+    else
+        you_have(buf, "");
+
+    if (wizard) {
+        Sprintf(buf, " %d", u.ualign.record);
+        enl_msg("Your alignment ", "is", "was", buf, "");
+    }
+
+    /*** Resistances to troubles ***/
+    if (Invulnerable)
+        you_are("invulnerable", from_what(INVULNERABLE));
+    if (Antimagic)
+        you_are("magic-protected", from_what(ANTIMAGIC));
+    if (Fire_resistance)
+        you_are("fire resistant", from_what(FIRE_RES));
+    if (Cold_resistance)
+        you_are("cold resistant", from_what(COLD_RES));
+    if (Sleep_resistance)
+        you_are("sleep resistant", from_what(SLEEP_RES));
+    if (Disint_resistance)
+        you_are("disintegration-resistant", from_what(DISINT_RES));
+    if (Shock_resistance)
+        you_are("shock resistant", from_what(SHOCK_RES));
+    if (Poison_resistance)
+        you_are("poison resistant", from_what(POISON_RES));
+    if (Acid_resistance)
+        you_are("acid resistant", from_what(ACID_RES));
+    if (Drain_resistance)
+        you_are("level-drain resistant", from_what(DRAIN_RES));
+    if (Sick_resistance)
+        you_are("immune to sickness", from_what(SICK_RES));
+    if (Stone_resistance)
+        you_are("petrification resistant", from_what(STONE_RES));
+    if (Halluc_resistance)
+        enl_msg(You_, "resist", "resisted", " hallucinations",
+                from_what(HALLUC_RES));
+    if (u.uedibility)
+        you_can("recognize detrimental food", "");
+
+    /*** Vision and senses ***/
+    if (!Blind && (Blinded || !haseyes(g.youmonst.data)))
+        you_can("see", from_what(-BLINDED)); /* Eyes of the Overworld */
+    if (See_invisible) {
+        if (!Blind)
+            enl_msg(You_, "see", "saw", " invisible", from_what(SEE_INVIS));
+        else
+            enl_msg(You_, "will see", "would have seen",
+                    " invisible when not blind", from_what(SEE_INVIS));
+    }
+    if (Blind_telepat)
+        you_are("telepathic", from_what(TELEPAT));
+    if (Warning)
+        you_are("warned", from_what(WARNING));
+    if (Warn_of_mon && g.context.warntype.obj) {
+        Sprintf(buf, "aware of the presence of %s",
+                (g.context.warntype.obj & M2_ORC) ? "orcs"
+                : (g.context.warntype.obj & M2_ELF) ? "elves"
+                : (g.context.warntype.obj & M2_DEMON) ? "demons" : something);
+        you_are(buf, from_what(WARN_OF_MON));
+    }
+    if (Warn_of_mon && g.context.warntype.polyd) {
+        Sprintf(buf, "aware of the presence of %s",
+                ((g.context.warntype.polyd & (M2_HUMAN | M2_ELF))
+                 == (M2_HUMAN | M2_ELF))
+                    ? "humans and elves"
+                    : (g.context.warntype.polyd & M2_HUMAN)
+                          ? "humans"
+                          : (g.context.warntype.polyd & M2_ELF)
+                                ? "elves"
+                                : (g.context.warntype.polyd & M2_ORC)
+                                      ? "orcs"
+                                      : (g.context.warntype.polyd & M2_DEMON)
+                                            ? "demons"
+                                            : "certain monsters");
+        you_are(buf, "");
+    }
+    if (Warn_of_mon && g.context.warntype.speciesidx >= LOW_PM) {
+        Sprintf(buf, "aware of the presence of %s",
+                makeplural(mons[g.context.warntype.speciesidx].mname));
+        you_are(buf, from_what(WARN_OF_MON));
+    }
+    if (Undead_warning)
+        you_are("warned of undead", from_what(WARN_UNDEAD));
+    if (Searching)
+        you_have("automatic searching", from_what(SEARCHING));
+    if (Clairvoyant)
+        you_are("clairvoyant", from_what(CLAIRVOYANT));
+    else if ((HClairvoyant || EClairvoyant) && BClairvoyant) {
+        Strcpy(buf, from_what(-CLAIRVOYANT));
+        if (!strncmp(buf, " because of ", 12))
+            /* overwrite substring; strncpy doesn't add terminator */
+            (void) strncpy(buf, " if not for ", 12);
+        enl_msg(You_, "could be", "could have been", " clairvoyant", buf);
+    }
+    if (Infravision)
+        you_have("infravision", from_what(INFRAVISION));
+    if (Detect_monsters)
+        you_are("sensing the presence of monsters", "");
+    if (u.umconf)
+        you_are("going to confuse monsters", "");
+
+    /*** Appearance and behavior ***/
+    if (Adornment) {
+        int adorn = 0;
+
+        if (uleft && uleft->otyp == RIN_ADORNMENT)
+            adorn += uleft->spe;
+        if (uright && uright->otyp == RIN_ADORNMENT)
+            adorn += uright->spe;
+        /* the sum might be 0 (+0 ring or two which negate each other);
+           that yields "you are charismatic" (which isn't pointless
+           because it potentially impacts seduction attacks) */
+        Sprintf(buf, "%scharismatic",
+                (adorn > 0) ? "more " : (adorn < 0) ? "less " : "");
+        you_are(buf, from_what(ADORNED));
+    }
+    if (Invisible)
+        you_are("invisible", from_what(INVIS));
+    else if (Invis)
+        you_are("invisible to others", from_what(INVIS));
+    /* ordinarily "visible" is redundant; this is a special case for
+       the situation when invisibility would be an expected attribute */
+    else if ((HInvis || EInvis) && BInvis)
+        you_are("visible", from_what(-INVIS));
+    if (Displaced)
+        you_are("displaced", from_what(DISPLACED));
+    if (Stealth)
+        you_are("stealthy", from_what(STEALTH));
+    if (Aggravate_monster)
+        enl_msg("You aggravate", "", "d", " monsters",
+                from_what(AGGRAVATE_MONSTER));
+    if (Conflict)
+        enl_msg("You cause", "", "d", " conflict", from_what(CONFLICT));
+
+    /*** Transportation ***/
+    if (Jumping)
+        you_can("jump", from_what(JUMPING));
+    if (Teleportation)
+        you_can("teleport", from_what(TELEPORT));
+    if (Teleport_control)
+        you_have("teleport control", from_what(TELEPORT_CONTROL));
+    /* actively levitating handled earlier as a status condition */
+    if (BLevitation) { /* levitation is blocked */
+        long save_BLev = BLevitation;
+
+        BLevitation = 0L;
+        if (Levitation) {
+            /* either trapped in the floor or inside solid rock
+               (or both if chained to buried iron ball and have
+               moved one step into solid rock somehow) */
+            boolean trapped = (save_BLev & I_SPECIAL) != 0L,
+                    terrain = (save_BLev & FROMOUTSIDE) != 0L;
+
+            Sprintf(buf, "%s%s%s",
+                    trapped ? " if not trapped" : "",
+                    (trapped && terrain) ? " and" : "",
+                    terrain ? if_surroundings_permitted : "");
+            enl_msg(You_, "would levitate", "would have levitated", buf, "");
+        }
+        BLevitation = save_BLev;
+    }
+    /* actively flying handled earlier as a status condition */
+    if (BFlying) { /* flight is blocked */
+        long save_BFly = BFlying;
+
+        BFlying = 0L;
+        if (Flying) {
+            enl_msg(You_, "would fly", "would have flown",
+                    /* wording quibble: for past tense, "hadn't been"
+                       would sound better than "weren't" (and
+                       "had permitted" better than "permitted"), but
+                       "weren't" and "permitted" are adequate so the
+                       extra complexity to handle that isn't worth it */
+                    Levitation
+                       ? " if you weren't levitating"
+                       : (save_BFly == I_SPECIAL)
+                          /* this is an oversimpliction; being trapped
+                             might also be blocking levitation so flight
+                             would still be blocked after escaping trap */
+                          ? " if you weren't trapped"
+                          : (save_BFly == FROMOUTSIDE)
+                             ? if_surroundings_permitted
+                             /* two or more of levitation, surroundings,
+                                and being trapped in the floor */
+                             : " if circumstances permitted",
+                    "");
+        }
+        BFlying = save_BFly;
+    }
+    /* actively walking on water handled earlier as a status condition */
+    if (Wwalking && !walking_on_water())
+        you_can("walk on water", from_what(WWALKING));
+    /* actively swimming (in water but not under it) handled earlier */
+    if (Swimming && (Underwater || !u.uinwater))
+        you_can("swim", from_what(SWIMMING));
+    if (Breathless)
+        you_can("survive without air", from_what(MAGICAL_BREATHING));
+    else if (Amphibious)
+        you_can("breathe water", from_what(MAGICAL_BREATHING));
+    if (Passes_walls)
+        you_can("walk through walls", from_what(PASSES_WALLS));
+
+    /*** Physical attributes ***/
+    if (Regeneration)
+        enl_msg("You regenerate", "", "d", "", from_what(REGENERATION));
+    if (Slow_digestion)
+        you_have("slower digestion", from_what(SLOW_DIGESTION));
+    if (u.uhitinc)
+        you_have(enlght_combatinc("to hit", u.uhitinc, final, buf), "");
+    if (u.udaminc)
+        you_have(enlght_combatinc("damage", u.udaminc, final, buf), "");
+    if (u.uspellprot || Protection) {
+        int prot = 0;
+
+        if (uleft && uleft->otyp == RIN_PROTECTION)
+            prot += uleft->spe;
+        if (uright && uright->otyp == RIN_PROTECTION)
+            prot += uright->spe;
+        if (HProtection & INTRINSIC)
+            prot += u.ublessed;
+        prot += u.uspellprot;
+        if (prot)
+            you_have(enlght_combatinc("defense", prot, final, buf), "");
+    }
+    if ((armpro = magic_negation(&g.youmonst)) > 0) {
+        /* magic cancellation factor, conferred by worn armor */
+        static const char *const mc_types[] = {
+            "" /*ordinary*/, "warded", "guarded", "protected",
+        };
+        /* sanity check */
+        if (armpro >= SIZE(mc_types))
+            armpro = SIZE(mc_types) - 1;
+        you_are(mc_types[armpro], "");
+    }
+    if (Half_physical_damage)
+        enlght_halfdmg(HALF_PHDAM, final);
+    if (Half_spell_damage)
+        enlght_halfdmg(HALF_SPDAM, final);
+    if (Half_gas_damage)
+        enl_msg(You_, "take", "took", " reduced poison gas damage", "");
+    /* polymorph and other shape change */
+    if (Protection_from_shape_changers)
+        you_are("protected from shape changers",
+                from_what(PROT_FROM_SHAPE_CHANGERS));
+    if (Unchanging) {
+        const char *what = 0;
+
+        if (!Upolyd) /* Upolyd handled below after current form */
+            you_can("not change from your current form",
+                    from_what(UNCHANGING));
+        /* blocked shape changes */
+        if (Polymorph)
+            what = !final ? "polymorph" : "have polymorphed";
+        else if (u.ulycn >= LOW_PM)
+            what = !final ? "change shape" : "have changed shape";
+        if (what) {
+            Sprintf(buf, "would %s periodically", what);
+            /* omit from_what(UNCHANGING); too verbose */
+            enl_msg(You_, buf, buf, " if not locked into your current form",
+                    "");
+        }
+    } else if (Polymorph) {
+        you_are("polymorphing periodically", from_what(POLYMORPH));
+    }
+    if (Polymorph_control)
+        you_have("polymorph control", from_what(POLYMORPH_CONTROL));
+    if (Upolyd && u.umonnum != u.ulycn
+        /* if we've died from turning into slime, we're polymorphed
+           right now but don't want to list it as a temporary attribute
+           [we need a more reliable way to detect this situation] */
+        && !(final == ENL_GAMEOVERDEAD
+             && u.umonnum == PM_GREEN_SLIME && !Unchanging)) {
+        /* foreign shape (except were-form which is handled below) */
+        if (!vampshifted(&g.youmonst))
+            Sprintf(buf, "polymorphed into %s", an(g.youmonst.data->mname));
+        else
+            Sprintf(buf, "polymorphed into %s in %s form",
+                    an(mons[g.youmonst.cham].mname), g.youmonst.data->mname);
+        if (wizard)
+            Sprintf(eos(buf), " (%d)", u.mtimedone);
+        you_are(buf, "");
+    }
+    if (lays_eggs(g.youmonst.data) && flags.female) /* Upolyd */
+        you_can("lay eggs", "");
+    if (u.ulycn >= LOW_PM) {
+        /* "you are a werecreature [in beast form]" */
+        Strcpy(buf, an(mons[u.ulycn].mname));
+        if (u.umonnum == u.ulycn) {
+            Strcat(buf, " in beast form");
+            if (wizard)
+                Sprintf(eos(buf), " (%d)", u.mtimedone);
+        }
+        you_are(buf, "");
+    }
+    if (Unchanging && Upolyd) /* !Upolyd handled above */
+        you_can("not change from your current form", from_what(UNCHANGING));
+    if (Hate_silver)
+        you_are("harmed by silver", "");
+    /* movement and non-armor-based protection */
+    if (Fast)
+        you_are(Very_fast ? "very fast" : "fast", from_what(FAST));
+    if (Reflecting)
+        you_have("reflection", from_what(REFLECTING));
+    if (Free_action)
+        you_have("free action", from_what(FREE_ACTION));
+    if (Fixed_abil)
+        you_have("fixed abilities", from_what(FIXED_ABIL));
+    if (Lifesaved)
+        enl_msg("Your life ", "will be", "would have been", " saved", "");
+
+    /*** Miscellany ***/
+    if (Luck) {
+        ltmp = abs((int) Luck);
+        Sprintf(buf, "%s%slucky",
+                ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "",
+                Luck < 0 ? "un" : "");
+        if (wizard)
+            Sprintf(eos(buf), " (%d)", Luck);
+        you_are(buf, "");
+    } else if (wizard)
+        enl_msg("Your luck ", "is", "was", " zero", "");
+    if (u.moreluck > 0)
+        you_have("extra luck", "");
+    else if (u.moreluck < 0)
+        you_have("reduced luck", "");
+    if (carrying(LUCKSTONE) || stone_luck(TRUE)) {
+        ltmp = stone_luck(FALSE);
+        if (ltmp <= 0)
+            enl_msg("Bad luck ", "does", "did", " not time out for you", "");
+        if (ltmp >= 0)
+            enl_msg("Good luck ", "does", "did", " not time out for you", "");
+    }
+
+    if (u.ugangr) {
+        Sprintf(buf, " %sangry with you",
+                u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : "");
+        if (wizard)
+            Sprintf(eos(buf), " (%d)", u.ugangr);
+        enl_msg(u_gname(), " is", " was", buf, "");
+    } else {
+        /*
+         * We need to suppress this when the game is over, because death
+         * can change the value calculated by can_pray(), potentially
+         * resulting in a false claim that you could have prayed safely.
+         */
+        if (!final) {
+#if 0
+            /* "can [not] safely pray" vs "could [not] have safely prayed" */
+            Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ",
+                    final ? "have " : "", final ? "ed" : "");
+#else
+            Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not ");
+#endif
+            if (wizard)
+                Sprintf(eos(buf), " (%d)", u.ublesscnt);
+            you_can(buf, "");
+        }
+    }
+
+#ifdef DEBUG
+    /* named fruit debugging (doesn't really belong here...); to enable,
+       include 'fruit' in DEBUGFILES list (even though it isn't a file...) */
+    if (wizard && explicitdebug("fruit")) {
+        struct fruit *f;
+
+        reorder_fruit(TRUE); /* sort by fruit index, from low to high;
+                              * this modifies the g.ffruit chain, so could
+                              * possibly mask or even introduce a problem,
+                              * but it does useful sanity checking */
+        for (f = g.ffruit; f; f = f->nextf) {
+            Sprintf(buf, "Fruit #%d ", f->fid);
+            enl_msg(buf, "is ", "was ", f->fname, "");
+        }
+        enl_msg("The current fruit ", "is ", "was ", g.pl_fruit, "");
+        Sprintf(buf, "%d", flags.made_fruit);
+        enl_msg("The made fruit flag ", "is ", "was ", buf, "");
+    }
+#endif
+
+    {
+        const char *p;
+
+        buf[0] = '\0';
+        if (final < 2) { /* still in progress, or quit/escaped/ascended */
+            p = "survived after being killed ";
+            switch (u.umortality) {
+            case 0:
+                p = !final ? (char *) 0 : "survived";
+                break;
+            case 1:
+                Strcpy(buf, "once");
+                break;
+            case 2:
+                Strcpy(buf, "twice");
+                break;
+            case 3:
+                Strcpy(buf, "thrice");
+                break;
+            default:
+                Sprintf(buf, "%d times", u.umortality);
+                break;
+            }
+        } else { /* game ended in character's death */
+            p = "are dead";
+            switch (u.umortality) {
+            case 0:
+                impossible("dead without dying?");
+            case 1:
+                break; /* just "are dead" */
+            default:
+                Sprintf(buf, " (%d%s time!)", u.umortality,
+                        ordin(u.umortality));
+                break;
+            }
+        }
+        if (p)
+            enl_msg(You_, "have been killed ", p, buf, "");
+    }
+}
+
+/* ^X command */
+int
+doattributes(VOID_ARGS)
+{
+    int mode = BASICENLIGHTENMENT;
+
+    /* show more--as if final disclosure--for wizard and explore modes */
+    if (wizard || discover)
+        mode |= MAGICENLIGHTENMENT;
+
+    enlightenment(mode, ENL_GAMEINPROGRESS);
+    return 0;
+}
+
+void
+youhiding(via_enlghtmt, msgflag)
+boolean via_enlghtmt; /* englightment line vs topl message */
+int msgflag;          /* for variant message phrasing */
+{
+    char *bp, buf[BUFSZ];
+
+    Strcpy(buf, "hiding");
+    if (U_AP_TYPE != M_AP_NOTHING) {
+        /* mimic; hero is only able to mimic a strange object or gold
+           or hallucinatory alternative to gold, so we skip the details
+           for the hypothetical furniture and monster cases */
+        bp = eos(strcpy(buf, "mimicking"));
+        if (U_AP_TYPE == M_AP_OBJECT) {
+            Sprintf(bp, " %s", an(simple_typename(g.youmonst.mappearance)));
+        } else if (U_AP_TYPE == M_AP_FURNITURE) {
+            Strcpy(bp, " something");
+        } else if (U_AP_TYPE == M_AP_MONSTER) {
+            Strcpy(bp, " someone");
+        } else {
+            ; /* something unexpected; leave 'buf' as-is */
+        }
+    } else if (u.uundetected) {
+        bp = eos(buf); /* points past "hiding" */
+        if (g.youmonst.data->mlet == S_EEL) {
+            if (is_pool(u.ux, u.uy))
+                Sprintf(bp, " in the %s", waterbody_name(u.ux, u.uy));
+        } else if (hides_under(g.youmonst.data)) {
+            struct obj *o = g.level.objects[u.ux][u.uy];
+
+            if (o)
+                Sprintf(bp, " underneath %s", ansimpleoname(o));
+        } else if (is_clinger(g.youmonst.data) || Flying) {
+            /* Flying: 'lurker above' hides on ceiling but doesn't cling */
+            Sprintf(bp, " on the %s", ceiling(u.ux, u.uy));
+        } else {
+            /* on floor; is_hider() but otherwise not special: 'trapper' */
+            if (u.utrap && u.utraptype == TT_PIT) {
+                struct trap *t = t_at(u.ux, u.uy);
+
+                Sprintf(bp, " in a %spit",
+                        (t && t->ttyp == SPIKED_PIT) ? "spiked " : "");
+            } else
+                Sprintf(bp, " on the %s", surface(u.ux, u.uy));
+        }
+    } else {
+        ; /* shouldn't happen; will result in generic "you are hiding" */
+    }
+
+    if (via_enlghtmt) {
+        int final = msgflag; /* 'final' is used by you_are() macro */
+
+        you_are(buf, "");
+    } else {
+        /* for dohide(), when player uses '#monster' command */
+        You("are %s %s.", msgflag ? "already" : "now", buf);
+    }
+}
+
+/* #conduct command [KMH]; shares enlightenment's tense handling */
+int
+doconduct(VOID_ARGS)
+{
+    show_conduct(0);
+    return 0;
+}
+
+/* display conducts; for doconduct(), also disclose() and dump_everything() */
+void
+show_conduct(final)
+int final;
+{
+    char buf[BUFSZ];
+    int ngenocided;
+
+    /* Create the conduct window */
+    g.en_win = create_nhwindow(NHW_MENU);
+    putstr(g.en_win, 0, "Voluntary challenges:");
+
+    if (u.uroleplay.blind)
+        you_have_been("blind from birth");
+    if (u.uroleplay.nudist)
+        you_have_been("faithfully nudist");
+
+    if (!u.uconduct.food)
+        enl_msg(You_, "have gone", "went", " without food", "");
+        /* but beverages are okay */
+    else if (!u.uconduct.unvegan)
+        you_have_X("followed a strict vegan diet");
+    else if (!u.uconduct.unvegetarian)
+        you_have_been("vegetarian");
+
+    if (!u.uconduct.gnostic)
+        you_have_been("an atheist");
+
+    if (!u.uconduct.weaphit) {
+        you_have_never("hit with a wielded weapon");
+    } else if (wizard) {
+        Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit,
+                plur(u.uconduct.weaphit));
+        you_have_X(buf);
+    }
+    if (!u.uconduct.killer)
+        you_have_been("a pacifist");
+
+    if (!u.uconduct.literate) {
+        you_have_been("illiterate");
+    } else if (wizard) {
+        Sprintf(buf, "read items or engraved %ld time%s", u.uconduct.literate,
+                plur(u.uconduct.literate));
+        you_have_X(buf);
+    }
+
+    ngenocided = num_genocides();
+    if (ngenocided == 0) {
+        you_have_never("genocided any monsters");
+    } else {
+        Sprintf(buf, "genocided %d type%s of monster%s", ngenocided,
+                plur(ngenocided), plur(ngenocided));
+        you_have_X(buf);
+    }
+
+    if (!u.uconduct.polypiles) {
+        you_have_never("polymorphed an object");
+    } else if (wizard) {
+        Sprintf(buf, "polymorphed %ld item%s", u.uconduct.polypiles,
+                plur(u.uconduct.polypiles));
+        you_have_X(buf);
+    }
+
+    if (!u.uconduct.polyselfs) {
+        you_have_never("changed form");
+    } else if (wizard) {
+        Sprintf(buf, "changed form %ld time%s", u.uconduct.polyselfs,
+                plur(u.uconduct.polyselfs));
+        you_have_X(buf);
+    }
+
+    if (!u.uconduct.wishes) {
+        you_have_X("used no wishes");
+    } else {
+        Sprintf(buf, "used %ld wish%s", u.uconduct.wishes,
+                (u.uconduct.wishes > 1L) ? "es" : "");
+        if (u.uconduct.wisharti) {
+            /* if wisharti == wishes
+             *  1 wish (for an artifact)
+             *  2 wishes (both for artifacts)
+             *  N wishes (all for artifacts)
+             * else (N is at least 2 in order to get here; M < N)
+             *  N wishes (1 for an artifact)
+             *  N wishes (M for artifacts)
+             */
+            if (u.uconduct.wisharti == u.uconduct.wishes)
+                Sprintf(eos(buf), " (%s",
+                        (u.uconduct.wisharti > 2L) ? "all "
+                          : (u.uconduct.wisharti == 2L) ? "both " : "");
+            else
+                Sprintf(eos(buf), " (%ld ", u.uconduct.wisharti);
+
+            Sprintf(eos(buf), "for %s)",
+                    (u.uconduct.wisharti == 1L) ? "an artifact"
+                                                : "artifacts");
+        }
+        you_have_X(buf);
+
+        if (!u.uconduct.wisharti)
+            enl_msg(You_, "have not wished", "did not wish",
+                    " for any artifacts", "");
+    }
+
+    show_achievements(final);
+
+    /* Pop up the window and wait for a key */
+    display_nhwindow(g.en_win, TRUE);
+    destroy_nhwindow(g.en_win);
+    g.en_win = WIN_ERR;
+}
+
+/* uses to decide whether there are any achievements to display */
+int
+count_uachieve()
+{
+    int acnt = 0;
+
+    /* these tests must be kept in sync with show_achievements() */
+    if (u.uroleplay.blind)
+        ++acnt;
+    if (u.uroleplay.nudist)
+        ++acnt;
+    if (u.uachieve.mines_luckstone)
+        ++acnt;
+    if (u.uachieve.finish_sokoban)
+        ++acnt;
+    if (u.uachieve.killed_medusa)
+        ++acnt;
+    if (u.uachieve.bell)
+        ++acnt;
+    if (u.uachieve.enter_gehennom)
+        ++acnt;
+    if (u.uachieve.menorah)
+        ++acnt;
+    if (u.uachieve.book)
+        ++acnt;
+    if (u.uevent.invoked)
+        ++acnt;
+    if (u.uachieve.amulet)
+        ++acnt;
+    if (In_endgame(&u.uz))
+        ++acnt;
+    if (Is_astralevel(&u.uz))
+        ++acnt;
+    if (u.uachieve.ascended)
+        ++acnt;
+
+    return acnt;
+}
+
+static void
+show_achievements(final)
+int final;
+{
+    int acnt;
+    char title[BUFSZ];
+    winid awin = WIN_ERR;
+
+    /* unfortunately we can't show the achievements (at least not all of
+       them) while the game is in progress because it would give away the
+       ID of luckstone (at Mine's End) and of real Amulet of Yendor */
+    if (!final && !wizard)
+        return;
+
+    /* first, figure whether any achievements have been accomplished
+       so that we don't show the header for them if the resulting list
+       below it would be empty */
+    if ((acnt = count_uachieve()) == 0)
+        return;
+
+    if (g.en_win != WIN_ERR) {
+        awin = g.en_win; /* end of game disclosure window */
+        putstr(awin, 0, "");
+    } else {
+        awin = create_nhwindow(NHW_MENU);
+    }
+    Sprintf(title, "Achievement%s:", plur(acnt));
+    putstr(awin, 0, title);
+    /* after 'blind' and 'nudist', which are the easiest if you die but
+       the hardest if you ascend, they're arranged in approximate order
+       of difficulty */
+    if (u.uroleplay.blind)
+        enl_msg(You_, "are exploring", "explored",
+                " without being able to see", "");
+    if (u.uroleplay.nudist)
+        enl_msg(You_, "have gone", "went", " without any armor", "");
+
+    if (u.uachieve.mines_luckstone)
+        enl_msg(You_, "have ", "", "completed the Gnomish Mines", "");
+    if (u.uachieve.finish_sokoban)
+        enl_msg(You_, "have ", "", "completed Sokoban", "");
+    if (u.uachieve.killed_medusa)
+        enl_msg(You_, "have ", "", "defeated Medusa", "");
+    if (u.uachieve.bell) {
+        /* alternate phrasing for present vs past and also for possessing
+           the item vs once held it */
+        enl_msg(You_,
+                u.uhave.bell ? "have" : "have handled",
+                u.uhave.bell ? "had" : "handled",
+                " the Bell of Opening", "");
+    }
+    /* wording is clumsy but the game is inconsistent about "entering
+       Gehennom"; the Valley is part of Gehennom but the message about
+       entering Gehennom is given when descending from the Valley to the
+       level below and that's also when the flag about entering gets set */
+    if (u.uachieve.enter_gehennom)
+        enl_msg(You_, "have ", "", "passed the Valley of the Dead", "");
+    if (u.uachieve.menorah) {
+        enl_msg(You_,
+                u.uhave.menorah ? "have" : "have handled",
+                u.uhave.menorah ? "had" : "handled",
+                " the Candelabrum of Invocation", "");
+    }
+    if (u.uachieve.book) {
+        enl_msg(You_,
+                u.uhave.book ? "have" : "have handled",
+                u.uhave.book ? "had" : "handled",
+                " the Book of the Dead", "");
+    }
+    if (u.uevent.invoked)
+        enl_msg(You_, "have ", "", "gained access to Moloch's Sanctum", "");
+    if (u.uachieve.amulet) {
+        /* extra alternate wording for past tense because ascension
+           requires giving up the Amulet */
+        enl_msg(You_,
+                u.uhave.amulet ? "have" : "have obtained",
+                u.uachieve.ascended ? "delivered"
+                 : u.uhave.amulet ? "had" : "had obtained",
+                " the Amulet of Yendor", "");
+    }
+
+    /* reaching Astral makes feedback about reaching the Planes be redundant
+       and asceding makes both be redundant, but we display all that apply */
+    if (In_endgame(&u.uz))
+        enl_msg(You_, "have ", "", "reached the Elemental Planes", "");
+    if (Is_astralevel(&u.uz))
+        enl_msg(You_, "have ", "", "reached the Astral Plane", "");
+    if (u.uachieve.ascended)
+        enlght_out(" You ascended!");
+
+    if (awin != g.en_win) {
+        display_nhwindow(awin, TRUE);
+        destroy_nhwindow(awin);
+    }
+}
+
+static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
+    "traditional: by monster level, by internal monster index",
+    "by monster toughness, by internal monster index",
+    "alphabetically, first unique monsters, then others",
+    "alphabetically, unique monsters and others intermixed",
+    "by monster class, high to low level within class",
+    "by monster class, low to high level within class",
+    "by count, high to low, by internal index within tied count",
+    "by count, low to high, by internal index within tied count",
+};
+
+static int CFDECLSPEC
+vanqsort_cmp(vptr1, vptr2)
+const genericptr vptr1;
+const genericptr vptr2;
+{
+    int indx1 = *(short *) vptr1, indx2 = *(short *) vptr2,
+        mlev1, mlev2, mstr1, mstr2, uniq1, uniq2, died1, died2, res;
+    const char *name1, *name2, *punct;
+    schar mcls1, mcls2;
+
+    switch (g.vanq_sortmode) {
+    default:
+    case VANQ_MLVL_MNDX:
+        /* sort by monster level */
+        mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
+        res = mlev2 - mlev1; /* mlevel high to low */
+        break;
+    case VANQ_MSTR_MNDX:
+        /* sort by monster toughness */
+        mstr1 = mons[indx1].difficulty, mstr2 = mons[indx2].difficulty;
+        res = mstr2 - mstr1; /* monstr high to low */
+        break;
+    case VANQ_ALPHA_SEP:
+        uniq1 = ((mons[indx1].geno & G_UNIQ) && indx1 != PM_HIGH_PRIEST);
+        uniq2 = ((mons[indx2].geno & G_UNIQ) && indx2 != PM_HIGH_PRIEST);
+        if (uniq1 ^ uniq2) { /* one or other uniq, but not both */
+            res = uniq2 - uniq1;
+            break;
+        } /* else both unique or neither unique */
+        /*FALLTHRU*/
+    case VANQ_ALPHA_MIX:
+        name1 = mons[indx1].mname, name2 = mons[indx2].mname;
+        res = strcmpi(name1, name2); /* caseblind alhpa, low to high */
+        break;
+    case VANQ_MCLS_HTOL:
+    case VANQ_MCLS_LTOH:
+        /* mons[].mlet is a small integer, 1..N, of type plain char;
+           if 'char' happens to be unsigned, (mlet1 - mlet2) would yield
+           an inappropriate result when mlet2 is greater than mlet1,
+           so force our copies (mcls1, mcls2) to be signed */
+        mcls1 = (schar) mons[indx1].mlet, mcls2 = (schar) mons[indx2].mlet;
+        /* S_ANT through S_ZRUTY correspond to lowercase monster classes,
+           S_ANGEL through S_ZOMBIE correspond to uppercase, and various
+           punctuation characters are used for classes beyond those */
+        if (mcls1 > S_ZOMBIE && mcls2 > S_ZOMBIE) {
+            /* force a specific order to the punctuation classes that's
+               different from the internal order;
+               internal order is ok if neither or just one is punctuation
+               since letters have lower values so come out before punct */
+            static const char punctclasses[] = {
+                S_LIZARD, S_EEL, S_GOLEM, S_GHOST, S_DEMON, S_HUMAN, '\0'
+            };
+
+            if ((punct = index(punctclasses, mcls1)) != 0)
+                mcls1 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
+            if ((punct = index(punctclasses, mcls2)) != 0)
+                mcls2 = (schar) (S_ZOMBIE + 1 + (int) (punct - punctclasses));
+        }
+        res = mcls1 - mcls2; /* class */
+        if (res == 0) {
+            mlev1 = mons[indx1].mlevel, mlev2 = mons[indx2].mlevel;
+            res = mlev1 - mlev2; /* mlevel low to high */
+            if (g.vanq_sortmode == VANQ_MCLS_HTOL)
+                res = -res; /* mlevel high to low */
+        }
+        break;
+    case VANQ_COUNT_H_L:
+    case VANQ_COUNT_L_H:
+        died1 = g.mvitals[indx1].died, died2 = g.mvitals[indx2].died;
+        res = died2 - died1; /* dead count high to low */
+        if (g.vanq_sortmode == VANQ_COUNT_L_H)
+            res = -res; /* dead count low to high */
+        break;
+    }
+    /* tiebreaker: internal mons[] index */
+    if (res == 0)
+        res = indx1 - indx2; /* mndx low to high */
+    return res;
+}
+
+/* returns -1 if cancelled via ESC */
+static int
+set_vanq_order()
+{
+    winid tmpwin;
+    menu_item *selected;
+    anything any;
+    int i, n, choice;
+
+    tmpwin = create_nhwindow(NHW_MENU);
+    start_menu(tmpwin);
+    any = cg.zeroany; /* zero out all bits */
+    for (i = 0; i < SIZE(vanqorders); i++) {
+        if (i == VANQ_ALPHA_MIX || i == VANQ_MCLS_HTOL) /* skip these */
+            continue;
+        any.a_int = i + 1;
+        add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, vanqorders[i],
+                 (i == g.vanq_sortmode)
+                    ? MENU_ITEMFLAGS_SELECTED : MENU_ITEMFLAGS_NONE);
+    }
+    end_menu(tmpwin, "Sort order for vanquished monster counts");
+
+    n = select_menu(tmpwin, PICK_ONE, &selected);
+    destroy_nhwindow(tmpwin);
+    if (n > 0) {
+        choice = selected[0].item.a_int - 1;
+        /* skip preselected entry if we have more than one item chosen */
+        if (n > 1 && choice == g.vanq_sortmode)
+            choice = selected[1].item.a_int - 1;
+        free((genericptr_t) selected);
+        g.vanq_sortmode = choice;
+    }
+    return (n < 0) ? -1 : g.vanq_sortmode;
+}
+
+/* #vanquished command */
+int
+dovanquished()
+{
+    list_vanquished('a', FALSE);
+    return 0;
+}
+
+/* high priests aren't unique but are flagged as such to simplify something */
+#define UniqCritterIndx(mndx) ((mons[mndx].geno & G_UNIQ) \
+                               && mndx != PM_HIGH_PRIEST)
+
+#define done_stopprint g.program_state.stopprint
+
+void
+list_vanquished(defquery, ask)
+char defquery;
+boolean ask;
+{
+    register int i;
+    int pfx, nkilled;
+    unsigned ntypes, ni;
+    long total_killed = 0L;
+    winid klwin;
+    short mindx[NUMMONS];
+    char c, buf[BUFSZ], buftoo[BUFSZ];
+    boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
+
+    dumping = (defquery == 'd');
+    if (dumping)
+        defquery = 'y';
+
+    /* get totals first */
+    ntypes = 0;
+    for (i = LOW_PM; i < NUMMONS; i++) {
+        if ((nkilled = (int) g.mvitals[i].died) == 0)
+            continue;
+        mindx[ntypes++] = i;
+        total_killed += (long) nkilled;
+    }
+
+    /* vanquished creatures list;
+     * includes all dead monsters, not just those killed by the player
+     */
+    if (ntypes != 0) {
+        char mlet, prev_mlet = 0; /* used as small integer, not character */
+        boolean class_header, uniq_header, was_uniq = FALSE;
+
+        c = ask ? yn_function(
+                            "Do you want an account of creatures vanquished?",
+                              ynaqchars, defquery)
+                : defquery;
+        if (c == 'q')
+            done_stopprint++;
+        if (c == 'y' || c == 'a') {
+            if (c == 'a') { /* ask player to choose sort order */
+                /* choose value for vanq_sortmode via menu; ESC cancels list
+                   of vanquished monsters but does not set 'done_stopprint' */
+                if (set_vanq_order() < 0)
+                    return;
+            }
+            uniq_header = (g.vanq_sortmode == VANQ_ALPHA_SEP);
+            class_header = (g.vanq_sortmode == VANQ_MCLS_LTOH
+                            || g.vanq_sortmode == VANQ_MCLS_HTOL);
+
+            klwin = create_nhwindow(NHW_MENU);
+            putstr(klwin, 0, "Vanquished creatures:");
+            if (!dumping)
+                putstr(klwin, 0, "");
+
+            qsort((genericptr_t) mindx, ntypes, sizeof *mindx, vanqsort_cmp);
+            for (ni = 0; ni < ntypes; ni++) {
+                i = mindx[ni];
+                nkilled = g.mvitals[i].died;
+                mlet = mons[i].mlet;
+                if (class_header && mlet != prev_mlet) {
+                    Strcpy(buf, def_monsyms[(int) mlet].explain);
+                    putstr(klwin, ask ? 0 : iflags.menu_headings,
+                           upstart(buf));
+                    prev_mlet = mlet;
+                }
+                if (UniqCritterIndx(i)) {
+                    Sprintf(buf, "%s%s",
+                            !type_is_pname(&mons[i]) ? "the " : "",
+                            mons[i].mname);
+                    if (nkilled > 1) {
+                        switch (nkilled) {
+                        case 2:
+                            Sprintf(eos(buf), " (twice)");
+                            break;
+                        case 3:
+                            Sprintf(eos(buf), " (thrice)");
+                            break;
+                        default:
+                            Sprintf(eos(buf), " (%d times)", nkilled);
+                            break;
+                        }
+                    }
+                    was_uniq = TRUE;
+                } else {
+                    if (uniq_header && was_uniq) {
+                        putstr(klwin, 0, "");
+                        was_uniq = FALSE;
+                    }
+                    /* trolls or undead might have come back,
+                       but we don't keep track of that */
+                    if (nkilled == 1)
+                        Strcpy(buf, an(mons[i].mname));
+                    else
+                        Sprintf(buf, "%3d %s", nkilled,
+                                makeplural(mons[i].mname));
+                }
+                /* number of leading spaces to match 3 digit prefix */
+                pfx = !strncmpi(buf, "the ", 3) ? 0
+                      : !strncmpi(buf, "an ", 3) ? 1
+                        : !strncmpi(buf, "a ", 2) ? 2
+                          : !digit(buf[2]) ? 4 : 0;
+                if (class_header)
+                    ++pfx;
+                Sprintf(buftoo, "%*s%s", pfx, "", buf);
+                putstr(klwin, 0, buftoo);
+            }
+            /*
+             * if (Hallucination)
+             *     putstr(klwin, 0, "and a partridge in a pear tree");
+             */
+            if (ntypes > 1) {
+                if (!dumping)
+                    putstr(klwin, 0, "");
+                Sprintf(buf, "%ld creatures vanquished.", total_killed);
+                putstr(klwin, 0, buf);
+            }
+            display_nhwindow(klwin, TRUE);
+            destroy_nhwindow(klwin);
+        }
+    } else if (defquery == 'a') {
+        /* #dovanquished rather than final disclosure, so pline() is ok */
+        pline("No creatures have been vanquished.");
+#ifdef DUMPLOG
+    } else if (dumping) {
+        putstr(0, 0, "No creatures were vanquished."); /* not pline() */
+#endif
+    }
+}
+
+/* number of monster species which have been genocided */
+int
+num_genocides()
+{
+    int i, n = 0;
+
+    for (i = LOW_PM; i < NUMMONS; ++i) {
+        if (g.mvitals[i].mvflags & G_GENOD) {
+            ++n;
+            if (UniqCritterIndx(i))
+                impossible("unique creature '%d: %s' genocided?",
+                           i, mons[i].mname);
+        }
+    }
+    return n;
+}
+
+static int
+num_extinct()
+{
+    int i, n = 0;
+
+    for (i = LOW_PM; i < NUMMONS; ++i) {
+        if (UniqCritterIndx(i))
+            continue;
+        if ((g.mvitals[i].mvflags & G_GONE) == G_EXTINCT)
+            ++n;
+    }
+    return n;
+}
+
+void
+list_genocided(defquery, ask)
+char defquery;
+boolean ask;
+{
+    register int i;
+    int ngenocided, nextinct;
+    char c;
+    winid klwin;
+    char buf[BUFSZ];
+    boolean dumping; /* for DUMPLOG; doesn't need to be conditional */
+
+    dumping = (defquery == 'd');
+    if (dumping)
+        defquery = 'y';
+
+    ngenocided = num_genocides();
+    nextinct = num_extinct();
+
+    /* genocided or extinct species list */
+    if (ngenocided != 0 || nextinct != 0) {
+        Sprintf(buf, "Do you want a list of %sspecies%s%s?",
+                (nextinct && !ngenocided) ? "extinct " : "",
+                (ngenocided) ? " genocided" : "",
+                (nextinct && ngenocided) ? " and extinct" : "");
+        c = ask ? yn_function(buf, ynqchars, defquery) : defquery;
+        if (c == 'q')
+            done_stopprint++;
+        if (c == 'y') {
+            klwin = create_nhwindow(NHW_MENU);
+            Sprintf(buf, "%s%s species:",
+                    (ngenocided) ? "Genocided" : "Extinct",
+                    (nextinct && ngenocided) ? " or extinct" : "");
+            putstr(klwin, 0, buf);
+            if (!dumping)
+                putstr(klwin, 0, "");
+
+            for (i = LOW_PM; i < NUMMONS; i++) {
+                /* uniques can't be genocided but can become extinct;
+                   however, they're never reported as extinct, so skip them */
+                if (UniqCritterIndx(i))
+                    continue;
+                if (g.mvitals[i].mvflags & G_GONE) {
+                    Sprintf(buf, " %s", makeplural(mons[i].mname));
+                    /*
+                     * "Extinct" is unfortunate terminology.  A species
+                     * is marked extinct when its birth limit is reached,
+                     * but there might be members of the species still
+                     * alive, contradicting the meaning of the word.
+                     */
+                    if ((g.mvitals[i].mvflags & G_GONE) == G_EXTINCT)
+                        Strcat(buf, " (extinct)");
+                    putstr(klwin, 0, buf);
+                }
+            }
+            if (!dumping)
+                putstr(klwin, 0, "");
+            if (ngenocided > 0) {
+                Sprintf(buf, "%d species genocided.", ngenocided);
+                putstr(klwin, 0, buf);
+            }
+            if (nextinct > 0) {
+                Sprintf(buf, "%d species extinct.", nextinct);
+                putstr(klwin, 0, buf);
+            }
+
+            display_nhwindow(klwin, TRUE);
+            destroy_nhwindow(klwin);
+        }
+#ifdef DUMPLOG
+    } else if (dumping) {
+        putstr(0, 0, "No species were genocided or became extinct.");
+#endif
+    }
+}
+
+/*
+ * align_str(), piousness(), mstatusline() and ustatusline() once resided
+ * in pline.c, then got moved to priest.c just to be out of there.  They
+ * fit better here.
+ */
+
+const char *
+align_str(alignment)
+aligntyp alignment;
+{
+    switch ((int) alignment) {
+    case A_CHAOTIC:
+        return "chaotic";
+    case A_NEUTRAL:
+        return "neutral";
+    case A_LAWFUL:
+        return "lawful";
+    case A_NONE:
+        return "unaligned";
+    }
+    return "unknown";
+}
+
+/* used for self-probing */
+char *
+piousness(showneg, suffix)
+boolean showneg;
+const char *suffix;
+{
+    static char buf[32]; /* bigger than "insufficiently neutral" */
+    const char *pio;
+
+    /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
+    if (u.ualign.record >= 20)
+        pio = "piously";
+    else if (u.ualign.record > 13)
+        pio = "devoutly";
+    else if (u.ualign.record > 8)
+        pio = "fervently";
+    else if (u.ualign.record > 3)
+        pio = "stridently";
+    else if (u.ualign.record == 3)
+        pio = "";
+    else if (u.ualign.record > 0)
+        pio = "haltingly";
+    else if (u.ualign.record == 0)
+        pio = "nominally";
+    else if (!showneg)
+        pio = "insufficiently";
+    else if (u.ualign.record >= -3)
+        pio = "strayed";
+    else if (u.ualign.record >= -8)
+        pio = "sinned";
+    else
+        pio = "transgressed";
+
+    Sprintf(buf, "%s", pio);
+    if (suffix && (!showneg || u.ualign.record >= 0)) {
+        if (u.ualign.record != 3)
+            Strcat(buf, " ");
+        Strcat(buf, suffix);
+    }
+    return buf;
+}
+
+/* stethoscope or probing applied to monster -- one-line feedback */
+void
+mstatusline(mtmp)
+struct monst *mtmp;
+{
+    aligntyp alignment = mon_aligntyp(mtmp);
+    char info[BUFSZ], monnambuf[BUFSZ];
+
+    info[0] = 0;
+    if (mtmp->mtame) {
+        Strcat(info, ", tame");
+        if (wizard) {
+            Sprintf(eos(info), " (%d", mtmp->mtame);
+            if (!mtmp->isminion)
+                Sprintf(eos(info), "; hungry %ld; apport %d",
+                        EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
+            Strcat(info, ")");
+        }
+    } else if (mtmp->mpeaceful)
+        Strcat(info, ", peaceful");
+
+    if (mtmp->data == &mons[PM_LONG_WORM]) {
+        int segndx, nsegs = count_wsegs(mtmp);
+
+        /* the worm code internals don't consider the head of be one of
+           the worm's segments, but we count it as such when presenting
+           worm feedback to the player */
+        if (!nsegs) {
+            Strcat(info, ", single segment");
+        } else {
+            ++nsegs; /* include head in the segment count */
+            segndx = wseg_at(mtmp, g.bhitpos.x, g.bhitpos.y);
+            Sprintf(eos(info), ", %d%s of %d segments",
+                    segndx, ordin(segndx), nsegs);
+        }
+    }
+    if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham])
+        /* don't reveal the innate form (chameleon, vampire, &c),
+           just expose the fact that this current form isn't it */
+        Strcat(info, ", shapechanger");
+    /* pets eating mimic corpses mimic while eating, so this comes first */
+    if (mtmp->meating)
+        Strcat(info, ", eating");
+    /* a stethoscope exposes mimic before getting here so this
+       won't be relevant for it, but wand of probing doesn't */
+    if (mtmp->mundetected || mtmp->m_ap_type)
+        mhidden_description(mtmp, TRUE, eos(info));
+    if (mtmp->mcan)
+        Strcat(info, ", cancelled");
+    if (mtmp->mconf)
+        Strcat(info, ", confused");
+    if (mtmp->mblinded || !mtmp->mcansee)
+        Strcat(info, ", blind");
+    if (mtmp->mstun)
+        Strcat(info, ", stunned");
+    if (mtmp->msleeping)
+        Strcat(info, ", asleep");
+#if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
+         (donning armor, for instance) as well as paralysis */
+    else if (mtmp->mfrozen)
+        Strcat(info, ", paralyzed");
+#else
+    else if (mtmp->mfrozen || !mtmp->mcanmove)
+        Strcat(info, ", can't move");
+#endif
+    /* [arbitrary reason why it isn't moving] */
+    else if ((mtmp->mstrategy & STRAT_WAITMASK) != 0)
+        Strcat(info, ", meditating");
+    if (mtmp->mflee)
+        Strcat(info, ", scared");
+    if (mtmp->mtrapped)
+        Strcat(info, ", trapped");
+    if (mtmp->mspeed)
+        Strcat(info, (mtmp->mspeed == MFAST) ? ", fast"
+                      : (mtmp->mspeed == MSLOW) ? ", slow"
+                         : ", [? speed]");
+    if (mtmp->minvis)
+        Strcat(info, ", invisible");
+    if (mtmp == u.ustuck)
+        Strcat(info, sticks(g.youmonst.data) ? ", held by you"
+                      : !u.uswallow ? ", holding you"
+                         : attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST)
+                            ? ", digesting you"
+                            : is_animal(u.ustuck->data) ? ", swallowing you"
+                               : ", engulfing you");
+    if (mtmp == u.usteed)
+        Strcat(info, ", carrying you");
+
+    /* avoid "Status of the invisible newt ..., invisible" */
+    /* and unlike a normal mon_nam, use "saddled" even if it has a name */
+    Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
+                               (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE));
+
+    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", monnambuf,
+          align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
+          find_mac(mtmp), info);
+}
+
+/* stethoscope or probing applied to hero -- one-line feedback */
+void
+ustatusline()
+{
+    char info[BUFSZ];
+
+    info[0] = '\0';
+    if (Sick) {
+        Strcat(info, ", dying from");
+        if (u.usick_type & SICK_VOMITABLE)
+            Strcat(info, " food poisoning");
+        if (u.usick_type & SICK_NONVOMITABLE) {
+            if (u.usick_type & SICK_VOMITABLE)
+                Strcat(info, " and");
+            Strcat(info, " illness");
+        }
+    }
+    if (Stoned)
+        Strcat(info, ", solidifying");
+    if (Slimed)
+        Strcat(info, ", becoming slimy");
+    if (Strangled)
+        Strcat(info, ", being strangled");
+    if (Vomiting)
+        Strcat(info, ", nauseated"); /* !"nauseous" */
+    if (Confusion)
+        Strcat(info, ", confused");
+    if (Blind) {
+        Strcat(info, ", blind");
+        if (u.ucreamed) {
+            if ((long) u.ucreamed < Blinded || Blindfolded
+                || !haseyes(g.youmonst.data))
+                Strcat(info, ", cover");
+            Strcat(info, "ed by sticky goop");
+        } /* note: "goop" == "glop"; variation is intentional */
+    }
+    if (Stunned)
+        Strcat(info, ", stunned");
+    if (!u.usteed && Wounded_legs) {
+        const char *what = body_part(LEG);
+        if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
+            what = makeplural(what);
+        Sprintf(eos(info), ", injured %s", what);
+    }
+    if (Glib)
+        Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
+    if (u.utrap)
+        Strcat(info, ", trapped");
+    if (Fast)
+        Strcat(info, Very_fast ? ", very fast" : ", fast");
+    if (u.uundetected)
+        Strcat(info, ", concealed");
+    if (Invis)
+        Strcat(info, ", invisible");
+    if (u.ustuck) {
+        if (sticks(g.youmonst.data))
+            Strcat(info, ", holding ");
+        else
+            Strcat(info, ", held by ");
+        Strcat(info, mon_nam(u.ustuck));
+    }
+
+    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", g.plname,
+          piousness(FALSE, align_str(u.ualign.type)),
+          Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
+          Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
+}
 
 /*insight.c*/
index ad17c0b8b00b1277b1eb3a78d08ae59857a69467..259597e7d447b6a6764bd917de693fd84b0b381f 100644 (file)
@@ -861,242 +861,4 @@ boolean ghostly;
     }
 }
 
-/*
- * align_str(), piousness(), mstatusline() and ustatusline() used to be
- * in pline.c, presumeably because the latter two generate one line of
- * output.  The USE_OLDARGS config gets warnings from 2016ish-vintage
- * gcc (for -Wint-to-pointer-cast, activated by -Wall or -W) when they
- * follow pline() itself.  Fixing up the variadic calls like is done for
- * lev_comp would be needlessly messy there.
- *
- * They don't belong here.  If/when enlightenment ever gets split off
- * from cmd.c (which definitely doesn't belong there), they should go
- * with it.
- */
-
-const char *
-align_str(alignment)
-aligntyp alignment;
-{
-    switch ((int) alignment) {
-    case A_CHAOTIC:
-        return "chaotic";
-    case A_NEUTRAL:
-        return "neutral";
-    case A_LAWFUL:
-        return "lawful";
-    case A_NONE:
-        return "unaligned";
-    }
-    return "unknown";
-}
-
-/* used for self-probing */
-char *
-piousness(showneg, suffix)
-boolean showneg;
-const char *suffix;
-{
-    static char buf[32]; /* bigger than "insufficiently neutral" */
-    const char *pio;
-
-    /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
-    if (u.ualign.record >= 20)
-        pio = "piously";
-    else if (u.ualign.record > 13)
-        pio = "devoutly";
-    else if (u.ualign.record > 8)
-        pio = "fervently";
-    else if (u.ualign.record > 3)
-        pio = "stridently";
-    else if (u.ualign.record == 3)
-        pio = "";
-    else if (u.ualign.record > 0)
-        pio = "haltingly";
-    else if (u.ualign.record == 0)
-        pio = "nominally";
-    else if (!showneg)
-        pio = "insufficiently";
-    else if (u.ualign.record >= -3)
-        pio = "strayed";
-    else if (u.ualign.record >= -8)
-        pio = "sinned";
-    else
-        pio = "transgressed";
-
-    Sprintf(buf, "%s", pio);
-    if (suffix && (!showneg || u.ualign.record >= 0)) {
-        if (u.ualign.record != 3)
-            Strcat(buf, " ");
-        Strcat(buf, suffix);
-    }
-    return buf;
-}
-
-/* stethoscope or probing applied to monster -- one-line feedback */
-void
-mstatusline(mtmp)
-struct monst *mtmp;
-{
-    aligntyp alignment = mon_aligntyp(mtmp);
-    char info[BUFSZ], monnambuf[BUFSZ];
-
-    info[0] = 0;
-    if (mtmp->mtame) {
-        Strcat(info, ", tame");
-        if (wizard) {
-            Sprintf(eos(info), " (%d", mtmp->mtame);
-            if (!mtmp->isminion)
-                Sprintf(eos(info), "; hungry %ld; apport %d",
-                        EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
-            Strcat(info, ")");
-        }
-    } else if (mtmp->mpeaceful)
-        Strcat(info, ", peaceful");
-
-    if (mtmp->data == &mons[PM_LONG_WORM]) {
-        int segndx, nsegs = count_wsegs(mtmp);
-
-        /* the worm code internals don't consider the head of be one of
-           the worm's segments, but we count it as such when presenting
-           worm feedback to the player */
-        if (!nsegs) {
-            Strcat(info, ", single segment");
-        } else {
-            ++nsegs; /* include head in the segment count */
-            segndx = wseg_at(mtmp, g.bhitpos.x, g.bhitpos.y);
-            Sprintf(eos(info), ", %d%s of %d segments",
-                    segndx, ordin(segndx), nsegs);
-        }
-    }
-    if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham])
-        /* don't reveal the innate form (chameleon, vampire, &c),
-           just expose the fact that this current form isn't it */
-        Strcat(info, ", shapechanger");
-    /* pets eating mimic corpses mimic while eating, so this comes first */
-    if (mtmp->meating)
-        Strcat(info, ", eating");
-    /* a stethoscope exposes mimic before getting here so this
-       won't be relevant for it, but wand of probing doesn't */
-    if (mtmp->mundetected || mtmp->m_ap_type)
-        mhidden_description(mtmp, TRUE, eos(info));
-    if (mtmp->mcan)
-        Strcat(info, ", cancelled");
-    if (mtmp->mconf)
-        Strcat(info, ", confused");
-    if (mtmp->mblinded || !mtmp->mcansee)
-        Strcat(info, ", blind");
-    if (mtmp->mstun)
-        Strcat(info, ", stunned");
-    if (mtmp->msleeping)
-        Strcat(info, ", asleep");
-#if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
-         (donning armor, for instance) as well as paralysis */
-    else if (mtmp->mfrozen)
-        Strcat(info, ", paralyzed");
-#else
-    else if (mtmp->mfrozen || !mtmp->mcanmove)
-        Strcat(info, ", can't move");
-#endif
-    /* [arbitrary reason why it isn't moving] */
-    else if (mtmp->mstrategy & STRAT_WAITMASK)
-        Strcat(info, ", meditating");
-    if (mtmp->mflee)
-        Strcat(info, ", scared");
-    if (mtmp->mtrapped)
-        Strcat(info, ", trapped");
-    if (mtmp->mspeed)
-        Strcat(info, (mtmp->mspeed == MFAST) ? ", fast"
-                      : (mtmp->mspeed == MSLOW) ? ", slow"
-                         : ", [? speed]");
-    if (mtmp->minvis)
-        Strcat(info, ", invisible");
-    if (mtmp == u.ustuck)
-        Strcat(info, sticks(g.youmonst.data) ? ", held by you"
-                      : !u.uswallow ? ", holding you"
-                         : attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST)
-                            ? ", digesting you"
-                            : is_animal(u.ustuck->data) ? ", swallowing you"
-                               : ", engulfing you");
-    if (mtmp == u.usteed)
-        Strcat(info, ", carrying you");
-
-    /* avoid "Status of the invisible newt ..., invisible" */
-    /* and unlike a normal mon_nam, use "saddled" even if it has a name */
-    Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
-                               (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE));
-
-    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", monnambuf,
-          align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
-          find_mac(mtmp), info);
-}
-
-/* stethoscope or probing applied to hero -- one-line feedback */
-void
-ustatusline()
-{
-    char info[BUFSZ];
-
-    info[0] = '\0';
-    if (Sick) {
-        Strcat(info, ", dying from");
-        if (u.usick_type & SICK_VOMITABLE)
-            Strcat(info, " food poisoning");
-        if (u.usick_type & SICK_NONVOMITABLE) {
-            if (u.usick_type & SICK_VOMITABLE)
-                Strcat(info, " and");
-            Strcat(info, " illness");
-        }
-    }
-    if (Stoned)
-        Strcat(info, ", solidifying");
-    if (Slimed)
-        Strcat(info, ", becoming slimy");
-    if (Strangled)
-        Strcat(info, ", being strangled");
-    if (Vomiting)
-        Strcat(info, ", nauseated"); /* !"nauseous" */
-    if (Confusion)
-        Strcat(info, ", confused");
-    if (Blind) {
-        Strcat(info, ", blind");
-        if (u.ucreamed) {
-            if ((long) u.ucreamed < Blinded || Blindfolded
-                || !haseyes(g.youmonst.data))
-                Strcat(info, ", cover");
-            Strcat(info, "ed by sticky goop");
-        } /* note: "goop" == "glop"; variation is intentional */
-    }
-    if (Stunned)
-        Strcat(info, ", stunned");
-    if (!u.usteed && Wounded_legs) {
-        const char *what = body_part(LEG);
-        if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
-            what = makeplural(what);
-        Sprintf(eos(info), ", injured %s", what);
-    }
-    if (Glib)
-        Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
-    if (u.utrap)
-        Strcat(info, ", trapped");
-    if (Fast)
-        Strcat(info, Very_fast ? ", very fast" : ", fast");
-    if (u.uundetected)
-        Strcat(info, ", concealed");
-    if (Invis)
-        Strcat(info, ", invisible");
-    if (u.ustuck) {
-        if (sticks(g.youmonst.data))
-            Strcat(info, ", holding ");
-        else
-            Strcat(info, ", held by ");
-        Strcat(info, mon_nam(u.ustuck));
-    }
-
-    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", g.plname,
-          piousness(FALSE, align_str(u.ualign.type)),
-          Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
-          Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
-}
-
 /*priest.c*/