diff --git a/doc/fixes36.3 b/doc/fixes36.3 index 756d69da9..dee5b5b40 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.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, @@ -191,6 +191,17 @@ 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] +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 @@ -348,6 +359,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/include/extern.h b/include/extern.h index f8544f150..3f55bdd0d 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. */ @@ -1048,7 +1048,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 *)); @@ -1375,6 +1376,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 257c12f98..9c2203799 100644 --- a/src/apply.c +++ b/src/apply.c @@ -377,10 +377,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; @@ -390,7 +395,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/invent.c b/src/invent.c index 9236528d2..85512038d 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. */ @@ -2951,30 +2951,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/mkobj.c b/src/mkobj.c index 300e29799..539b980f3 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 = cg.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 void check_contained(container, mesg) diff --git a/src/objnam.c b/src/objnam.c index aef37c6fa..1809de346 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. */ @@ -1041,7 +1041,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/options.c b/src/options.c index 6d95f02a7..5fc631d45 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. */ @@ -761,9 +761,9 @@ initoptions_init() */ /* this detects the IBM-compatible console on most 386 boxes */ if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) { - if (!g.symset[PRIMARY].name) + if (!g.symset[PRIMARY].explicitly) load_symset("IBMGraphics", PRIMARY); - if (!g.symset[ROGUESET].name) + if (!g.symset[ROGUESET].explicitly) load_symset("RogueIBM", ROGUESET); switch_symbols(TRUE); #ifdef TEXTCOLOR @@ -778,7 +778,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 (!g.symset[PRIMARY].name) + if (!g.symset[PRIMARY].explicitly) load_symset("DECGraphics", PRIMARY); switch_symbols(TRUE); } @@ -787,15 +787,13 @@ initoptions_init() #if defined(MSDOS) || defined(WIN32) /* Use IBM defaults. Can be overridden via config file */ - if (!g.symset[PRIMARY].name) { + if (!g.symset[PRIMARY].explicitly) load_symset("IBMGraphics_2", PRIMARY); - } - if (!g.symset[ROGUESET].name) { + if (!g.symset[ROGUESET].explicitly) load_symset("RogueEpyx", ROGUESET); - } #endif #ifdef MAC_GRAPHICS_ENV - if (!symset[PRIMARY].name) + if (!g.symset[PRIMARY].explicitly) load_symset("MACGraphics", PRIMARY); switch_symbols(TRUE); #endif /* MAC_GRAPHICS_ENV */ @@ -5303,7 +5301,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; g.symset_list = (struct symsetentry *) 0; @@ -5386,9 +5384,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 = g.symset_list; sl; sl = sl->next) { /* check restrictions */ @@ -5398,20 +5400,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); diff --git a/src/shk.c b/src/shk.c index d1fe08227..74c3ec669 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. */ @@ -2898,8 +2898,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)) { @@ -3196,9 +3196,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; } /* @@ -3214,14 +3214,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, @@ -3230,7 +3243,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