This is a slightly modified version of Scott Bigham's sticky patch, version 5. The differences are: - Re-worked for use with patchable Nethack. - The I command displays the sticky status. Bones/save compatibility: This patch uses 1 object bit in a bones-safe manner. As long as you don't add more than 6 object bits this patch is entirely bones compatible, and adding the patch is save compatible. See http://www.argon.org/~roderick/nethack/#object-bits for details. This patch is available at http://www.argon.org/~roderick/nethack/. Roderick Schertler diff -r -X /home/roderick/.diff-exclude -uN base.patchable/dat/cmdhelp work.sticky/dat/cmdhelp --- base.patchable/dat/cmdhelp 2003-02-23 09:43:15.000000000 -0500 +++ work.sticky/dat/cmdhelp 2003-03-23 10:06:34.000000000 -0500 @@ -119,3 +119,4 @@ M-u Untrap something (trap, door, or chest) M-v Print compile time options for this version of NetHack M-w Wipe off your face +M-y Set 'sticky' inventory slots (if STICKY_OBJECTS compile option set) diff -r -X /home/roderick/.diff-exclude -uN base.patchable/dat/hh work.sticky/dat/hh --- base.patchable/dat/hh 2003-02-23 09:43:16.000000000 -0500 +++ work.sticky/dat/hh 2003-03-23 10:06:34.000000000 -0500 @@ -104,6 +104,7 @@ M-u untrap untrap something M-v version print compile time options for this version M-w wipe wipe off your face +M-y sticky set 'sticky' inventory slots (if compiled in) If the "number_pad" option is on, these additional variants are available: diff -r -X /home/roderick/.diff-exclude -uN base.patchable/doc/Guidebook.mn work.sticky/doc/Guidebook.mn --- base.patchable/doc/Guidebook.mn 2003-02-23 09:43:18.000000000 -0500 +++ work.sticky/doc/Guidebook.mn 2003-03-23 10:06:34.000000000 -0500 @@ -707,6 +707,13 @@ Rub a lamp or a stone. .lp #sit Sit down. +.lp #sticky +Toggle the 'stickiness' of an object. An object marked 'sticky' will try +harder to keep its inventory letter (as per the +.op fixinv +option), displacing any other object that might have taken its inventory +letter after it was dropped. Only available if the STICKY_OBJECTS option +was enabled at compile-time. .lp #turn Turn undead. .lp #twoweapon @@ -773,6 +780,8 @@ #version .lp M-w #wipe +.lp M-y +#sticky (if compiled in) .pg If the .op number_pad diff -r -X /home/roderick/.diff-exclude -uN base.patchable/doc/Guidebook.tex work.sticky/doc/Guidebook.tex --- base.patchable/doc/Guidebook.tex 2003-02-23 09:43:18.000000000 -0500 +++ work.sticky/doc/Guidebook.tex 2003-03-23 10:06:34.000000000 -0500 @@ -941,6 +941,14 @@ \item[\tb{\#sit}] Sit down. %.lp +\item[\tb{\#sticky}] +Toggle the 'stickiness' of an object. An object marked 'sticky' will try +harder to keep its inventory letter (as per the +{\it fixinv\/} +option), displacing any other object that might have taken its inventory +letter after it was dropped. Only available if the {\tt STICKY\_OBJECTS} +option was enabled at compile time. +%.lp \item[\tb{\#turn}] Turn undead. %.lp @@ -1036,6 +1044,9 @@ %.lp \item[\tb{M-w}] {\tt\#wipe} +%.lp +\item[\tb{M-y}] +{\tt\#sticky} (if compiled in) \elist %.pg diff -r -X /home/roderick/.diff-exclude -uN base.patchable/include/config.h work.sticky/include/config.h --- base.patchable/include/config.h 2003-03-20 16:41:57.000000000 -0500 +++ work.sticky/include/config.h 2003-03-23 10:07:07.000000000 -0500 @@ -364,6 +364,12 @@ /* * options patch point; see $top/README.patchable */ + +#define STICKY_OBJECTS /* "sticky" inventory slot */ + +/* + * options patch point; see $top/README.patchable + */ /* * options patch point; see $top/README.patchable */ diff -r -X /home/roderick/.diff-exclude -uN base.patchable/include/extern.h work.sticky/include/extern.h --- base.patchable/include/extern.h 2003-02-23 09:43:20.000000000 -0500 +++ work.sticky/include/extern.h 2003-03-23 10:06:34.000000000 -0500 @@ -803,6 +803,9 @@ E void NDECL(free_invbuf); E void NDECL(reassign); E int NDECL(doorganize); +#ifdef STICKY_OBJECTS +E int NDECL(dosticky); +#endif /* STICKY_OBJECTS */ E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_buc, (struct obj *,int)); E void FDECL(carry_obj_effects, (struct obj *)); diff -r -X /home/roderick/.diff-exclude -uN base.patchable/include/obj.h work.sticky/include/obj.h --- base.patchable/include/obj.h 2003-03-20 16:41:57.000000000 -0500 +++ work.sticky/include/obj.h 2003-03-23 10:06:34.000000000 -0500 @@ -91,6 +91,12 @@ /* * obj bitfield patch point; see $top/README.patchable */ +#ifdef STICKY_OBJECTS + Bitfield(sticky,1); /* "sticky" inventory slot */ +#endif + /* + * obj bitfield patch point; see $top/README.patchable + */ /* * obj bitfield patch point; see $top/README.patchable */ diff -r -X /home/roderick/.diff-exclude -uN base.patchable/src/bones.c work.sticky/src/bones.c --- base.patchable/src/bones.c 2003-03-20 16:41:56.000000000 -0500 +++ work.sticky/src/bones.c 2003-03-23 10:06:34.000000000 -0500 @@ -85,6 +85,12 @@ /* * resetobjs patch point; see $top/README.patchable */ +#ifdef STICKY_OBJECTS + otmp->sticky = 0; +#endif /* STICKY_OBJECTS */ + /* + * resetobjs patch point; see $top/README.patchable + */ /* * resetobjs patch point; see $top/README.patchable */ diff -r -X /home/roderick/.diff-exclude -uN base.patchable/src/cmd.c work.sticky/src/cmd.c --- base.patchable/src/cmd.c 2003-02-23 09:43:25.000000000 -0500 +++ work.sticky/src/cmd.c 2003-03-23 10:06:34.000000000 -0500 @@ -97,6 +97,9 @@ extern int NDECL(dowieldquiver); /**/ extern int NDECL(dozap); /**/ extern int NDECL(doorganize); /**/ +#ifdef STICKY_OBJECTS +extern int NDECL(dosticky); /**/ +#endif /* STICKY_OBJECTS */ #endif /* DUMB */ #ifdef OVL1 @@ -1431,6 +1434,9 @@ {'x', FALSE, doswapweapon}, {'X', TRUE, enter_explore_mode}, /* 'y', 'Y' : go nw */ +#ifdef STICKY_OBJECTS + {M('y'), TRUE, dosticky}, +#endif /* STICKY_OBJECTS */ {'z', FALSE, dozap}, {'Z', TRUE, docast}, {'<', FALSE, doup}, @@ -1485,6 +1491,9 @@ #endif {"rub", "rub a lamp or a stone", dorub, FALSE}, {"sit", "sit down", dosit, FALSE}, +#ifdef STICKY_OBJECTS + {"sticky", "set 'sticky' inventory slots", dosticky, TRUE}, +#endif /* STICKY_OBJECTS */ {"turn", "turn undead", doturn, TRUE}, {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE}, {"untrap", "untrap something", dountrap, FALSE}, diff -r -X /home/roderick/.diff-exclude -uN base.patchable/src/invent.c work.sticky/src/invent.c --- base.patchable/src/invent.c 2003-02-23 09:43:27.000000000 -0500 +++ work.sticky/src/invent.c 2003-03-23 10:06:34.000000000 -0500 @@ -31,6 +31,9 @@ #ifdef OVLB +#ifdef STICKY_OBJECTS +boolean sticky_inv_hack = 0; /* blech ick yuck... */ +#endif /* STICKY_OBJECTS */ static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */ #ifdef WIZARD @@ -159,6 +162,9 @@ struct obj **potmp, **pobj; { register struct obj *otmp = *potmp, *obj = *pobj; +#ifdef STICKY_OBJECTS + boolean sticky_hack = 0; +#endif /* STICKY_OBJECTS */ if(mergable(otmp, obj)) { /* Approximate age: we do it this way because if we were to @@ -223,8 +229,20 @@ } #endif /*0*/ +#ifdef STICKY_OBJECTS + if (flags.invlet_constant && obj->invlet && + obj->sticky && !otmp->sticky) { + otmp->invlet = obj->invlet; + otmp->sticky = 1; + sticky_hack = 1; + } +#endif /* STICKY_OBJECTS */ obfree(obj,otmp); /* free(obj), bill->otmp */ return(1); +#ifdef STICKY_OBJECTS + /* if we're not merging in inventory, this will be a nop */ + if (sticky_hack) reorder_invent(); +#endif /* STICKY_OBJECTS */ } return 0; } @@ -302,6 +320,10 @@ struct obj *obj; { struct obj *otmp, *prev; +#ifdef STICKY_OBJECTS + struct obj *otmp2; + char save_invlet = '\0'; +#endif /* STICKY_OBJECTS */ if (obj->where != OBJ_FREE) panic("addinv: obj not free"); @@ -314,6 +336,16 @@ return obj; #endif +#ifdef STICKY_OBJECTS + /* if object is sticky, find the object we'll be displacing */ + if (flags.invlet_constant && obj->invlet && obj->sticky) { + save_invlet = obj->invlet; + for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) + if (otmp2->invlet == save_invlet) + break; + } +#endif /* STICKY_OBJECTS */ + /* 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)) { @@ -322,7 +354,15 @@ } /* didn't merge, so insert into chain */ if (flags.invlet_constant || !prev) { - if (flags.invlet_constant) assigninvlet(obj); + if (flags.invlet_constant) { + assigninvlet(obj); +#ifdef STICKY_OBJECTS + if (save_invlet) { + if (otmp2) otmp2->invlet = obj->invlet; + obj->invlet = save_invlet; + } +#endif /* STICKY_OBJECTS */ + } obj->nobj = invent; /* insert at beginning */ invent = obj; if (flags.invlet_constant) reorder_invent(); @@ -1614,9 +1654,16 @@ #endif } else { /* ordinary inventory display or pickup message */ +#ifndef STICKY_OBJECTS Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), (dot ? "." : "")); +#else + Sprintf(li, "%c %c %s%s", + (use_invlet ? obj->invlet : let), + (use_invlet && obj->sticky ? '=' : '-'), + (txt ? txt : doname(obj)), (dot ? "." : "")); +#endif /* STICKY_OBJECTS */ } if (savequan) obj->quan = savequan; @@ -1751,9 +1798,19 @@ classcount++; } any.a_char = ilet; +#ifdef STICKY_OBJECTS + /* + * Yes, this is evil and disgusting. If you + * have a better way of doing this, jump on it. + */ + sticky_inv_hack = otmp->sticky; +#endif /* STICKY_OBJECTS */ add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); +#ifdef STICKY_OBJECTS + sticky_inv_hack = 0; +#endif /* STICKY_OBJECTS */ } } } @@ -2689,6 +2746,23 @@ return(0); } +#ifdef STICKY_OBJECTS +int +dosticky() /* toggle "sticky" inventory slot */ +{ + struct obj *obj; + char allowall[2]; + + /* get a pointer to the object the user wants to modify */ + allowall[0] = ALL_CLASSES; allowall[1] = '\0'; + if (!(obj = getobj(allowall,"mark"))) return 0; + + obj->sticky = !obj->sticky; + prinv(obj->sticky ? "Marking:" : "Unmarking:", obj, 0L); + return(0); +} +#endif /* STICKY_OBJECTS */ + /* common to display_minventory and display_cinventory */ STATIC_OVL void invdisp_nothing(hdr, txt) diff -r -X /home/roderick/.diff-exclude -uN base.patchable/src/pickup.c work.sticky/src/pickup.c --- base.patchable/src/pickup.c 2003-02-23 09:43:29.000000000 -0500 +++ work.sticky/src/pickup.c 2003-03-23 10:06:34.000000000 -0500 @@ -53,6 +53,9 @@ /* if you can figure this out, give yourself a hearty pat on the back... */ #define GOLD_CAPACITY(w,n) (((w) * -100L) - ((n) + 50L) - 1L) +#ifdef STICKY_OBJECTS +extern boolean sticky_inv_hack; /* blech ick yuck */ +#endif /* STICKY_OBJECTS */ static const char moderateloadmsg[] = "You have a little trouble lifting"; static const char nearloadmsg[] = "You have much trouble lifting"; static const char overloadmsg[] = "You have extreme difficulty lifting"; @@ -692,10 +695,20 @@ } any.a_obj = curr; +#ifdef STICKY_OBJECTS + /* + * Yes, this is evil and disgusting. If you + * have a better way of doing this, jump on it. + */ + sticky_inv_hack = curr->sticky; +#endif /* STICKY_OBJECTS */ add_menu(win, obj_to_glyph(curr), &any, qflags & USE_INVLET ? curr->invlet : 0, def_oc_syms[(int)objects[curr->otyp].oc_class], ATR_NONE, doname(curr), MENU_UNSELECTED); +#ifdef STICKY_OBJECTS + sticky_inv_hack = 0; +#endif /* STICKY_OBJECTS */ } pack++; } while (qflags & INVORDER_SORT && *pack); diff -r -X /home/roderick/.diff-exclude -uN base.patchable/util/makedefs.c work.sticky/util/makedefs.c --- base.patchable/util/makedefs.c 2003-03-20 16:41:56.000000000 -0500 +++ work.sticky/util/makedefs.c 2003-03-23 10:06:34.000000000 -0500 @@ -752,6 +752,12 @@ /* * patch list patch point; see $top/README.patchable */ +#ifdef STICKY_OBJECTS + "patch: sticky objects v5-patchable", +#endif + /* + * patch list patch point; see $top/README.patchable + */ /* * patch list patch point; see $top/README.patchable */ diff -r -X /home/roderick/.diff-exclude -uN base.patchable/win/X11/winmenu.c work.sticky/win/X11/winmenu.c --- base.patchable/win/X11/winmenu.c 2003-02-23 09:43:49.000000000 -0500 +++ work.sticky/win/X11/winmenu.c 2003-03-23 10:06:34.000000000 -0500 @@ -67,6 +67,10 @@ #define reset_menu_count(mi) ((mi)->counting = FALSE, (mi)->menu_count = 0L) +#ifdef STICKY_OBJECTS +extern boolean sticky_inv_hack; /* blech ick yuck */ +#endif /* STICKY_OBJECTS */ + static const char menu_translations[] = "#override\n\ @@ -633,6 +637,13 @@ len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : ' '); +#ifdef STICKY_OBJECTS + /* + * Yes, this is a disgustingly ugly way of doing this. If you have + * a better idea, jump on it. + */ + if (sticky_inv_hack) buf[2] = '='; +#endif /* STICKY_OBJECTS */ (void) strncpy(buf+4, str, len); buf[4+len] = '\0'; item->str = copy_of(buf); diff -r -X /home/roderick/.diff-exclude -uN base.patchable/win/tty/wintty.c work.sticky/win/tty/wintty.c --- base.patchable/win/tty/wintty.c 2003-02-23 09:43:46.000000000 -0500 +++ work.sticky/win/tty/wintty.c 2003-03-23 10:06:34.000000000 -0500 @@ -110,6 +110,9 @@ #endif }; +#ifdef STICKY_OBJECTS +extern boolean sticky_inv_hack; /* blech ick yuck */ +#endif /* STICKY_OBJECTS */ static int maxwin = 0; /* number of windows in use */ winid BASE_WINDOW; struct WinDesc *wins[MAXWIN]; @@ -1997,6 +2000,13 @@ len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : '?'); +#ifdef STICKY_OBJECTS + /* + * Yes, this is a disgustingly ugly way of doing this. If you have + * a better idea, jump on it. + */ + if (sticky_inv_hack) buf[2] = '='; +#endif /* STICKY_OBJECTS */ (void) strncpy(buf+4, str, len); buf[4+len] = '\0'; newstr = buf;