diff --git a/include/extern.h b/include/extern.h index 0fd51656f..13616d872 100644 --- a/include/extern.h +++ b/include/extern.h @@ -441,6 +441,7 @@ E void FDECL(wary_dog, (struct monst *, BOOLEAN_P)); /* ### dogmove.c ### */ +E struct obj *FDECL(droppables, (struct monst *)); E int FDECL(dog_nutrition, (struct monst *,struct obj *)); E int FDECL(dog_eat, (struct monst *,struct obj *,int,int,BOOLEAN_P)); E int FDECL(dog_move, (struct monst *,int)); @@ -1245,6 +1246,7 @@ E boolean FDECL(olfaction, (struct permonst *)); E boolean FDECL(itsstuck, (struct monst *)); E boolean FDECL(mb_trapped, (struct monst *)); +E boolean FDECL(monhaskey, (struct monst *,BOOLEAN_P)); E void FDECL(mon_regen, (struct monst *,BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int,int,struct monst *)); diff --git a/src/dogmove.c b/src/dogmove.c index 8add2faff..b6139f5c2 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)dogmove.c 3.5 2005/10/10 */ +/* SCCS Id: @(#)dogmove.c 3.5 2005/10/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,43 +13,109 @@ STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *)); STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int)); STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); -STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *)); STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P, XCHAR_P,XCHAR_P)); STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P)); STATIC_DCL void FDECL(quickmimic, (struct monst *)); -STATIC_OVL struct obj * -DROPPABLES(mon) -register struct monst *mon; +/* pick a carried item for pet to drop */ +struct obj * +droppables(mon) +struct monst *mon; { - register struct obj *obj; - struct obj *wep = MON_WEP(mon); - boolean item1 = FALSE, item2 = FALSE, item3 = FALSE; + struct obj *obj, *wep, + dummy, *pickaxe, *unihorn, *key; - if (is_animal(mon->data) || mindless(mon->data)) - item1 = item2 = item3 = TRUE; - if (!tunnels(mon->data) || !needspick(mon->data)) - item1 = TRUE; - if (nohands(mon->data) || verysmall(mon->data)) - item3 = TRUE; - for(obj = mon->minvent; obj; obj = obj->nobj) { - if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK - || !which_armor(mon, W_ARMS))) { - item1 = TRUE; - continue; - } - if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) { - item2 = TRUE; - continue; - } - if (!item3 && obj->otyp == SKELETON_KEY) { - item3 = TRUE; - continue; - } - if (!obj->owornmask && obj != wep) return obj; +#ifndef TOURIST +#define CREDIT_CARD STRANGE_OBJECT /* avoids messy conditionalization */ +#endif + +#ifndef GOLDOBJ + if (mon->mgold) return &zeroobj; /* pet has something to drop */ +#endif + dummy = zeroobj; + dummy.otyp = GOLD_PIECE; /* not STRANGE_OBJECT or tools of interest */ + dummy.oartifact = 1; /* so real artifact won't override "don't keep it" */ + pickaxe = unihorn = key = (struct obj *)0; + wep = MON_WEP(mon); + + if (is_animal(mon->data) || mindless(mon->data)) { + /* won't hang on to any objects of these types */ + pickaxe = unihorn = key = &dummy; /* act as if already have them */ + } else { + /* don't hang on to pick-axe if can't use one or don't need one */ + if (!tunnels(mon->data) || !needspick(mon->data)) pickaxe = &dummy; + /* don't hang on to key if can't open doors */ + if (nohands(mon->data) || verysmall(mon->data)) key = &dummy; + } + if (wep) { + if (is_pick(wep)) pickaxe = wep; + if (wep->otyp == UNICORN_HORN) unihorn = wep; + /* don't need any wielded check for keys... */ + } + + for (obj = mon->minvent; obj; obj = obj->nobj) { + switch (obj->otyp) { + case DWARVISH_MATTOCK: + /* reject mattock if couldn't wield it */ + if (which_armor(mon, W_ARMS)) break; + /* keep mattock in preference to pick unless pick is already + wielded or is an artifact and mattock isn't */ + if (pickaxe && pickaxe->otyp == PICK_AXE && + pickaxe != wep && (!pickaxe->oartifact || obj->oartifact)) + return pickaxe; /* drop the one we earlier decided to keep */ + /*FALLTHRU*/ + case PICK_AXE: + if (!pickaxe || (obj->oartifact && !pickaxe->oartifact)) { + if (pickaxe) return pickaxe; + pickaxe = obj; /* keep this digging tool */ + continue; + } + break; + + case UNICORN_HORN: + /* reject cursed unicorn horns */ + if (obj->cursed) break; + /* keep artifact unihorn in preference to ordinary one */ + if (!unihorn || (obj->oartifact && !unihorn->oartifact)) { + if (unihorn) return unihorn; + unihorn = obj; /* keep this unicorn horn */ + continue; + } + break; + + case SKELETON_KEY: + /* keep key in preference to lock-pick */ + if (key && key->otyp == LOCK_PICK && + (!key->oartifact || obj->oartifact)) + return key; /* drop the one we earlier decided to keep */ + /*FALLTHRU*/ + case LOCK_PICK: + /* keep lock-pick in preference to credit card */ + if (key && key->otyp == CREDIT_CARD && + (!key->oartifact || obj->oartifact)) + return key; + /*FALLTHRU*/ + case CREDIT_CARD: + if (!key || (obj->oartifact && !key->oartifact)) { + if (key) return key; + key = obj; /* keep this unlocking tool */ + continue; + } + break; + + default: + break; } - return (struct obj *)0; + + if (!obj->owornmask && obj != wep) return obj; + } + +#ifndef TOURIST +#undef CREDIT_CARD +#endif + + return (struct obj *)0; /* don't drop anything */ } static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; @@ -288,11 +354,7 @@ int udist; /* if we are carrying sth then we drop it (perhaps near @) */ /* Note: if apport == 1 then our behaviour is independent of udist */ /* Use udist+1 so steed won't cause divide by zero */ -#ifndef GOLDOBJ - if(DROPPABLES(mtmp) || mtmp->mgold) { -#else - if(DROPPABLES(mtmp)) { -#endif + if (droppables(mtmp)) { if (!rn2(udist+1) || !rn2(edog->apport)) if(rn2(10) < edog->apport){ relobj(mtmp, (int)mtmp->minvis, TRUE); @@ -363,7 +425,7 @@ int after, udist, whappr; omy = mtmp->my; in_masters_sight = couldsee(omx, omy); - dog_has_minvent = (DROPPABLES(mtmp) != 0); + dog_has_minvent = (droppables(mtmp) != 0); if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ gtyp = APPORT; @@ -595,7 +657,7 @@ register int after; /* this is extra fast monster movement */ } if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; - if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= UNLOCKDOOR; + if (monhaskey(mtmp, TRUE)) allowflags |= UNLOCKDOOR; /* note: the Wizard and Riders can unlock doors without a key; they won't use that ability if someone manages to tame them */ } diff --git a/src/monmove.c b/src/monmove.c index 85c2b46fa..1fb1d4934 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)monmove.c 3.5 2005/10/05 */ +/* SCCS Id: @(#)monmove.c 3.5 2005/10/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -39,6 +39,18 @@ register struct monst *mtmp; return(FALSE); } +/* check whether a monster is carrying a locking/unlocking tool */ +boolean +monhaskey(mon, for_unlocking) +struct monst *mon; +boolean for_unlocking; /* true => credit card ok, false => not ok */ +{ +#ifdef TOURIST + if (for_unlocking && m_carrying(mon, CREDIT_CARD)) return TRUE; +#endif + return m_carrying(mon, SKELETON_KEY) || m_carrying(mon, LOCK_PICK); +} + STATIC_OVL void watch_on_duty(mtmp) register struct monst *mtmp; @@ -676,7 +688,7 @@ register int after; #endif can_tunnel = tunnels(ptr); can_open = !(nohands(ptr) || verysmall(ptr)); - can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) || + can_unlock = ((can_open && monhaskey(mtmp, TRUE)) || mtmp->iswiz || is_rider(ptr)); doorbuster = is_giant(ptr); if(mtmp->wormno) goto not_special; @@ -1120,7 +1132,8 @@ postmov: && !can_tunnel /* taken care of below */ ) { struct rm *here = &levl[mtmp->mx][mtmp->my]; - boolean btrapped = (here->doormask & D_TRAPPED); + boolean btrapped = (here->doormask & D_TRAPPED), + observeit = canseeit && canspotmon(mtmp); if(here->doormask & (D_LOCKED|D_CLOSED) && (amorphous(ptr) || (!amorphous(ptr) && can_fog(mtmp) && @@ -1138,7 +1151,7 @@ postmov: if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { - if (canseemon(mtmp)) + if (observeit) pline("%s unlocks and opens a door.", Monnam(mtmp)); else if (canseeit) @@ -1158,7 +1171,9 @@ postmov: if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { - if (canseeit) + if (observeit) + pline("%s opens a door.", Monnam(mtmp)); + else if (canseeit) You_see("a door open."); else if (!Deaf) You_hear("a door open."); @@ -1176,7 +1191,10 @@ postmov: if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { - if (canseeit) + if (observeit) + pline("%s smashes down a door.", + Monnam(mtmp)); + else if (canseeit) You_see("a door crash open."); else if (!Deaf) You_hear("a door crash open."); diff --git a/src/steal.c b/src/steal.c index d3225a8bd..772cb04d2 100644 --- a/src/steal.c +++ b/src/steal.c @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)steal.c 3.5 2005/07/14 */ +/* SCCS Id: @(#)steal.c 3.5 2005/10/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -573,59 +573,32 @@ struct monst *mon; /* release the objects the creature is carrying */ void -relobj(mtmp,show,is_pet) -register struct monst *mtmp; -register int show; +relobj(mtmp, show, is_pet) +struct monst *mtmp; +int show; boolean is_pet; /* If true, pet should keep wielded/worn items */ { - register struct obj *otmp; - register int omx = mtmp->mx, omy = mtmp->my; - struct obj *keepobj = 0; - struct obj *wep = MON_WEP(mtmp); - boolean item1 = FALSE, item2 = FALSE; + struct obj *otmp; + int omx = mtmp->mx, omy = mtmp->my; - if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data)) - item1 = item2 = TRUE; - if (!tunnels(mtmp->data) || !needspick(mtmp->data)) - item1 = TRUE; - - while ((otmp = mtmp->minvent) != 0) { - obj_extract_self(otmp); - /* special case: pick-axe and unicorn horn are non-worn */ - /* items that we also want pets to keep 1 of */ - /* (It is a coincidence that these can also be wielded.) */ - if (otmp->owornmask || otmp == wep || - ((!item1 && otmp->otyp == PICK_AXE) || - (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) { - if (is_pet) { /* dont drop worn/wielded item */ - if (otmp->otyp == PICK_AXE) - item1 = TRUE; - if (otmp->otyp == UNICORN_HORN && !otmp->cursed) - item2 = TRUE; - otmp->nobj = keepobj; - keepobj = otmp; - continue; - } - } - mdrop_obj(mtmp, otmp, is_pet && flags.verbose); - } - - /* put kept objects back */ - while ((otmp = keepobj) != (struct obj *)0) { - keepobj = otmp->nobj; - (void) add_to_minv(mtmp, otmp); - } #ifndef GOLDOBJ + /* handle gold first since droppables() would get stuck on it */ if (mtmp->mgold) { - register long g = mtmp->mgold; + long g = mtmp->mgold; + (void) mkgold(g, omx, omy); if (is_pet && cansee(omx, omy) && flags.verbose) - pline("%s drops %ld gold piece%s.", Monnam(mtmp), - g, plur(g)); + pline("%s drops %ld gold piece%s.", Monnam(mtmp), + g, plur(g)); mtmp->mgold = 0L; } #endif - + + while ((otmp = (is_pet ? droppables(mtmp) : mtmp->minvent)) != 0) { + obj_extract_self(otmp); + mdrop_obj(mtmp, otmp, is_pet && flags.verbose); + } + if (show & cansee(omx, omy)) newsym(omx, omy); }