diff --git a/dat/opthelp b/dat/opthelp index de91c565b..35337d104 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -50,6 +50,7 @@ null allow nulls to be sent to your terminal [True] try turning this option off (forcing NetHack to use its own delay code) if moving objects seem to teleport across rooms perm_invent keep inventory in a permanent window [False] +pickup_stolen override pickup_types for stolen objects [True] pickup_thrown override pickup_types for thrown objects [True] pushweapon when wielding a new weapon, put your previously [False] wielded weapon into the secondary weapon slot diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 33563866e..e634e6232 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -4394,6 +4394,15 @@ level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default \(oqS\(cq). Persistent. +.lp pickup_stolen +If this option is on and +.op autopickup +is also on, try to pick up things that a monster stole from you, even if they +aren't in +.op pickup_types +or match an autopickup exception. +Default is on. +Persistent. .lp pickup_thrown If this option is on and .op autopickup diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 6254b89d2..57fee5760 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -4815,6 +4815,14 @@ level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). Persistent. %.lp +\item[\ib{pickup\verb+_+stolen}] +If this option is on and ``{\it autopickup\/}'' is also on, try to pick up +things that a monster stole from you, even if they aren't in +``{\it pickup\verb+_+types\/}'' or +match an autopickup exception. +Default is on. +Persistent. +%.lp \item[\ib{pickup\verb+_+thrown}] If this option is on and ``{\it autopickup\/}'' is also on, try to pick up things that you threw, even if they aren't in diff --git a/include/flag.h b/include/flag.h index 852878931..aa2a6420b 100644 --- a/include/flag.h +++ b/include/flag.h @@ -48,6 +48,7 @@ struct flag { boolean nopick_dropped; /* items you dropped may be autopicked */ boolean null; /* OK to send nulls to the terminal */ boolean pickup; /* whether you pickup or move and look */ + boolean pickup_stolen; /* auto-pickup items stolen by a monster */ boolean pickup_thrown; /* auto-pickup items you threw */ boolean pushweapon; /* When wielding, push old weapon into second slot */ boolean quick_farsight; /* True disables map browsing during random diff --git a/include/obj.h b/include/obj.h index 7c430c38f..f3d8a424e 100644 --- a/include/obj.h +++ b/include/obj.h @@ -124,10 +124,9 @@ struct obj { #define on_ice recharged /* corpse on ice */ Bitfield(lamplit, 1); /* a light-source -- can be lit */ Bitfield(globby, 1); /* combines with like types on adjacent squares */ - Bitfield(greased, 1); /* covered with grease */ - Bitfield(nomerge, 1); /* set temporarily to prevent merging */ - Bitfield(was_thrown, 1); /* thrown by hero since last picked up */ - Bitfield(was_dropped, 1); /* dropped deliberately by the hero */ + Bitfield(greased, 1); /* covered with grease */ + Bitfield(nomerge, 1); /* set temporarily to prevent merging */ + Bitfield(how_lost, 2); /* stolen by mon or thrown, dropped by hero */ Bitfield(in_use, 1); /* for magic items before useup items */ Bitfield(bypass, 1); /* mark this as an object to be skipped by bhito() */ @@ -459,6 +458,12 @@ struct obj { #define POTHIT_MONST_THROW 2 /* thrown by a monster */ #define POTHIT_OTHER_THROW 3 /* propelled by some other means [scatter()] */ +/* tracking how an item left your inventory */ +#define LOST_NONE 0 /* still in inventory, or method not covered below */ +#define LOST_THROWN 1 /* thrown or fired by the hero */ +#define LOST_DROPPED 2 /* dropped or tipped out of a container by the hero */ +#define LOST_STOLEN 3 /* stolen from hero's inventory by a monster */ + /* * Notes for adding new oextra structures: * diff --git a/include/optlist.h b/include/optlist.h index 8823f28ab..689810349 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -534,6 +534,9 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTC(pickup_burden, Advanced, 20, opt_in, set_in_game, No, Yes, No, Yes, NoAlias, "maximum burden picked up before prompt") + NHOPTB(pickup_stolen, Behavior, 0, opt_out, set_in_game, + On, Yes, No, No, NoAlias, &flags.pickup_stolen, Term_False, + "autopickup thrown items") NHOPTB(pickup_thrown, Behavior, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.pickup_thrown, Term_False, "autopickup thrown items") diff --git a/src/bones.c b/src/bones.c index c6d79d830..4497fcf9b 100644 --- a/src/bones.c +++ b/src/bones.c @@ -107,8 +107,7 @@ resetobjs(struct obj *ochain, boolean restore) otmp->cknown = 0; otmp->invlet = 0; otmp->no_charge = 0; - otmp->was_thrown = 0; - otmp->was_dropped = 0; + otmp->how_lost = LOST_NONE; /* strip user-supplied names */ /* Statue and some corpse names are left intact, diff --git a/src/do.c b/src/do.c index 86a81d8d0..3ff95fac9 100644 --- a/src/do.c +++ b/src/do.c @@ -760,7 +760,7 @@ drop(struct obj *obj) if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) You("drop %s.", doname(obj)); } - obj->was_dropped = 1; + obj->how_lost = LOST_DROPPED; dropx(obj); return ECMD_TIME; } diff --git a/src/dothrow.c b/src/dothrow.c index 8ecab42e9..e04f22e4e 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1504,7 +1504,7 @@ throwit(struct obj *obj, } gt.thrownobj = obj; - gt.thrownobj->was_thrown = 1; + gt.thrownobj->how_lost = LOST_THROWN; iflags.returning_missile = AutoReturn(obj, wep_mask) ? (genericptr_t) obj : (genericptr_t) 0; /* NOTE: No early returns after this point or returning_missile @@ -1719,7 +1719,7 @@ throwit(struct obj *obj, if (tethered_weapon) tmp_at(DISP_END, 0); /* when this location is stepped on, the weapon will be - auto-picked up due to 'obj->was_thrown' of 1; + auto-picked up due to 'obj->how_lost' of LOST_THROWN; addinv() prevents thrown Mjollnir from being placed into the quiver slot, but an aklys will end up there if that slot is empty at the time; since hero will need to diff --git a/src/invent.c b/src/invent.c index 33cbba494..b6a2dd011 100644 --- a/src/invent.c +++ b/src/invent.c @@ -942,7 +942,8 @@ merged(struct obj **potmp, struct obj **pobj) items, where this would be too spammy as such items get unidentified by monsters very frequently). */ if (discovered && otmp->where == OBJ_INVENT - && !obj->was_thrown && !otmp->was_thrown) { + && obj->how_lost != LOST_THROWN + && otmp->how_lost != LOST_THROWN) { pline("You learn more about your items by comparing them."); } @@ -1049,8 +1050,8 @@ addinv_core0(struct obj *obj, struct obj *other_obj, obj->no_charge = 0; /* should not be set in hero's invent */ if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ - obj_was_thrown = obj->was_thrown; - obj->was_thrown = obj->was_dropped = 0; /* not meaningful for invent */ + obj_was_thrown = (obj->how_lost == LOST_THROWN); + obj->how_lost = LOST_NONE; if (gl.loot_reset_justpicked) { gl.loot_reset_justpicked = FALSE; @@ -4823,8 +4824,7 @@ mergable( if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit - || obj->was_thrown != otmp->was_thrown - || obj->was_dropped != otmp->was_dropped) + || obj->how_lost != otmp->how_lost) return FALSE; if (obj->oclass == FOOD_CLASS diff --git a/src/mkobj.c b/src/mkobj.c index 44b23165b..c926276ed 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -2863,9 +2863,10 @@ objlist_sanity(struct obj *objlist, int wheretype, const char *mesg) for (obj = objlist; obj; obj = obj->nobj) { if (obj->where != wheretype) insane_object(obj, ofmt0, mesg, (struct monst *) 0); - if (obj->was_thrown && obj->was_dropped) { - insane_object(obj, "%s obj is both thrown and dropped! %s %s: %s", - mesg, obj->ocarry); + if (obj->where == OBJ_INVENT && obj->how_lost != LOST_NONE) { + char lostbuf[40]; + Sprintf(lostbuf, "how_lost=%d obj in inventory!", obj->how_lost); + insane_object(obj, ofmt0, lostbuf, (struct monst *) 0); } if (Has_contents(obj)) { if (wheretype == OBJ_ONBILL) diff --git a/src/nhlobj.c b/src/nhlobj.c index d5bbaf381..619af7de0 100644 --- a/src/nhlobj.c +++ b/src/nhlobj.c @@ -312,7 +312,7 @@ l_obj_to_table(lua_State *L) nhl_add_table_entry_int(L, "globby", obj->globby); nhl_add_table_entry_int(L, "greased", obj->greased); nhl_add_table_entry_int(L, "nomerge", obj->nomerge); - nhl_add_table_entry_int(L, "was_thrown", obj->was_thrown); + nhl_add_table_entry_int(L, "how_lost", obj->how_lost); nhl_add_table_entry_int(L, "in_use", obj->in_use); nhl_add_table_entry_int(L, "bypass", obj->bypass); nhl_add_table_entry_int(L, "cknown", obj->cknown); diff --git a/src/options.c b/src/options.c index 740bcaa9a..a3c9f1688 100644 --- a/src/options.c +++ b/src/options.c @@ -8594,6 +8594,7 @@ doset_simple_menu(void) spelling of their names; emphasize what it means */ if (allopt[i].idx == opt_pickup_types || allopt[i].idx == opt_pickup_thrown + || allopt[i].idx == opt_pickup_stolen || allopt[i].idx == opt_dropped_nopick) Strcat(buf, " (for autopickup)"); add_menu(tmpwin, &nul_glyphinfo, &any, 0, 0, diff --git a/src/pickup.c b/src/pickup.c index d7c7c2026..7b7781116 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -904,10 +904,12 @@ autopick_testobj(struct obj *otmp, boolean calc_costly) if (costly && !otmp->no_charge) return FALSE; - /* pickup_thrown/nopick_dropped override pickup_types and exceptions */ - if (flags.pickup_thrown && otmp->was_thrown) + /* pickup_thrown/pickup_stolen/nopick_dropped override pickup_types and + exceptions */ + if ((flags.pickup_thrown && otmp->how_lost == LOST_THROWN) + || (flags.pickup_stolen && otmp->how_lost == LOST_STOLEN)) return TRUE; - if (flags.nopick_dropped && otmp->was_dropped) + if (flags.nopick_dropped && otmp->how_lost == LOST_DROPPED) return FALSE; /* check for pickup_types */ @@ -3667,7 +3669,7 @@ tipcontainer(struct obj *box) /* or bag */ (void) add_to_container(targetbox, otmp); } } else if (highdrop) { - otmp->was_dropped = 1; + otmp->how_lost = LOST_DROPPED; /* might break or fall down stairs; handles altars itself */ hitfloor(otmp, TRUE); } else { @@ -3680,7 +3682,7 @@ tipcontainer(struct obj *box) /* or bag */ pline("%s%c", doname(otmp), nobj ? ',' : '.'); iflags.last_msg = PLNMSG_OBJNAM_ONLY; } - otmp->was_dropped = 1; + otmp->how_lost = LOST_DROPPED; dropy(otmp); if (iflags.last_msg != PLNMSG_OBJNAM_ONLY) terse = FALSE; /* terse formatting has been interrupted */ diff --git a/src/steal.c b/src/steal.c index eff28499d..1ddf9da5b 100644 --- a/src/steal.c +++ b/src/steal.c @@ -527,6 +527,7 @@ steal(struct monst* mtmp, char* objnambuf) (void) encumber_msg(); could_petrify = (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])); + otmp->how_lost = LOST_STOLEN; (void) mpickobj(mtmp, otmp); /* may free otmp */ if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) { minstapetrify(mtmp, TRUE);