From: nethack.rankin Date: Thu, 3 Feb 2011 21:49:36 +0000 (+0000) Subject: mimic-as-door stealing key (trunk only) X-Git-Tag: MOVE2GIT~269 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c34efb07bdc9f89bc1249ff2281528e658b09c7a;p=nethack mimic-as-door stealing key (trunk only) Suggested by a month ago when he reported that attempting to unlock a door which was actually a mimic simply told the player that the door was not locked or that there was no door. He thought that mimic should take the key/pick/card away from the hero. This gives a 50% chance for the unlocking tool to be stolen and become part of the mimic's inventory; it will be dropped when mimic is killed. The theft routine has groundwork to be able to be used to take the hero's wielded or thrown weapon when hitting, but the attack code doesn't call it so that won't happen (and the theft code hasn't been tested under that circumstance). I'm not sure whether mimics should be able to grab weapons, but g.cubes perhaps should, and if puddings could then "pudding farming" [using a low damage iron weapon to split puddings, yielding tons of experience, death drops, and #offer fodder when they're killed and repeatable for as long as at least one pudding is kept healthy enough to be split again] would become tougher to accomplish. [The item drop and corpse aspects have been toned down quite a bit since 3.4.3, but with sufficient patience it is still possible to abuse.] --- diff --git a/doc/fixes35.0 b/doc/fixes35.0 index f4fdb603a..776ec1947 100644 --- a/doc/fixes35.0 +++ b/doc/fixes35.0 @@ -467,6 +467,7 @@ Add M-C and M-R meta-key shortcuts for #conduct and #ride, respectively can now use ESC to cancel out of prompts for playing musical instruments being crowned gives an additional benefit: one extra skill slot/credit chatting to a gecko or shopkeeper while hallucinating gives alternate message +mimic posing as door might steal hero's key when [un]locking is attempted Platform- and/or Interface-Specific New Features diff --git a/include/extern.h b/include/extern.h index 2e599816b..4b36a5a6e 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2171,6 +2171,7 @@ E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P)); E int FDECL(steal, (struct monst *, char *)); E int FDECL(mpickobj, (struct monst *,struct obj *)); E void FDECL(stealamulet, (struct monst *)); +E void FDECL(maybe_absorb_item, (struct monst *,struct obj *,int,int)); E void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P)); E void FDECL(mdrop_special_objs, (struct monst *)); E void FDECL(relobj, (struct monst *,int,BOOLEAN_P)); diff --git a/src/lock.c b/src/lock.c index 0fce4639c..c90793cdc 100644 --- a/src/lock.c +++ b/src/lock.c @@ -406,6 +406,8 @@ pick_lock(pick) mtmp->mappearance == S_hcdoor)) { /* "The door actually was a !" */ stumble_onto_mimic(mtmp); + /* mimic might keep the key (50% chance, 10% for PYEC) */ + maybe_absorb_item(mtmp, pick, 50, 10); return PICKLOCK_LEARNED_SOMETHING; } if(!IS_DOOR(door->typ)) { diff --git a/src/steal.c b/src/steal.c index fa1f49a32..bfe773572 100644 --- a/src/steal.c +++ b/src/steal.c @@ -509,6 +509,10 @@ register struct obj *otmp; pline("%s out.", Tobjnam(otmp, "go")); snuff_otmp = TRUE; } + /* if monster is acquiring a thrown or kicked object, the throwing + or kicking code shouldn't continue to track and place it */ + if (otmp == thrownobj) thrownobj = 0; + else if (otmp == kickedobj) kickedobj = 0; /* for hero owned object on shop floor, mtmp is taking possession and if it's eventually dropped in a shop, shk will claim it */ if (!mtmp->mtame) otmp->no_charge = 0; @@ -571,6 +575,46 @@ struct monst *mtmp; } } +/* when a mimic gets poked with something, it might take that thing + (at present, only implemented for when the hero does the poking) */ +void +maybe_absorb_item(mon, obj, ochance, achance) +struct monst *mon; +struct obj *obj; +int ochance, achance; /* percent chance for ordinary item, artifact */ +{ + if (obj == uball || obj == uchain || obj->oclass == ROCK_CLASS || + obj_resists(obj, 100 - ochance, 100 - achance) || + !touch_artifact(obj, mon)) + return; + + if (carried(obj)) { + if (obj->owornmask) remove_worn_item(obj, TRUE); + if (obj->unpaid) subfrombill(obj, shop_keeper(*u.ushops)); + if (cansee(mon->mx, mon->my)) { + const char *MonName = Monnam(mon); + + /* mon might be invisible; avoid "It pulls ... and absorbs it!" */ + if (!strcmp(MonName, "It")) MonName = "Something"; + pline("%s pulls %s away from you and absorbs %s!", + MonName, yname(obj), (obj->quan > 1L) ? "them" : "it"); + } else { + const char *hand_s = body_part(HAND); + + if (bimanual(obj)) hand_s = makeplural(hand_s); + pline("%s %s pulled from your %s!", + upstart(yname(obj)), otense(obj, "are"), hand_s); + } + freeinv(obj); + } else { + /* not carried; presumeably thrown or kicked */ + if (canspotmon(mon)) + pline("%s absorbs %s!", Monnam(mon), yname(obj)); + } + /* add to mon's inventory */ + (void) mpickobj(mon, obj); +} + /* drop one object taken from a (possibly dead) monster's inventory */ void mdrop_obj(mon, obj, verbosely)