diff -pruN slashem-0.0.8E0-official/dat/opthelp slashem-0.0.8E0-loot/dat/opthelp --- slashem-0.0.8E0-official/dat/opthelp 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/dat/opthelp 2005-12-11 23:54:07.000000000 +0100 @@ -53,6 +53,10 @@ verbose print more commentary dur There are further boolean options controlled by compilation flags. +Boolean option if ITEMCAT was set at compile time: +like_swimming allow category "Items known to be Rustprone" in + selection menus [FALSE] + Boolean option if INSURANCE was set at compile time: checkpoint save game state after each level change, for possible [TRUE] recovery after program crash @@ -138,6 +142,12 @@ runmode controls how often the map scores the parts of the score list you wish to see when the game ends You choose a combination of top scores, scores around the top scores, and all of your own scores. [!own/3 top/2 around] +sortloot controls the sortloot patch [none]: + full -- All pickup lists of items are sorted by item description + loot -- When inventory letters are shown, has no effect. + Otherwise sorts by description + none -- Works the traditional way, like without the patch + suppress_alert disable various version-specific warnings about changes in game play or the user interface, such as notification given for engravings that reading is now done via 'r.' diff -pruN slashem-0.0.8E0-official/doc/Guidebook.mn slashem-0.0.8E0-loot/doc/Guidebook.mn --- slashem-0.0.8E0-official/doc/Guidebook.mn 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/doc/Guidebook.mn 2005-12-11 23:54:07.000000000 +0100 @@ -1990,6 +1990,8 @@ after you restore, making death permane restore from the last save. (default off). .lp legacy Display an introductory message when starting the game (default on). +.lp like_swimming +Allow category ``Items known to be Rustprone'' in selection menus. .lp lit_corridor Show corridor squares seen by night vision or a light source held by your character as lit (default off). @@ -2228,6 +2230,18 @@ enough to quantify their damage. Show total weight in inventory on bottom line (default off). .lp "silent " Suppress terminal beeps (default on). +.lp sortloot +Controls the behavior of the sortloot patch that sorts pickup lists for +inventory and #loot commands and some others. +The possible values are: +.sd +.si +full - always sort the lists; +loot - only sort the lists that don't use inventory + letters, like with the #loot and pickup commands; +none - show lists the traditional way without sorting. +.ei +.ed .lp sortpack Sort the pack contents by type when displaying inventory (default on). .lp sound diff -pruN slashem-0.0.8E0-official/doc/Guidebook.tex slashem-0.0.8E0-loot/doc/Guidebook.tex --- slashem-0.0.8E0-official/doc/Guidebook.tex 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/doc/Guidebook.tex 2005-12-11 23:54:07.000000000 +0100 @@ -2724,6 +2724,11 @@ restore from the last save. (default off Display an introductory message when starting the game (default on). %.lp +\item[\ib{like\_swimming}] +Allow category ``Items known to be Rustprone'' in selection menus. +%.lp + + \item[\ib{lit\_corridor}] Show corridor squares seen by night vision or a light source held by your character as lit (default off). @@ -3054,6 +3059,23 @@ Show total weight in inventory on bottom Suppress terminal beeps (default on). %.lp +\item[\ib{sortloot}] +Controls the behavior of the sortloot patch that sorts pickup lists for +inventory and \#loot commands and some others. + +The possible values are: +%.sd +%.si +{\tt full} --- always sort the lists;\\ +{\tt loot} --- only sort the lists that don't use inventory + letters, like with the \#loot and pickup commands;\\ +{\tt none} --- show lists the traditional way without sorting. +%.ei +%.ed +%.lp +The default is 'none', the way an unpatched game works. + + \item[\ib{sortpack}] Sort the pack contents by type when displaying inventory (default on). %.lp diff -pruN slashem-0.0.8E0-official/include/config.h slashem-0.0.8E0-loot/include/config.h --- slashem-0.0.8E0-official/include/config.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/config.h 2005-12-12 00:47:56.000000000 +0100 @@ -465,6 +465,17 @@ typedef unsigned char uchar; #define DISPLAY_LAYERS /* Improved support for transparent tile sets - ALI */ +#define SORTLOOT /*J. Demeyer, J. Lahtinen, B. Shrieder sortloot patch*/ +#define MENULOOTING /*P. Kallinen, C. Crous, Jym menu looting patch*/ + +/*S. Traykov, Jym additionnal items categories*/ +#define ITEMCAT /* un'I'dentified and 'r'ustprone*/ + /* 'r' need OPTIONS=like_swimming in config file*/ +#define ITEMCAT_JP /* item just 'P'icked up */ +#define ITEMCAT_AP /* 'Q' : auto-picked up items (honour exceptions) */ +#define ITEMCAT_NEG /* 'Z' inverse selection */ + + /* * Section 5: EXPERIMENTAL STUFF * diff -pruN slashem-0.0.8E0-official/include/extern.h slashem-0.0.8E0-loot/include/extern.h --- slashem-0.0.8E0-official/include/extern.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/extern.h 2005-12-11 23:54:07.000000000 +0100 @@ -1479,6 +1479,9 @@ E char *FDECL(doname, (struct obj *)); E boolean FDECL(not_fully_identified, (struct obj *)); E char *FDECL(corpse_xname, (struct obj *,BOOLEAN_P)); E char *FDECL(cxname, (struct obj *)); +#ifdef SORTLOOT +E char *FDECL(cxname2, (struct obj *)); +#endif E char *FDECL(killer_xname, (struct obj *)); E char *FDECL(killer_cxname, (struct obj *,BOOLEAN_P)); E const char *FDECL(singular, (struct obj *,char *(*)(OBJ_P))); @@ -1609,6 +1612,13 @@ E int FDECL(ck_bag, (struct obj *)); E int FDECL(in_container, (struct obj *)); E int FDECL(out_container, (struct obj *)); #endif +#ifdef ITEMCAT_JP +E void FDECL(jpick_free, (struct obj *)); +#endif +#ifdef ITEMCAT_AP +E int FDECL(is_autopicked, (struct obj *)); +#endif + E int FDECL(pickup, (int)); E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P)); E int FDECL(query_category, (const char *, struct obj *, int, diff -pruN slashem-0.0.8E0-official/include/flag.h slashem-0.0.8E0-loot/include/flag.h --- slashem-0.0.8E0-official/include/flag.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/flag.h 2005-12-11 23:54:07.000000000 +0100 @@ -173,6 +173,9 @@ struct flag { */ struct instance_flags { +#ifdef ITEMCAT + boolean like_swimming; /* category r - Items known to be Rustprone */ +#endif /* ITEMCAT */ boolean cbreak; /* in cbreak mode, rogue format */ boolean DECgraphics; /* use DEC VT-xxx extended character set */ boolean echo; /* 1 to echo characters */ @@ -303,6 +306,9 @@ struct instance_flags { #define MAX_ALTKEYHANDLER 25 char altkeyhandler[MAX_ALTKEYHANDLER]; #endif +#ifdef SORTLOOT + uchar sortloot; +#endif }; /* diff -pruN slashem-0.0.8E0-official/include/hack.h slashem-0.0.8E0-loot/include/hack.h --- slashem-0.0.8E0-official/include/hack.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/hack.h 2005-12-11 23:54:07.000000000 +0100 @@ -171,6 +171,16 @@ NEARDATA extern coord bhitpos; /* place #define BUC_UNCURSED 0x200 #define BUC_UNKNOWN 0x400 #define BUC_ALLBKNOWN (BUC_BLESSED|BUC_CURSED|BUC_UNCURSED) +#ifdef ITEMCAT +#define UNIDENTIFIED 0x800 +#define RUSTPRONE 0x1000 +#endif +#ifdef ITEMCAT_JP +#define JUSTPICKED 0x2000 +#endif +#ifdef ITEMCAT_AP +#define AUTOPICKED 0x4000 +#endif #define ALL_TYPES_SELECTED -2 /* Flags to control find_mid() */ diff -pruN slashem-0.0.8E0-official/include/objclass.h slashem-0.0.8E0-loot/include/objclass.h --- slashem-0.0.8E0-official/include/objclass.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/objclass.h 2005-12-11 23:54:07.000000000 +0100 @@ -69,6 +69,14 @@ struct objclass { /* primary damage: fire/rust/--- */ /* is_flammable(otmp), is_rottable(otmp) in mkobj.c */ #define is_rustprone(otmp) (objects[otmp->otyp].oc_material == IRON) +#ifdef ITEMCAT +/* is rustprone, and rust matters (is displayed in inventory listing) */ +#define is_rustprone2(otmp) (is_rustprone(otmp) && (otmp->oclass==WEAPON_CLASS || otmp->oclass==ARMOR_CLASS || otmp->oclass==TOOL_CLASS || otmp->oclass==WAND_CLASS || otmp->oclass==RING_CLASS || otmp->oclass==BALL_CLASS || otmp->oclass==CHAIN_CLASS)) +/* rustproneness should not be immediately visible */ +#define hide_rust(otmp) ((otmp->otyp==GAUNTLETS_OF_POWER || otmp->otyp==KICKING_BOOTS) && !otmp->oeroded) +/* object is known to be rustprone and is NOT known to be rustproof */ +#define is_known_rustprone(otmp) (is_rustprone2(otmp) && !(otmp->rknown && otmp->oerodeproof) && (!hide_rust(otmp) || objects[otmp->otyp].oc_name_known)) +#endif /* ITEMCAT */ /* secondary damage: rot/acid/acid */ #define is_corrodeable(otmp) (objects[otmp->otyp].oc_material == COPPER || objects[otmp->otyp].oc_material == IRON) diff -pruN slashem-0.0.8E0-official/include/obj.h slashem-0.0.8E0-loot/include/obj.h --- slashem-0.0.8E0-official/include/obj.h 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/include/obj.h 2005-12-11 23:54:07.000000000 +0100 @@ -385,4 +385,21 @@ struct obj { #define CONTAINED_TOO 0x1 #define BURIED_TOO 0x2 +#ifdef ITEMCAT +#ifdef ITEMCAT_OLDSTYLE +# ifdef MAIL +# define BKNOWN(otmp) (otmp->bknown || otmp->otyp == SCR_MAIL) +# else +# define BKNOWN(otmp) (otmp->bknown) +# endif +#else +# define BKNOWN(otmp) (1) +#endif + +/* faster version of not_fully_identified() for item selection + * (invent.c/pickup.c) */ +#define NOT_IDENTIFIED_ITEMCAT(otmp) (otmp->oclass != COIN_CLASS && !(otmp->known && otmp->dknown && BKNOWN(otmp) && objects[otmp->otyp].oc_name_known) || (otmp->oartifact && undiscovered_artifact(otmp->oartifact)) || (!otmp->rknown && ((otmp->oclass == ARMOR_CLASS || otmp->oclass == WEAPON_CLASS || is_weptool(otmp) || otmp->oclass == BALL_CLASS)) && (is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp)))) + +#endif /* ITEMCAT */ + #endif /* OBJ_H */ diff -pruN slashem-0.0.8E0-official/src/do.c slashem-0.0.8E0-loot/src/do.c --- slashem-0.0.8E0-official/src/do.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/do.c 2005-12-11 23:54:07.000000000 +0100 @@ -678,7 +678,11 @@ int retry; #endif menu_item *pick_list; boolean all_categories = TRUE; +#ifndef ITEMCAT_NEG boolean drop_everything = FALSE; +#else + int drop_everything = 0; +#endif #ifndef GOLDOBJ if (u.ugold) { @@ -698,18 +702,43 @@ int retry; all_categories = FALSE; n = query_category("Drop what type of items?", invent, - UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | - BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, + UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL +#ifdef ITEMCAT_JP + | JUSTPICKED +#endif +#ifdef ITEMCAT_AP + | AUTOPICKED +#endif +#ifdef ITEMCAT + | UNIDENTIFIED | RUSTPRONE +#endif + | BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, &pick_list, PICK_ANY); if (!n) goto drop_done; for (i = 0; i < n; i++) { +#ifdef ITEMCAT_NEG + if (pick_list[i].item.a_int == 'Z') + drop_everything|=2; +#endif if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_categories = TRUE; else if (pick_list[i].item.a_int == 'A') +#ifndef ITEMCAT_NEG drop_everything = TRUE; +#else + drop_everything|=1; +#endif else add_valid_menu_class(pick_list[i].item.a_int); } +#ifdef ITEMCAT_NEG + switch(drop_everything) { + case 3: + return 0; + case 2: + drop_everything=0; + } +#endif free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { unsigned ggoresults = 0; diff -pruN slashem-0.0.8E0-official/src/end.c slashem-0.0.8E0-loot/src/end.c --- slashem-0.0.8E0-official/src/end.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/end.c 2005-12-11 23:46:58.000000000 +0100 @@ -1121,6 +1121,11 @@ boolean identified, all_containers, want /* The original container_contents function */ { register struct obj *box, *obj; +#ifdef SORTLOOT + struct obj **oarray; + int i,j,n; + char *invlet; +#endif /* SORTLOOT */ char buf[BUFSZ]; for (box = list; box; box = box->nobj) { @@ -1129,13 +1134,52 @@ boolean identified, all_containers, want continue; /* wrong type of container */ } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); +#ifdef SORTLOOT + /* count the number of items */ + for (n = 0, obj = box->cobj; obj; obj = obj->nobj) n++; + /* Make a temporary array to store the objects sorted */ + oarray = (struct obj **) alloc(n*sizeof(struct obj*)); + + /* Add objects to the array */ + i = 0; + invlet = flags.inv_order; + nextclass: + for (obj = box->cobj; obj; obj = obj->nobj) { + if (!flags.sortpack || obj->oclass == *invlet) { + if (iflags.sortloot == 'f' + || iflags.sortloot == 'l') { + /* Insert object at correct index */ + for (j = i; j; j--) { + if (strcmpi(cxname2(obj), cxname2(oarray[j-1]))>0 + || (flags.sortpack && + oarray[j-1]->oclass != obj->oclass)) + break; + oarray[j] = oarray[j-1]; + } + oarray[j] = obj; + i++; + } else { + /* Just add it to the array */ + oarray[i++] = obj; + } + } + } /* for loop */ + if (flags.sortpack) { + if (*++invlet) goto nextclass; + } +#endif /* SORTLOOT */ Sprintf(buf, "Contents of %s:", the(xname(box))); putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); #ifdef DUMP_LOG if (dump_fp) dump("", buf); #endif +#ifdef SORTLOOT + for (i = 0; i < n; i++) { + obj = oarray[i]; +#else for (obj = box->cobj; obj; obj = obj->nobj) { +#endif if (identified) { makeknown(obj->otyp); obj->known = obj->bknown = diff -pruN slashem-0.0.8E0-official/src/invent.c slashem-0.0.8E0-loot/src/invent.c --- slashem-0.0.8E0-official/src/invent.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/invent.c 2005-12-11 23:54:07.000000000 +0100 @@ -614,6 +614,11 @@ void freeinv(obj) register struct obj *obj; { +#ifdef ITEMCAT_JP +/* this is a very uncritical thing so we do it here. if the jpicklist was + * persistent, this should have been in extract_nobj() itself */ + jpick_free(obj); +#endif /* ITEMCAT_JP */ extract_nobj(obj, &invent); freeinv_core(obj); update_inventory(); @@ -1935,6 +1940,10 @@ long* out_cnt; #endif { struct obj *otmp; +#ifdef SORTLOOT + struct obj **oarray; + int i, j; +#endif char ilet, ret; char *invlet = flags.inv_order; int n, classcount; @@ -2026,10 +2035,67 @@ long* out_cnt; return ret; } +#ifdef SORTLOOT + /* count the number of items */ + for (n = 0, otmp = invent; otmp; otmp = otmp->nobj) + if(!lets || !*lets || index(lets, otmp->invlet)) n++; + + /* Make a temporary array to store the objects sorted */ + oarray = (struct obj **)alloc(n*sizeof(struct obj*)); + + /* Add objects to the array */ + i = 0; + for(otmp = invent; otmp; otmp = otmp->nobj) + if(!lets || !*lets || index(lets, otmp->invlet)) { + if (iflags.sortloot == 'f') { + /* Insert object at correct index */ + for (j = i; j; j--) { + if (strcmpi(cxname2(otmp), cxname2(oarray[j-1]))>0) break; + oarray[j] = oarray[j-1]; + } + oarray[j] = otmp; + i++; + } else { + /* Just add it to the array */ + oarray[i++] = otmp; + } + } +#endif /* SORTLOOT */ + start_menu(win); nextclass: classcount = 0; any.a_void = 0; /* set all bits to zero */ +#ifdef SORTLOOT + for(i = 0; i < n; i++) { + otmp = oarray[i]; + ilet = otmp->invlet; + if (!flags.sortpack || otmp->oclass == *invlet) { + if (flags.sortpack && !classcount) { + any.a_void = 0; /* zero */ + add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, + let_to_name(*invlet, FALSE), MENU_UNSELECTED); +#ifdef DUMP_LOG + if (want_dump) + dump(" ", let_to_name(*invlet, FALSE)); +#endif + classcount++; + } + any.a_char = ilet; + add_menu(win, obj_to_glyph(otmp), + &any, ilet, 0, ATR_NONE, doname(otmp), + MENU_UNSELECTED); +#ifdef DUMP_LOG + if (want_dump) { + char letbuf[7]; + sprintf(letbuf, " %c - ", ilet); + dump(letbuf, doname(otmp)); + } +#endif + } + } +#else /* SORTLOOT */ + for(otmp = invent; otmp; otmp = otmp->nobj) { ilet = otmp->invlet; if(!lets || !*lets || index(lets, ilet)) { @@ -2058,6 +2124,7 @@ nextclass: } } } +#endif /* SORTLOOT */ if (flags.sortpack) { if (*++invlet) goto nextclass; #ifdef WIZARD @@ -2067,6 +2134,9 @@ nextclass: } #endif } +#ifdef SORTLOOT + free(oarray); +#endif end_menu(win, (char *) 0); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); @@ -2166,6 +2236,21 @@ count_buc(list, type) if (list->oclass != COIN_CLASS && !list->bknown) count++; break; +#ifdef ITEMCAT + case UNIDENTIFIED: + if (NOT_IDENTIFIED_ITEMCAT(list)) + count++; + break; + case RUSTPRONE: + if (list->oclass != COIN_CLASS && is_known_rustprone(list)) + count++; + break; +#endif /* ITEMCAT */ +#ifdef ITEMCAT_AP + case AUTOPICKED: + count+=is_autopicked(list); + break; +#endif default: impossible("need count of curse status %d?", type); return 0; diff -pruN slashem-0.0.8E0-official/src/objnam.c slashem-0.0.8E0-loot/src/objnam.c --- slashem-0.0.8E0-official/src/objnam.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/objnam.c 2005-12-11 23:43:50.000000000 +0100 @@ -971,6 +971,16 @@ struct obj *obj; return corpse_xname(obj, FALSE); return xname(obj); } +#ifdef SORTLOOT +char * +cxname2(obj) +struct obj *obj; +{ + if (obj->otyp == CORPSE) + return corpse_xname(obj, TRUE); + return xname2(obj); +} +#endif /* SORTLOOT */ /* treat an object as fully ID'd when it might be used as reason for death */ char * diff -pruN slashem-0.0.8E0-official/src/options.c slashem-0.0.8E0-loot/src/options.c --- slashem-0.0.8E0-official/src/options.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/options.c 2005-12-11 23:54:07.000000000 +0100 @@ -130,6 +130,9 @@ static struct Bool_Opt #endif {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */ {"legacy", &flags.legacy, TRUE, DISP_IN_GAME}, +#ifdef ITEMCAT + {"like_swimming", &iflags.like_swimming, FALSE, SET_IN_GAME}, +#endif /* ITEMCAT */ {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME}, {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME}, #ifdef MAC_GRAPHICS_ENV @@ -367,6 +370,10 @@ static struct Comp_Opt { "scroll_amount", "amount to scroll map when scroll_margin is reached", 20, DISP_IN_GAME }, /*WC*/ { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/ +#ifdef SORTLOOT + { "sortloot", "sort object selection lists by description", 4, SET_IN_GAME }, +#endif + #ifdef MSDOS { "soundcard", "type of sound card to use", 20, SET_IN_FILE }, #endif @@ -614,6 +621,9 @@ initoptions() (genericptr_t)def_inv_order, sizeof flags.inv_order); flags.pickup_types[0] = '\0'; flags.pickup_burden = MOD_ENCUMBER; +#ifdef SORTLOOT + iflags.sortloot = 'n'; +#endif for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO; @@ -2139,6 +2149,24 @@ goodfruit: return; } +#ifdef SORTLOOT + fullname = "sortloot"; + if (match_optname(opts, fullname, 4, TRUE)) { + op = string_for_env_opt(fullname, opts, FALSE); + if (op) { + switch (tolower(*op)) { + case 'n': + case 'l': + case 'f': iflags.sortloot = tolower(*op); + break; + default: badoption(opts); + return; + } + } + return; + } +#endif /* SORTLOOT */ + fullname = "suppress_alert"; if (match_optname(opts, fullname, 4, TRUE)) { op = string_for_opt(opts, negated); @@ -2770,6 +2798,12 @@ static NEARDATA const char *runmodes[] = "teleport", "run", "walk", "crawl" }; +#ifdef SORTLOOT +static NEARDATA const char *sortltype[] = { + "none", "loot", "full" +}; +#endif + /* * Convert the given string of object classes to a string of default object * symbols. @@ -3047,7 +3081,8 @@ boolean setinitial,setfromfile; boolean retval = FALSE; /* Special handling of menustyle, pickup_burden, pickup_types, - * disclose, runmode, msg_window, menu_headings, and number_pad options. + * disclose, runmode, msg_window, menu_headings, number_pad and sortloot + #ifdef AUTOPICKUP_EXCEPTIONS * Also takes care of interactive autopickup_exception_handling changes. #endif @@ -3202,6 +3237,26 @@ boolean setinitial,setfromfile; } destroy_nhwindow(tmpwin); retval = TRUE; +#ifdef SORTLOOT + } else if (!strcmp("sortloot", optname)) { + const char *sortl_name; + menu_item *sortl_pick = (menu_item *)0; + tmpwin = create_nhwindow(NHW_MENU); + start_menu(tmpwin); + for (i = 0; i < SIZE(sortltype); i++) { + sortl_name = sortltype[i]; + any.a_char = *sortl_name; + add_menu(tmpwin, NO_GLYPH, &any, *sortl_name, 0, + ATR_NONE, sortl_name, MENU_UNSELECTED); + } + end_menu(tmpwin, "Select loot sorting type:"); + if (select_menu(tmpwin, PICK_ONE, &sortl_pick) > 0) { + iflags.sortloot = sortl_pick->item.a_char; + free((genericptr_t)sortl_pick); + } + destroy_nhwindow(tmpwin); + retval = TRUE; +#endif } #endif else if (!strcmp("align_message", optname) || @@ -3586,6 +3641,17 @@ char *buf; if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin); else Strcpy(buf, defopt); } +#ifdef SORTLOOT + else if (!strcmp(optname, "sortloot")) { + char *sortname = (char *)NULL; + for (i=0; i < SIZE(sortltype) && sortname==(char *)NULL; i++) { + if (iflags.sortloot == sortltype[i][0]) + sortname = (char *)sortltype[i]; + } + if (sortname != (char *)NULL) + Sprintf(buf, "%s", sortname); + } +#endif else if (!strcmp(optname, "player_selection")) Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog"); #ifdef MSDOS diff -pruN slashem-0.0.8E0-official/src/pickup.c slashem-0.0.8E0-loot/src/pickup.c --- slashem-0.0.8E0-official/src/pickup.c 2005-12-08 01:20:02.000000000 +0100 +++ slashem-0.0.8E0-loot/src/pickup.c 2005-12-12 00:18:47.000000000 +0100 @@ -27,17 +27,27 @@ STATIC_DCL int FDECL(count_categories, ( STATIC_DCL long FDECL(carry_count, (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *)); STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P)); +STATIC_DCL boolean FDECL(container_explodes, (struct obj *, struct obj *)); STATIC_PTR int FDECL(in_container,(struct obj *)); STATIC_PTR int FDECL(ck_bag,(struct obj *)); STATIC_PTR int FDECL(out_container,(struct obj *)); STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *)); STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *)); -STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P)); -STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P)); +STATIC_DCL int FDECL(menu_loot, (int, struct obj *, int)); +STATIC_DCL int FDECL(ioa_menu, (const char *,struct obj *, + BOOLEAN_P, BOOLEAN_P, int, struct obj*)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(able_to_loot, (int, int)); STATIC_DCL boolean FDECL(mon_beside, (int, int)); +#ifdef ITEMCAT_JP +char *ctg_justpicked="Items just Picked up"; +char *ctg_justremoved="Items just taken out"; +char **jpick_ctg=&ctg_justpicked; +STATIC_PTR int FDECL(is_justpicked,(struct obj *)); +#define DESTROY_JPICK(j) while(*(j)) { struct jpick *next=(*(j))->next_pick; free((genericptr_t) *(j)); *(j)=next; } +#endif + /* define for query_objlist() and autopickup() */ #define FOLLOW(curr, flags) \ (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) @@ -55,6 +65,30 @@ STATIC_DCL boolean FDECL(mon_beside, (in /* if you can figure this out, give yourself a hearty pat on the back... */ #define GOLD_CAPACITY(w,n) (((w) * -100L) - ((n) + 50L) - 1L) +/* + * Decide whether an object being placed into a container will cause + * it to magically explode. If the object is a bag itself, check + * recursively. Take into account if container is itself inside bags + * of holding. + */ +STATIC_OVL boolean +container_explodes(cont, obj) + struct obj *cont; + struct obj *obj; +{ + int depth; + if(Is_mbag(cont)&&mbag_explodes(obj, 0)) + return TRUE; + for(depth=1; cont->where==OBJ_CONTAINED; cont=cont->ocontainer, ++depth) { + if(Is_mbag(cont->ocontainer) + &&(mbag_explodes(cont, 0)||mbag_explodes(obj, depth))) + return TRUE; + } + return FALSE; +} + + + /* A variable set in use_container(), to be used by the callback routines */ /* in_container() and out_container() from askchain() and use_container(). */ /* Also used by memu_loot() and container_gone(). */ @@ -93,6 +127,61 @@ boolean here; /* flag for type of obj l } } +#ifdef ITEMCAT_AP +int +is_autopicked(obj) +register struct obj *obj; +{ + const char *otypes = flags.pickup_types; +#ifndef AUTOPICKUP_EXCEPTIONS + if (!*otypes || index(otypes, obj->oclass)) +#else + if ((!*otypes || index(otypes, obj->oclass) || + is_autopickup_exception(obj, TRUE)) && + !is_autopickup_exception(obj, FALSE)) +#endif + return 1; + return 0; +} +#endif /* ITEMCAT_AP */ +#ifdef ITEMCAT_JP +/* just picked items llist */ +struct jpick { + struct obj *o; + struct jpick *next_pick; +}; +static NEARDATA struct jpick *jpick_head=(struct jpick *)0; +STATIC_PTR int +is_justpicked(obj) +register struct obj *obj; +{ + struct jpick *list=jpick_head; + while(list) { + if(obj==list->o) + return 1; + list=list->next_pick; + } + return 0; +} +void +jpick_free(obj) +register struct obj *obj; +{ + struct jpick **p=&jpick_head; + struct jpick *next; + + while(*p) { + next=(*p)->next_pick; + if(obj==(*p)->o) { + free((genericptr_t) *p); + *p=next; + break; + } + p=&(*p)->next_pick; + } +} +#endif /* ITEMCAT_JP */ + #ifndef GOLDOBJ int collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount) @@ -317,6 +406,17 @@ struct obj *obj; return (obj != uchain); } +#define ALLOW_APPLY(obj) (Is_container((obj)) && !((obj)->otyp==BAG_OF_TRICKS&&objects[BAG_OF_TRICKS].oc_name_known)) +/* allow applying for containers or unIDd BoTricks / query_objlist callback */ +boolean +allow_apply(obj) +struct obj *obj; +{ + return ALLOW_APPLY(obj); + /* return Is_container(obj) + &&!(obj->otyp==BAG_OF_TRICKS&&objects[BAG_OF_TRICKS].oc_name_known); */ +} + /* query_objlist callback: return TRUE */ /*ARGSUSED*/ boolean @@ -330,24 +430,53 @@ boolean allow_category(obj) struct obj *obj; { +#ifdef ITEMCAT_NEG + int result=0; + int itemcat_negate=(index(valid_menu_classes,'Z') != (char *)0); +#define Return result = +#else +#define Return return +#endif if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || (index(valid_menu_classes, obj->oclass) != (char *)0)) - return TRUE; + Return TRUE; else if (((index(valid_menu_classes,'U') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed))) - return TRUE; + Return TRUE; else if (((index(valid_menu_classes,'B') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed))) - return TRUE; + Return TRUE; else if (((index(valid_menu_classes,'C') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed))) - return TRUE; + Return TRUE; else if (((index(valid_menu_classes,'X') != (char *)0) && (obj->oclass != COIN_CLASS && !obj->bknown))) - return TRUE; + Return TRUE; +#ifdef ITEMCAT + else if (((index(valid_menu_classes,'I') != (char *)0) && + NOT_IDENTIFIED_ITEMCAT(obj))) + Return TRUE; + else if (((index(valid_menu_classes,'r') != (char *)0) && + (obj->oclass != COIN_CLASS && is_known_rustprone(obj)))) + Return TRUE; +#endif /* ITEMCAT */ +#ifdef ITEMCAT_JP + else if (((index(valid_menu_classes,'P') != (char *)0) && + (is_justpicked(obj)))) + Return TRUE; +#endif +#ifdef ITEMCAT_AP + else if (((index(valid_menu_classes,'Q') != (char *)0) && + (is_autopicked(obj)))) + Return TRUE; +#endif else - return FALSE; + Return FALSE; +#ifdef ITEMCAT_NEG + return itemcat_negate?(!result):result; +#undef Return +#endif } #if 0 /* not used */ @@ -396,6 +525,9 @@ int what; /* should be a long */ boolean autopickup = what > 0; struct obj *objchain; int traverse_how; +#ifdef ITEMCAT_JP + struct jpick *jtmp=jpick_head; +#endif if (what < 0) /* pick N of something */ count = -what; @@ -449,6 +581,10 @@ int what; /* should be a long */ if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0); } +#ifdef ITEMCAT_JP + jpick_head=(struct jpick *) 0; +#endif + add_valid_menu_class(0); /* reset */ if (!u.uswallow) { objchain = level.objects[u.ux][u.uy]; @@ -534,7 +670,19 @@ menu_pickup: FALSE, #endif &via_menu)) { - if (!via_menu) return (0); + if (!via_menu) +#ifdef ITEMCAT_JP + { + if(jpick_head) { + jpick_ctg=&ctg_justpicked; + DESTROY_JPICK(&jtmp) + } else + jpick_head=jtmp; + return (0); + } +#else + return (0); +#endif /* ITEMCAT_JP */ n = query_objlist("Pick up what?", objchain, traverse_how|(selective ? 0 : INVORDER_SORT), @@ -598,6 +746,13 @@ end_query: /* see whether there's anything else here, after auto-pickup is done */ if (autopickup) check_here(n_picked > 0); } +#ifdef ITEMCAT_JP + if(jpick_head) { + jpick_ctg=&ctg_justpicked; + DESTROY_JPICK(&jtmp) + } else + jpick_head=jtmp; +#endif return (n_tried > 0); } @@ -701,9 +856,15 @@ menu_item **pick_list; /* return list o int how; /* type of query */ boolean FDECL((*allow), (OBJ_P));/* allow function */ { +#ifdef SORTLOOT + int i, j; +#endif int n; winid win; struct obj *curr, *last; +#ifdef SORTLOOT + struct obj **oarray; +#endif char *pack; anything any; boolean printed_type_name; @@ -727,6 +888,32 @@ boolean FDECL((*allow), (OBJ_P));/* allo (*pick_list)->count = last->quan; return 1; } +#ifdef SORTLOOT + /* Make a temporary array to store the objects sorted */ + oarray = (struct obj **)alloc(n*sizeof(struct obj*)); + + /* Add objects to the array */ + i = 0; + for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { + if ((*allow)(curr)) { + if (iflags.sortloot == 'f' || + (iflags.sortloot == 'l' && !(qflags & USE_INVLET))) + { + /* Insert object at correct index */ + for (j = i; j; j--) + { + if (strcmpi(cxname2(curr), cxname2(oarray[j-1]))>0) break; + oarray[j] = oarray[j-1]; + } + oarray[j] = curr; + i++; + } else { + /* Just add it to the array */ + oarray[i++] = curr; + } + } + } +#endif /* SORTLOOT */ win = create_nhwindow(NHW_MENU); start_menu(win); @@ -741,7 +928,12 @@ boolean FDECL((*allow), (OBJ_P));/* allo pack = flags.inv_order; do { printed_type_name = FALSE; - for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { +#ifdef SORTLOOT + for (i = 0; i < n; i++) { + curr = oarray[i]; +#else /* SORTLOOT */ + for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { +#endif /* SORTLOOT */ if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && will_feel_cockatrice(curr, FALSE)) { destroy_nhwindow(win); /* stop the menu and revert */ @@ -769,6 +961,10 @@ boolean FDECL((*allow), (OBJ_P));/* allo pack++; } while (qflags & INVORDER_SORT && *pack); +#ifdef SORTLOOT + free(oarray); +#endif + end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); @@ -808,6 +1004,19 @@ int how; /* type of query */ boolean collected_type_name; char invlet; int ccount; +#ifdef ITEMCAT + boolean do_unident = FALSE; + boolean do_rustprone = FALSE; +#endif +#ifdef ITEMCAT_JP + boolean do_justpicked = FALSE; +#endif +#ifdef ITEMCAT_AP + boolean do_autopicked = FALSE; +#endif +#ifdef ITEMCAT_NEG + boolean do_invsel = FALSE; +#endif boolean do_unpaid = FALSE; boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE, do_buc_unknown = FALSE; @@ -833,6 +1042,27 @@ int how; /* type of query */ num_buc_types++; } +#ifdef ITEMCAT + if ((qflags & UNIDENTIFIED) && count_buc(olist, UNIDENTIFIED)) + do_unident = TRUE; + + if (iflags.like_swimming && (qflags & RUSTPRONE) && count_buc(olist, RUSTPRONE)) + do_rustprone = TRUE; + +#endif +#ifdef ITEMCAT_JP + if ((qflags & JUSTPICKED) && jpick_head!=(struct jpick *) 0) + do_justpicked = TRUE; +#endif +#ifdef ITEMCAT_AP + if ((qflags & AUTOPICKED) && count_buc(olist, AUTOPICKED)) + do_autopicked = TRUE; +#endif +#ifdef ITEMCAT_NEG + if (how!=PICK_ONE) + do_invsel = TRUE; +#endif + ccount = count_categories(olist, qflags); /* no point in actually showing a menu for a single category */ if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) { @@ -917,6 +1147,48 @@ int how; /* type of query */ "Auto-select every item being worn" : "Auto-select every item", MENU_UNSELECTED); } +#ifdef ITEMCAT_JP + if (do_justpicked) { + invlet = 'P'; + any.a_void = 0; + any.a_int = 'P'; + add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, + *jpick_ctg, + MENU_UNSELECTED); + } +#endif /*ITEMCAT_JP*/ +#ifdef ITEMCAT + if (do_unident) { + invlet = 'I'; + any.a_void = 0; + any.a_int = 'I'; + add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, + "Unidentified Items", + MENU_UNSELECTED); + } +#endif /* ITEMCAT */ +#ifdef ITEMCAT_AP + if (do_autopicked) { + invlet = 'Q'; + any.a_void = 0; + any.a_int = 'Q'; + add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, + "Auto-picked items", + MENU_UNSELECTED + ); + } +#endif /* ITEMCAT_AP */ +#ifdef ITEMCAT_NEG + if (do_invsel) { + invlet = 'Z'; + any.a_void = 0; + any.a_int = 'Z'; + add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, + "Inverse selection", + MENU_UNSELECTED + ); + } +#endif /* ITEMCAT_AP */ /* items with b/u/c/unknown if there are any */ if (do_blessed) { invlet = 'B'; @@ -947,6 +1219,16 @@ int how; /* type of query */ "Items of unknown B/C/U status", MENU_UNSELECTED); } +#ifdef ITEMCAT + if (iflags.like_swimming && do_rustprone) { + invlet = 'r'; + any.a_void = 0; + any.a_int = 'r'; + add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, + "Items known to be Rustprone", + MENU_UNSELECTED); + } +#endif /* ITEMCAT */ end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); @@ -1386,6 +1668,9 @@ struct obj * pick_obj(otmp) struct obj *otmp; { +#ifdef ITEMCAT_JP + struct jpick *pick; +#endif obj_extract_self(otmp); if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { char saveushops[5], fakeshop[2]; @@ -1409,7 +1694,18 @@ struct obj *otmp; if (otmp->was_thrown) /* likewise */ otmp->was_thrown = 0; newsym(otmp->ox, otmp->oy); - return addinv(otmp); /* might merge it with other objects */ +#ifdef ITEMCAT_JP + otmp=addinv(otmp); /* might merge it with other objects */ + if(otmp->oclass!=COIN_CLASS) { + pick=(struct jpick *) alloc(sizeof(struct jpick)); + pick->next_pick=jpick_head; + pick->o=otmp; + jpick_head=pick; + } + return otmp; +#else + return addinv(otmp); +#endif /* ITEMCAT_JP */ } /* @@ -1518,6 +1814,35 @@ int x, y; } int +#ifdef MENULOOTING +do_loot_cont(cobj, noit) +struct obj *cobj; +boolean noit; +{ + if (!cobj) return 0; + + if (cobj->olocked) { + pline("Hmmm, %s seems to be locked.", noit ? the(xname(cobj)) : "it"); + return 0; + } + if (cobj->otyp == BAG_OF_TRICKS) { + int tmp; + You("carefully open the bag..."); + pline("It develops a huge set of teeth and bites you!"); + tmp = rnd(10); + if (Half_physical_damage) tmp = (tmp+1) / 2; + losehp(tmp, "carnivorous bag", KILLED_BY_AN); + makeknown(BAG_OF_TRICKS); + return 1; + } + + You("carefully open %s...", the(xname(cobj))); + return use_container(cobj, 0); +} + + +int +#endif doloot() /* loot a container on the floor or loot saddle from mon. */ { struct obj *cobj, *nobj; @@ -1530,6 +1855,9 @@ doloot() /* loot a container on the floo char qbuf[BUFSZ]; int prev_inquiry = 0; boolean prev_loot = FALSE; +#ifdef MENULOOTING + int num_cont = 0; +#endif if (check_capacity((char *)0)) { /* "Can't do that while carrying so much stuff." */ @@ -1544,13 +1872,38 @@ doloot() /* loot a container on the floo lootcont: if (container_at(cc.x, cc.y, FALSE)) { +#ifndef MENULOOTING boolean any = FALSE; +#else + winid win; + anything any; + menu_item *pick_list; +#endif if (!able_to_loot(cc.x, cc.y)) return 0; for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { +#ifdef MENULOOTING + if (Is_container(cobj)) num_cont++; +#endif nobj = cobj->nexthere; +#ifdef MENULOOTING + } + + timepassed = 0; +#endif + +#ifdef MENULOOTING + if (num_cont > 1) { + /* use a menu to loot many containers */ + int n, i; + any.a_void = 0; + win = create_nhwindow(NHW_MENU); + start_menu(win); + for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { +#endif if (Is_container(cobj)) { +#ifndef MENULOOTING Sprintf(qbuf, "There is %s here, loot it?", safe_qbuf("", sizeof("There is here, loot it?"), doname(cobj), an(simple_typename(cobj->otyp)), @@ -1559,11 +1912,19 @@ lootcont: if (c == 'q') return (timepassed); if (c == 'n') continue; any = TRUE; +#else + any.a_obj = cobj; + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, doname(cobj), + MENU_UNSELECTED); +#endif +#ifndef MENULOOTING if (cobj->olocked) { pline("Hmmm, it seems to be locked."); continue; +#endif } +#ifndef MENULOOTING if (cobj->otyp == BAG_OF_TRICKS) { int tmp; You("carefully open the bag..."); @@ -1574,15 +1935,58 @@ lootcont: makeknown(BAG_OF_TRICKS); timepassed = 1; continue; +#else + nobj = cobj->nexthere; +#endif } - +#ifdef MENULOOTING + end_menu(win, "Loot which containers?"); + n = select_menu(win, PICK_ANY, &pick_list); + destroy_nhwindow(win); +#endif + +#ifndef MENULOOTING You("carefully open %s...", the(xname(cobj))); timepassed |= use_container(&cobj, 0); +#else + if (n > 0) + for (i = 0; i < n; i++) { + timepassed |= do_loot_cont(pick_list[i].item.a_obj, TRUE); + if (multi < 0) { /* chest trap, stop looting */ + free((genericptr_t) pick_list); + return 1; + } + } + + free((genericptr_t) pick_list); + + /* don't ask for looting in a direction, if the menu was + cancelled, or if we did open any containers. */ + if (n != 0) return timepassed; + } else { + /* use the old style looting: ask y/n for each container */ + boolean didany = FALSE; + for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { + nobj = cobj->nexthere; + if (Is_container(cobj)) { + Sprintf(qbuf, "There is %s here, loot it?", doname(cobj)); + c = ynq(qbuf); + + if (c == 'q') return 0; + if (c == 'n') continue; + didany = TRUE; + timepassed |= do_loot_cont(cobj, FALSE); +#endif /* might have triggered chest trap or magic bag explosion */ if (multi < 0 || !cobj) return 1; } } - if (any) c = 'y'; +#ifndef MENULOOTING + if (any) c = 'y'; +#else + if (didany) c = 'y'; + } +#endif } else if (Confusion) { #ifndef GOLDOBJ if (u.ugold){ @@ -1749,6 +2153,18 @@ boolean *prev_loot; } /* + * Returns the outermost container enclosing the one specified by arg + */ +struct obj * +outermost_container(container) +struct obj *container; +{ + struct obj *tobj; + for(tobj=container; tobj->where==OBJ_CONTAINED; + tobj=tobj->ocontainer); +} + +/* * Decide whether an object being placed into a magic bag will cause * it to explode. If the object is a bag itself, check recursively. */ @@ -1872,7 +2288,8 @@ STATIC_PTR int in_container(obj) register struct obj *obj; { - boolean floor_container = !carried(current_container); + struct obj *outermost=outermost_container(current_container); + boolean floor_container = !carried(outermost); boolean was_unpaid = FALSE; char buf[BUFSZ]; @@ -1885,6 +2302,9 @@ register struct obj *obj; } else if (obj == current_container) { pline("That would be an interesting topological exercise."); return 0; + } else if (obj == outermost) { + pline("That would be a very interesting topological exercise."); + return 0; } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) { Norep("You cannot %s %s you are wearing.", Icebox ? "refrigerate" : "stash", something); @@ -1981,7 +2401,7 @@ register struct obj *obj; /* mark a non-reviving corpse as such */ if (rot_alarm) obj->norevive = 1; } - } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { + } else if (container_explodes(current_container, obj)) { /* explicitly mention what item is triggering the explosion */ pline( "As you put %s inside, you are blasted by a magical explosion!", @@ -1997,13 +2417,13 @@ register struct obj *obj; if (Has_contents(obj)) delete_contents(obj); obfree(obj, (struct obj *)0); - delete_contents(current_container); + delete_contents(outermost); if (!floor_container) - useup(current_container); - else if (obj_here(current_container, u.ux, u.uy)) - useupf(current_container, current_container->quan); + useup(outermost); + else if (obj_here(outermost, u.ux, u.uy)) + useupf(outermost, obj->quan); else - panic("in_container: bag not found."); + panic("in_container: container not found."); losehp(d(6,6),"magical explosion", KILLED_BY_AN); current_container = 0; /* baggone = TRUE; */ @@ -2044,6 +2464,9 @@ register struct obj *obj; boolean is_gold = (obj->oclass == COIN_CLASS); int res, loadlev; long count; +#ifdef ITEMCAT_JP + struct jpick *pick; +#endif if (!current_container) { impossible(" no current_container?"); @@ -2099,6 +2522,14 @@ register struct obj *obj; verbalize("You sneaky cad! Get out of here with that pick!"); otmp = addinv(obj); +#ifdef ITEMCAT_JP + if(!is_gold) { + pick=(struct jpick *) alloc(sizeof(struct jpick)); + pick->next_pick=jpick_head; + pick->o=otmp; + jpick_head=pick; + } +#endif loadlev = near_capacity(); prinv(loadlev ? (loadlev < MOD_ENCUMBER ? @@ -2208,12 +2639,13 @@ int held; #endif struct monst *shkp; boolean one_by_one, allflag, quantum_cat = FALSE, - loot_out = FALSE, loot_in = FALSE; + loot_out = FALSE, loot_in = FALSE, loot_app = FALSE; char select[MAXOCLASSES+1]; char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; long loss = 0L; - int cnt = 0, used = 0, lcnt = 0, + int cnt = 0, used = 0, lcnt = 0, appcnt = 0, menu_on_request; + struct obj *appwhat=NULL; emptymsg[0] = '\0'; if (nohands(youmonst.data)) { @@ -2223,6 +2655,15 @@ int held; You("have no free %s.", body_part(HAND)); return 0; } + if ((obj->where==OBJ_CONTAINED)&&(obj->otyp==BAG_OF_TRICKS)) { + struct obj *cont=obj->ocontainer; + int tmp; + You("try to open the bag..."); + pline("It slips from your fingers and hides in %s!", + the(xname(cont))); + makeknown(BAG_OF_TRICKS); + return 1; + } if (obj->olocked) { pline("%s to be locked.", Tobjnam(obj, "seem")); if (held) You("must put it down to unlock."); @@ -2262,8 +2703,14 @@ int held; } } /* Count the number of contained objects. */ - for (curr = obj->cobj; curr; curr = curr->nobj) - cnt++; + for (curr = obj->cobj; curr; curr = curr->nobj) { + cnt++; + if(ALLOW_APPLY(curr)) { + if(!appcnt) + appwhat=curr; + ++appcnt; + } + } if (loss) /* magic bag lost some shop goods */ You("owe %ld %s for lost merchandise.", loss, currency(loss)); @@ -2301,20 +2748,22 @@ int held; menuprompt[0] = '\0'; if (!cnt) Sprintf(menuprompt, "%s ", emptymsg); Strcat(menuprompt, "Do what?"); - t = in_or_out_menu(menuprompt, current_container, - outokay, inokay); + t = ioa_menu(menuprompt, current_container, + outokay, inokay, appcnt, appwhat); + if (t <= 0) { used = 0; goto containerdone; } loot_out = (t & 0x01) != 0; loot_in = (t & 0x02) != 0; + loot_app = (t & 0x04) != 0; } else { /* MENU_COMBINATION or MENU_PARTIAL */ loot_out = (yn_function(qbuf, "ynq", 'n') == 'y'); } if (loot_out) { add_valid_menu_class(0); /* reset */ - used |= menu_loot(0, current_container, FALSE) > 0; + used |= menu_loot(0, current_container, 0) > 0; } } else { /* traditional code */ @@ -2335,6 +2784,14 @@ ask_again2: FALSE, #endif &menu_on_request)) { +#ifdef ITEMCAT_JP + /* normally one wouldn't use traditional + itemcat_jp, + * so we don't make extra checks whether something + * relevant was in fact picked up, just destroy the + * list for consistency. */ + jpick_ctg=&ctg_justremoved; + DESTROY_JPICK(&jpick_head) +#endif if (askchain((struct obj **)¤t_container->cobj, (one_by_one ? (char *)0 : select), allflag, out_container, @@ -2343,14 +2800,14 @@ ask_again2: used = 1; } else if (menu_on_request < 0) { used |= menu_loot(menu_on_request, - current_container, FALSE) > 0; + current_container, 0) > 0; } /*FALLTHRU*/ case 'n': break; case 'm': menu_on_request = -2; /* triggers ALL_CLASSES */ - used |= menu_loot(menu_on_request, current_container, FALSE) > 0; + used |= menu_loot(menu_on_request, current_container, 0) > 0; break; case 'q': default: @@ -2384,7 +2841,7 @@ ask_again2: case 'm': add_valid_menu_class(0); /* reset */ menu_on_request = -2; /* triggers ALL_CLASSES */ - used |= menu_loot(menu_on_request, current_container, TRUE) > 0; + used |= menu_loot(menu_on_request, current_container, 1) > 0; break; case 'q': default: @@ -2412,7 +2869,7 @@ ask_again2: #endif add_valid_menu_class(0); /* reset */ if (flags.menu_style != MENU_TRADITIONAL) { - used |= menu_loot(0, current_container, TRUE) > 0; + used |= menu_loot(0, current_container, 1) > 0; } else { /* traditional code */ menu_on_request = 0; @@ -2428,7 +2885,7 @@ ask_again2: used = 1; } else if (menu_on_request < 0) { used |= menu_loot(menu_on_request, - current_container, TRUE) > 0; + current_container, 1) > 0; } } } @@ -2446,33 +2903,59 @@ ask_again2: containerdone: *objp = current_container; /* might have become null */ current_container = 0; /* avoid hanging on to stale pointer */ + + if(loot_app) { + if(appcnt==1) + used=use_container(&appwhat, 1); + else + used=menu_loot(0, current_container, 2); + } return used; } /* Loot a container (take things out, put things in), using a menu. */ STATIC_OVL int -menu_loot(retry, container, put_in) +menu_loot(retry, container, mode) int retry; struct obj *container; -boolean put_in; +int mode; /* 0 - take out, 1 - put in, 2 - apply */ { int n, i, n_looted = 0; boolean all_categories = TRUE, loot_everything = FALSE; char buf[BUFSZ]; - const char *takeout = "Take out", *putin = "Put in"; + const char *takeout = "Take out", *putin = "Put in", *apply = "Apply"; struct obj *otmp, *otmp2; menu_item *pick_list; int mflags, res; long count; +#ifdef ITEMCAT_JP + struct jpick *jtmp; +#endif if (retry) { all_categories = (retry == -2); - } else if (flags.menu_style == MENU_FULL) { + } else if ((flags.menu_style == MENU_FULL) && (mode < 2)) { all_categories = FALSE; - Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout); - mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN : - ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN; - n = query_category(buf, put_in ? invent : container->cobj, + Sprintf(buf,"%s what type of objects?", mode ? putin : takeout); + mflags = mode ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN +#ifdef ITEMCAT_JP + | JUSTPICKED +#endif +#ifdef ITEMCAT_AP + | AUTOPICKED +#endif +#ifdef ITEMCAT + | UNIDENTIFIED | RUSTPRONE +#endif + : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN +#ifdef ITEMCAT + | UNIDENTIFIED | RUSTPRONE +#endif +#ifdef ITEMCAT_AP + | AUTOPICKED +#endif + ; + n = query_category(buf, mode ? invent : container->cobj, mflags, &pick_list, PICK_ANY); if (!n) return 0; for (i = 0; i < n; i++) { @@ -2487,58 +2970,99 @@ boolean put_in; } if (loot_everything) { +#ifdef ITEMCAT_NEG + if(index(valid_menu_classes,'Z') != (char *)0) + return 0; +#endif +#ifdef ITEMCAT_JP + jtmp=jpick_head; + jpick_head=(struct jpick *) 0; +#endif for (otmp = container->cobj; otmp; otmp = otmp2) { otmp2 = otmp->nobj; res = out_container(otmp); if (res < 0) break; } +#ifdef ITEMCAT_JP + if(jpick_head) { + jpick_ctg=&ctg_justremoved; + DESTROY_JPICK(&jtmp) + } else + jpick_head=jtmp; +#endif } else { mflags = INVORDER_SORT; - if (put_in && flags.invlet_constant) mflags |= USE_INVLET; - Sprintf(buf,"%s what?", put_in ? putin : takeout); - n = query_objlist(buf, put_in ? invent : container->cobj, + if (mode==1 && flags.invlet_constant) mflags |= USE_INVLET; + Sprintf(buf,"%s what?", mode ? (mode==1?putin:apply) : takeout); + if(mode<2) + n = query_objlist(buf, mode ? invent : container->cobj, mflags, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); + else + n = query_objlist(buf, container->cobj, mflags, &pick_list, + PICK_ONE, allow_apply); if (n) { - n_looted = n; - for (i = 0; i < n; i++) { - otmp = pick_list[i].item.a_obj; - count = pick_list[i].count; - if (count > 0 && count < otmp->quan) { - otmp = splitobj(otmp, count); - /* special split case also handled by askchain() */ - } - res = put_in ? in_container(otmp) : out_container(otmp); - if (res < 0) { - if (!current_container) { - /* otmp caused current_container to explode; - both are now gone */ - otmp = 0; /* and break loop */ - } else if (otmp && otmp != pick_list[i].item.a_obj) { - /* split occurred, merge again */ - (void) merged(&pick_list[i].item.a_obj, &otmp); - } - break; - } + n_looted = n; +#ifdef ITEMCAT_JP + if(!mode) { + jtmp=jpick_head; + jpick_head=(struct jpick *) 0; + } +#endif + if(mode<2) { + for (i = 0; i < n; i++) { + otmp = pick_list[i].item.a_obj; + count = pick_list[i].count; + if (count > 0 && count < otmp->quan) { + otmp = splitobj(otmp, count); + /* special split case also handled by askchain() */ + } + res = mode ? in_container(otmp) : out_container(otmp); + if (res < 0) { + if (!current_container) { + /* otmp caused current_container to explode; + both are now gone */ + otmp = 0; /* and break loop */ + } else if (otmp != pick_list[i].item.a_obj) { + /* split occurred, merge again */ + (void) merged(&pick_list[i].item.a_obj, &otmp); } - free((genericptr_t)pick_list); + break; + } + } +#ifdef ITEMCAT_JP + if(!mode) { + if(jpick_head) { + jpick_ctg=&ctg_justremoved; + DESTROY_JPICK(&jtmp) + } else + jpick_head=jtmp; + } +#endif + } else { + otmp = pick_list[0].item.a_obj; + n_looted=use_container(&otmp, 1); + } + free((genericptr_t)pick_list); } } return n_looted; } STATIC_OVL int -in_or_out_menu(prompt, obj, outokay, inokay) +ioa_menu(prompt, obj, outokay, inokay, appcnt, appwhat) const char *prompt; struct obj *obj; boolean outokay, inokay; +int appcnt; +struct obj *appwhat; { winid win; anything any; menu_item *pick_list; char buf[BUFSZ]; int n; - const char *menuselector = iflags.lootabc ? "abc" : "oib"; + const char *menuselector = iflags.lootabc ? "abcd" : "oiba"; any.a_void = 0; win = create_nhwindow(NHW_MENU); @@ -2561,6 +3085,16 @@ boolean outokay, inokay; add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, "Both of the above", MENU_UNSELECTED); } + menuselector++; + if(appcnt) { + any.a_int = 4; + if(appcnt==1) + Sprintf(buf,"Apply %s inside", the(xname(appwhat))); + else + Sprintf(buf,"Apply %s from %s", something, the(xname(obj))); + add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, + MENU_UNSELECTED); + } end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win);