From f1146757393a1401730fe4d6c03a30245efb3c7b Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 18 Oct 2019 15:00:16 -0700 Subject: [PATCH 1/3] containers in shops Fix a couple of bugs I stumbled across while testing something else. The sell prompt for a container dropped in a shop had phrasing issues. This fixes a couple but there are more. The message composition assumes that contents fall into two categories: those already owned by the shop and those the shopkeeper is offering to buy from the hero. But there is a third: stuff the shopkeeper doesn't care about so won't buy. The count_contents() routine can supply total contents or shop-owned contents. Subtracting one from the other yields combined hero-owned without any way to separate out shk-cares and don't-care. --- doc/fixes36.3 | 11 ++++++++++- include/extern.h | 5 +++-- src/invent.c | 22 ++++++++++++---------- src/objnam.c | 4 ++-- src/shk.c | 27 ++++++++++++++++++++------- 5 files changed, 47 insertions(+), 22 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 756d69da9..b3c2dcead 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.141 $ $NHDT-Date: 1571363147 2019/10/18 01:45:47 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.142 $ $NHDT-Date: 1571435999 2019/10/18 21:59:59 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -191,6 +191,15 @@ yellow dragons had green breath partly eaten food in a bones level shop would show a non-zero sale price while on the floor but not be placed on shop bill if picked up; sale price should have been "no charge" +when non-empty container is dropped in shop and hero is asked whether to sell, + counting the subset of contents owned by hero vs those owned by shk + could obtain wrong answer because the container had been placed on + the floor but the 'unpaid' and 'no_charge' flags of its contents + hadn't been updated yet, they were still set for when it was carried +in a shop which doesn't care about tools: You drop a containing 1 item. + offers you for your items in your . Sell them? + [plural 'items' and 'them' were including the box along with the one + item in it even though shk was only offering to buy its contents] Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index d4e255744..e2fd85dca 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1567213888 2019/08/31 01:11:28 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.728 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1571436000 2019/10/18 22:00:00 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.730 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1047,7 +1047,8 @@ E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_buc, (struct obj *, int, boolean (*)(OBJ_P))); E void FDECL(tally_BUCX, (struct obj *, BOOLEAN_P, int *, int *, int *, int *, int *)); -E long FDECL(count_contents, (struct obj *, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); +E long FDECL(count_contents, (struct obj *, + BOOLEAN_P, BOOLEAN_P, BOOLEAN_P, BOOLEAN_P)); E void FDECL(carry_obj_effects, (struct obj *)); E const char *FDECL(currency, (long)); E void FDECL(silly_thing, (const char *, struct obj *)); diff --git a/src/invent.c b/src/invent.c index be2a24497..0e11e52f4 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 invent.c $NHDT-Date: 1570566378 2019/10/08 20:26:18 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.264 $ */ +/* NetHack 3.6 invent.c $NHDT-Date: 1571436003 2019/10/18 22:00:03 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.265 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2961,30 +2961,32 @@ int *bcp, *ucp, *ccp, *xcp, *ocp; /* count everything inside a container, or just shop-owned items inside */ long -count_contents(container, nested, quantity, everything) +count_contents(container, nested, quantity, everything, newdrop) struct obj *container; boolean nested, /* include contents of any nested containers */ quantity, /* count all vs count separate stacks */ - everything; /* all objects vs only unpaid objects */ + everything, /* all objects vs only unpaid objects */ + newdrop; /* on floor, but hero-owned items haven't been marked + * no_charge yet and shop-owned items are still marked + * unpaid -- used when asking the player whether to sell */ { struct obj *otmp, *topc; boolean shoppy = FALSE; long count = 0L; - if (!everything) { + if (!everything && !newdrop) { + xchar x, y; + for (topc = container; topc->where == OBJ_CONTAINED; topc = topc->ocontainer) continue; - if (topc->where == OBJ_FLOOR) { - xchar x, y; - - (void) get_obj_location(topc, &x, &y, CONTAINED_TOO); + if (topc->where == OBJ_FLOOR && get_obj_location(topc, &x, &y, 0)) shoppy = costly_spot(x, y); - } } for (otmp = container->cobj; otmp; otmp = otmp->nobj) { if (nested && Has_contents(otmp)) - count += count_contents(otmp, nested, quantity, everything); + count += count_contents(otmp, nested, quantity, everything, + newdrop); if (everything || otmp->unpaid || (shoppy && !otmp->no_charge)) count += quantity ? otmp->quan : 1L; } diff --git a/src/objnam.c b/src/objnam.c index 59b6397cd..5903e3b9b 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1562186589 2019/07/03 20:43:09 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.245 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1571436005 2019/10/18 22:00:05 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.247 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1047,7 +1047,7 @@ unsigned doname_flags; /* we count the number of separate stacks, which corresponds to the number of inventory slots needed to be able to take everything out if no merges occur */ - long itemcount = count_contents(obj, FALSE, FALSE, TRUE); + long itemcount = count_contents(obj, FALSE, FALSE, TRUE, FALSE); Sprintf(eos(bp), " containing %ld item%s", itemcount, plur(itemcount)); diff --git a/src/shk.c b/src/shk.c index 0cb7e2ab1..f111b3dcc 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 shk.c $NHDT-Date: 1571363715 2019/10/18 01:55:15 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.170 $ */ +/* NetHack 3.6 shk.c $NHDT-Date: 1571436007 2019/10/18 22:00:07 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.171 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2904,8 +2904,8 @@ boolean peaceful, silent; /* gather information for message(s) prior to manipulating bill */ was_unpaid = obj->unpaid ? TRUE : FALSE; if (Has_contents(obj)) { - c_count = count_contents(obj, TRUE, FALSE, TRUE); - u_count = count_contents(obj, TRUE, FALSE, FALSE); + c_count = count_contents(obj, TRUE, FALSE, TRUE, FALSE); + u_count = count_contents(obj, TRUE, FALSE, FALSE, FALSE); } if (!billable(&shkp, obj, roomno, FALSE)) { @@ -3209,9 +3209,9 @@ xchar x, y; if (container) { /* number of items owned by shk */ - shksc = count_contents(obj, TRUE, TRUE, FALSE); + shksc = count_contents(obj, TRUE, TRUE, FALSE, TRUE); /* number of items owned by you (total - shksc) */ - yourc = count_contents(obj, TRUE, TRUE, TRUE) - shksc; + yourc = count_contents(obj, TRUE, TRUE, TRUE, TRUE) - shksc; only_partially_your_contents = shksc && yourc; } /* @@ -3227,14 +3227,27 @@ xchar x, y; (The case where it has contents already entirely owned by the shk is treated the same was if it were empty since the hero isn't selling any of those contents.) - Your container: + Your container and shk is willing to buy it: "... your . Sell it?" "... your and its contents. Sell them?" "... your and item inside. Sell them?" "... your and items inside. Sell them?" + Your container but shk only cares about the contents: + "... your item in your . Sell it?" + "... your items in your . Sell them?" Shk's container: "... your item in the . Sell it?" "... your items in the . Sell them?" + FIXME: + "your items" should sometimes be "some of your items" + (when container has some stuff the shk is willing to buy + and other stuff he or she doesn't care about); likewise, + "your item" should sometimes be "one of your items". + That would make the prompting even more verbose so + living without it might be a good thing. + FIXME too: + when container's contents are unknown, plural "items" + should be used to not give away information. */ Sprintf(qbuf, "%s offers%s %ld gold piece%s for %s%s ", Shknam(shkp), short_funds ? " only" : "", offer, @@ -3243,7 +3256,7 @@ xchar x, y; ? ((yourc == 1L) ? "your item in " : "your items in ") : "", obj->unpaid ? "the" : "your"); - one = obj->unpaid ? (yourc == 1L) : (obj->quan == 1L && !cltmp); + one = !ltmp ? (yourc == 1L) : (obj->quan == 1L && !cltmp); Sprintf(qsfx, "%s. Sell %s?", (cltmp && ltmp) ? (only_partially_your_contents From 46225955bc98afeac51d2cfbfe47aac6be140f2a Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 18 Oct 2019 18:23:47 -0700 Subject: [PATCH 2/3] symset and roguesymset options For 'O's menu, make the current symbol set be pre-selected so that the set in use is clearly marked while contemplating changing it. Using Return or Enter will pick it again; Escape is now needed to deliberately not make any selection. Also, change several symbol set initializations to use the new method of deciding whether the default symbols are still in place. --- doc/fixes36.3 | 3 ++- src/options.c | 50 +++++++++++++++++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index b3c2dcead..b787a3c1e 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.142 $ $NHDT-Date: 1571435999 2019/10/18 21:59:59 $ +$NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.143 $ $NHDT-Date: 1571448220 2019/10/19 01:23:40 $ This fixes36.3 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.2 in May 2019. Please note, however, @@ -357,6 +357,7 @@ status highlighting using percentage rules now supported for experience level the start of the current Xp level to the start of the next Xp level; 100% isn't possible so used as special case for next_Xp_lvl - 1 Exp_pt wizard-mode: display effect to show where an unseen wished-for monster landed +for 'O's symset and roguesymset menus, mark current symbol set as preselected curses: enable latent mouse support curses: give menus and text windows a minimum size of 5x25 since tiny ones can sometimes be overlooked when shown over old messages rather than map diff --git a/src/options.c b/src/options.c index ddbe794f8..f4975688a 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1571347977 2019/10/17 21:32:57 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.379 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1571448220 2019/10/19 01:23:40 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.380 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -784,9 +784,9 @@ initoptions_init() */ /* this detects the IBM-compatible console on most 386 boxes */ if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) { - if (!symset[PRIMARY].name) + if (!symset[PRIMARY].explicitly) load_symset("IBMGraphics", PRIMARY); - if (!symset[ROGUESET].name) + if (!symset[ROGUESET].explicitly) load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); #ifdef TEXTCOLOR @@ -801,7 +801,7 @@ initoptions_init() /* [could also check "xterm" which emulates vtXXX by default] */ && !strncmpi(opts, "vt", 2) && AS && AE && index(AS, '\016') && index(AE, '\017')) { - if (!symset[PRIMARY].name) + if (!symset[PRIMARY].explicitly) load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } @@ -810,15 +810,13 @@ initoptions_init() #if defined(MSDOS) || defined(WIN32) /* Use IBM defaults. Can be overridden via config file */ - if (!symset[PRIMARY].name) { + if (!symset[PRIMARY].explicitly) load_symset("IBMGraphics_2", PRIMARY); - } - if (!symset[ROGUESET].name) { + if (!symset[ROGUESET].explicitly) load_symset("RogueEpyx", ROGUESET); - } #endif #ifdef MAC_GRAPHICS_ENV - if (!symset[PRIMARY].name) + if (!symset[PRIMARY].explicitly) load_symset("MACGraphics", PRIMARY); switch_symbols(TRUE); #endif /* MAC_GRAPHICS_ENV */ @@ -5368,7 +5366,7 @@ boolean setinitial, setfromfile; nothing_to_do = FALSE; char *symset_name, fmtstr[20]; struct symsetentry *sl; - int res, which_set, setcount = 0, chosen = -2; + int res, which_set, setcount = 0, chosen = -2, defindx = 0; which_set = rogueflag ? ROGUESET : PRIMARY; symset_list = (struct symsetentry *) 0; @@ -5451,9 +5449,13 @@ boolean setinitial, setfromfile; #else nhUse(big_desc); #endif - any.a_int = 1; + any.a_int = 1; /* -1 + 2 [see 'if (sl->name) {' below]*/ + if (!symset_name) + defindx = any.a_int; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, - "Default Symbols", MENU_UNSELECTED); + "Default Symbols", + (any.a_int == defindx) ? MENU_SELECTED + : MENU_UNSELECTED); for (sl = symset_list; sl; sl = sl->next) { /* check restrictions */ @@ -5463,20 +5465,34 @@ boolean setinitial, setfromfile; if (sl->handling == H_MAC) continue; #endif - if (sl->name) { + /* +2: sl->idx runs from 0 to N-1 for N symsets; + +1 because Defaults are implicitly in slot [0]; + +1 again so that valid data is never 0 */ any.a_int = sl->idx + 2; + if (symset_name && !strcmpi(sl->name, symset_name)) + defindx = any.a_int; Sprintf(buf, fmtstr, sl->name, sl->desc ? sl->desc : ""); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, - buf, MENU_UNSELECTED); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, + (any.a_int == defindx) ? MENU_SELECTED + : MENU_UNSELECTED); } } Sprintf(buf, "Select %ssymbol set:", rogueflag ? "rogue level " : ""); end_menu(tmpwin, buf); - if (select_menu(tmpwin, PICK_ONE, &symset_pick) > 0) { - chosen = symset_pick->item.a_int - 2; + n = select_menu(tmpwin, PICK_ONE, &symset_pick); + if (n > 0) { + chosen = symset_pick[0].item.a_int; + /* if picking non-preselected entry yields 2, make sure + that we're going with the non-preselected one */ + if (n == 2 && chosen == defindx) + chosen = symset_pick[1].item.a_int; + chosen -= 2; /* convert menu index to symset index; + * "Default symbols" have index -1 */ free((genericptr_t) symset_pick); + } else if (n == 0 && defindx > 0) { + chosen = defindx - 2; } destroy_nhwindow(tmpwin); From c099e0a1ffbd16de41860cfa7dc10681d829d69f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 19 Oct 2019 12:05:33 -0400 Subject: [PATCH 3/3] grammar fix for "That walking shoes is really a small mimic" --- doc/fixes36.3 | 2 ++ include/extern.h | 1 + src/apply.c | 11 +++++++++-- src/mkobj.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) diff --git a/doc/fixes36.3 b/doc/fixes36.3 index b787a3c1e..dee5b5b40 100644 --- a/doc/fixes36.3 +++ b/doc/fixes36.3 @@ -200,6 +200,8 @@ in a shop which doesn't care about tools: You drop a containing 1 item. offers you for your items in your . Sell them? [plural 'items' and 'them' were including the box along with the one item in it even though shk was only offering to buy its contents] +grammar correction for "That walking shoes is really a small mimic" when + applying a stethoscope Fixes to Post-3.6.2 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index e2fd85dca..8552e195f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1379,6 +1379,7 @@ E struct obj *FDECL(obj_nexto_xy, (struct obj *, int, int, BOOLEAN_P)); E struct obj *FDECL(obj_absorb, (struct obj **, struct obj **)); E struct obj *FDECL(obj_meld, (struct obj **, struct obj **)); E void FDECL(pudding_merge_message, (struct obj *, struct obj *)); +E struct obj *FDECL(init_dummyobj, (struct obj *, SHORT_P, long)); /* ### mkroom.c ### */ diff --git a/src/apply.c b/src/apply.c index 11bd09d03..3c11c6114 100644 --- a/src/apply.c +++ b/src/apply.c @@ -383,10 +383,15 @@ register struct obj *obj; newsym(mtmp->mx, mtmp->my); } else if (mtmp->mappearance) { const char *what = "thing"; + boolean use_plural = FALSE; + struct obj dummyobj, *odummy; switch (M_AP_TYPE(mtmp)) { case M_AP_OBJECT: - what = simple_typename(mtmp->mappearance); + odummy = init_dummyobj(&dummyobj, mtmp->mappearance, 1L); + what = simple_typename(odummy->otyp); + use_plural = (is_boots(odummy) || is_gloves(odummy) + || odummy->otyp == LENSES); break; case M_AP_MONSTER: /* ignore Hallucination here */ what = mons[mtmp->mappearance].mname; @@ -396,7 +401,9 @@ register struct obj *obj; break; } seemimic(mtmp); - pline("That %s is really %s.", what, mnm); + pline("%s %s %s really %s.", + use_plural ? "Those" : "That", what, + use_plural ? "are" : "is", mnm); } else if (flags.verbose && !canspotmon(mtmp)) { There("is %s there.", mnm); } diff --git a/src/mkobj.c b/src/mkobj.c index 6975ca966..6f5abbcc0 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2470,6 +2470,38 @@ struct monst *mon; } } +/* + * Initialize a dummy obj with just enough info + * to allow some of the tests in obj.h that + * take an obj pointer to work. + * + */ +struct obj * +init_dummyobj(obj, otyp, oquan) +struct obj *obj; +short otyp; +long oquan; +{ + if (obj) { + *obj = zeroobj; + obj->otyp = otyp; + obj->oclass = objects[otyp].oc_class; + /* obj->dknown = 0; */ + /* suppress known except for amulets (needed for fakes and real A-of-Y) */ + obj->known = (obj->oclass == AMULET_CLASS) + ? obj->known + /* default is "on" for types which don't use it */ + : !objects[otyp].oc_uses_known; + obj->quan = oquan ? oquan : 1L; + obj->corpsenm = NON_PM; /* suppress statue and figurine details */ + /* but suppressing fruit details leads to "bad fruit #0" + [perhaps we should force "slime mold" rather than use xname?] */ + if (obj->otyp == SLIME_MOLD) + obj->spe = 1; + } + return obj; +} + /* obj sanity check: check objects inside container */ STATIC_OVL void check_contained(container, mesg)