diff -Ndur nethack-3.4.3/src/objnam.c nethack-patched/src/objnam.c --- nethack-3.4.3/src/objnam.c 2006-12-04 21:59:04.000000000 +0000 +++ nethack-patched/src/objnam.c 2007-02-28 00:53:20.000000000 +0000 @@ -1738,6 +1738,152 @@ { (const char *)0, 0 }, }; + +static struct obj * +ron_getobj(olist, typ, bucstatus, ispoisoned, erodeproof, spe, name) +struct obj *olist; +int typ, bucstatus; +int ispoisoned, erodeproof, spe; +const char *name; +{ + struct obj *otmp; + for (otmp = olist; otmp; otmp = otmp->nobj) { + if (otmp->otyp != typ) continue; + if (bucstatus == 1 && !otmp->blessed) continue; + if (bucstatus == 2 && (otmp->blessed || otmp->cursed)) continue; + if (bucstatus == 3 && !otmp->cursed) continue; + if (ispoisoned && !otmp->opoisoned) continue; + if (erodeproof && !otmp->oerodeproof) continue; + if (name && !(otmp->onamelth && !strcmp(name, ONAME(otmp)))) + continue; + if (spe != -998 && otmp->spe != spe) continue; + /* That's all the checks we can make. */ + return otmp; + } + return((struct obj *) 0); +} + +/* + Find a monster who seems to match the given traits. Match on these criteria: + (1) Does the monster's name match a given name ("Bob")? ownercnt must be -3. 100% match. + (2) Does the monster's type match the name ("gnome")? 25% match. + (2a) Is the monster visible? +25% match, or +50% if "the" was given. + (2b) Is the monster carrying a matching object? +25% match. + Return the most likely match. +*/ +static struct monst * +ron_locateowner(mname, ownercnt, mgold, typ, bucstatus, ispoisoned, erodeproof, name) +const char *mname; +int ownercnt, mgold, typ; +int bucstatus, ispoisoned, erodeproof; +const char *name; +{ + struct monst *mtmp, *bestmatch=0; + int ptmp, bestp=0; + /* Just check the monsters on this level. Checking visited levels is way too hard. */ + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + ptmp = 0; + if (ownercnt == -3 && mtmp->isshk && !strcmp(shkname(mtmp), mname)) { + ptmp = 100; /* match "Asidonhopo" at 100% */ + } else if (ownercnt == -3 && mtmp->mnamelth && !strcmp(NAME(mtmp), mname)) { + ptmp = 100; /* match "Fido" at 100% */ + } else if (!strcmp(mtmp->data->mname, mname) || /* "gnome lord" */ + mtmp->ispriest && !strcmp("priest", mname)) { /* "priest" */ + ptmp = 25; + if (canspotmon(mtmp)) ptmp += (ownercnt == -3)? 50: 25; + if (mgold != -9) { +#ifdef GOLDOBJ + struct obj *mongold = findgold(mtmp->minvent); + int mqgold = (mongold == 0)? 0: mongold->quan; + if (mqgold >= mgold) + ptmp += 25; +#else + if (mtmp->mgold >= mgold) + ptmp += 25; +#endif + } + else if (ron_getobj(mtmp->minvent, typ, bucstatus, ispoisoned, erodeproof, -998, name)) + ptmp += 25; + } + if (ptmp > bestp) { + bestp = ptmp; + bestmatch = mtmp; + } + } + return bestmatch; +} + + +/* Given *bp of the form "12 ^blessed +5 arrows" or "1 ^Longbow of Diana", return 12 or 1, + respectively. Return 0 for "0 ^arrows"; return -2 for "the ^arrow". Advance *bp to the + marked position in each string. Return -1 for "an" and -2 for "the". +*/ +static int +ron_number(bp) +register char **bp; +{ + int cnt, cl; + cnt = -3; + cl = 0; + if (!strncmpi(*bp, "an ", cl=3) || + !strncmpi(*bp, "a ", cl=2)) { + cnt = -1; + } else if (!strncmpi(*bp, "the ", cl=4)) { + cnt = -2; + } else if (digit(**bp) && strcmp(*bp, "0")) { + cnt = atoi(*bp); + while(digit(**bp)) (*bp)++; + while(**bp == ' ') (*bp)++; + cl = 0; + } else + cl = 0; + *bp += cl; + return cnt; +} + +/* Given *bp of the form "Brad's ^pit" or "Croesus' ^gold", return + "Brad" or "Croesus", respectively, and advance *bp to the marked + location in each string. + Return 0 if no "owner" string exists, e.g. "^+4 blessed arrows". +*/ +static char * +ron_owner(bp) +register char **bp; +{ + char *spc, *tmp; + + spc = (*bp); + while (1) { + if ((spc = strchr(spc+1, ' ')) == (char *)0 || spc < *bp + 2) + return (char *) 0; + if (spc[-1] == '\'' && strchr("SsXx", spc[-2])) { + tmp = spc-1; /* "Brad^'s pit" */ + goto found_owner; + } else if (spc[-2] == '\'' && strchr("Ss", spc[-1])) { + tmp = spc-2; + goto found_owner; /* "Croesus^' gold" */ + /* Handle "a dagger named John's Dagger" at the expense of "an archlich named Bob's gold", + since the latter could be phrased better as simply "Bob's gold". */ + } else if (spc > (*bp)+6 && !strncmp(spc-6, " named", 6)) { + return (char *) 0; + } else if (spc > (*bp)+7 && !strncmp(spc-7, " called", 7)) { + return (char *) 0; + } else if (spc > (*bp)+8 && !strncmp(spc-8, " labeled", 8)) { + return (char *) 0; + } else if (spc > (*bp)+9 && !strncmp(spc-9, " labelled", 9)) { + return (char *) 0; + } + } + +found_owner: + *tmp = '\0'; + tmp = *bp; + *bp = spc+1; + return tmp; +} + + /* * Return something wished for. Specifying a null pointer for * the user request string results in a random object. Otherwise, @@ -1748,7 +1894,7 @@ */ struct obj * readobjnam(bp, no_wish, from_user) -register char *bp; +char *bp; struct obj *no_wish; boolean from_user; { @@ -1757,11 +1903,12 @@ register struct obj *otmp; int cnt, spe, spesgn, typ, very, rechrg; int blessed, uncursed, iscursed, ispoisoned, isgreased; + int bucstatus; /* blessed=1, uncursed=2, cursed=3 */ int eroded, eroded2, erodeproof; #ifdef INVISIBLE_OBJECTS int isinvisible; #endif - int halfeaten, mntmp, contents; + int halfeaten, mntmp, contents, ownercnt; int islit, unlabeled, ishistoric, isdiluted; struct fruit *f; int ftype = current_fruit; @@ -1784,6 +1931,9 @@ char oclass; char *un, *dn, *actualn; const char *name=0; + const char *owner=0; + struct monst *mowner=0; + boolean asked_for_gold, all_the_gold; cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed = @@ -1799,6 +1949,9 @@ contents = UNDEFINED; oclass = 0; actualn = dn = un = 0; + ownercnt = 0; + asked_for_gold = FALSE; + all_the_gold = FALSE; if (!bp) goto any; /* first, remove extra whitespace they may have typed */ @@ -1810,21 +1963,31 @@ /* save the [nearly] unmodified choice string */ Strcpy(fruitbuf, bp); + + /* Get numbers and owners from the front of the string. */ + + if (!bp) goto any; + cnt = ron_number(&bp); + if (cnt < 0) { + ownercnt = cnt; /* "the gnome's aklys", "Bill's 20 arrows" */ + owner = ron_owner(&bp); + cnt = (owner? ron_number(&bp): 0); + } else if (cnt >= 0 && !strncmpi(bp, "of ", 3)) { + bp += 3; /* "2 of Bill's arrows" */ + ownercnt = ron_number(&bp); /* "2 of the gnome's 5 arrows" */ + owner = ron_owner(&bp); + (void) ron_number(&bp); + } + if (cnt == -3) all_the_gold = TRUE; + if (cnt < 0) cnt = 1; + + /* Get adjectives and qualifiers from the front of the string. */ + for(;;) { register int l; if (!bp || !*bp) goto any; - if (!strncmpi(bp, "an ", l=3) || - !strncmpi(bp, "a ", l=2)) { - cnt = 1; - } else if (!strncmpi(bp, "the ", l=4)) { - ; /* just increment `bp' by `l' below */ - } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { - cnt = atoi(bp); - while(digit(*bp)) bp++; - while(*bp == ' ') bp++; - l = 0; - } else if (*bp == '+' || *bp == '-') { + if (*bp == '+' || *bp == '-') { spesgn = (*bp++ == '+') ? 1 : -1; spe = atoi(bp); while(digit(*bp)) bp++; @@ -1894,7 +2057,9 @@ } else break; bp += l; } - if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */ + + /* Get qualifiers (charges) from the end of the string. */ + if (strlen(bp) > 1) { if ((p = rindex(bp, '(')) != 0) { if (p > bp && p[-1] == ' ') p[-1] = 0; @@ -2088,25 +2253,8 @@ if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") || !strcmpi(bp, "gold") || !strcmpi(bp, "money") || !strcmpi(bp, "coin") || *bp == GOLD_SYM) { - if (cnt > 5000 -#ifdef WIZARD - && !wizard -#endif - ) cnt=5000; - if (cnt < 1) cnt=1; -#ifndef GOLDOBJ - if (from_user) - pline("%d gold piece%s.", cnt, plur(cnt)); - u.ugold += cnt; - flags.botl=1; - return (&zeroobj); -#else - otmp = mksobj(GOLD_PIECE, FALSE, FALSE); - otmp->quan = cnt; - otmp->owt = weight(otmp); - flags.botl=1; - return (otmp); -#endif + asked_for_gold = TRUE; + goto typfnd; } if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS @@ -2315,6 +2463,22 @@ /* avoid stupid mistakes */ if((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz)) trap = ROCKTRAP; +#ifdef BRADS_PIT + if (trap == PIT && owner && + !strncmp(owner, BRADS_TEXT, (sizeof BRADS_TEXT)-3) && + owner[(sizeof BRADS_TEXT)-3] == '\0') { + if (brads_pit.created) { + pline("Sorry..."); + return(&zeroobj); + } + (void) maketrap(u.ux, u.uy, trap); + if (!brads_pit.created) + make_engr_at(u.ux,u.uy,BRADS_TEXT,0L,ENGRAVE); + brads_pit.created = TRUE; + pline("%s pit.", BRADS_TEXT); + return(&zeroobj); + } +#endif (void) maketrap(u.ux, u.uy, trap); pline("%s.", An(tname)); return(&zeroobj); @@ -2413,6 +2577,20 @@ if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))]; typfnd: if (typ) oclass = objects[typ].oc_class; + bucstatus = blessed ? 1 : (uncursed ? 2 : (iscursed ? 3 : 0)); + + if (owner && !mowner) { + /* Time to figure out from whom, exactly, we're trying to steal an item. + Basically, look for somebody called the given name; or else, look for + somebody of the given monster type who's carrying an object of the given + description, and preferably is visible. */ + /* Pass only a few of our flags; it shouldn't really matter. */ + const char *aname = (name? name: actualn); + mowner = ron_locateowner(owner, ownercnt, (asked_for_gold? (all_the_gold? -3: cnt): -9), + typ, bucstatus, ispoisoned, erodeproof, aname); + if (!mowner) /* No such monster exists? */ + return 0; + } /* check for some objects that are not allowed */ if (typ && objects[typ].oc_unique) { @@ -2437,8 +2615,53 @@ } } + if (asked_for_gold) { + if (!owner) { + if (cnt > 5000 +#ifdef WIZARD + && !wizard +#endif + ) + cnt = 5000; + if (cnt < 1) cnt = 1; +#ifndef GOLDOBJ + u.ugold += cnt; + otmp = (&zeroobj); +#else + otmp = mksobj(GOLD_PIECE, FALSE, FALSE); + otmp->quan = cnt; + otmp->owt = weight(otmp); +#endif + } else { +#ifndef GOLDOBJ + int mgold = mowner->mgold; +#else + struct obj *mongold = findgold(mowner->minvent); + int mgold = (mongold == 0)? 0: mongold->quan; +#endif + if (all_the_gold) cnt = mgold; + else if (cnt > mgold) cnt = rnl(mgold+1); +#ifndef GOLDOBJ + mowner->mgold -= cnt; + u.ugold += cnt; + otmp = (&zeroobj); +#else + if (cnt != 0) { + if (cnt < mongold->quan) + splitobj(mongold, cnt); + obj_extract_self(mongold); + otmp = mongold; + } else + otmp = (&zeroobj); +#endif + } + if (from_user) pline("%d gold pieces.", cnt); + flags.botl=1; + return(otmp); + } + /* catch any other non-wishable objects */ - if (objects[typ].oc_nowish + if (objects[typ].oc_nowish && !owner #ifdef WIZARD && !wizard #endif @@ -2447,18 +2670,40 @@ /* convert magic lamps to regular lamps before lighting them or setting the charges */ - if (typ == MAGIC_LAMP + if (typ == MAGIC_LAMP && !owner #ifdef WIZARD && !wizard #endif ) typ = OIL_LAMP; - if(typ) { + if (!owner) { + if(typ) { otmp = mksobj(typ, TRUE, FALSE); - } else { + } else { otmp = mkobj(oclass, FALSE); if (otmp) typ = otmp->otyp; + } + } else { + long unwornmask; + otmp = ron_getobj(mowner->minvent, typ, bucstatus, + ispoisoned, erodeproof, spesgn ? spe : -998, name); + if (!otmp) return 0; + obj_extract_self(otmp); + if (otmp == MON_WEP(mowner)) + possibly_unwield(mowner, FALSE); /* grab it right from his hand! */ + else if ((unwornmask = otmp->owornmask) != 0L) { + mowner->misc_worn_check &= ~unwornmask; + if (otmp->owornmask & W_WEP) { + setmnotwielded(mowner, otmp); + MON_NOWEP(mowner); + } + otmp->owornmask = 0L; + update_mon_intrinsics(mowner, otmp, FALSE, FALSE); + } + if (canseemon(mowner)) + pline("%s looks startled!", Monnam(mowner)); + return(otmp); /* don't reset any of its properties */ } if (islit &&