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 ""
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
.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
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));
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));
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 *));
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,
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 ### */
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
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 *));
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;
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();
#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;
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:
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",
/* 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]
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;
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);
'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;
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];
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++)
return u.dx || u.dy;
}
-/* decide whether a character (user input keystroke) requests screen repaint */
+/* decide whether character (user input keystroke) requests screen repaint */
boolean
redraw_cmd(c)
char c;
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);
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;
|| (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 */
}
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;
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));
}
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')
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)
/* 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*/
}
}
-/*
- * 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*/