From 467ee34b2fe1ca5ac159d4b1178633dc83453efc Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 26 Apr 2015 15:56:28 +0300 Subject: [PATCH 01/17] Prevent possible buffer overflow getlin() gets at most a BUFSZ string from user; make the buf big enough to hold that _and_ the query itself. --- src/dungeon.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dungeon.c b/src/dungeon.c index 8c436e1c8..43f4afab1 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1868,9 +1868,10 @@ donamelevel() if (!(mptr = find_mapseen(&u.uz))) return 0; if (mptr->custom) { - char qbuf[BUFSZ]; - Sprintf(qbuf, "Replace annotation \"%s\" with?", mptr->custom); - getlin(qbuf, nbuf); + const char querystr[] = "Replace annotation \"%s\" with?"; + char tmpbuf[BUFSZ + sizeof(querystr)]; + Sprintf(tmpbuf, querystr, mptr->custom); + getlin(tmpbuf, nbuf); } else getlin("What do you want to call this dungeon level?", nbuf); if (index(nbuf, '\033')) return 0; From b4741d62062c30545c501bb35d776e5d8b042ad0 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 27 Apr 2015 01:22:39 -0700 Subject: [PATCH 02/17] more BUCX: union vs intersection Fix filtering used by the 'D' command, and a few other activities that allow both object class filtering and bless/curse state filtering, so that when both class(es) and state(s) are specified, objects need to match both rather than either. D?C will present the player with cursed scrolls to drop rather than all scrolls plus all other cursed objects. This also fixes another instance when gold could end up with its bknown flag set. --- doc/fixes35.0 | 3 ++ src/pickup.c | 78 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/doc/fixes35.0 b/doc/fixes35.0 index 991c41011..02f3e4e8d 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -903,6 +903,9 @@ some monsters can eat through iron bars inaccessible niches occasionally have iron bars in front sinks may teleport or polymorph shopkeepers give honorifics to vampires and elves +when commands (D, A, object identify) mix object class filtering with BUCX + filtering, take the intersection rather than the union (so ?B picks + blessed scrolls rather than all scrolls plus blessed everything) Platform- and/or Interface-Specific Fixes diff --git a/src/pickup.c b/src/pickup.c index 3866c2287..4277a3ea2 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 pickup.c $NHDT-Date: 1426558927 2015/03/17 02:22:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.131 $ */ +/* NetHack 3.5 pickup.c $NHDT-Date: 1430122768 2015/04/27 08:19:28 $ $NHDT-Branch: master $:$NHDT-Revision: 1.150 $ */ /* NetHack 3.5 pickup.c $Date: 2012/02/16 03:01:38 $ $Revision: 1.123 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -308,8 +308,10 @@ struct obj *obj; return (obj->quan >= val_for_n_or_more); } -/* List of valid menu classes for query_objlist() and allow_category callback */ -static char valid_menu_classes[MAXOCLASSES + 2]; +/* list of valid menu classes for query_objlist() and allow_category callback + (with room for all object classes, 'u'npaid, BUCX, and terminator) */ +static char valid_menu_classes[MAXOCLASSES + 1 + 4 + 1]; +static boolean class_filter, bucx_filter, shop_filter; void add_valid_menu_class(c) @@ -317,10 +319,19 @@ int c; { static int vmc_count = 0; - if (c == 0) /* reset */ - vmc_count = 0; - else - valid_menu_classes[vmc_count++] = (char)c; + if (c == 0) { /* reset */ + vmc_count = 0; + class_filter = bucx_filter = shop_filter = FALSE; + } else { + valid_menu_classes[vmc_count++] = (char)c; + /* categorize the new class */ + switch (c) { + case 'B': case 'U': case 'C': /*FALLTHRU*/ + case 'X': bucx_filter = TRUE; break; + case 'u': shop_filter = TRUE; break; + default: class_filter = TRUE; break; + } + } valid_menu_classes[vmc_count] = '\0'; } @@ -345,26 +356,47 @@ boolean allow_category(obj) struct obj *obj; { - if (Role_if(PM_PRIEST)) obj->bknown = TRUE; - - /* if obj's class is in the list, then obj is acceptable */ - if (index(valid_menu_classes, obj->oclass)) - return TRUE; /* unpaid and BUC checks don't apply to coins */ if (obj->oclass == COIN_CLASS) + return index(valid_menu_classes, COIN_CLASS) ? TRUE : FALSE; + + if (Role_if(PM_PRIEST)) obj->bknown = TRUE; + /* + * There are three types of filters possible and the first and + * third can have more than one entry: + * 1) object class (armor, potion, &c); + * 2) unpaid shop item; + * 3) bless/curse state (blessed, uncursed, cursed, BUC-unknown). + * When only one type is present, the situation is simple: + * to be accepted, obj's status must match one of the entries. + * When more than one type is present, the obj will now only + * be accepted when it matches one entry of each type. + * So ?!B will accept blessed scrolls or potions, and [u will + * accept unpaid armor. (In 3.4.3, an object was accepted by + * this filter if it met any entry of any type, so ?!B resulted + * in accepting all scrolls and potions regardless of bless/curse + * state plus all blessed non-scroll, non-potion objects.) + */ + /* if class is expected but obj's class is not in the list, reject */ + if (class_filter && !index(valid_menu_classes, obj->oclass)) + return FALSE; + /* if unpaid is expected and obj isn't unpaid, reject (treat a container + holding any unpaid object as unpaid even if isn't unpaid itself) */ + if (shop_filter && !obj->unpaid + && !(Has_contents(obj) && count_unpaid(obj) > 0)) return FALSE; - /* check for unpaid item */ - if (index(valid_menu_classes, 'u') && - (obj->unpaid || (Has_contents(obj) && count_unpaid(obj)))) - return TRUE; /* check for particular bless/curse state */ - if (!obj->bknown ? index(valid_menu_classes, 'X') : /* unknown BUC state */ - obj->blessed ? index(valid_menu_classes, 'B') : /* known blessed */ - !obj->cursed ? index(valid_menu_classes, 'U') : /* known uncursed */ - index(valid_menu_classes, 'C')) /* known cursed */ - return TRUE; - /* obj isn't acceptable */ - return FALSE; + if (bucx_filter) { + /* first categorize this object's bless/curse state */ + char bucx = !obj->bknown ? 'X' + : obj->blessed ? 'B' : obj->cursed ? 'C' : 'U'; + + /* if its category is not in the list, reject */ + if (!index(valid_menu_classes, bucx)) + return FALSE; + } + /* obj didn't fail any of the filter checks, so accept */ + return TRUE; } #if 0 /* not used */ From 4fa3c39b552587339c21d03258890347d3369c49 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 16:18:59 +0300 Subject: [PATCH 03/17] Show only beginning of annotation when redoing it --- src/dungeon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dungeon.c b/src/dungeon.c index 43f4afab1..3d1bfcb65 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1868,9 +1868,9 @@ donamelevel() if (!(mptr = find_mapseen(&u.uz))) return 0; if (mptr->custom) { - const char querystr[] = "Replace annotation \"%s\" with?"; - char tmpbuf[BUFSZ + sizeof(querystr)]; - Sprintf(tmpbuf, querystr, mptr->custom); + char tmpbuf[BUFSZ]; + Sprintf(tmpbuf, "Replace annotation \"%.30s%s\" with?", + mptr->custom, strlen(mptr->custom) > 30 ? "..." : ""); getlin(tmpbuf, nbuf); } else getlin("What do you want to call this dungeon level?", nbuf); From eecd19caa95e8b909be2c0e140d375fc22103ac6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 17:45:40 +0300 Subject: [PATCH 04/17] Allow changing menucolors in-game via Options --- include/color.h | 1 + src/options.c | 321 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 268 insertions(+), 54 deletions(-) diff --git a/include/color.h b/include/color.h index a772dd84c..5b4b966f5 100644 --- a/include/color.h +++ b/include/color.h @@ -53,6 +53,7 @@ struct menucoloring { struct nhregex *match; + char *origstr; int color, attr; struct menucoloring *next; }; diff --git a/src/options.c b/src/options.c index 1e3d18338..c5397b40d 100644 --- a/src/options.c +++ b/src/options.c @@ -498,6 +498,13 @@ STATIC_OVL boolean FDECL(is_wc2_option, (const char *)); STATIC_OVL boolean FDECL(wc2_supported, (const char *)); STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *)); STATIC_OVL int FDECL(count_ape_maps, (int *, int *)); +STATIC_DCL const char *FDECL(clr2colorname, (int)); +STATIC_DCL const char *FDECL(attr2attrname, (int)); +STATIC_DCL int NDECL(query_color); +STATIC_DCL int NDECL(query_attr); +STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int)); +STATIC_DCL void FDECL(free_one_menu_coloring, (int)); +STATIC_DCL int NDECL(count_menucolors); void @@ -1163,6 +1170,108 @@ static const struct { {"inverse", ATR_INVERSE} }; +const char * +clr2colorname(clr) +int clr; +{ + int i; + for (i = 0; i < SIZE(colornames); i++) + if (colornames[i].color == clr) + return colornames[i].name; + return NULL; +} + +const char * +attr2attrname(attr) +int attr; +{ + int i; + for (i = 0; i < SIZE(attrnames); i++) + if (attrnames[i].attr == attr) + return attrnames[i].name; + return NULL; +} + +int +query_color() +{ + winid tmpwin; + anything any; + int i, pick_cnt; + menu_item *picks = (menu_item *)0; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + for (i = 0; i < SIZE(colornames); i++) { + any.a_int = i + 1; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name, MENU_UNSELECTED); + } + end_menu(tmpwin, "Pick a color"); + pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); + destroy_nhwindow(tmpwin); + if (pick_cnt > 0) { + i = colornames[picks->item.a_int - 1].color; + free((genericptr_t)picks); + return i; + } + return -1; +} + +int +query_attr() +{ + winid tmpwin; + anything any; + int i, pick_cnt; + menu_item *picks = (menu_item *)0; + + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + for (i = 0; i < SIZE(attrnames); i++) { + any.a_int = i + 1; + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr, attrnames[i].name, MENU_UNSELECTED); + } + end_menu(tmpwin, "Pick an attribute"); + pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); + destroy_nhwindow(tmpwin); + if (pick_cnt > 0) { + i = attrnames[picks->item.a_int - 1].attr; + free((genericptr_t)picks); + return i; + } + return -1; +} + +boolean +add_menu_coloring_parsed(str, c, a) +char *str; +int c, a; +{ + struct menucoloring *tmp; + if (!str) return FALSE; + tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring)); + tmp->match = regex_init(); + if (!regex_compile(str, tmp->match)) { + static const char *re_error = "Menucolor regex error"; + if (!iflags.window_inited) + raw_printf("\n%s: %s\n", re_error, regex_error_desc(tmp->match)); + else + pline("%s: %s", re_error, regex_error_desc(tmp->match)); + wait_synch(); + free(tmp); + return FALSE; + } else { + tmp->next = menu_colorings; + tmp->origstr = dupstr(str); + tmp->color = c; + tmp->attr = a; + menu_colorings = tmp; + return TRUE; + } +} + /* parse '"regex_string"=color&attr' and add it to menucoloring */ boolean add_menu_coloring(str) @@ -1212,20 +1321,7 @@ char *str; } } - tmp = (struct menucoloring *)alloc(sizeof(struct menucoloring)); - tmp->match = regex_init(); - if (!regex_compile(tmps, tmp->match)) { - raw_printf("\nMenucolor regex error: %s\n", regex_error_desc(tmp->match)); - wait_synch(); - free(tmp); - return FALSE; - } else { - tmp->next = menu_colorings; - tmp->color = c; - tmp->attr = a; - menu_colorings = tmp; - return TRUE; - } + return add_menu_coloring_parsed(tmps, c, a); } boolean @@ -1252,11 +1348,48 @@ free_menu_coloring() while (tmp) { struct menucoloring *tmp2 = tmp->next; regex_free(tmp->match); + free(tmp->origstr); free(tmp); tmp = tmp2; } } +void +free_one_menu_coloring(idx) +int idx; /* 0 .. */ +{ + struct menucoloring *tmp = menu_colorings; + struct menucoloring *prev = NULL; + + while (tmp) { + if (idx == 0) { + struct menucoloring *next = tmp->next; + regex_free(tmp->match); + free(tmp->origstr); + free(tmp); + if (prev) prev->next = next; + else menu_colorings = next; + return; + } + idx--; + prev = tmp; + tmp = tmp->next; + } +} + + +int +count_menucolors() +{ + int count = 0; + struct menucoloring *tmp = menu_colorings; + + while (tmp) { + count++; + tmp = tmp->next; + } + return count; +} void parseoptions(opts, tinitial, tfrom_file) @@ -3087,6 +3220,11 @@ doset() doset_add_menu(tmpwin, compopt[i].name, (pass == DISP_IN_GAME) ? 0 : indexoffset); } + any.a_int = -3; + Sprintf(buf2, "(%d currently set)", count_menucolors()); + Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", + "menucolors", buf2); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); #ifdef STATUS_VIA_WINDOWPORT # ifdef STATUS_HILITES any.a_int = -2; @@ -3138,6 +3276,10 @@ doset() } else # endif #endif + if (opt_indx == -4) { + (void)special_handling("menucolors", + setinitial, fromfile); + } else if (opt_indx < boolcount) { /* boolean option */ Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", @@ -3177,6 +3319,57 @@ doset() return 0; } +int +handle_add_list_remove(optname, numtotal) +char *optname; +int numtotal; +{ + winid tmpwin; + anything any; + int i, pick_cnt, pick_idx, opt_idx; + menu_item *pick_list = (menu_item *)0; + static const struct action { + char letr; + const char *desc; + } action_titles[] = { + { 'a', "add new %s" }, /* [0] */ + { 'l', "list %s" }, /* [1] */ + { 'r', "remove existing %s" }, /* [2] */ + { 'x', "exit this menu" }, /* [3] */ + }; + + opt_idx = 0; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + for (i = 0; i < SIZE(action_titles); i++) { + char tmpbuf[BUFSZ]; + any.a_int++; + /* omit list and remove if there aren't any yet */ + if (!numtotal && (i == 1 || i == 2)) continue; + Sprintf(tmpbuf, action_titles[i].desc, (i == 1) ? makeplural(optname) : optname); + add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, + 0, ATR_NONE, tmpbuf, +#if 0 /* this ought to work but doesn't... */ + (action_titles[i].letr == 'x') ? MENU_SELECTED : +#endif + MENU_UNSELECTED); + } + end_menu(tmpwin, "Do what?"); + if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) { + for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { + opt_idx = pick_list[pick_idx].item.a_int - 1; + } + free((genericptr_t)pick_list); + pick_list = (menu_item *)0; + } + destroy_nhwindow(tmpwin); + + if (pick_cnt < 1) opt_idx = 3; /* none selected, exit menu */ + return opt_idx; +} + + struct symsetentry *symset_list = 0; /* files.c will populate this with list of available sets */ @@ -3483,50 +3676,68 @@ boolean setinitial,setfromfile; free((genericptr_t)mode_pick); } destroy_nhwindow(tmpwin); - } else if (!strcmp("autopickup_exception", optname)) { - int pick_cnt, pick_idx, opt_idx, pass; - int totalapes = 0, numapes[2] = {0,0}; - menu_item *pick_list = (menu_item *)0; - char apebuf[1+BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ - struct autopickup_exception *ape; - static const struct ape_action { - char letr; - const char *desc; - } action_titles[] = { - { 'a', "add new autopickup exception" }, /* [0] */ - { 'l', "list autopickup exceptions" }, /* [1] */ - { 'r', "remove existing autopickup exception" }, /* [2] */ - { 'x', "exit this menu" }, /* [3] */ - }; - - ape_again: - opt_idx = 0; - totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); - tmpwin = create_nhwindow(NHW_MENU); - start_menu(tmpwin); - any = zeroany; - for (i = 0; i < SIZE(action_titles); i++) { - any.a_int++; - /* omit list and remove if there aren't any yet */ - if (!totalapes && (i == 1 || i == 2)) continue; - add_menu(tmpwin, NO_GLYPH, &any, action_titles[i].letr, - 0, ATR_NONE, action_titles[i].desc, -#if 0 /* this ought to work but doesn't... */ - (action_titles[i].letr == 'x') ? MENU_SELECTED : -#endif - MENU_UNSELECTED); - } - end_menu(tmpwin, "Do what?"); - if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) { - for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { - opt_idx = pick_list[pick_idx].item.a_int - 1; + } else if (!strcmp("menucolors", optname)) { + int opt_idx, nmc, mcclr, mcattr; + char mcbuf[BUFSZ]; +menucolors_again: + nmc = count_menucolors(); + opt_idx = handle_add_list_remove("menucolor", nmc); + if (opt_idx == 3) { + ; /* done--fall through to function exit */ + } else if (opt_idx == 0) { /* add new */ + getlin("What new menucolor pattern?", mcbuf); + if (*mcbuf == '\033' || !*mcbuf) goto menucolors_again; + mcclr = query_color(); + if (mcclr == -1) goto menucolors_again; + mcattr = query_attr(); + if (mcattr == -1) goto menucolors_again; + if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) { + pline("Error adding the menu color."); + wait_synch(); + goto menucolors_again; + } + } else { /* list or remove */ + int pick_idx, pick_cnt; + int mc_idx; + menu_item *pick_list = (menu_item *)0; + struct menucoloring *tmp = menu_colorings; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + any = zeroany; + mc_idx = 0; + while (tmp) { + const char *sattr = attr2attrname(tmp->attr); + const char *sclr = clr2colorname(tmp->color); + any.a_int = (++mc_idx); + Sprintf(mcbuf, "\"%s\"=%s%s%s", tmp->origstr, sclr, + (tmp->attr != ATR_NONE) ? " & " : "", + (tmp->attr != ATR_NONE) ? sattr : ""); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, mcbuf, MENU_UNSELECTED); + tmp = tmp->next; + } + Sprintf(mcbuf, "%s menu colors", + (opt_idx == 1) ? "List of" : "Remove which"); + end_menu(tmpwin, mcbuf); + pick_cnt = select_menu(tmpwin, + (opt_idx == 1) ? PICK_NONE : PICK_ANY, + &pick_list); + if (pick_cnt > 0) { + for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) + free_one_menu_coloring(pick_list[pick_idx].item.a_int - 1 - pick_idx); } free((genericptr_t)pick_list); pick_list = (menu_item *)0; + destroy_nhwindow(tmpwin); + if (pick_cnt >= 0) goto menucolors_again; } - destroy_nhwindow(tmpwin); - - if (pick_cnt < 1 || opt_idx == 3) { + } else if (!strcmp("autopickup_exception", optname)) { + int opt_idx, pass, totalapes = 0, numapes[2] = {0,0}; + char apebuf[1+BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ + struct autopickup_exception *ape; +ape_again: + totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); + opt_idx = handle_add_list_remove("autopickup exception", totalapes); + if (opt_idx == 3) { ; /* done--fall through to function exit */ } else if (opt_idx == 0) { /* add new */ getlin("What new autopickup exception pattern?", &apebuf[1]); @@ -3546,6 +3757,8 @@ boolean setinitial,setfromfile; goto ape_again; } } else { /* list or remove */ + int pick_idx, pick_cnt; + menu_item *pick_list = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { From 93cbd1fbb1b74d7a597ea0d9b681bdff345e1860 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 18:43:55 +0300 Subject: [PATCH 05/17] Allow all text attributes for menu_headings --- doc/Guidebook.mn | 4 ++-- doc/Guidebook.tex | 5 ++-- src/options.c | 61 ++++++++++++----------------------------------- 3 files changed, 20 insertions(+), 50 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 9466f72e5..c700b8a0d 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -2097,8 +2097,8 @@ Implemented by the Amiga, Gem and tty ports. Default '^'. .lp menu_headings Controls how the headings in a menu are highlighted. -Values are 'bold', 'inverse', or 'underline'. -Not all ports can actually display all three types. +Values are 'none', 'bold', 'dim', 'underline', 'blink', or 'inverse'. +Not all ports can actually display all types. .lp menu_invert_all Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 7855d595b..2b7e2deba 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -2530,8 +2530,9 @@ Implemented by the Amiga, Gem and tty ports. Default `\verb+^+'. \item[\ib{menu\_headings}] Controls how the headings in a menu are highlighted. -Values are ``{\tt bold}'', ``{\tt inverse}'', or ``{\tt underline}''. -Not all ports can actually display all three types. +Values are ``{\tt none}'', ``{\tt bold}'', ``{\tt dim}'', +``{\tt underline}'', ``{\tt blink}'', or ``{\tt inverse}''. +Not all ports can actually display all types. \item[\ib{menu\_invert\_all}] Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. diff --git a/src/options.c b/src/options.c index c5397b40d..7c0998917 100644 --- a/src/options.c +++ b/src/options.c @@ -283,7 +283,7 @@ static struct Comp_Opt 4, SET_IN_FILE }, { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE }, - { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME }, + { "menu_headings", "text attribute for menu headings", 9, SET_IN_GAME }, { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE }, { "menu_invert_page", "invert all items on this page of a menu", 4, SET_IN_FILE }, @@ -501,7 +501,7 @@ STATIC_OVL int FDECL(count_ape_maps, (int *, int *)); STATIC_DCL const char *FDECL(clr2colorname, (int)); STATIC_DCL const char *FDECL(attr2attrname, (int)); STATIC_DCL int NDECL(query_color); -STATIC_DCL int NDECL(query_attr); +STATIC_DCL int FDECL(query_attr, (char *)); STATIC_DCL boolean FDECL(add_menu_coloring_parsed, (char *, int, int)); STATIC_DCL void FDECL(free_one_menu_coloring, (int)); STATIC_DCL int NDECL(count_menucolors); @@ -1219,7 +1219,8 @@ query_color() } int -query_attr() +query_attr(prompt) +char *prompt; { winid tmpwin; anything any; @@ -1233,7 +1234,7 @@ query_attr() any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, attrnames[i].attr, attrnames[i].name, MENU_UNSELECTED); } - end_menu(tmpwin, "Pick an attribute"); + end_menu(tmpwin, prompt ? prompt : "Pick an attribute"); pick_cnt = select_menu(tmpwin, PICK_ONE, &picks); destroy_nhwindow(tmpwin); if (pick_cnt > 0) { @@ -2751,14 +2752,12 @@ goodfruit: else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } - if (!strcmpi(opts,"bold")) - iflags.menu_headings = ATR_BOLD; - else if (!strcmpi(opts,"inverse")) - iflags.menu_headings = ATR_INVERSE; - else if (!strcmpi(opts,"underline")) - iflags.menu_headings = ATR_ULINE; - else - badoption(opts); + for (i = 0; i < SIZE(attrnames); i++) + if (!strcmpi(opts, attrnames[i].name)) { + iflags.menu_headings = attrnames[i].attr; + return; + } + badoption(opts); return; } @@ -3647,35 +3646,8 @@ boolean setinitial,setfromfile; } destroy_nhwindow(tmpwin); } else if (!strcmp("menu_headings", optname)) { - static const char *mhchoices[3] = {"bold", "inverse", "underline"}; - const char *npletters = "biu"; - menu_item *mode_pick = (menu_item *)0; - - tmpwin = create_nhwindow(NHW_MENU); - start_menu(tmpwin); - any = zeroany; - for (i = 0; i < SIZE(mhchoices); i++) { - any.a_int = i + 1; - add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0, - ATR_NONE, mhchoices[i], MENU_UNSELECTED); - } - end_menu(tmpwin, "How to highlight menu headings:"); - if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { - int mode = mode_pick->item.a_int - 1; - switch(mode) { - case 2: - iflags.menu_headings = ATR_ULINE; - break; - case 0: - iflags.menu_headings = ATR_BOLD; - break; - case 1: - default: - iflags.menu_headings = ATR_INVERSE; - } - free((genericptr_t)mode_pick); - } - destroy_nhwindow(tmpwin); + int mhattr = query_attr("How to highlight menu headings:"); + if (mhattr != -1) iflags.menu_headings = mhattr; } else if (!strcmp("menucolors", optname)) { int opt_idx, nmc, mcclr, mcattr; char mcbuf[BUFSZ]; @@ -3689,7 +3661,7 @@ menucolors_again: if (*mcbuf == '\033' || !*mcbuf) goto menucolors_again; mcclr = query_color(); if (mcclr == -1) goto menucolors_again; - mcattr = query_attr(); + mcattr = query_attr(NULL); if (mcattr == -1) goto menucolors_again; if (!add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) { pline("Error adding the menu color."); @@ -4083,10 +4055,7 @@ char *buf; else if (!strcmp(optname, "menu_invert_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_headings")) { - Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ? - "bold" : (iflags.menu_headings == ATR_INVERSE) ? - "inverse" : (iflags.menu_headings == ATR_ULINE) ? - "underline" : "unknown"); + Sprintf(buf, "%s", attr2attrname(iflags.menu_headings)); } else if (!strcmp(optname, "menu_invert_page")) Sprintf(buf, "%s", to_be_done); From f0699b76d9a6fde10ca1fc19870a7a4949c67559 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 21:09:26 +0300 Subject: [PATCH 06/17] Add is_watch define for watchmen --- include/mondata.h | 2 ++ src/dig.c | 3 +-- src/dokick.c | 6 ++---- src/fountain.c | 3 +-- src/mon.c | 9 +++------ src/monmove.c | 2 +- src/uhitm.c | 3 +-- 7 files changed, 11 insertions(+), 17 deletions(-) diff --git a/include/mondata.h b/include/mondata.h index 1a4d8eb9c..5043f8aaa 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -134,6 +134,8 @@ #define is_displacer(ptr) (((ptr)->mflags3 & M3_DISPLACES) != 0L) #define is_mplayer(ptr) (((ptr) >= &mons[PM_ARCHEOLOGIST]) && \ ((ptr) <= &mons[PM_WIZARD])) +#define is_watch(ptr) ((ptr) == &mons[PM_WATCHMAN] || \ + (ptr) == &mons[PM_WATCH_CAPTAIN]) #define is_rider(ptr) ((ptr) == &mons[PM_DEATH] || \ (ptr) == &mons[PM_FAMINE] || \ (ptr) == &mons[PM_PESTILENCE]) diff --git a/src/dig.c b/src/dig.c index 1d7d5dd7a..9f031f1c5 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1171,8 +1171,7 @@ watch_dig(mtmp, x, y, zap) if (!mtmp) { for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if ((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) && + if (is_watch(mtmp->data) && mtmp->mcansee && m_canseeu(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) break; diff --git a/src/dokick.c b/src/dokick.c index d558bdd38..6626c601c 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1198,8 +1198,7 @@ dumb: if (in_town(x, y)) for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) && + if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { if (canspotmon(mtmp)) @@ -1218,8 +1217,7 @@ dumb: if (in_town(x, y)) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if ((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) && + if (is_watch(mtmp->data) && mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) { if (canspotmon(mtmp)) pline("%s yells:", Amonnam(mtmp)); diff --git a/src/fountain.c b/src/fountain.c index 405fac4a3..03a373843 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -169,8 +169,7 @@ boolean isyou; /* Warn about future fountain use. */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if ((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) && + if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { pline("%s yells:", Amonnam(mtmp)); diff --git a/src/mon.c b/src/mon.c index 3a2fc402b..665ca989b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -3117,9 +3117,7 @@ register boolean silent; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if((mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) - && mtmp->mpeaceful) { + if (is_watch(mtmp->data) && mtmp->mpeaceful) { ct++; if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { if (distu(mtmp->mx, mtmp->my) == 2) nct++; @@ -3157,9 +3155,8 @@ pacify_guards() for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - if (mtmp->data == &mons[PM_WATCHMAN] || - mtmp->data == &mons[PM_WATCH_CAPTAIN]) - mtmp->mpeaceful = 1; + if (is_watch(mtmp->data)) + mtmp->mpeaceful = 1; } } diff --git a/src/monmove.c b/src/monmove.c index a7a3ca46f..990955861 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -400,7 +400,7 @@ register struct monst *mtmp; } /* the watch will look around and see if you are up to no good :-) */ - if (mdat == &mons[PM_WATCHMAN] || mdat == &mons[PM_WATCH_CAPTAIN]) + if (is_watch(mdat)) watch_on_duty(mtmp); else if (is_mind_flayer(mdat) && !rn2(20)) { diff --git a/src/uhitm.c b/src/uhitm.c index 19361c261..a7ecbed9b 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -516,8 +516,7 @@ int thrown; /* HMON_xxx (0 => hand-to-hand, other => ranged) */ anger_guards = (mon->mpeaceful && (mon->ispriest || mon->isshk || - mon->data == &mons[PM_WATCHMAN] || - mon->data == &mons[PM_WATCH_CAPTAIN])); + is_watch(mon->data))); result = hmon_hitmon(mon, obj, thrown); if (mon->ispriest && !rn2(2)) ghod_hitsu(mon); if (anger_guards) (void)angry_guards(!!Deaf); From 0903df974f5e0b30c592dbc648cd691fbc0a7d05 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 21:31:25 +0300 Subject: [PATCH 07/17] Unify guards yelling --- include/extern.h | 1 + src/dokick.c | 14 +++----------- src/monmove.c | 18 ++++++++++++++---- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/extern.h b/include/extern.h index 4bf8dbbf3..eb736303a 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1373,6 +1373,7 @@ E void FDECL(mon_regen, (struct monst *,BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int,int,struct monst *)); E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P)); +E void FDECL(mon_yells, (struct monst *, const char *)); E int FDECL(dochug, (struct monst *)); E int FDECL(m_move, (struct monst *,int)); E void FDECL(dissolve_bars, (int,int)); diff --git a/src/dokick.c b/src/dokick.c index 6626c601c..5a380fc91 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1201,11 +1201,7 @@ dumb: if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { - if (canspotmon(mtmp)) - pline("%s yells:", Amonnam(mtmp)); - else - You_hear("someone yell:"); - verbalize("Halt, thief! You're under arrest!"); + mon_yells(mtmp, "Halt, thief! You're under arrest!"); (void) angry_guards(FALSE); break; } @@ -1219,15 +1215,11 @@ dumb: if (DEADMONSTER(mtmp)) continue; if (is_watch(mtmp->data) && mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) { - if (canspotmon(mtmp)) - pline("%s yells:", Amonnam(mtmp)); - else - You_hear("someone yell:"); if(levl[x][y].looted & D_WARNED) { - verbalize("Halt, vandal! You're under arrest!"); + mon_yells(mtmp, "Halt, vandal! You're under arrest!"); (void) angry_guards(FALSE); } else { - verbalize("Hey, stop damaging that door!"); + mon_yells(mtmp, "Hey, stop damaging that door!"); levl[x][y].looted |= D_WARNED; } break; diff --git a/src/monmove.c b/src/monmove.c index 990955861..f98a58aca 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -50,6 +50,18 @@ boolean for_unlocking; /* true => credit card ok, false => not ok */ return m_carrying(mon, SKELETON_KEY) || m_carrying(mon, LOCK_PICK); } +void +mon_yells(mon, shout) +struct monst *mon; +const char *shout; +{ + if (canspotmon(mon)) + pline("%s yells:", Amonnam(mon)); + else + You_hear("someone yell:"); + verbalize(shout); +} + STATIC_OVL void watch_on_duty(mtmp) register struct monst *mtmp; @@ -63,13 +75,11 @@ register struct monst *mtmp; (levl[x][y].doormask & D_LOCKED)) { if(couldsee(mtmp->mx, mtmp->my)) { - - pline("%s yells:", Amonnam(mtmp)); if(levl[x][y].looted & D_WARNED) { - verbalize("Halt, thief! You're under arrest!"); + mon_yells(mtmp, "Halt, thief! You're under arrest!"); (void) angry_guards(!!Deaf); } else { - verbalize("Hey, stop picking that lock!"); + mon_yells(mtmp, "Hey, stop picking that lock!"); levl[x][y].looted |= D_WARNED; } stop_occupation(); From 86dc5cf5880412f8b641fa5c37353fef82c5a2fa Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Apr 2015 22:15:23 +0300 Subject: [PATCH 08/17] Unify getting terrain under drawbridge --- include/extern.h | 1 + src/dbridge.c | 12 ++++++++++++ src/dungeon.c | 7 +------ src/mkmaze.c | 7 +------ src/monmove.c | 13 ++++--------- 5 files changed, 19 insertions(+), 21 deletions(-) diff --git a/include/extern.h b/include/extern.h index eb736303a..a185be710 100644 --- a/include/extern.h +++ b/include/extern.h @@ -222,6 +222,7 @@ E boolean FDECL(is_lava, (int,int)); E boolean FDECL(is_pool_or_lava, (int,int)); E boolean FDECL(is_ice, (int,int)); E boolean FDECL(is_moat, (int,int)); +E schar FDECL(db_under_typ, (int)); E int FDECL(is_drawbridge_wall, (int,int)); E boolean FDECL(is_db_wall, (int,int)); E boolean FDECL(find_drawbridge, (int *,int*)); diff --git a/src/dbridge.c b/src/dbridge.c index 8c4b90031..e2aa105ab 100644 --- a/src/dbridge.c +++ b/src/dbridge.c @@ -103,6 +103,18 @@ int x, y; return FALSE; } +schar +db_under_typ(mask) +int mask; +{ + switch (mask & DB_UNDER) { + case DB_ICE: return ICE; break; + case DB_LAVA: return LAVAPOOL; break; + case DB_MOAT: return MOAT; break; + default: return STONE; break; + } +} + /* * We want to know whether a wall (or a door) is the portcullis (passageway) * of an eventual drawbridge. diff --git a/src/dungeon.c b/src/dungeon.c index 3d1bfcb65..95d6c0946 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -2207,12 +2207,7 @@ recalc_mapseen() if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) { ltyp = levl[x][y].typ; if (ltyp == DRAWBRIDGE_UP) - switch (levl[x][y].drawbridgemask & DB_UNDER) { - case DB_ICE: ltyp = ICE; break; - case DB_LAVA: ltyp = LAVAPOOL; break; - case DB_MOAT: ltyp = MOAT; break; - default: ltyp = STONE; break; - } + ltyp = db_under_typ(levl[x][y].drawbridgemask); if ((mtmp = m_at(x, y)) != 0 && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp)) ltyp = cmap_to_type(mtmp->mappearance); diff --git a/src/mkmaze.c b/src/mkmaze.c index 42851c0df..923a51f1d 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1157,12 +1157,7 @@ xchar x,y; lev = &levl[x][y]; ltyp = lev->typ; if (ltyp == DRAWBRIDGE_UP) - switch (lev->drawbridgemask & DB_UNDER) { - case DB_ICE: ltyp = ICE; break; - case DB_LAVA: ltyp = LAVAPOOL; break; - case DB_MOAT: ltyp = MOAT; break; - default: ltyp = STONE; break; - } + ltyp = db_under_typ(lev->drawbridgemask); if (ltyp == LAVAPOOL) return "lava"; diff --git a/src/monmove.c b/src/monmove.c index f98a58aca..9b4d47cce 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1305,15 +1305,10 @@ register int x, y; { int levtyp = levl[x][y].typ; - if (levtyp == DRAWBRIDGE_UP) { - /* use underlying terrain in front of closed drawbridge */ - switch (levl[x][y].drawbridgemask & DB_UNDER) { - case DB_MOAT: levtyp = MOAT; break; - case DB_LAVA: levtyp = LAVAPOOL; break; - case DB_ICE: levtyp = ICE; break; - case DB_FLOOR: levtyp = ROOM; break; - } - } + /* use underlying terrain in front of closed drawbridge */ + if (levtyp == DRAWBRIDGE_UP) + levtyp = db_under_typ(levl[x][y].drawbridgemask); + return (boolean)(ACCESSIBLE(levtyp) && !closed_door(x, y)); } From 3924b01e73dd6f93220b6d4d0c1d2642a32aa218 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 27 Apr 2015 23:42:06 -0400 Subject: [PATCH 09/17] trade a segfault for a panic Changes to be committed: modified: src/invent.c modified: src/options.c Apparently we need this based on Pasi's segfault. We just don't yet know why we need them. Also fix a warning: ..\src\options.c(1282) : warning C4101: 'tmp' : unreferenced local variable --- src/invent.c | 5 +++++ src/options.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/invent.c b/src/invent.c index b1aee908b..176d2b8d2 100644 --- a/src/invent.c +++ b/src/invent.c @@ -395,6 +395,7 @@ addinv(obj) struct obj *obj; { struct obj *otmp, *prev; + int saved_otyp = (int)obj->otyp; /* for panic */ if (obj->where != OBJ_FREE) panic("addinv: obj not free"); @@ -411,12 +412,16 @@ struct obj *obj; extra to quivered stack is more useful than to wielded one */ if (uquiver && merged(&uquiver, &obj)) { obj = uquiver; + if (!obj) + panic("addinv: null obj after quiver merge otyp=%d", saved_otyp); goto added; } /* merge if possible; find end of chain in the process */ for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) if (merged(&otmp, &obj)) { obj = otmp; + if (!obj) + panic("addinv: null obj after merge otyp=%d", saved_otyp); goto added; } /* didn't merge, so insert into chain */ diff --git a/src/options.c b/src/options.c index 7c0998917..fe83b2f1a 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 options.c $NHDT-Date: 1429953065 2015/04/25 09:11:05 $ $NHDT-Branch: master $:$NHDT-Revision: 1.186 $ */ +/* NetHack 3.5 options.c $NHDT-Date: 1430192504 2015/04/28 03:41:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.189 $ */ /* NetHack 3.5 options.c $Date: 2012/04/09 02:56:30 $ $Revision: 1.153 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1279,7 +1279,6 @@ add_menu_coloring(str) char *str; { int i, c = NO_COLOR, a = ATR_NONE; - struct menucoloring *tmp; char *tmps, *cs = strchr(str, '='); if (!cs || !str) return FALSE; From d9ac7f3de77d6b620971ec356c49a2531920c984 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Apr 2015 12:46:39 +0300 Subject: [PATCH 10/17] Exclude "grey" from color picker menu --- src/options.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/options.c b/src/options.c index fe83b2f1a..83d957537 100644 --- a/src/options.c +++ b/src/options.c @@ -1204,6 +1204,7 @@ query_color() start_menu(tmpwin); any = zeroany; for (i = 0; i < SIZE(colornames); i++) { + if (!strcmp(colornames[i].name, "grey")) continue; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, colornames[i].name, MENU_UNSELECTED); } From f83523eeb4daa4fce3d83f4a1b8eb10cdac9c51f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Apr 2015 14:13:01 +0300 Subject: [PATCH 11/17] Make spell list title obey menu_headings --- src/spell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spell.c b/src/spell.c index 3de41b5ec..bccb6a590 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1401,7 +1401,7 @@ int *spell_no; Sprintf(buf, "Name\tLevel\tCategory\tFail\tRetention"); fmt = "%s\t%-d\t%s\t%-d%%\t%s"; } - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { splnum = !spl_orderindx ? i : spl_orderindx[i]; Sprintf(buf, fmt, From d7688873858c0f7b59ad0ee2872914983723c572 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 28 Apr 2015 22:14:20 +0300 Subject: [PATCH 12/17] Unquiver gold before making it vanish This fixes a complaint for "deleting worn obj": If reading a cursed spellbook took your money, and the gold was quivered. --- src/sit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sit.c b/src/sit.c index fd4207af5..9f2c1d9e6 100644 --- a/src/sit.c +++ b/src/sit.c @@ -15,6 +15,7 @@ take_gold() nobj = otmp->nobj; if (otmp->oclass == COIN_CLASS) { lost_money = 1; + remove_worn_item(otmp, FALSE); delobj(otmp); } } From b8cfa9b33fe885e074183733cc83390068d4195e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 29 Apr 2015 16:28:01 +0300 Subject: [PATCH 13/17] Prevent monsters throwing items out of map If a monster was in the projectile's path, the projectile stopping checks would not be reached. The thrown object could fly up to the maximum range, through walls, or even outside the map. --- src/mthrowu.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index 1ff6cddc3..e8095332c 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -421,7 +421,8 @@ struct obj *obj; /* missile (or stack providing it) */ (void) drop_throw(singleobj, hitu, u.ux, u.uy); break; } - } else if (!range /* reached end of path */ + } + if (!range /* reached end of path */ /* missile hits edge of screen */ || !isok(bhitpos.x+dx,bhitpos.y+dy) /* missile hits the wall */ @@ -440,7 +441,7 @@ struct obj *obj; /* missile (or stack providing it) */ tmp_at(bhitpos.x, bhitpos.y); delay_output(); } - if (isok(bhitpos.x, bhitpos.y)) tmp_at(bhitpos.x, bhitpos.y); + tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); From 0d3c8584528591c9f85e3009b119f6403f8931a4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 29 Apr 2015 17:04:49 +0300 Subject: [PATCH 14/17] Check for valid coord in obj_nexto_xy --- src/mkobj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mkobj.c b/src/mkobj.c index a9d0ebfe8..699c5dbdb 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2194,7 +2194,7 @@ unsigned oid; for (fx = ex; abs(fx - ex) < 3; fx += dx) { for (fy = ey; abs(fy - ey) < 3; fy += dy) { /* 0, 0 was checked above */ - if (fx != x || fy != y) { + if (isok(fx,fy) && (fx != x || fy != y)) { if ((otmp = sobj_at(otyp, fx, fy)) != 0) { return otmp; } From 9edec130637e5872306230559d7d101578f3aeb4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 29 Apr 2015 20:35:46 +0300 Subject: [PATCH 15/17] Extract ball and chain before flooreffects --- src/ball.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ball.c b/src/ball.c index e1fa4b72a..c078f5ed3 100644 --- a/src/ball.c +++ b/src/ball.c @@ -112,12 +112,14 @@ placebc() return; } + obj_extract_self(uchain); (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */ if (carried(uball)) /* the ball is carried */ u.bc_order = BCPOS_DIFFER; else { /* ball might rust -- already checked when carried */ + obj_extract_self(uball); (void) flooreffects(uball, u.ux, u.uy, ""); place_object(uball, u.ux, u.uy); u.bc_order = BCPOS_CHAIN; From 97a5bdfb172b019963ee68cbf01e6405a68e328f Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 29 Apr 2015 20:54:11 -0400 Subject: [PATCH 16/17] comment rearranged Requested by Sean for some work he's doing for reindent. --- src/zap.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/zap.c b/src/zap.c index bec35c8dc..9d74271dc 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 zap.c $NHDT-Date: 1428207622 2015/04/05 04:20:22 $ $NHDT-Branch: nhmall-booktribute $:$NHDT-Revision: 1.215 $ */ +/* NetHack 3.5 zap.c $NHDT-Date: 1430355196 2015/04/30 00:53:16 $ $NHDT-Branch: master $:$NHDT-Revision: 1.218 $ */ /* NetHack 3.5 zap.c $Date: 2013/11/05 00:57:56 $ $Revision: 1.183 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2870,9 +2870,11 @@ int skill; else if (dex < 8) hit_bon -= 1; else if (dex < 14) - hit_bon -= 0; /* Will change when print stuff below removed */ + /* Will change when print stuff below removed */ + hit_bon -= 0; else - hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */ + /* Even increment for dextrous heroes (see weapon.c abon) */ + hit_bon += dex - 14; return hit_bon; } From fcfab90907805242e803502e39f516e7061cab5b Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 29 Apr 2015 23:53:31 -0400 Subject: [PATCH 17/17] fix a panic and infinite recursion Changes to be committed: modified: src/ball.c modified: src/display.c modified: src/mon.c --- src/ball.c | 20 +++++++++++++++----- src/display.c | 7 ++++++- src/mon.c | 4 ++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/ball.c b/src/ball.c index c078f5ed3..3cd8e0eae 100644 --- a/src/ball.c +++ b/src/ball.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 ball.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* NetHack 3.5 ball.c $NHDT-Date: 1430365884 2015/04/30 03:51:24 $ $NHDT-Branch: master $:$NHDT-Revision: 1.22 $ */ /* NetHack 3.5 ball.c $Date: 2011/08/30 22:13:26 $ $Revision: 1.17 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -102,7 +102,7 @@ ballfall() * It is assumed that when this is called, the ball and chain are NOT * attached to the object list. * - * Should not be called while swallowed. + * Should not be called while swallowed except on waterlevel. */ void placebc() @@ -112,14 +112,12 @@ placebc() return; } - obj_extract_self(uchain); (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */ if (carried(uball)) /* the ball is carried */ u.bc_order = BCPOS_DIFFER; else { /* ball might rust -- already checked when carried */ - obj_extract_self(uball); (void) flooreffects(uball, u.ux, u.uy, ""); place_object(uball, u.ux, u.uy); u.bc_order = BCPOS_CHAIN; @@ -135,7 +133,19 @@ placebc() void unplacebc() { - if (u.uswallow) return; /* ball&chain not placed while swallowed */ + if (u.uswallow) { + if (Is_waterlevel(&u.uz)) { + /* we need to proceed with the removal from the floor + * so that movebubbles() processing will disregard it as + * intended. Ignore all the vision stuff. + */ + if (!carried(uball)) + obj_extract_self(uball); + obj_extract_self(uchain); + } + /* ball&chain not unplaced while swallowed */ + return; + } if (!carried(uball)) { obj_extract_self(uball); diff --git a/src/display.c b/src/display.c index f2e18df61..3cd92f916 100644 --- a/src/display.c +++ b/src/display.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 display.c $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* NetHack 3.5 display.c $NHDT-Date: 1430365890 2015/04/30 03:51:30 $ $NHDT-Branch: master $:$NHDT-Revision: 1.49 $ */ /* NetHack 3.5 display.c $Date: 2011/12/05 03:17:36 $ $Revision: 1.34 $ */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ @@ -1363,11 +1363,16 @@ row_refresh(start,stop,y) void cls() { + static boolean in_cls = 0; + + if (in_cls) return; + in_cls = TRUE; display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ context.botlx = 1; /* force update of botl window */ clear_nhwindow(WIN_MAP); /* clear physical screen */ clear_glyph_buffer(); /* this is sort of an extra effort, but OK */ + in_cls = FALSE; } /* diff --git a/src/mon.c b/src/mon.c index 665ca989b..287b496d0 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.5 mon.c $NHDT-Date: 1429666918 2015/04/22 01:41:58 $ $NHDT-Branch: master $:$NHDT-Revision: 1.165 $ */ +/* NetHack 3.5 mon.c $NHDT-Date: 1430365894 2015/04/30 03:51:34 $ $NHDT-Branch: master $:$NHDT-Revision: 1.168 $ */ /* NetHack 3.5 mon.c $Date: 2012/05/16 02:15:10 $ $Revision: 1.126 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1850,7 +1850,7 @@ register struct monst *mtmp; u.uy = mtmp->my; u.uswallow = 0; u.uswldtim = 0; - if (Punished) placebc(); + if (BALL_IN_MON) placebc(); vision_full_recalc = 1; docrt(); }