diff --git a/dat/history b/dat/history index c6ff13b31..b201c094d 100644 --- a/dat/history +++ b/dat/history @@ -215,10 +215,12 @@ necessary updates to the community at large. The official NetHack web site is maintained by Ken Lorber at http://www.nethack.org/. -On behalf of the NetHack community, thank you very much once again to -M. Drew Streib, Pasi Kallinen and Robin Bandy for providing public -NetHack servers at nethack.alt.org and devnull.net and/or for hosting annual -NetHack tournaments. +On behalf of the NetHack community, thank you very much once again to +M. Drew Streib and Pasi Kallinen for providing a public NetHack server +at nethack.alt.org. Thanks to Keith Simpson and Andy Thomson for +hardfought.org. Thanks to all those unnamed dungeoneers who invest their +time and effort into annual NetHack tournaments such as Junehack +and in days past, devnull.net (gone for now, but not forgotten). - - - - - - - - - - diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e1c67b7fa..1b669c79f 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4593,7 +4593,7 @@ The official NetHack web site is maintained by \fBKen Lorber\fP at http://www.ne SPECIAL THANKS .pg On behalf of the NetHack community, thank you very much once -again to \fBM. Drew Streib\fP, \fBPasi Kallinen\fP for providing a +again to \fBM. Drew Streib\fP and \fBPasi Kallinen\fP for providing a public NetHack server at nethack.alt.org. Thanks to \fBKeith Simpson\fP and \fBAndy Thomson\fP for hardfought.org. Thanks to all those unnamed dungeoneers who invest their time and effort into annual diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index a89c13b07..f12b651a6 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -5377,7 +5377,7 @@ http:{\tt /}{\tt /}www.nethack.org{\tt /}. \subsection*{Special Thanks} \nd On behalf of the {\it NetHack\/} community, thank you very much once -again to {\it M. Drew Streib}, {\it Pasi Kallinen} for providing a +again to {\it M. Drew Streib} and {\it Pasi Kallinen} for providing a public NetHack server at nethack.alt.org. Thanks to {\it Keith Simpson} and {\it Andy Thomson} for hardfought.org. Thanks to all those unnamed dungeoneers who invest their time and effort into annual diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 443dfec50..67f487211 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -128,6 +128,30 @@ cancelled shapeshifter hit by polymorph magic will become uncancelled polymorph zap which creates a new long worm (or retains an old one via wizard mode monpolycontrol) can hit that worm multiple times (tail segments) wishing for "orange" could yield orange or orange colored gem/potion/spellbook +a sleeping or paralyzed mon would be frightened by its reflection when + applying a mirror +prevent leash showing unseen monster as "attached to it" +gremlins seemed impervious to Sunsword's light yet a flash from a camera + caused them to cry out in pain +when objects migrate (fall down stairs) and invisible hero (w/o see invisible, + no-autopickup) descends, stairs get shown instead of object(s) on them +drum of earthquake was causing deafness but oddly enough only when used up +known bear trap was being forgotten about by a player polymorphed into a + flying monster if the player unsuccessfully tried to #untrap it and + moved onto the trap square as a result +no leash-related message is given when a leashed pet yellow light explodes +shop messages refer to shk by name even when shk is not visible but some + used pronoun "it" or "its" in same sentence; ditto for vault guards +poly'd hero and monsters could eat through iron bars in areas where walls + were flagged as non-diggable +Samurai seeing items at a distance could have them be described by their + ordinary names rather than by their Japanese names +wizard mode ^T shouldn't have been diminishing player power but it was + and hilite_status:power settings really drew attention to that +fix missing space in "would flyif you weren't levitating" +a wand of polymorph lost its magical ability for the turn just because the + player using it to engrave happened to be blind, which didn't make + a much sense Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -136,11 +160,16 @@ fix access violation when --debug:xxxx has no other args after it setting the inverse attribute for gold had the space before "$:" getting highlighted along with the gold field sortloot segfaulted when filtering a subset of items (seen with 'A' command) +orctown: prevent Bad fruit #0 and some minor tuning +make long extended commands list be more navigable +simplify #wizidentify; don't rely on having bold menu entries tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status values so that comparisons are correct -orctown: prevent Bad fruit #0 and some minor tuning +tty: fix an out of bounds error in tty_status_update() for BL_HUNGER case +X11: its use of genl_status_update exposed a negative index use that could + lead to a segfault Platform- and/or Interface-Specific Fixes diff --git a/doc/window.doc b/doc/window.doc index a7141d448..a564d5b7b 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -776,6 +776,20 @@ to support: | hitpointbar | WC2_HITPOINTBAR | wc2_hitpointbar |boolean | +--------------------+--------------------+--------------------+--------+ + more wincap2 for STATUS_HILITES support and control + +--------------------------------- +---------------------------+ + | To inform the game engine | | + | that the window port is equipped | bit to set in wincap mask | + | to receive the following in its | | + | x_status_update() routine | | + |----------------------------------+---------------------------+ + | BL_FLUSH to render buffered | WC2_FLUSH_STATUS | + | field changes now | | + |----------------------------------+---------------------------+ + | BL_RESET to indicate that all | WC2_RESET_STATUS | + | fields should be redone | | + +----------------------------------+---------------------------+ + align_message -- where to place message window (top, bottom, left, right) align_status -- where to place status display (top, bottom, left, right). ascii_map -- port should display an ascii map if it can. diff --git a/include/extern.h b/include/extern.h index 7e1fb1270..345442345 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1438,6 +1438,7 @@ FDECL(can_blnd, (struct monst *, struct monst *, UCHAR_P, struct obj *)); E boolean FDECL(ranged_attk, (struct permonst *)); E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(mon_hates_silver, (struct monst *)); +E boolean FDECL(mon_hates_light, (struct monst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_blow, (struct monst *)); E boolean FDECL(can_chant, (struct monst *)); @@ -1457,7 +1458,7 @@ E int FDECL(monsndx, (struct permonst *)); E int FDECL(name_to_mon, (const char *)); E int FDECL(name_to_monclass, (const char *, int *)); E int FDECL(gender, (struct monst *)); -E int FDECL(pronoun_gender, (struct monst *)); +E int FDECL(pronoun_gender, (struct monst *, BOOLEAN_P)); E boolean FDECL(levl_follower, (struct monst *)); E int FDECL(little_to_big, (int)); E int FDECL(big_to_little, (int)); @@ -2358,7 +2359,8 @@ E boolean FDECL(safe_teleds, (BOOLEAN_P)); E boolean FDECL(teleport_pet, (struct monst *, BOOLEAN_P)); E void NDECL(tele); E boolean FDECL(scrolltele, (struct obj *)); -E int NDECL(dotele); +E int NDECL(dotelecmd); +E int FDECL(dotele, (BOOLEAN_P)); E void NDECL(level_tele); E void FDECL(domagicportal, (struct trap *)); E void FDECL(tele_trap, (struct trap *)); diff --git a/include/mondata.h b/include/mondata.h index 95153ce5d..0b1df5ccc 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -175,6 +175,8 @@ #define is_vampire(ptr) ((ptr)->mlet == S_VAMPIRE) +#define hates_light(ptr) ((ptr) == &mons[PM_GREMLIN]) + /* used to vary a few messages */ #define weirdnonliving(ptr) (is_golem(ptr) || (ptr)->mlet == S_VORTEX) #define nonliving(ptr) \ diff --git a/include/rm.h b/include/rm.h index 9d80551db..7fd41c47c 100644 --- a/include/rm.h +++ b/include/rm.h @@ -381,7 +381,7 @@ extern struct symsetentry symset[NUM_GRAPHICS]; /* from drawing.c */ #define DB_UNDER 28 /* mask for underneath */ /* - * Wall information. + * Wall information. Nondiggable also applies to iron bars. */ #define WM_MASK 0x07 /* wall mode (bottom three bits) */ #define W_NONDIGGABLE 0x08 diff --git a/include/winprocs.h b/include/winprocs.h index 3c19d4f03..a0c490f11 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -214,7 +214,9 @@ extern #define WC2_HITPOINTBAR 0x0040L /* 07 show bar representing hit points */ #define WC2_FLUSH_STATUS 0x0080L /* 08 call status_update(BL_FLUSH) after updating status window fields */ - /* 24 free bits */ +#define WC2_RESET_STATUS 0x0100L /* 09 call status_update(BL_RESET) to indicate + draw everything */ + /* 23 free bits */ #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 diff --git a/include/you.h b/include/you.h index 15fb5f9b3..461b9656f 100644 --- a/include/you.h +++ b/include/you.h @@ -236,12 +236,18 @@ struct Gender { increment to 3 if you allow neuter roles */ extern const struct Gender genders[]; /* table of available genders */ +/* pronouns for the hero */ #define uhe() (genders[flags.female ? 1 : 0].he) #define uhim() (genders[flags.female ? 1 : 0].him) #define uhis() (genders[flags.female ? 1 : 0].his) -#define mhe(mtmp) (genders[pronoun_gender(mtmp)].he) -#define mhim(mtmp) (genders[pronoun_gender(mtmp)].him) -#define mhis(mtmp) (genders[pronoun_gender(mtmp)].his) +/* corresponding pronouns for monsters; yields "it" when mtmp can't be seen */ +#define mhe(mtmp) (genders[pronoun_gender(mtmp, FALSE)].he) +#define mhim(mtmp) (genders[pronoun_gender(mtmp, FALSE)].him) +#define mhis(mtmp) (genders[pronoun_gender(mtmp, FALSE)].his) +/* override "it" if reason is lack of visibility rather than neuter species */ +#define noit_mhe(mtmp) (genders[pronoun_gender(mtmp, TRUE)].he) +#define noit_mhim(mtmp) (genders[pronoun_gender(mtmp, TRUE)].him) +#define noit_mhis(mtmp) (genders[pronoun_gender(mtmp, TRUE)].his) /*** Unified structure specifying alignment information ***/ struct Align { diff --git a/src/apply.c b/src/apply.c index 07269a358..0fa842636 100644 --- a/src/apply.c +++ b/src/apply.c @@ -215,12 +215,9 @@ int rx, ry, *resp; /* (most corpses don't retain the monster's sex, so we're usually forced to use generic pronoun here) */ if (mtmp) { - mptr = &mons[mtmp->mnum]; - /* can't use mhe() here; it calls pronoun_gender() which - expects monster to be on the map (visibility check) */ - if ((humanoid(mptr) || (mptr->geno & G_UNIQ) - || type_is_pname(mptr)) && !is_neuter(mptr)) - gndr = (int) mtmp->female; + mptr = mtmp->data = &mons[mtmp->mnum]; + /* TRUE: override visibility check--it's not on the map */ + gndr = pronoun_gender(mtmp, TRUE); } else { mptr = &mons[corpse->corpsenm]; if (is_female(mptr)) @@ -956,9 +953,20 @@ struct obj *obj; (void) rloc(mtmp, TRUE); } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) { - if (vis) - pline("%s is frightened by its reflection.", Monnam(mtmp)); - monflee(mtmp, d(2, 4), FALSE, FALSE); + boolean do_react = TRUE; + + if (mtmp->mfrozen) { + if (vis) + You("discern no obvious reaction from %s.", mon_nam(mtmp)); + else + You_feel("a bit silly gesturing the mirror in that direction."); + do_react = FALSE; + } + if (do_react) { + if (vis) + pline("%s is frightened by its reflection.", Monnam(mtmp)); + monflee(mtmp, d(2, 4), FALSE, FALSE); + } } else if (!Blind) { if (mtmp->minvis && !See_invisible) ; diff --git a/src/botl.c b/src/botl.c index 8ffe73c5e..721ad2316 100644 --- a/src/botl.c +++ b/src/botl.c @@ -810,7 +810,8 @@ boolean *valsetlist; * the display, call status_update() with BL_FLUSH. * */ - if (context.botlx) + if (context.botlx && + (windowprocs.wincap2 & WC2_RESET_STATUS) != 0L) status_update(BL_RESET, (genericptr_t) 0, 0, 0, NO_COLOR, &cond_hilites[0]); else if ((windowprocs.wincap2 & WC2_FLUSH_STATUS) != 0L) diff --git a/src/cmd.c b/src/cmd.c index b5c6ee1a2..f9bed807f 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -116,7 +116,7 @@ extern int NDECL(dosit); /**/ extern int NDECL(dotalk); /**/ extern int NDECL(docast); /**/ extern int NDECL(dovspell); /**/ -extern int NDECL(dotele); /**/ +extern int NDECL(dotelecmd); /**/ extern int NDECL(dountrap); /**/ extern int NDECL(doversion); /**/ extern int NDECL(doextversion); /**/ @@ -361,39 +361,158 @@ doextcmd(VOID_ARGS) return retval; } -/* here after #? - now list all full-word commands */ +/* here after #? - now list all full-word commands and provid + some navigation capability through the long list */ int doextlist(VOID_ARGS) { register const struct ext_func_tab *efp; - char buf[BUFSZ]; - winid datawin; - char ch = cmd_from_func(doextcmd); + char buf[BUFSZ], searchbuf[BUFSZ], promptbuf[QBUFSZ]; + winid menuwin; + anything any; + menu_item *selected; + int n, pass; + int menumode = 0, menushown[2], onelist = 0; + boolean redisplay = TRUE, search = FALSE; + static const char *headings[] = { "Extended commands", + "Debugging Extended Commands" }; - datawin = create_nhwindow(NHW_TEXT); - putstr(datawin, 0, ""); - putstr(datawin, 0, " Extended Commands List"); - putstr(datawin, 0, ""); - if (ch) { - Sprintf(buf, " Press '%s', then type:", - visctrl(ch)); - putstr(datawin, 0, buf); - putstr(datawin, 0, ""); - } + searchbuf[0] = '\0'; + menuwin = create_nhwindow(NHW_MENU); - for (efp = extcmdlist; efp->ef_txt; efp++) { - if (!wizard && (efp->flags & WIZMODECMD)) - continue; - Sprintf(buf, " %-15s %c %s.", - efp->ef_txt, - (efp->flags & AUTOCOMPLETE) ? '*' : ' ', - efp->ef_desc); - putstr(datawin, 0, buf); + while (redisplay) { + redisplay = FALSE; + any = zeroany; + start_menu(menuwin); + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "Extended Commands List", MENU_UNSELECTED); + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "", MENU_UNSELECTED); + + Strcpy(buf, menumode ? "Show" : "Hide"); + Strcat(buf, " commands that don't autocomplete"); + if (!menumode) + Strcat(buf, " (those not marked with [A])"); + any.a_int = 1; + add_menu(menuwin, NO_GLYPH, &any, 'a', 0, ATR_NONE, buf, + MENU_UNSELECTED); + + if (!*searchbuf) { + any.a_int = 2; + add_menu(menuwin, NO_GLYPH, &any, 's', 0, ATR_NONE, + "Search extended commands", MENU_UNSELECTED); + } else { + Strcpy(buf, "Show all, clear search"); + if (strlen(buf) + strlen(searchbuf) + strlen(" (\"\")") < QBUFSZ) + Sprintf(eos(buf), " (\"%s\")", searchbuf); + any.a_int = 3; + add_menu(menuwin, NO_GLYPH, &any, 's', 0, ATR_NONE, + buf, MENU_UNSELECTED); + } + if (wizard) { + 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", + MENU_UNSELECTED); + } + any = zeroany; + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "", MENU_UNSELECTED); + menushown[0] = menushown[1] = 0; + n = 0; + for (pass = 0; pass <= 1; ++pass) { + /* skip second pass if not in wizard mode or wizard mode + commands are being integrated into a single list */ + if (pass == 1 && (onelist || !wizard)) + break; + for (efp = extcmdlist; efp->ef_txt; efp++) { + int wizc; + + /* if hiding non-autocomplete commands, skip such */ + if (menumode == 1 && (efp->flags & AUTOCOMPLETE) == 0) + continue; + /* if searching, skip this command if it doesn't match */ + if (*searchbuf + && !strstri(efp->ef_txt, searchbuf) + && !strstri(efp->ef_desc, searchbuf)) + continue; + /* skip wizard mode commands if not in wizard mode; + when showing two sections, skip wizard mode commands + in pass==0 and skip other commands in pass==1 */ + wizc = (efp->flags & WIZMODECMD) != 0; + if (wizc && !wizard) + continue; + if (!onelist && pass != wizc) + continue; + + /* We're about to show an item, have we shown the menu yet? + Doing menu in inner loop like this on demand avoids a + heading with no subordinate entries on the search + results menu. */ + if (!menushown[pass]) { + Strcpy(buf, headings[pass]); + add_menu(menuwin, NO_GLYPH, &any, 0, 0, + iflags.menu_headings, buf, MENU_UNSELECTED); + menushown[pass] = 1; + } + Sprintf(buf, " %-14s %-3s %s", + efp->ef_txt, + (efp->flags & AUTOCOMPLETE) ? "[A]" : " ", + efp->ef_desc); + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + buf, MENU_UNSELECTED); + ++n; + } + if (n) + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "", MENU_UNSELECTED); + } + if (*searchbuf && !n) + add_menu(menuwin, NO_GLYPH, &any, 0, 0, ATR_NONE, + "no matches", MENU_UNSELECTED); + + end_menu(menuwin, (char *) 0); + n = select_menu(menuwin, PICK_ONE, &selected); + if (n > 0) { + switch (selected[0].item.a_int) { + case 1: /* 'a': toggle show/hide non-autocomplete */ + menumode = 1 - menumode; /* toggle 0 -> 1, 1 -> 0 */ + redisplay = TRUE; + break; + case 2: /* 's' when not searching yet: enable search */ + search = TRUE; + break; + case 3: /* 's' when already searching: disable search */ + search = FALSE; + searchbuf[0] = '\0'; + redisplay = TRUE; + break; + case 4: /* 'z': toggle showing wizard mode commands separately */ + search = FALSE; + searchbuf[0] = '\0'; + onelist = 1 - onelist; /* toggle 0 -> 1, 1 -> 0 */ + redisplay = TRUE; + break; + } + free((genericptr_t) selected); + } else { + search = FALSE; + searchbuf[0] = '\0'; + } + if (search) { + Strcpy(promptbuf, "Extended command list search phrase"); + Strcat(promptbuf, "?"); + getlin(promptbuf, searchbuf); + (void) mungspaces(searchbuf); + if (searchbuf[0] == '\033') + searchbuf[0] = '\0'; + if (*searchbuf) + redisplay = TRUE; + search = FALSE; + } } - putstr(datawin, 0, ""); - putstr(datawin, 0, " Commands marked with a * will be autocompleted."); - display_nhwindow(datawin, FALSE); - destroy_nhwindow(datawin); + destroy_nhwindow(menuwin); return 0; } @@ -644,14 +763,11 @@ wiz_identify(VOID_ARGS) /* command remapping might leave #wizidentify as the only way to invoke us, in which case cmd_from_func() will yield NUL; it won't matter to display_inventory()/display_pickinv() - if ^I invokes some other command--what matters is that it - is never an inventory letter */ + if ^I invokes some other command--what matters is that + display_pickinv() and xname() see override_ID as nonzero */ if (!iflags.override_ID) iflags.override_ID = C('I'); - /* C('I') == ^I == default keystroke for wiz_identify; - it doesn't matter whether the command has been remapped */ - if (display_inventory((char *) 0, TRUE) == C('I')) - identify_pack(0, FALSE); + (void) display_inventory((char *) 0, FALSE); iflags.override_ID = 0; } else pline("Unavailable command '%s'.", @@ -2352,7 +2468,7 @@ int final; if (Flying) enl_msg(You_, "would fly", "would have flown", Levitation - ? "if you weren't levitating" + ? " if you weren't levitating" : (save_BFly == FROMOUTSIDE) ? if_surroundings_permitted /* both surroundings and [latent] levitation */ @@ -3017,7 +3133,7 @@ struct ext_func_tab extcmdlist[] = { { 'x', "swap", "swap wielded and secondary weapons", doswapweapon }, { 'T', "takeoff", "take off one piece of armor", dotakeoff }, { 'A', "takeoffall", "remove all armor", doddoremarm }, - { C('t'), "teleport", "teleport around the level", dotele, IFBURIED }, + { C('t'), "teleport", "teleport around the level", dotelecmd, IFBURIED }, { '\0', "terrain", "show map without obstructions", doterrain, IFBURIED | AUTOCOMPLETE }, { '\0', "therecmdmenu", diff --git a/src/dig.c b/src/dig.c index 0a1669813..a89b354be 100644 --- a/src/dig.c +++ b/src/dig.c @@ -2086,7 +2086,7 @@ escape_tomb() if ((Teleportation || can_teleport(youmonst.data)) && (Teleport_control || rn2(3) < Luck+2)) { You("attempt a teleport spell."); - (void) dotele(); /* calls unearth_you() */ + (void) dotele(FALSE); /* calls unearth_you() */ } else if (u.uburied) { /* still buried after 'port attempt */ boolean good; diff --git a/src/dokick.c b/src/dokick.c index 4a4ac6b93..99858a62f 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1658,6 +1658,8 @@ boolean near_hero; stackobj(otmp); if (!noscatter) (void) scatter(nx, ny, rnd(2), 0, otmp); + else + newsym(nx, ny); } else { /* random location */ /* set dummy coordinates because there's no current position for rloco() to update */ diff --git a/src/dothrow.c b/src/dothrow.c index 00978165f..5a559ae4e 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -664,12 +664,8 @@ int x, y; mon->mundetected = 0; /* wakeup() will handle mimic */ mnam = a_monnam(mon); /* after unhiding */ - pronoun = mhim(mon); + pronoun = noit_mhim(mon); if (!strcmp(mnam, "it")) { - /* mhim() uses pronoun_gender() which forces neuter if monster - can't be seen; we want him/her for humanoid sensed by touch */ - if (!strcmp(pronoun, "it") && humanoid(mon->data)) - pronoun = genders[mon->female].him; mnam = !strcmp(pronoun, "it") ? "something" : "someone"; } if (!glyph_is_monster(glyph) && !glyph_is_invisible(glyph)) diff --git a/src/engrave.c b/src/engrave.c index 48dc2bd40..abd531abf 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -7,6 +7,7 @@ #include "lev.h" STATIC_VAR NEARDATA struct engr *head_engr; +STATIC_DCL const char *NDECL(blengr); char * random_engraving(outbuf) @@ -472,6 +473,7 @@ doengrave() boolean teleengr = FALSE; /* TRUE if we move the old engraving */ boolean zapwand = FALSE; /* TRUE if we remove a wand charge */ xchar type = DUST; /* Type of engraving made */ + xchar oetype = 0; /* will be set to type of current engraving */ char buf[BUFSZ]; /* Buffer for final/poly engraving text */ char ebuf[BUFSZ]; /* Buffer for initial engraving text */ char fbuf[BUFSZ]; /* Buffer for "your fingers" */ @@ -494,6 +496,8 @@ doengrave() ebuf[0] = (char) 0; post_engr_text[0] = (char) 0; maxelen = BUFSZ - 1; + if (oep) + oetype = oep->engr_type; if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE) type = ENGR_BLOOD; @@ -676,9 +680,17 @@ doengrave() if (!Blind) { type = (xchar) 0; /* random */ (void) random_engraving(buf); + } else { + /* keep the same type so that feels don't + change and only the text is altered, + but you won't know anyway because + you're a _blind writer_ */ + if (oetype) + type = oetype; + xcrypt(blengr(), buf); } dengr = TRUE; - } + } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: @@ -890,7 +902,8 @@ doengrave() /* Something has changed the engraving here */ if (*buf) { make_engr_at(u.ux, u.uy, buf, moves, type); - pline_The("engraving now reads: \"%s\".", buf); + if (!Blind) + pline_The("engraving now reads: \"%s\".", buf); ptext = FALSE; } if (zapwand && (otmp->spe < 0)) { @@ -1286,4 +1299,31 @@ const char *str; return; } +static const char blind_writing[][21] = { + {0x44, 0x66, 0x6d, 0x69, 0x62, 0x65, 0x22, 0x45, 0x7b, 0x71, + 0x65, 0x6d, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + {0x51, 0x67, 0x60, 0x7a, 0x7f, 0x21, 0x40, 0x71, 0x6b, 0x71, + 0x6f, 0x67, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x49, 0x6d, 0x73, 0x69, 0x62, 0x65, 0x22, 0x4c, 0x61, 0x7c, + 0x6d, 0x67, 0x24, 0x42, 0x7f, 0x69, 0x6c, 0x77, 0x67, 0x7e, 0x00}, + {0x4b, 0x6d, 0x6c, 0x66, 0x30, 0x4c, 0x6b, 0x68, 0x7c, 0x7f, + 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x51, 0x67, 0x70, 0x7a, 0x7f, 0x6f, 0x67, 0x68, 0x64, 0x71, + 0x21, 0x4f, 0x6b, 0x6d, 0x7e, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x4c, 0x63, 0x76, 0x61, 0x71, 0x21, 0x48, 0x6b, 0x7b, 0x75, + 0x67, 0x63, 0x24, 0x45, 0x65, 0x6b, 0x6b, 0x65, 0x00, 0x00, 0x00}, + {0x4c, 0x67, 0x68, 0x6b, 0x78, 0x68, 0x6d, 0x76, 0x7a, 0x75, + 0x21, 0x4f, 0x71, 0x7a, 0x75, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00}, + {0x44, 0x66, 0x6d, 0x7c, 0x78, 0x21, 0x50, 0x65, 0x66, 0x65, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0x44, 0x66, 0x73, 0x69, 0x62, 0x65, 0x22, 0x56, 0x7d, 0x63, + 0x69, 0x76, 0x6b, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +}; + +STATIC_OVL const char * +blengr(VOID_ARGS) +{ + return blind_writing[rn2(SIZE(blind_writing))]; +} + /*engrave.c*/ diff --git a/src/explode.c b/src/explode.c index c48f9ffb1..fc2855c1d 100644 --- a/src/explode.c +++ b/src/explode.c @@ -657,6 +657,7 @@ struct obj *obj; /* only scatter this obj */ (void) break_statue(otmp); place_object(otmp, sx, sy); /* put fragments on floor */ } + newsym(sx, sy); /* in case it's beyond radius of 'farthest' */ used_up = TRUE; /* 1 in 10 chance of destruction of obj; glass, egg destruction */ diff --git a/src/hack.c b/src/hack.c index 70671b45f..fabd7e17f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -364,8 +364,8 @@ moverock() /* * still_chewing() * - * Chew on a wall, door, or boulder. Returns TRUE if still eating, FALSE - * when done. + * Chew on a wall, door, or boulder. [What about statues?] + * Returns TRUE if still eating, FALSE when done. */ STATIC_OVL int still_chewing(x, y) @@ -379,7 +379,10 @@ xchar x, y; (void) memset((genericptr_t) &context.digging, 0, sizeof (struct dig_info)); - if (!boulder && IS_ROCK(lev->typ) && !may_dig(x, y)) { + if (!boulder + && ((IS_ROCK(lev->typ) && !may_dig(x, y)) + /* may_dig() checks W_NONDIGGABLE but doesn't handle iron bars */ + || (lev->typ == IRONBARS && (lev->wall_info & W_NONDIGGABLE)))) { You("hurt your teeth on the %s.", (lev->typ == IRONBARS) ? "bars" diff --git a/src/invent.c b/src/invent.c index 4262a5153..84e6367df 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2593,24 +2593,27 @@ long *out_cnt; char prompt[QBUFSZ]; unid_cnt = count_unidentified(invent); - add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Debug Identify", - MENU_UNSELECTED); + Sprintf(prompt, "Debug Identify"); /* 'title' rather than 'prompt' */ + if (unid_cnt) + Sprintf(eos(prompt), + " -- unidentified or partially identified item%s", + plur(unid_cnt)); + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED); if (!unid_cnt) { add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "(all items are permanently identified already)", MENU_UNSELECTED); } else { any.a_obj = &wizid_fakeobj; + Sprintf(prompt, "select %s to permanently identify", + (unid_cnt == 1) ? "it": "any or all of them"); /* wiz_identify stuffed the wiz_identify command character (^I) into iflags.override_ID for our use as an accelerator; - it could be ambiguous as a selector but the only time it - is wanted is in case where no item is being selected */ - Sprintf(prompt, - "Select %sthe %d bolded item%s to permanently identify (%s for all)", - (unid_cnt == 1) ? "": "any of ", unid_cnt, - (unid_cnt > 1) ? "s" : "", - visctrl(iflags.override_ID)); + it could be ambiguous if player has assigned a letter to + the #wizidentify command */ + if (unid_cnt > 1) + Sprintf(eos(prompt), " (%s for all)", + visctrl(iflags.override_ID)); add_menu(win, NO_GLYPH, &any, '_', iflags.override_ID, ATR_NONE, prompt, MENU_UNSELECTED); wizid = TRUE; @@ -2630,6 +2633,8 @@ nextclass: if (lets && !index(lets, otmp->invlet)) continue; if (!flags.sortpack || otmp->oclass == *invlet) { + if (wizid && !not_fully_identified(otmp)) + continue; any = zeroany; /* all bits zero */ ilet = otmp->invlet; if (flags.sortpack && !classcount) { @@ -2643,9 +2648,7 @@ nextclass: any.a_obj = otmp; else any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, - (wizid && not_fully_identified(otmp)) ? - ATR_BOLD : ATR_NONE, + add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } @@ -2678,21 +2681,18 @@ nextclass: } end_menu(win, query && *query ? query : (char *) 0); - n = select_menu(win, wizid ? PICK_ANY : - want_reply ? PICK_ONE : PICK_NONE, &selected); + n = select_menu(win, + wizid ? PICK_ANY : want_reply ? PICK_ONE : PICK_NONE, + &selected); if (n > 0) { if (wizid) { - int i = n; + int i; ret = '\0'; - while (--i >= 0) { + for (i = 0; i < n; ++i) { otmp = selected[i].item.a_obj; if (otmp == &wizid_fakeobj) { - /* C('I') == ^I == default keystroke for wiz_identify; - it is guaranteed not to be in use as an inventory letter - (wiz_identify might be remapped to an ordinary letter, - making iflags.override_ID ambiguous as a return value) */ - ret = C('I'); + identify_pack(0, FALSE); } else { if (not_fully_identified(otmp)) (void) identify(otmp); diff --git a/src/mhitm.c b/src/mhitm.c index 95413843c..dfff12b26 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -47,9 +47,10 @@ mon_nam_too(outbuf, mon, other_mon) char *outbuf; struct monst *mon, *other_mon; { - Strcpy(outbuf, mon_nam(mon)); - if (mon == other_mon) - switch (pronoun_gender(mon)) { + if (mon != other_mon) + Strcpy(outbuf, mon_nam(mon)); + else + switch (pronoun_gender(mon, FALSE)) { case 0: Strcpy(outbuf, "himself"); break; @@ -781,10 +782,17 @@ struct attack *mattk; /* Kill off aggressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { + boolean was_leashed = (magr->mleashed); + mondead(magr); if (!DEADMONSTER(magr)) return result; /* life saved */ result |= MM_AGR_DIED; + + /* mondead() -> m_detach() -> m_unleash() always suppresses + the m_unleash() slack message, so deliver it here instead */ + if (was_leashed) + Your("leash falls slack."); } if (magr->mtame) /* give this one even if it was visible */ You(brief_feeling, "melancholy"); diff --git a/src/mhitu.c b/src/mhitu.c index 97229ba60..7ae3ff103 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -2613,7 +2613,7 @@ struct monst *mon; ; } else if (rn2(20) < ACURR(A_CHA)) { pline("%s demands that you pay %s, but you refuse...", - noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon)); + noit_Monnam(mon), noit_mhim(mon)); } else if (u.umonnum == PM_LEPRECHAUN) { pline("%s tries to take your money, but fails...", noit_Monnam(mon)); } else { diff --git a/src/mon.c b/src/mon.c index 9cdf9b6d9..72f3df1a6 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1320,7 +1320,11 @@ nexttry: /* eels prefer the water, but if there is no water nearby, && !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx, ny))) continue; /* KMH -- Added iron bars */ - if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) + if (ntyp == IRONBARS + && (!(flag & ALLOW_BARS) + || ((levl[nx][ny].wall_info & W_NONDIGGABLE) + && (dmgtype(mdat, AD_RUST) + || dmgtype(mdat, AD_CORR))))) continue; if (IS_DOOR(ntyp) && !(amorphous(mdat) || can_fog(mon)) && (((levl[nx][ny].doormask & D_CLOSED) && !(flag & OPENDOOR)) diff --git a/src/mondata.c b/src/mondata.c index 2a6134863..ffffb9e85 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -312,6 +312,14 @@ register struct permonst *ptr; || (ptr->mlet == S_IMP && ptr != &mons[PM_TENGU])); } +/* True if specific monster is especially affected by light-emitting weapons */ +boolean +mon_hates_light(mon) +struct monst *mon; +{ + return (boolean) (hates_light(mon->data)); +} + /* True iff the type of monster pass through iron bars */ boolean passes_bars(mptr) @@ -892,10 +900,13 @@ register struct monst *mtmp; /* Like gender(), but lower animals and such are still "it". This is the one we want to use when printing messages. */ int -pronoun_gender(mtmp) +pronoun_gender(mtmp, override_vis) register struct monst *mtmp; +boolean override_vis; /* if True then 'no it' unless neuter */ { - if (is_neuter(mtmp->data) || !canspotmon(mtmp)) + if (!override_vis && !canspotmon(mtmp)) + return 2; + if (is_neuter(mtmp->data)) return 2; return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) || type_is_pname(mtmp->data)) ? (int) mtmp->female : 2; diff --git a/src/monmove.c b/src/monmove.c index 90b4f33c1..fc32ebfb8 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -255,6 +255,14 @@ struct monst *mon; } } +#define flees_light(mon) ((mon)->data == &mons[PM_GREMLIN] && \ + (uwep && artifact_light(uwep) && uwep->lamplit)) + +/* we could include this in the above macro, but probably overkill/overhead */ +/* (!((which_armor((mon), W_ARMC) != 0) && ((which_armor((mon), W_ARMH) != 0))) && */ + + + /* monster begins fleeing for the specified time, 0 means untimed flee * if first, only adds fleetime if monster isn't already fleeing * if fleemsg, prints a message about new flight, otherwise, caller should */ @@ -289,9 +297,15 @@ boolean fleemsg; /* unfortunately we can't distinguish between temporary sleep and temporary paralysis, so both conditions receive the same alternate message */ - if (!mtmp->mcanmove || !mtmp->data->mmove) + if (!mtmp->mcanmove || !mtmp->data->mmove) { pline("%s seems to flinch.", Adjmonnam(mtmp, "immobile")); - else + } else if (flees_light(mtmp)) { + if (rn2(10) || Deaf) + pline("%s flees from the painful light of %s.", + Monnam(mtmp), bare_artifactname(uwep)); + else + verbalize("Bright light!"); + } else pline("%s turns to flee.", Monnam(mtmp)); } mtmp->mflee = 1; @@ -306,7 +320,7 @@ register struct monst *mtmp; int *inrange, *nearby, *scared; { int seescaryx, seescaryy; - boolean sawscary = FALSE; + boolean sawscary = FALSE, bravegremlin = (rn2(5) == 0); *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (BOLT_LIM * BOLT_LIM)); @@ -329,6 +343,7 @@ int *inrange, *nearby, *scared; sawscary = onscary(seescaryx, seescaryy, mtmp); if (*nearby && (sawscary + || (flees_light(mtmp) && !bravegremlin) || (!mtmp->mpeaceful && in_your_sanctuary(mtmp, 0, 0)))) { *scared = 1; monflee(mtmp, rnd(rn2(7) ? 10 : 100), TRUE, TRUE); @@ -336,6 +351,8 @@ int *inrange, *nearby, *scared; *scared = 0; } +#undef flees_light + /* perform a special one-time action for a monster; returns -1 if nothing special happened, 0 if monster uses up its turn, 1 if monster is killed */ STATIC_OVL int @@ -1371,7 +1388,8 @@ postmov: add_damage(mtmp->mx, mtmp->my, 0L); } } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { - if (may_dig(mtmp->mx, mtmp->my) + /* 3.6.2: was using may_dig() but it doesn't handle bars */ + if (!(levl[mtmp->mx][mtmp->my].wall_info & W_NONDIGGABLE) && (dmgtype(ptr, AD_RUST) || dmgtype(ptr, AD_CORR))) { if (canseemon(mtmp)) pline("%s eats through the iron bars.", Monnam(mtmp)); diff --git a/src/music.c b/src/music.c index 71253f6e1..cb63bde90 100644 --- a/src/music.c +++ b/src/music.c @@ -445,6 +445,11 @@ generic_lvl_desc() return "dungeon"; } +const char *beats[] = { + "stepper", "one drop", "slow two", "triple stroke roll", + "double shuffle", "half-time shuffle", "second line", "train" +}; + /* * The player is trying to extract something from his/her instrument. */ @@ -454,6 +459,7 @@ struct obj *instr; { int damage, mode, do_spec = !(Stunned || Confusion); struct obj itmp; + boolean mundane = FALSE; itmp = *instr; itmp.oextra = (struct oextra *) 0; /* ok on this copy as instr maintains @@ -462,8 +468,10 @@ struct obj *instr; /* if won't yield special effect, make sound of mundane counterpart */ if (!do_spec || instr->spe <= 0) - while (objects[itmp.otyp].oc_magic) + while (objects[itmp.otyp].oc_magic) { itmp.otyp -= 1; + mundane = TRUE; + } #ifdef MAC mac_speaker(&itmp, "C"); #endif @@ -579,6 +587,10 @@ struct obj *instr; exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ + /* a drum of earthquake does cause not cause deafness + while still magically functional, nor afterwards + when it invokes the LEATHER_DRUM case instead and + mundane is flagged */ consume_obj_charge(instr, TRUE); You("produce a heavy, thunderous rolling!"); @@ -589,10 +601,15 @@ struct obj *instr; makeknown(DRUM_OF_EARTHQUAKE); break; case LEATHER_DRUM: /* Awaken monsters */ - You("beat a deafening row!"); - awaken_monsters(u.ulevel * 40); - incr_itimeout(&HDeaf, rn1(20, 30)); - exercise(A_WIS, FALSE); + if (!mundane) { + You("beat a deafening row!"); + incr_itimeout(&HDeaf, rn1(20, 30)); + exercise(A_WIS, FALSE); + } else + You("%s %s.", + rn2(2) ? "butcher" : rn2(2) ? "manage" : "pull off", + an(beats[rn2(SIZE(beats))])); + awaken_monsters(u.ulevel * (mundane ? 5 : 40)); context.botl = TRUE; break; default: diff --git a/src/objnam.c b/src/objnam.c index 692291417..ce952c36f 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1537313446 2018/09/18 23:30:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.208 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1537659941 2018/09/22 23:45:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.212 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -12,7 +12,7 @@ STATIC_DCL char *FDECL(strprepend, (char *, const char *)); STATIC_DCL short FDECL(rnd_otyp_by_wpnskill, (SCHAR_P)); -STATIC_DCL short FDECL(rnd_otyp_by_namedesc, (char *, CHAR_P)); +STATIC_DCL short FDECL(rnd_otyp_by_namedesc, (const char *, CHAR_P, int)); STATIC_DCL boolean FDECL(wishymatch, (const char *, const char *, BOOLEAN_P)); STATIC_DCL char *NDECL(nextobuf); STATIC_DCL void FDECL(releaseobuf, (char *)); @@ -403,7 +403,7 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ register struct objclass *ocl = &objects[typ]; int nn = ocl->oc_name_known, omndx = obj->corpsenm; const char *actualn = OBJ_NAME(*ocl); - const char *dn = OBJ_DESCR(*ocl) ? OBJ_DESCR(*ocl) : actualn; + const char *dn = OBJ_DESCR(*ocl); const char *un = ocl->oc_uname; boolean pluralize = (obj->quan != 1L) && !(cxn_flags & CXN_SINGULAR); boolean known, dknown, bknown; @@ -411,6 +411,10 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) actualn = Japanese_item_name(typ); + /* 3.6.2: this used to be part of 'dn's initialization, but it + needs to come after possibly overriding 'actualn' */ + if (!dn) + dn = actualn; buf[0] = '\0'; /* @@ -1052,7 +1056,7 @@ unsigned doname_flags; obj->leashmon = 0; } else { Sprintf(eos(bp), " (attached to %s)", - a_monnam(mlsh)); + noit_mon_nam(mlsh)); } break; } @@ -2693,6 +2697,7 @@ schar skill; { int i, n = 0; short otyp = STRANGE_OBJECT; + for (i = bases[WEAPON_CLASS]; i < NUM_OBJECTS && objects[i].oc_class == WEAPON_CLASS; i++) if (objects[i].oc_skill == skill) { @@ -2711,20 +2716,29 @@ schar skill; } STATIC_OVL short -rnd_otyp_by_namedesc(name, oclass) -char *name; +rnd_otyp_by_namedesc(name, oclass, xtra_prob) +const char *name; char oclass; +int xtra_prob; /* to force 0% random generation items to also be considered */ { int i, n = 0; short validobjs[NUM_OBJECTS]; register const char *zn; - long maxprob = 0; + int prob, maxprob = 0; - if (!name) + if (!name || !*name) return STRANGE_OBJECT; memset((genericptr_t) validobjs, 0, sizeof validobjs); + /* FIXME: + * When this spans classes (the !oclass case), the item + * probabilities are not very useful because they don't take + * the class generation probability into account. [If 10% + * of spellbooks were blank and 1% of scrolls were blank, + * "blank" would have 10/11 chance to yield a blook even though + * scrolls are supposed to be much more common than books.] + */ for (i = oclass ? bases[(int) oclass] : STRANGE_OBJECT + 1; i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass); ++i) { @@ -2737,17 +2751,15 @@ char oclass; || ((zn = objects[i].oc_uname) != 0 && wishymatch(name, zn, FALSE))) { validobjs[n++] = (short) i; - maxprob += (objects[i].oc_prob + 1); + maxprob += (objects[i].oc_prob + xtra_prob); } } if (n > 0 && maxprob) { - long prob = rn2(maxprob); - - i = 0; - while (i < n - 1 - && (prob -= (objects[validobjs[i]].oc_prob + 1)) >= 0) - i++; + prob = rn2(maxprob); + for (i = 0; i < n - 1; i++) + if ((prob -= (objects[validobjs[i]].oc_prob + xtra_prob)) < 0) + break; return validobjs[i]; } return STRANGE_OBJECT; @@ -2757,7 +2769,7 @@ int shiny_obj(oclass) char oclass; { - return (int) rnd_otyp_by_namedesc("shiny", oclass); + return (int) rnd_otyp_by_namedesc("shiny", oclass, 0); } /* @@ -3390,10 +3402,10 @@ srch: } } - if (((typ = rnd_otyp_by_namedesc(actualn, oclass)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(dn, oclass)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(un, oclass)) != STRANGE_OBJECT) - || ((typ = rnd_otyp_by_namedesc(origbp, oclass)) != STRANGE_OBJECT)) + if (((typ = rnd_otyp_by_namedesc(actualn, oclass, 1)) != STRANGE_OBJECT) + || ((typ = rnd_otyp_by_namedesc(dn, oclass, 1)) != STRANGE_OBJECT) + || ((typ = rnd_otyp_by_namedesc(un, oclass, 1)) != STRANGE_OBJECT) + || ((typ = rnd_otyp_by_namedesc(origbp, oclass, 1)) != STRANGE_OBJECT)) goto typfnd; typ = 0; diff --git a/src/shk.c b/src/shk.c index e0b7cae8b..6eb4ab71a 100644 --- a/src/shk.c +++ b/src/shk.c @@ -435,9 +435,9 @@ boolean newlev; plname); else pline("%s %s that you need to pay before leaving%s", - Shknam(shkp), - NOTANGRY(shkp) ? "points out" : "makes it clear", - NOTANGRY(shkp) ? "." : "!"); + Shknam(shkp), + NOTANGRY(shkp) ? "points out" : "makes it clear", + NOTANGRY(shkp) ? "." : "!"); return; } @@ -580,12 +580,12 @@ char *enterstring; return; /* no dialog */ if (Invis) { - pline("%s senses your presence.", shkname(shkp)); + pline("%s senses your presence.", Shknam(shkp)); if (!Deaf && !muteshk(shkp)) verbalize("Invisible customers are not welcome!"); else pline("%s stands firm as if %s knows you are there.", - Shknam(shkp), mhe(shkp)); + Shknam(shkp), noit_mhe(shkp)); return; } @@ -594,21 +594,18 @@ char *enterstring; if (ANGRY(shkp)) { if (!Deaf && !muteshk(shkp)) verbalize("So, %s, you dare return to %s %s?!", plname, - s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); + s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); else pline("%s seems %s over your return to %s %s!", - Shknam(shkp), - angrytexts[rn2(SIZE(angrytexts))], - mhis(shkp), - shtypes[rt - SHOPBASE].name); + Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], + noit_mhis(shkp), shtypes[rt - SHOPBASE].name); } else if (eshkp->robbed) { if (!Deaf) pline("%s mutters imprecations against shoplifters.", - shkname(shkp)); + Shknam(shkp)); else pline("%s is combing through %s inventory list.", - Shknam(shkp), - mhis(shkp)); + Shknam(shkp), noit_mhis(shkp)); } else { if (!Deaf && !muteshk(shkp)) verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname, @@ -655,20 +652,20 @@ char *enterstring; tool, plur(cnt)); else pline("%s %s to let you in with your %s%s.", - Shknam(shkp), - NOTANGRY(shkp) ? "is hesitant" : "refuses", - tool, plur(cnt)); + Shknam(shkp), + NOTANGRY(shkp) ? "is hesitant" : "refuses", + tool, plur(cnt)); should_block = TRUE; } else if (u.usteed) { if (!Deaf && !muteshk(shkp)) verbalize(NOTANGRY(shkp) ? "Will you please leave %s outside?" : "Leave %s outside.", - y_monnam(u.usteed)); + y_monnam(u.usteed)); else pline("%s %s to let you in while you're riding %s.", - Shknam(shkp), - NOTANGRY(shkp) ? "doesn't want" : "refuses", - y_monnam(u.usteed)); + Shknam(shkp), + NOTANGRY(shkp) ? "doesn't want" : "refuses", + y_monnam(u.usteed)); should_block = TRUE; } else { should_block = @@ -1343,7 +1340,7 @@ proceed: } else { if (umoney > ltmp) { You("give %s the %ld gold piece%s %s asked for.", - shkname(shkp), ltmp, plur(ltmp), mhe(shkp)); + shkname(shkp), ltmp, plur(ltmp), noit_mhe(shkp)); pay(ltmp, shkp); } else { You("give %s all your%s gold.", shkname(shkp), @@ -1353,7 +1350,8 @@ proceed: pline("But you have hidden gold!"); } if ((umoney < ltmp / 2L) || (umoney < ltmp && stashed_gold)) - pline("Unfortunately, %s doesn't look satisfied.", mhe(shkp)); + pline("Unfortunately, %s doesn't look satisfied.", + noit_mhe(shkp)); else make_happy_shk(shkp, FALSE); } @@ -1373,13 +1371,14 @@ proceed: if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else - pline(not_enough_money, mhim(shkp)); + pline(not_enough_money, noit_mhim(shkp)); return 1; } - pline("But since %s shop has been robbed recently,", mhis(shkp)); + pline("But since %s shop has been robbed recently,", + noit_mhis(shkp)); pline("you %scompensate %s for %s losses.", (umoney < ltmp) ? "partially " : "", shkname(shkp), - mhis(shkp)); + noit_mhis(shkp)); pay(umoney < ltmp ? umoney : ltmp, shkp); make_happy_shk(shkp, FALSE); } else { @@ -1390,11 +1389,14 @@ proceed: if (!umoney) pline(no_money, stashed_gold ? " seem to" : ""); else - pline(not_enough_money, mhim(shkp)); + pline(not_enough_money, noit_mhim(shkp)); return 1; } You("try to appease %s by giving %s 1000 gold pieces.", - x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE), mhim(shkp)); + canspotmon(shkp) + ? x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE) + : shkname(shkp), + noit_mhim(shkp)); pay(1000L, shkp); if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3)) make_happy_shk(shkp, FALSE); @@ -1538,13 +1540,13 @@ proceed: } if (!ANGRY(shkp) && paid) { if (!Deaf && !muteshk(shkp)) - verbalize("Thank you for shopping in %s %s!", s_suffix(shkname(shkp)), - shtypes[eshkp->shoptype - SHOPBASE].name); + verbalize("Thank you for shopping in %s %s!", + s_suffix(shkname(shkp)), + shtypes[eshkp->shoptype - SHOPBASE].name); else pline("%s nods appreciatively at you for shopping in %s %s!", - Shknam(shkp), - mhis(shkp), - shtypes[eshkp->shoptype - SHOPBASE].name); + Shknam(shkp), noit_mhis(shkp), + shtypes[eshkp->shoptype - SHOPBASE].name); } return 1; } @@ -1778,7 +1780,7 @@ int croaked; if (cansee(shkp->mx, shkp->my) && croaked) { takes[0] = '\0'; if (has_head(shkp->data) && !rn2(2)) - Sprintf(takes, ", shakes %s %s,", mhis(shkp), + Sprintf(takes, ", shakes %s %s,", noit_mhis(shkp), mbodypart(shkp, HEAD)); pline("%s %slooks at your corpse%s and %s.", Shknam(shkp), (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "", @@ -1797,7 +1799,7 @@ int croaked; taken = (invent != 0); if (taken) pline("%s gratefully inherits all your possessions.", - shkname(shkp)); + Shknam(shkp)); set_repo_loc(shkp); goto clear; } @@ -1828,7 +1830,7 @@ int croaked; if (umoney > 0) money2mon(shkp, umoney); context.botl = 1; - pline("%s %s all your possessions.", shkname(shkp), takes); + pline("%s %s all your possessions.", Shknam(shkp), takes); taken = TRUE; /* where to put player's invent (after disclosure) */ set_repo_loc(shkp); @@ -1838,7 +1840,7 @@ int croaked; pline("%s %s the %ld %s %sowed %s.", Shknam(shkp), takes, loss, currency(loss), strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ", - mhim(shkp)); + noit_mhim(shkp)); /* shopkeeper has now been paid in full */ pacify_shk(shkp); eshkp->following = 0; @@ -2218,9 +2220,8 @@ boolean quietly; verbalize("I won't stock that. Take it out of here!"); else pline("%s shakes %s %s in refusal.", - Shknam(shkp), - mhis(shkp), - mbodypart(shkp, HEAD)); + Shknam(shkp), noit_mhis(shkp), + mbodypart(shkp, HEAD)); } } return TRUE; @@ -3010,7 +3011,7 @@ xchar x, y; if (sell_how == SELL_NORMAL || auto_credit) { c = sell_response = 'y'; } else if (sell_response != 'n') { - pline("%s cannot pay you at present.", shkname(shkp)); + pline("%s cannot pay you at present.", Shknam(shkp)); Sprintf(qbuf, "Will you accept %ld %s in credit for ", tmpcr, currency(tmpcr)); c = ynaq(safe_qbuf(qbuf, qbuf, "?", obj, doname, thesimpleoname, @@ -3079,7 +3080,7 @@ xchar x, y; "... your items in the . Sell them?" */ Sprintf(qbuf, "%s offers%s %ld gold piece%s for %s%s ", - shkname(shkp), short_funds ? " only" : "", offer, + Shknam(shkp), short_funds ? " only" : "", offer, plur(offer), (cltmp && !ltmp) ? ((yourc == 1L) ? "your item in " : "your items in ") @@ -3650,8 +3651,7 @@ struct monst *shkp; Hello(shkp), plname); else pline("%s holds out %s upturned %s.", - Shknam(shkp), - mhis(shkp), + Shknam(shkp), noit_mhis(shkp), mbodypart(shkp, HAND)); followmsg = moves; if (!rn2(9)) { @@ -3805,7 +3805,7 @@ register int fall; */ if (lang == 2) pline("%s curses %s inability to grab your backpack!", - shkname(shkp), mhim(shkp)); + Shknam(shkp), noit_mhim(shkp)); rile_shk(shkp); return; #endif @@ -3816,16 +3816,16 @@ register int fall; if (distu(shkp->mx, shkp->my) > 2) { if (lang == 2) pline("%s curses you in anger and frustration!", - shkname(shkp)); + Shknam(shkp)); else if (lang == 1) growl(shkp); rile_shk(shkp); return; } else - pline("%s %s, and %s your backpack!", shkname(shkp), + pline("%s %s, and %s your backpack!", Shknam(shkp), makeplural(locomotion(shkp->data, "leap")), grabs); } else - pline("%s %s your backpack!", shkname(shkp), grabs); + pline("%s %s your backpack!", Shknam(shkp), grabs); for (obj = invent; obj; obj = obj2) { obj2 = obj->nobj; @@ -3957,7 +3957,7 @@ boolean cant_mollify; if (uinshp) { if (um_dist(shkp->mx, shkp->my, 1) && !um_dist(shkp->mx, shkp->my, 3)) { - pline("%s leaps towards you!", shkname(shkp)); + pline("%s leaps towards you!", Shknam(shkp)); mnexto(shkp); } pursue = um_dist(shkp->mx, shkp->my, 1); @@ -4004,16 +4004,16 @@ boolean cant_mollify; else pline("%s is %s that you decided to %s %s %s!", Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], - dmgstr, mhis(shkp), dugwall ? "shop" : "door"); + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); } else { if (!Deaf) { - pline("%s shouts:", shkname(shkp)); + pline("%s shouts:", Shknam(shkp)); verbalize("Who dared %s my %s?", dmgstr, dugwall ? "shop" : "door"); } else { pline("%s is %s that someone decided to %s %s %s!", Shknam(shkp), angrytexts[rn2(SIZE(angrytexts))], - dmgstr, mhis(shkp), dugwall ? "shop" : "door"); + dmgstr, noit_mhis(shkp), dugwall ? "shop" : "door"); } } hot_pursuit(shkp); @@ -4039,10 +4039,8 @@ boolean cant_mollify; verbalize("Oh, yes! You'll pay!"); else pline("%s lunges %s %s toward your %s!", - Shknam(shkp), - mhis(shkp), - mbodypart(shkp, HAND), - body_part(NECK)); + Shknam(shkp), noit_mhis(shkp), + mbodypart(shkp, HAND), body_part(NECK)); } else growl(shkp); hot_pursuit(shkp); @@ -4221,9 +4219,9 @@ struct monst *shkp; eshk = ESHK(shkp); if (ANGRY(shkp)) { pline("%s %s how much %s dislikes %s customers.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "mentions" : "indicates", - mhe(shkp), eshk->robbed ? "non-paying" : "rude"); + noit_mhe(shkp), eshk->robbed ? "non-paying" : "rude"); } else if (eshk->following) { if (strncmp(eshk->customer, plname, PL_NSIZ)) { if (!Deaf && !muteshk(shkp)) @@ -4242,35 +4240,35 @@ struct monst *shkp; register long total = addupbill(shkp) + eshk->debit; pline("%s %s that your bill comes to %ld %s.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "says" : "indicates", total, currency(total)); } else if (eshk->debit) { pline("%s %s that you owe %s %ld %s.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "reminds you" : "indicates", - mhim(shkp), eshk->debit, currency(eshk->debit)); + noit_mhim(shkp), eshk->debit, currency(eshk->debit)); } else if (eshk->credit) { pline("%s encourages you to use your %ld %s of credit.", - shkname(shkp), eshk->credit, currency(eshk->credit)); + Shknam(shkp), eshk->credit, currency(eshk->credit)); } else if (eshk->robbed) { pline("%s %s about a recent robbery.", Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "complains" : "indicates concern"); } else if ((shkmoney = money_cnt(shkp->minvent)) < 50L) { pline("%s %s that business is bad.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "complains" : "indicates"); } else if (shkmoney > 4000) { pline("%s %s that business is good.", - shkname(shkp), + Shknam(shkp), (!Deaf && !muteshk(shkp)) ? "says" : "indicates"); } else if (is_izchak(shkp, FALSE)) { if (!Deaf && !muteshk(shkp)) pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))], shkname(shkp)); } else { if (!Deaf && !muteshk(shkp)) - pline("%s talks about the problem of shoplifters.", shkname(shkp)); + pline("%s talks about the problem of shoplifters.", Shknam(shkp)); } } @@ -4472,7 +4470,7 @@ register xchar x, y; && ESHK(shkp)->shd.y == y && shkp->mcanmove && !shkp->msleeping && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) { - pline("%s%s blocks your way!", shkname(shkp), + pline("%s%s blocks your way!", Shknam(shkp), Invis ? " senses your motion and" : ""); return TRUE; } @@ -4509,7 +4507,7 @@ register xchar x, y; && (x == sx - 1 || x == sx + 1 || y == sy - 1 || y == sy + 1) && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) || u.usteed)) { - pline("%s%s blocks your way!", shkname(shkp), + pline("%s%s blocks your way!", Shknam(shkp), Invis ? " senses your motion and" : ""); return TRUE; } diff --git a/src/sp_lev.c b/src/sp_lev.c index 1d6b0cd3a..11d692501 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -621,6 +621,7 @@ schar filling; schar lit; { int x, y; + for (x = 2; x <= x_maze_max; x++) for (y = 0; y <= y_maze_max; y++) { SET_TYPLIT(x, y, filling, lit); @@ -636,11 +637,21 @@ xchar x1, y1, x2, y2; int prop; { register xchar x, y; + struct rm *lev; - for (y = max(y1, 0); y <= min(y2, ROWNO - 1); y++) - for (x = max(x1, 0); x <= min(x2, COLNO - 1); x++) - if (IS_STWALL(levl[x][y].typ) || IS_TREE(levl[x][y].typ)) - levl[x][y].wall_info |= prop; + x1 = max(x1, 1); + x2 = min(x2, COLNO - 1); + y1 = max(y1, 0); + y2 = min(y2, ROWNO - 1); + for (y = y1; y <= y2; y++) + for (x = x1; x <= x2; x++) { + lev = &levl[x][y]; + if (IS_STWALL(lev->typ) || IS_TREE(lev->typ) + /* 3.6.2: made iron bars eligible to be flagged nondiggable + (checked by chewing(hack.c) and zap_over_floor(zap.c)) */ + || lev->typ == IRONBARS) + lev->wall_info |= prop; + } } STATIC_OVL void diff --git a/src/teleport.c b/src/teleport.c index 5003ed82d..615292d5d 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -492,7 +492,14 @@ struct obj *scroll; } int -dotele() +dotelecmd() +{ + return dotele((wizard) ? TRUE : FALSE); +} + +int +dotele(break_the_rules) +boolean break_the_rules; { struct trap *trap; boolean trap_once = FALSE; @@ -529,7 +536,7 @@ dotele() castit = TRUE; break; } - if (!wizard) { + if (!break_the_rules) { if (!castit) { if (!Teleportation) You("don't know that spell."); @@ -541,7 +548,7 @@ dotele() } if (u.uhunger <= 100 || ACURR(A_STR) < 6) { - if (!wizard) { + if (!break_the_rules) { You("lack the strength %s.", castit ? "for a teleport spell" : "to teleport"); return 1; @@ -550,7 +557,7 @@ dotele() energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2; if (u.uen <= energy) { - if (wizard) + if (break_the_rules) energy = u.uen; else { You("lack the energy %s.", @@ -567,11 +574,13 @@ dotele() exercise(A_WIS, TRUE); if (spelleffects(sp_no, TRUE)) return 1; - else if (!wizard) + else if (!break_the_rules) return 0; } else { - u.uen -= energy; - context.botl = 1; + if (!break_the_rules) { + u.uen -= energy; + context.botl = 1; + } } } diff --git a/src/trap.c b/src/trap.c index f7d1d0bc9..b9252d18e 100644 --- a/src/trap.c +++ b/src/trap.c @@ -3693,7 +3693,7 @@ drown() && (Teleport_control || rn2(3) < Luck + 2)) { You("attempt a teleport spell."); /* utcsri!carroll */ if (!level.flags.noteleport) { - (void) dotele(); + (void) dotele(FALSE); if (!is_pool(u.ux, u.uy)) return TRUE; } else @@ -3991,6 +3991,16 @@ boolean force_failure; } } else if (under_u) { dotrap(ttmp, 0); + } else if (ttype == BEAR_TRAP && (Levitation || Flying)) { + /* There was a report of oddities of the trap + vanishing from view due to tseen being cleared + (which was deliberate to work around a check_here() + issue). Since you won't actually end up in the trap + during the #untrap operation anyway due to + Levitation and Flying checks further along, + just avoid the whole "vanishing trap" scenario + by failing the #untrap operation right here. */ + You("couldn't reach it from your vantage point."); } else { move_into_trap(ttmp); } diff --git a/src/uhitm.c b/src/uhitm.c index b240eef26..5dd5b8623 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -658,6 +658,7 @@ int dieroll; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE, unpoisonmsg = FALSE; boolean silvermsg = FALSE, silverobj = FALSE; + boolean lightobj = FALSE; boolean valid_weapon_attack = FALSE; boolean unarmed = !uwep && !uarm && !uarms; boolean hand_to_hand = (thrown == HMON_MELEE @@ -699,7 +700,10 @@ int dieroll; } } } else { - Strcpy(saved_oname, cxname(obj)); + if (!(artifact_light(obj) && obj->lamplit)) + Strcpy(saved_oname, cxname(obj)); + else + Strcpy(saved_oname, bare_artifactname(obj)); if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { /* is it not a melee weapon? */ @@ -803,6 +807,8 @@ int dieroll; silvermsg = TRUE; silverobj = TRUE; } + if (artifact_light(obj) && obj->lamplit && mon_hates_light(mon)) + lightobj = TRUE; if (u.usteed && !thrown && tmp > 0 && weapon_type(obj) == P_LANCE && mon != u.ustuck) { jousting = joust(mon, obj); @@ -1251,6 +1257,29 @@ int dieroll; whom = strcat(s_suffix(whom), " flesh"); pline(fmt, whom); } + if (lightobj) { + const char *fmt; + char *whom = mon_nam(mon); + char emitlightobjbuf[BUFSZ]; + + if (canspotmon(mon)) { + if (saved_oname[0]) { + Sprintf(emitlightobjbuf, + "%s radiance penetrates deep into", + s_suffix(saved_oname)); + Strcat(emitlightobjbuf, " %s!"); + fmt = emitlightobjbuf; + } else + fmt = "The light sears %s!"; + } else { + *whom = highc(*whom); /* "it" -> "It" */ + fmt = "%s is seared!"; + } + /* note: s_suffix returns a modifiable buffer */ + if (!noncorporeal(mdat) && !amorphous(mdat)) + whom = strcat(s_suffix(whom), " flesh"); + pline(fmt, whom); + } /* if a "no longer poisoned" message is coming, it will be last; obj->opoisoned was cleared above and any message referring to "poisoned " has now been given; we want just "" for diff --git a/src/vault.c b/src/vault.c index 22bf15e9c..eea24737d 100644 --- a/src/vault.c +++ b/src/vault.c @@ -452,7 +452,8 @@ invault() if (!Blind) pline( "%s holds out %s palm and beckons with %s other hand.", - noit_Monnam(guard), mhis(guard), mhis(guard)); + noit_Monnam(guard), noit_mhis(guard), + noit_mhis(guard)); } else { verbalize( "Most likely all your gold was stolen from this vault."); @@ -707,7 +708,7 @@ register struct monst *grd; if (Deaf) { if (!Blind) pline("%s holds out %s palm demandingly!", - noit_Monnam(grd), mhis(grd)); + noit_Monnam(grd), noit_mhis(grd)); } else { verbalize("Drop all your gold, scoundrel!"); } @@ -716,7 +717,7 @@ register struct monst *grd; if (Deaf) { if (!Blind) pline("%s rubs %s hands with enraged delight!", - noit_Monnam(grd), mhis(grd)); + noit_Monnam(grd), noit_mhis(grd)); } else { verbalize("So be it, rogue!"); } diff --git a/src/weapon.c b/src/weapon.c index 2b7b3bf0a..b680f864c 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -329,6 +329,8 @@ struct monst *mon; bonus += rnd(4); if (objects[otyp].oc_material == SILVER && mon_hates_silver(mon)) bonus += rnd(20); + if (artifact_light(otmp) && otmp->lamplit && hates_light(ptr)) + bonus += rnd(8); /* if the weapon is going to get a double damage bonus, adjust this bonus so that effectively it's added after the doubling */ diff --git a/src/windows.c b/src/windows.c index 96d9a218d..c87e4ca43 100644 --- a/src/windows.c +++ b/src/windows.c @@ -930,7 +930,7 @@ unsigned long *colormasks UNUSED; is buffered so final BL_FLUSH is needed to produce output) */ windowprocs.wincap2 |= WC2_FLUSH_STATUS; - if (idx != BL_FLUSH) { + if (idx >= 0) { if (!status_activefields[idx]) return; switch (idx) { @@ -972,11 +972,20 @@ unsigned long *colormasks UNUSED; break; } return; /* processed one field other than BL_FLUSH */ - } /* (idx != BL_FLUSH) */ + } /* (idx >= 0, thus not BL_FLUSH, BL_RESET, BL_CHARACTERISTICS) */ + + /* does BL_RESET require any specific code to ensure all fields ? */ + + if (!(idx == BL_FLUSH || idx == BL_RESET)) + return; /* We've received BL_FLUSH; time to output the gathered data */ nb = newbot1; *nb = '\0'; + /* BL_FLUSH is the only pseudo-index value we need to check for + in the loop below because it is the only entry used to pad the + end of the fieldorder array. We could stop on any + negative (illegal) index, but this should be fine */ for (i = 0; (idx1 = fieldorder[0][i]) != BL_FLUSH; ++i) { if (status_activefields[idx1]) Strcpy(nb = eos(nb), status_vals[idx1]); diff --git a/win/X11/winX.c b/win/X11/winX.c index 5c1de3c12..5da69a6ec 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -100,7 +100,10 @@ struct window_procs X11_procs = { "X11", (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT), - 0L, /* WC2 flag mask */ +#if defined(STATUS_HILITES) + WC2_FLUSH_STATUS | WC2_RESET_STATUS | +#endif + 0L, X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 5c98c0299..34cc45f5d 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -67,6 +67,7 @@ struct window_procs tty_procs = { #endif #if defined(STATUS_HILITES) | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_RESET_STATUS #endif | WC2_DARKGRAY), tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, @@ -3665,6 +3666,9 @@ unsigned long *colormasks; char *fval = (char *) 0; boolean reset_state = NO_RESET; + if ((fldidx < BL_RESET) || (fldidx >= MAXBLSTATS)) + return; + if ((fldidx >= 0 && fldidx < MAXBLSTATS) && !status_activefields[fldidx]) return; @@ -3726,11 +3730,13 @@ unsigned long *colormasks; case BL_HUNGER: /* The core sends trailing blanks for some fields. Let's suppress the trailing blanks */ - lastchar = eos(status_vals[fldidx]); - lastchar--; - while (*lastchar == ' ' && lastchar >= status_vals[fldidx]) { - *lastchar-- = '\0'; - tty_status[NOW][fldidx].lth--; + if (tty_status[NOW][fldidx].lth > 0) { + lastchar = eos(status_vals[fldidx]); + lastchar--; + while (lastchar >= status_vals[fldidx] && *lastchar == ' ') { + *lastchar-- = '\0'; + tty_status[NOW][fldidx].lth--; + } } break; case BL_TITLE: diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 77432f751..fea75b177 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -88,7 +88,7 @@ struct window_procs mswin_procs = { | WC_VARY_MSGCOUNT | WC_WINDOWCOLORS | WC_PLAYER_SELECTION | WC_SPLASH_SCREEN | WC_POPUP_DIALOG | WC_MOUSE_SUPPORT, #ifdef STATUS_HILITES - WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_HILITE_STATUS | + WC2_HITPOINTBAR | WC2_FLUSH_STATUS | WC2_RESET_STATUS | WC2_HILITE_STATUS | #endif 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname, mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows,