From 425bfb2a6116028b4eaece664a5ea01319099cd9 Mon Sep 17 00:00:00 2001 From: jwalz Date: Sat, 5 Jan 2002 21:05:53 +0000 Subject: [PATCH] *** empty log message *** --- src/steal.c | 571 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 src/steal.c diff --git a/src/steal.c b/src/steal.c new file mode 100644 index 000000000..665c87710 --- /dev/null +++ b/src/steal.c @@ -0,0 +1,571 @@ +/* SCCS Id: @(#)steal.c 3.3 2001/10/15 */ +/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" + +STATIC_PTR int NDECL(stealarm); + +#ifdef OVLB +STATIC_DCL const char *FDECL(equipname, (struct obj *)); + +STATIC_OVL const char * +equipname(otmp) +register struct obj *otmp; +{ + return ( +#ifdef TOURIST + (otmp == uarmu) ? "shirt" : +#endif + (otmp == uarmf) ? "boots" : + (otmp == uarms) ? "shield" : + (otmp == uarmg) ? "gloves" : + (otmp == uarmc) ? cloak_simple_name(otmp) : + (otmp == uarmh) ? "helmet" : "armor"); +} + +#ifndef GOLDOBJ +long /* actually returns something that fits in an int */ +somegold() +{ +#ifdef LINT /* long conv. ok */ + return(0L); +#else + return (long)( (u.ugold < 100) ? u.ugold : + (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) ); +#endif +} + +void +stealgold(mtmp) +register struct monst *mtmp; +{ + register struct obj *gold = g_at(u.ux, u.uy); + register long tmp; + + if (gold && ( !u.ugold || gold->quan > u.ugold || !rn2(5))) { + mtmp->mgold += gold->quan; + delobj(gold); + newsym(u.ux, u.uy); + pline("%s quickly snatches some gold from between your %s!", + Monnam(mtmp), makeplural(body_part(FOOT))); + if(!u.ugold || !rn2(5)) { + if (!tele_restrict(mtmp)) rloc(mtmp); + monflee(mtmp, 0, FALSE, FALSE); + } + } else if(u.ugold) { + u.ugold -= (tmp = somegold()); + Your("purse feels lighter."); + mtmp->mgold += tmp; + if (!tele_restrict(mtmp)) rloc(mtmp); + monflee(mtmp, 0, FALSE, FALSE); + flags.botl = 1; + } +} + +#else /* !GOLDOBJ */ + +long /* actually returns something that fits in an int */ +somegold(long umoney) +{ +#ifdef LINT /* long conv. ok */ + return(0L); +#else + return (long)( (umoney < 100) ? umoney : + (umoney > 10000) ? rnd(10000) : rnd((int) umoney) ); +#endif +} + +/* +Find the first (and hopefully only) gold object in a chain. +Used when leprechaun (or you as leprechaun) looks for +someone else's gold. Returns a pointer so the gold may +be seized without further searching. +May search containers too. +Deals in gold only, as leprechauns don't care for lesser coins. +*/ +struct obj * +findgold(chain) +register struct obj *chain; +{ + while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj; + return chain; +} + +/* +Steal gold coins only. Leprechauns don't care for lesser coins. +*/ +void +stealgold(mtmp) +register struct monst *mtmp; +{ + register struct obj *fgold = g_at(u.ux, u.uy); + register struct obj *ygold; + register long tmp; + + /* skip lesser coins on the floor */ + while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere; + + /* Do you have real gold? */ + ygold = findgold(invent); + + if (fgold && ( !ygold || fgold->quan > ygold->quan || !rn2(5))) { + obj_extract_self(fgold); + add_to_minv(mtmp, fgold); + newsym(u.ux, u.uy); + pline("%s quickly snatches some gold from between your %s!", + Monnam(mtmp), makeplural(body_part(FOOT))); + if(!ygold || !rn2(5)) { + if (!tele_restrict(mtmp)) rloc(mtmp); + monflee(mtmp, 0, FALSE, FALSE); + } + } else if(ygold) { + const int gold_price = objects[GOLD_PIECE].oc_cost; + tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price; + tmp = min(tmp, ygold->quan); + if (tmp < ygold->quan) splitobj(ygold, tmp); + freeinv(ygold); + add_to_minv(mtmp, ygold); + Your("purse feels lighter."); + if (!tele_restrict(mtmp)) rloc(mtmp); + monflee(mtmp, 0, FALSE, FALSE); + flags.botl = 1; + } +} +#endif /* GOLDOBJ */ + +/* steal armor after you finish taking it off */ +unsigned int stealoid; /* object to be stolen */ +unsigned int stealmid; /* monster doing the stealing */ + +STATIC_PTR int +stealarm() +{ + register struct monst *mtmp; + register struct obj *otmp; + + for(otmp = invent; otmp; otmp = otmp->nobj) { + if(otmp->o_id == stealoid) { + for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if(mtmp->m_id == stealmid) { + if(DEADMONSTER(mtmp)) impossible("stealarm(): dead monster stealing"); + if(!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */ + goto botm; + if(otmp->unpaid) + subfrombill(otmp, shop_keeper(*u.ushops)); + freeinv(otmp); + pline("%s steals %s!", Monnam(mtmp), doname(otmp)); + (void) mpickobj(mtmp,otmp); /* may free otmp */ + monflee(mtmp, 0, FALSE, FALSE); + if (!tele_restrict(mtmp)) rloc(mtmp); + break; + } + } + break; + } + } +botm: stealoid = 0; + return 0; +} + +/* An object you're wearing has been taken off by a monster (theft or + seduction). Also used if a worn item gets transformed (stone to flesh). */ +void +remove_worn_item(obj) +struct obj *obj; +{ + if (donning(obj)) + cancel_don(); + if (!obj->owornmask) + return; + + if (obj->owornmask & W_ARMOR) { + if (obj == uskin) { + impossible("Removing embedded scales?"); + skinback(TRUE); /* uarm = uskin; uskin = 0; */ + } + if (obj == uarm) (void) Armor_off(); + else if (obj == uarmc) (void) Cloak_off(); + else if (obj == uarmf) (void) Boots_off(); + else if (obj == uarmg) (void) Gloves_off(); + else if (obj == uarmh) (void) Helmet_off(); + else if (obj == uarms) (void) Shield_off(); + else setworn((struct obj *)0, obj->owornmask & W_ARMOR); + } else if (obj->owornmask & W_AMUL) { + Amulet_off(); + } else if (obj->owornmask & W_RING) { + Ring_gone(obj); + } else if (obj->owornmask & W_TOOL) { + Blindf_off(obj); + } else if (obj->owornmask & (W_BALL|W_CHAIN)) { + unpunish(); + } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) { + if (obj == uwep) + uwepgone(); + else if (obj == uswapwep) + uswapwepgone(); + else if (obj == uquiver) + uqwepgone(); + } + + /* catchall */ + if (obj->owornmask) setnotworn(obj); +} + +/* Returns 1 when something was stolen (or at least, when N should flee now) + * Returns -1 if the monster died in the attempt + * Avoid stealing the object stealoid + */ +int +steal(mtmp, objnambuf) +struct monst *mtmp; +char *objnambuf; +{ + struct obj *otmp; + int tmp, could_petrify, named = 0, armordelay; + boolean monkey_business; /* true iff an animal is doing the thievery */ + + if (objnambuf) *objnambuf = '\0'; + /* the following is true if successful on first of two attacks. */ + if(!monnear(mtmp, u.ux, u.uy)) return(0); + + if (!invent || (inv_cnt() == 1 && uskin)) { +nothing_to_steal: + /* Not even a thousand men in armor can strip a naked man. */ + if(Blind) + pline("Somebody tries to rob you, but finds nothing to steal."); + else + pline("%s tries to rob you, but there is nothing to steal!", + Monnam(mtmp)); + return(1); /* let her flee */ + } + + monkey_business = is_animal(mtmp->data); + if (monkey_business) { + ; /* skip ring special cases */ + } else if (Adornment & LEFT_RING) { + otmp = uleft; + goto gotobj; + } else if (Adornment & RIGHT_RING) { + otmp = uright; + goto gotobj; + } + + tmp = 0; + for(otmp = invent; otmp; otmp = otmp->nobj) + if ((!uarm || otmp != uarmc) && otmp != uskin +#ifdef INVISIBLE_OBJECTS + && (!otmp->oinvis || perceives(mtmp->data)) +#endif + ) + tmp += ((otmp->owornmask & + (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1); + if (!tmp) goto nothing_to_steal; + tmp = rn2(tmp); + for(otmp = invent; otmp; otmp = otmp->nobj) + if ((!uarm || otmp != uarmc) && otmp != uskin +#ifdef INVISIBLE_OBJECTS + && (!otmp->oinvis || perceives(mtmp->data)) +#endif + ) + if((tmp -= ((otmp->owornmask & + (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0) + break; + if(!otmp) { + impossible("Steal fails!"); + return(0); + } + /* can't steal gloves while wielding - so steal the wielded item. */ + if (otmp == uarmg && uwep) + otmp = uwep; + /* can't steal armor while wearing cloak - so steal the cloak. */ + else if(otmp == uarm && uarmc) otmp = uarmc; +#ifdef TOURIST + else if(otmp == uarmu && uarmc) otmp = uarmc; + else if(otmp == uarmu && uarm) otmp = uarm; +#endif +gotobj: + if(otmp->o_id == stealoid) return(0); + + /* animals can't overcome curse stickiness nor unlock chains */ + if (monkey_business) { + boolean ostuck; + /* is the player prevented from voluntarily giving up this item? + (ignores loadstones; the !can_carry() check will catch those) */ + if (otmp == uball) + ostuck = TRUE; /* effectively worn; curse is implicit */ + else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) + ostuck = FALSE; /* not really worn; curse doesn't matter */ + else + ostuck = (otmp->cursed && otmp->owornmask); + + if (ostuck || !can_carry(mtmp, otmp)) { + static const char *how[] = { "steal","snatch","grab","take" }; + cant_take: + pline("%s tries to %s your %s but gives up.", + Monnam(mtmp), how[rn2(SIZE(how))], + (otmp->owornmask & W_ARMOR) ? equipname(otmp) : xname(otmp)); + /* the fewer items you have, the less likely the thief + is going to stick around to try again (0) instead of + running away (1) */ + return !rn2(inv_cnt() / 5 + 2); + } + } + + if (otmp->otyp == LEASH && otmp->leashmon) { + if (monkey_business && otmp->cursed) goto cant_take; + o_unleash(otmp); + } + + /* you're going to notice the theft... */ + stop_occupation(); + + if((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))){ + switch(otmp->oclass) { + case TOOL_CLASS: + case AMULET_CLASS: + case RING_CLASS: + case FOOD_CLASS: /* meat ring */ + remove_worn_item(otmp); + break; + case ARMOR_CLASS: + armordelay = objects[otmp->otyp].oc_delay; + /* Stop putting on armor which has been stolen. */ + if (donning(otmp)) { + remove_worn_item(otmp); + break; + } else if (monkey_business) { + /* animals usually don't have enough patience + to take off items which require extra time */ + if (armordelay >= 1 && rn2(10)) goto cant_take; + remove_worn_item(otmp); + break; + } else { + int curssv = otmp->cursed; + int slowly; + + otmp->cursed = 0; + /* can't charm you without first waking you */ + if (multi < 0 && is_fainted()) unmul((char *)0); + slowly = (armordelay >= 1 || multi < 0); + if(flags.female) + pline("%s charms you. You gladly %s your %s.", + Blind ? "She" : Monnam(mtmp), + curssv ? "let her take" : + slowly ? "start removing" : "hand over", + equipname(otmp)); + else + pline("%s seduces you and %s off your %s.", + Blind ? "It" : Adjmonnam(mtmp, "beautiful"), + curssv ? "helps you to take" : + slowly ? "you start taking" : "you take", + equipname(otmp)); + named++; + /* the following is to set multi for later on */ + nomul(-armordelay); + remove_worn_item(otmp); + otmp->cursed = curssv; + if(multi < 0){ + /* + multi = 0; + nomovemsg = 0; + afternmv = 0; + */ + stealoid = otmp->o_id; + stealmid = mtmp->m_id; + afternmv = stealarm; + return(0); + } + } + break; + default: + impossible("Tried to steal a strange worn thing. [%d]", + otmp->oclass); + } + } + else if (otmp->owornmask) + remove_worn_item(otmp); + + /* do this before removing it from inventory */ + if (objnambuf) Strcpy(objnambuf, yname(otmp)); + + freeinv(otmp); + pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); + could_petrify = (otmp->otyp == CORPSE && + touch_petrifies(&mons[otmp->corpsenm])); + (void) mpickobj(mtmp,otmp); /* may free otmp */ + if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) { + minstapetrify(mtmp, TRUE); + return -1; + } + return((multi < 0) ? 0 : 1); +} + +#endif /* OVLB */ +#ifdef OVL1 + +/* Returns 1 if otmp is free'd, 0 otherwise. */ +int +mpickobj(mtmp,otmp) +register struct monst *mtmp; +register struct obj *otmp; +{ + int freed_otmp; + +#ifndef GOLDOBJ + if (otmp->oclass == GOLD_CLASS) { + mtmp->mgold += otmp->quan; + obfree(otmp, (struct obj *)0); + freed_otmp = 1; + } else { +#endif + boolean snuff_otmp = FALSE; + /* don't want hidden light source inside the monster; assumes that + engulfers won't have external inventories; whirly monsters cause + the light to be extinguished rather than letting it shine thru */ + if (otmp->lamplit && /* hack to avoid function calls for most objs */ + obj_sheds_light(otmp) && + attacktype(mtmp->data, AT_ENGL)) { + /* this is probably a burning object that you dropped or threw */ + if (u.uswallow && mtmp == u.ustuck && !Blind) + pline("%s go%s out.", The(xname(otmp)), + otmp->quan == 1L ? "es" : ""); + snuff_otmp = TRUE; + } + /* Must do carrying effects on object prior to add_to_minv() */ + carry_obj_effects(otmp); + /* add_to_minv() might free otmp [if merged with something else], + so we have to call it after doing the object checks */ + freed_otmp = add_to_minv(mtmp, otmp); + /* and we had to defer this until object is in mtmp's inventory */ + if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my); +#ifndef GOLDOBJ + } +#endif + return freed_otmp; +} + +#endif /* OVL1 */ +#ifdef OVLB + +void +stealamulet(mtmp) +struct monst *mtmp; +{ + struct obj *otmp = (struct obj *)0; + int real=0, fake=0; + + /* select the artifact to steal */ + if(u.uhave.amulet) { + real = AMULET_OF_YENDOR; + fake = FAKE_AMULET_OF_YENDOR; + } else if(u.uhave.questart) { + for(otmp = invent; otmp; otmp = otmp->nobj) + if(is_quest_artifact(otmp)) break; + if (!otmp) return; /* should we panic instead? */ + } else if(u.uhave.bell) { + real = BELL_OF_OPENING; + fake = BELL; + } else if(u.uhave.book) { + real = SPE_BOOK_OF_THE_DEAD; + } else if(u.uhave.menorah) { + real = CANDELABRUM_OF_INVOCATION; + } else return; /* you have nothing of special interest */ + + if (!otmp) { + /* If we get here, real and fake have been set up. */ + for(otmp = invent; otmp; otmp = otmp->nobj) + if(otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz)) + break; + } + + if (otmp) { /* we have something to snatch */ + if (otmp->owornmask) + remove_worn_item(otmp); + freeinv(otmp); + /* mpickobj wont merge otmp because none of the above things + to steal are mergable */ + (void) mpickobj(mtmp,otmp); /* may merge and free otmp */ + pline("%s stole %s!", Monnam(mtmp), doname(otmp)); + if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) + rloc(mtmp); + } +} + +#endif /* OVLB */ +#ifdef OVL0 + +/* release the objects the creature is carrying */ +void +relobj(mtmp,show,is_pet) +register struct monst *mtmp; +register 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; + + 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; + } + mtmp->misc_worn_check &= ~(otmp->owornmask); +#ifdef STEED + /* don't charge for an owned saddle on dead pet */ + if (mtmp->mtame && mtmp->mhp == 0 && + (otmp->owornmask & W_SADDLE) && !otmp->unpaid && + costly_spot(mtmp->mx, mtmp->my)) + otmp->no_charge = 1; +#endif + otmp->owornmask = 0L; + } + if (is_pet && cansee(omx, omy) && flags.verbose) + pline("%s drops %s.", Monnam(mtmp), + distant_name(otmp, doname)); + if (flooreffects(otmp, omx, omy, "fall")) continue; + place_object(otmp, omx, omy); + stackobj(otmp); + } + /* put kept objects back */ + while ((otmp = keepobj) != (struct obj *)0) { + keepobj = otmp->nobj; + (void) add_to_minv(mtmp, otmp); + } +#ifndef GOLDOBJ + if (mtmp->mgold) { + register 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)); + mtmp->mgold = 0L; + } +#endif + + if (show & cansee(omx, omy)) + newsym(omx, omy); +} + +#endif /* OVL0 */ + +/*steal.c*/