Home | History | Annotate | Line # | Download | only in hack
      1 /*	$NetBSD: hack.objnam.c,v 1.11 2011/08/07 06:03:45 dholland Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
      5  * Amsterdam
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions are
     10  * met:
     11  *
     12  * - Redistributions of source code must retain the above copyright notice,
     13  * this list of conditions and the following disclaimer.
     14  *
     15  * - Redistributions in binary form must reproduce the above copyright
     16  * notice, this list of conditions and the following disclaimer in the
     17  * documentation and/or other materials provided with the distribution.
     18  *
     19  * - Neither the name of the Stichting Centrum voor Wiskunde en
     20  * Informatica, nor the names of its contributors may be used to endorse or
     21  * promote products derived from this software without specific prior
     22  * written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
     27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     35  */
     36 
     37 /*
     38  * Copyright (c) 1982 Jay Fenlason <hack (at) gnu.org>
     39  * All rights reserved.
     40  *
     41  * Redistribution and use in source and binary forms, with or without
     42  * modification, are permitted provided that the following conditions
     43  * are met:
     44  * 1. Redistributions of source code must retain the above copyright
     45  *    notice, this list of conditions and the following disclaimer.
     46  * 2. Redistributions in binary form must reproduce the above copyright
     47  *    notice, this list of conditions and the following disclaimer in the
     48  *    documentation and/or other materials provided with the distribution.
     49  * 3. The name of the author may not be used to endorse or promote products
     50  *    derived from this software without specific prior written permission.
     51  *
     52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
     55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 __RCSID("$NetBSD: hack.objnam.c,v 1.11 2011/08/07 06:03:45 dholland Exp $");
     67 #endif				/* not lint */
     68 
     69 #include <stdlib.h>
     70 #include "hack.h"
     71 #include "extern.h"
     72 #define Snprintf (void) snprintf
     73 #define Strcat  (void) strcat
     74 #define	Strcpy	(void) strcpy
     75 #define	PREFIX	15
     76 
     77 static char *strprepend(char *, char *);
     78 static char *sitoa(int);
     79 
     80 static char *
     81 strprepend(char *s, char *pref)
     82 {
     83 	int             i = strlen(pref);
     84 	if (i > PREFIX) {
     85 		pline("WARNING: prefix too short.");
     86 		return (s);
     87 	}
     88 	s -= i;
     89 	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
     90 	return (s);
     91 }
     92 
     93 static char *
     94 sitoa(int a)
     95 {
     96 	static char     buf[13];
     97 	Snprintf(buf, sizeof(buf), (a < 0) ? "%d" : "+%d", a);
     98 	return (buf);
     99 }
    100 
    101 char           *
    102 typename(int otyp)
    103 {
    104 	static char     buf[BUFSZ];
    105 	size_t bufpos;
    106 	struct objclass *ocl = &objects[otyp];
    107 	const char     *an = ocl->oc_name;
    108 	const char     *dn = ocl->oc_descr;
    109 	char           *un = ocl->oc_uname;
    110 	int             nn = ocl->oc_name_known;
    111 	switch (ocl->oc_olet) {
    112 	case POTION_SYM:
    113 		Strcpy(buf, "potion");
    114 		break;
    115 	case SCROLL_SYM:
    116 		Strcpy(buf, "scroll");
    117 		break;
    118 	case WAND_SYM:
    119 		Strcpy(buf, "wand");
    120 		break;
    121 	case RING_SYM:
    122 		Strcpy(buf, "ring");
    123 		break;
    124 	default:
    125 		if (nn) {
    126 			Strcpy(buf, an);
    127 			if (otyp >= TURQUOISE && otyp <= JADE)
    128 				Strcat(buf, " stone");
    129 			if (un) {
    130 				bufpos = strlen(buf);
    131 				Snprintf(buf+bufpos, sizeof(buf)-bufpos,
    132 					" called %s", un);
    133 			}
    134 			if (dn) {
    135 				bufpos = strlen(buf);
    136 				Snprintf(buf+bufpos, sizeof(buf)-bufpos,
    137 					" (%s)", dn);
    138 			}
    139 		} else {
    140 			strlcpy(buf, dn ? dn : an, sizeof(buf));
    141 			if (ocl->oc_olet == GEM_SYM) {
    142 				strlcat(buf, " gem", sizeof(buf));
    143 			}
    144 			if (un) {
    145 				bufpos = strlen(buf);
    146 				Snprintf(buf+bufpos, sizeof(buf)-bufpos,
    147 					" called %s", un);
    148 			}
    149 		}
    150 		return (buf);
    151 	}
    152 	/* here for ring/scroll/potion/wand */
    153 	if (nn) {
    154 		bufpos = strlen(buf);
    155 		Snprintf(buf+bufpos, sizeof(buf)-bufpos, " of %s", an);
    156 	}
    157 	if (un) {
    158 		bufpos = strlen(buf);
    159 		Snprintf(buf+bufpos, sizeof(buf)-bufpos, " called %s", un);
    160 	}
    161 	if (dn) {
    162 		bufpos = strlen(buf);
    163 		Snprintf(buf+bufpos, sizeof(buf)-bufpos, " (%s)", dn);
    164 	}
    165 	return (buf);
    166 }
    167 
    168 char           *
    169 xname(struct obj *obj)
    170 {
    171 	static char     bufr[BUFSZ];
    172 	/* caution: doname() and aobjnam() below "know" these sizes */
    173 	char           *buf = &(bufr[PREFIX]);	/* leave room for "17 -3 " */
    174 	size_t          bufmax = sizeof(bufr) - PREFIX;
    175 	int             nn = objects[obj->otyp].oc_name_known;
    176 	const char     *an = objects[obj->otyp].oc_name;
    177 	const char     *dn = objects[obj->otyp].oc_descr;
    178 	char           *un = objects[obj->otyp].oc_uname;
    179 	int             pl = (obj->quan != 1);
    180 
    181 	if (!obj->dknown && !Blind)
    182 		obj->dknown = 1;/* %% doesnt belong here */
    183 	switch (obj->olet) {
    184 	case AMULET_SYM:
    185 		Strcpy(buf, (obj->spe < 0 && obj->known)
    186 		       ? "cheap plastic imitation of the " : "");
    187 		Strcat(buf, "Amulet of Yendor");
    188 		break;
    189 	case TOOL_SYM:
    190 		if (!nn) {
    191 			strlcpy(buf, dn, bufmax);
    192 			break;
    193 		}
    194 		strlcpy(buf, an, bufmax);
    195 		break;
    196 	case FOOD_SYM:
    197 		if (obj->otyp == DEAD_HOMUNCULUS && pl) {
    198 			pl = 0;
    199 			Strcpy(buf, "dead homunculi");
    200 			break;
    201 		}
    202 		/* fungis ? */
    203 		/* FALLTHROUGH */
    204 	case WEAPON_SYM:
    205 		if (obj->otyp == WORM_TOOTH && pl) {
    206 			pl = 0;
    207 			Strcpy(buf, "worm teeth");
    208 			break;
    209 		}
    210 		if (obj->otyp == CRYSKNIFE && pl) {
    211 			pl = 0;
    212 			Strcpy(buf, "crysknives");
    213 			break;
    214 		}
    215 		/* FALLTHROUGH */
    216 	case ARMOR_SYM:
    217 	case CHAIN_SYM:
    218 	case ROCK_SYM:
    219 		strlcpy(buf, an, bufmax);
    220 		break;
    221 	case BALL_SYM:
    222 		Snprintf(buf, bufmax, "%sheavy iron ball",
    223 		  (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
    224 		break;
    225 	case POTION_SYM:
    226 		if (nn || un || !obj->dknown) {
    227 			Strcpy(buf, "potion");
    228 			if (pl) {
    229 				pl = 0;
    230 				Strcat(buf, "s");
    231 			}
    232 			if (!obj->dknown)
    233 				break;
    234 			if (un) {
    235 				Strcat(buf, " called ");
    236 				strlcat(buf, un, bufmax);
    237 			} else {
    238 				Strcat(buf, " of ");
    239 				strlcat(buf, an, bufmax);
    240 			}
    241 		} else {
    242 			strlcpy(buf, dn, bufmax);
    243 			strlcat(buf, " potion", bufmax);
    244 		}
    245 		break;
    246 	case SCROLL_SYM:
    247 		Strcpy(buf, "scroll");
    248 		if (pl) {
    249 			pl = 0;
    250 			Strcat(buf, "s");
    251 		}
    252 		if (!obj->dknown)
    253 			break;
    254 		if (nn) {
    255 			Strcat(buf, " of ");
    256 			strlcat(buf, an, bufmax);
    257 		} else if (un) {
    258 			Strcat(buf, " called ");
    259 			strlcat(buf, un, bufmax);
    260 		} else {
    261 			Strcat(buf, " labeled ");
    262 			strlcat(buf, dn, bufmax);
    263 		}
    264 		break;
    265 	case WAND_SYM:
    266 		if (!obj->dknown)
    267 			Snprintf(buf, bufmax, "wand");
    268 		else if (nn)
    269 			Snprintf(buf, bufmax, "wand of %s", an);
    270 		else if (un)
    271 			Snprintf(buf, bufmax, "wand called %s", un);
    272 		else
    273 			Snprintf(buf, bufmax, "%s wand", dn);
    274 		break;
    275 	case RING_SYM:
    276 		if (!obj->dknown)
    277 			Snprintf(buf, bufmax, "ring");
    278 		else if (nn)
    279 			Snprintf(buf, bufmax, "ring of %s", an);
    280 		else if (un)
    281 			Snprintf(buf, bufmax, "ring called %s", un);
    282 		else
    283 			Snprintf(buf, bufmax, "%s ring", dn);
    284 		break;
    285 	case GEM_SYM:
    286 		if (!obj->dknown) {
    287 			Strcpy(buf, "gem");
    288 			break;
    289 		}
    290 		if (!nn) {
    291 			Snprintf(buf, bufmax, "%s gem", dn);
    292 			break;
    293 		}
    294 		strlcpy(buf, an, bufmax);
    295 		if (obj->otyp >= TURQUOISE && obj->otyp <= JADE)
    296 			strlcat(buf, " stone", bufmax);
    297 		break;
    298 	default:
    299 		Snprintf(buf, bufmax, "glorkum %c (0%o) %u %d",
    300 			obj->olet, obj->olet, obj->otyp, obj->spe);
    301 	}
    302 	if (pl) {
    303 		char           *p;
    304 
    305 		for (p = buf; *p; p++) {
    306 			if (!strncmp(" of ", p, 4)) {
    307 				/* pieces of, cloves of, lumps of */
    308 				int             c1, c2 = 's';
    309 
    310 				do {
    311 					c1 = c2;
    312 					c2 = *p;
    313 					*p++ = c1;
    314 				} while (c1);
    315 				goto nopl;
    316 			}
    317 		}
    318 		p = eos(buf) - 1;
    319 		if (*p == 's' || *p == 'z' || *p == 'x' ||
    320 		    (*p == 'h' && p[-1] == 's')) {
    321 			/* boxes */
    322 			strlcat(buf, "es", bufmax);
    323 		} else if (*p == 'y' && !strchr(vowels, p[-1])) {
    324 			/* rubies, zruties */
    325 			*p = '\0';
    326 			strlcat(buf, "ies", bufmax);
    327 		} else {
    328 			strlcat(buf, "s", bufmax);
    329 		}
    330 	}
    331 nopl:
    332 	if (obj->onamelth) {
    333 		strlcat(buf, " named ", bufmax);
    334 		strlcat(buf, ONAME(obj), bufmax);
    335 	}
    336 	return (buf);
    337 }
    338 
    339 char           *
    340 doname(struct obj *obj)
    341 {
    342 	char            prefix[PREFIX];
    343 	char           *bp = xname(obj);
    344 	size_t          bppos, bpmax;
    345 
    346 	/* XXX do this better somehow w/o knowing internals of xname() */
    347 	bpmax = BUFSZ - PREFIX;
    348 
    349 	if (obj->quan != 1)
    350 		Snprintf(prefix, sizeof(prefix), "%u ", obj->quan);
    351 	else
    352 		Strcpy(prefix, "a ");
    353 	switch (obj->olet) {
    354 	case AMULET_SYM:
    355 		if (strncmp(bp, "cheap ", 6))
    356 			Strcpy(prefix, "the ");
    357 		break;
    358 	case ARMOR_SYM:
    359 		if (obj->owornmask & W_ARMOR)
    360 			strlcat(bp, " (being worn)", bpmax);
    361 		/* FALLTHROUGH */
    362 	case WEAPON_SYM:
    363 		if (obj->known) {
    364 			strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
    365 			strlcat(prefix, " ", sizeof(prefix));
    366 		}
    367 		break;
    368 	case WAND_SYM:
    369 		if (obj->known) {
    370 			bppos = strlen(bp);
    371 			Snprintf(bp+bppos, bpmax-bppos, " (%d)", obj->spe);
    372 		}
    373 		break;
    374 	case RING_SYM:
    375 		if (obj->owornmask & W_RINGR)
    376 			strlcat(bp, " (on right hand)", bpmax);
    377 		if (obj->owornmask & W_RINGL)
    378 			strlcat(bp, " (on left hand)", bpmax);
    379 		if (obj->known && (objects[obj->otyp].bits & SPEC)) {
    380 			strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
    381 			strlcat(prefix, " ", sizeof(prefix));
    382 		}
    383 		break;
    384 	}
    385 	if (obj->owornmask & W_WEP)
    386 		strlcat(bp, " (weapon in hand)", bpmax);
    387 	if (obj->unpaid)
    388 		strlcat(bp, " (unpaid)", bpmax);
    389 	if (!strcmp(prefix, "a ") && strchr(vowels, *bp))
    390 		Strcpy(prefix, "an ");
    391 	bp = strprepend(bp, prefix);
    392 	return (bp);
    393 }
    394 
    395 /* used only in hack.fight.c (thitu) */
    396 void
    397 setan(const char *str, char *buf, size_t bufmax)
    398 {
    399 	if (strchr(vowels, *str))
    400 		Snprintf(buf, bufmax, "an %s", str);
    401 	else
    402 		Snprintf(buf, bufmax, "a %s", str);
    403 }
    404 
    405 char           *
    406 aobjnam(struct obj *otmp, const char *verb)
    407 {
    408 	char           *bp = xname(otmp);
    409 	char            prefix[PREFIX];
    410 	size_t          bpmax;
    411 
    412 	/* XXX do this better somehow w/o knowing internals of xname() */
    413 	bpmax = BUFSZ - PREFIX;
    414 
    415 	if (otmp->quan != 1) {
    416 		Snprintf(prefix, sizeof(prefix), "%u ", otmp->quan);
    417 		bp = strprepend(bp, prefix);
    418 	}
    419 	if (verb) {
    420 		/* verb is given in plural (i.e., without trailing s) */
    421 		strlcat(bp, " ", bpmax);
    422 		if (otmp->quan != 1)
    423 			strlcat(bp, verb, bpmax);
    424 		else if (!strcmp(verb, "are"))
    425 			strlcat(bp, "is", bpmax);
    426 		else {
    427 			strlcat(bp, verb, bpmax);
    428 			strlcat(bp, "s", bpmax);
    429 		}
    430 	}
    431 	return (bp);
    432 }
    433 
    434 char           *
    435 Doname(struct obj *obj)
    436 {
    437 	char           *s = doname(obj);
    438 
    439 	if ('a' <= *s && *s <= 'z')
    440 		*s -= ('a' - 'A');
    441 	return (s);
    442 }
    443 
    444 static const char *const wrp[] = {"wand", "ring", "potion", "scroll", "gem"};
    445 static const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM};
    446 
    447 struct obj     *
    448 readobjnam(char *bp)
    449 {
    450 	char           *p;
    451 	unsigned        ii;
    452 	int		i;
    453 	int             cnt, spe, spesgn, typ, heavy;
    454 	char            let;
    455 	char           *un, *dn, *an;
    456 	/* int the = 0; char *oname = 0; */
    457 	cnt = spe = spesgn = typ = heavy = 0;
    458 	let = 0;
    459 	an = dn = un = 0;
    460 	for (p = bp; *p; p++)
    461 		if ('A' <= *p && *p <= 'Z')
    462 			*p += 'a' - 'A';
    463 	if (!strncmp(bp, "the ", 4)) {
    464 		/* the = 1; */
    465 		bp += 4;
    466 	} else if (!strncmp(bp, "an ", 3)) {
    467 		cnt = 1;
    468 		bp += 3;
    469 	} else if (!strncmp(bp, "a ", 2)) {
    470 		cnt = 1;
    471 		bp += 2;
    472 	}
    473 	if (!cnt && digit(*bp)) {
    474 		cnt = atoi(bp);
    475 		while (digit(*bp))
    476 			bp++;
    477 		while (*bp == ' ')
    478 			bp++;
    479 	}
    480 	if (!cnt)
    481 		cnt = 1;	/* %% what with "gems" etc. ? */
    482 
    483 	if (*bp == '+' || *bp == '-') {
    484 		spesgn = (*bp++ == '+') ? 1 : -1;
    485 		spe = atoi(bp);
    486 		while (digit(*bp))
    487 			bp++;
    488 		while (*bp == ' ')
    489 			bp++;
    490 	} else {
    491 		p = strrchr(bp, '(');
    492 		if (p) {
    493 			if (p > bp && p[-1] == ' ')
    494 				p[-1] = 0;
    495 			else
    496 				*p = 0;
    497 			p++;
    498 			spe = atoi(p);
    499 			while (digit(*p))
    500 				p++;
    501 			if (strcmp(p, ")"))
    502 				spe = 0;
    503 			else
    504 				spesgn = 1;
    505 		}
    506 	}
    507 	/*
    508 	 * now we have the actual name, as delivered by xname, say green
    509 	 * potions called whisky scrolls labeled "QWERTY" egg dead zruties
    510 	 * fortune cookies very heavy iron ball named hoei wand of wishing
    511 	 * elven cloak
    512 	 */
    513 	for (p = bp; *p; p++)
    514 		if (!strncmp(p, " named ", 7)) {
    515 			*p = 0;
    516 			/* oname = p+7; */
    517 		}
    518 	for (p = bp; *p; p++)
    519 		if (!strncmp(p, " called ", 8)) {
    520 			*p = 0;
    521 			un = p + 8;
    522 		}
    523 	for (p = bp; *p; p++)
    524 		if (!strncmp(p, " labeled ", 9)) {
    525 			*p = 0;
    526 			dn = p + 9;
    527 		}
    528 	/* first change to singular if necessary */
    529 	if (cnt != 1) {
    530 		/* find "cloves of garlic", "worthless pieces of blue glass" */
    531 		for (p = bp; *p; p++)
    532 			if (!strncmp(p, "s of ", 5)) {
    533 				while ((*p = p[1]) != '\0')
    534 					p++;
    535 				goto sing;
    536 			}
    537 		/* remove -s or -es (boxes) or -ies (rubies, zruties) */
    538 		p = eos(bp);
    539 		if (p[-1] == 's') {
    540 			if (p[-2] == 'e') {
    541 				if (p[-3] == 'i') {
    542 					if (!strcmp(p - 7, "cookies"))
    543 						goto mins;
    544 					Strcpy(p - 3, "y");
    545 					goto sing;
    546 				}
    547 				/* note: cloves / knives from clove / knife */
    548 				if (!strcmp(p - 6, "knives")) {
    549 					Strcpy(p - 3, "fe");
    550 					goto sing;
    551 				}
    552 				/* note: nurses, axes but boxes */
    553 				if (!strcmp(p - 5, "boxes")) {
    554 					p[-2] = 0;
    555 					goto sing;
    556 				}
    557 			}
    558 	mins:
    559 			p[-1] = 0;
    560 		} else {
    561 			if (!strcmp(p - 9, "homunculi")) {
    562 				Strcpy(p - 1, "us");	/* !! makes string
    563 							 * longer */
    564 				goto sing;
    565 			}
    566 			if (!strcmp(p - 5, "teeth")) {
    567 				Strcpy(p - 5, "tooth");
    568 				goto sing;
    569 			}
    570 			/* here we cannot find the plural suffix */
    571 		}
    572 	}
    573 sing:
    574 	if (!strcmp(bp, "amulet of yendor")) {
    575 		typ = AMULET_OF_YENDOR;
    576 		goto typfnd;
    577 	}
    578 	p = eos(bp);
    579 	if (!strcmp(p - 5, " mail")) {	/* Note: ring mail is not a ring ! */
    580 		let = ARMOR_SYM;
    581 		an = bp;
    582 		goto srch;
    583 	}
    584 	for (ii = 0; ii < sizeof(wrpsym); ii++) {
    585 		int             j = strlen(wrp[ii]);
    586 		if (!strncmp(bp, wrp[ii], j)) {
    587 			let = wrpsym[ii];
    588 			bp += j;
    589 			if (!strncmp(bp, " of ", 4))
    590 				an = bp + 4;
    591 			/* else if(*bp) ?? */
    592 			goto srch;
    593 		}
    594 		if (!strcmp(p - j, wrp[ii])) {
    595 			let = wrpsym[ii];
    596 			p -= j;
    597 			*p = 0;
    598 			if (p[-1] == ' ')
    599 				p[-1] = 0;
    600 			dn = bp;
    601 			goto srch;
    602 		}
    603 	}
    604 	if (!strcmp(p - 6, " stone")) {
    605 		p[-6] = 0;
    606 		let = GEM_SYM;
    607 		an = bp;
    608 		goto srch;
    609 	}
    610 	if (!strcmp(bp, "very heavy iron ball")) {
    611 		heavy = 1;
    612 		typ = HEAVY_IRON_BALL;
    613 		goto typfnd;
    614 	}
    615 	an = bp;
    616 srch:
    617 	if (!an && !dn && !un)
    618 		goto any;
    619 	i = 1;
    620 	if (let)
    621 		i = bases[letindex(let)];
    622 	while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) {
    623 		const char           *zn = objects[i].oc_name;
    624 
    625 		if (!zn)
    626 			goto nxti;
    627 		if (an && strcmp(an, zn))
    628 			goto nxti;
    629 		if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
    630 			goto nxti;
    631 		if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
    632 			goto nxti;
    633 		typ = i;
    634 		goto typfnd;
    635 nxti:
    636 		i++;
    637 	}
    638 any:
    639 	if (!let)
    640 		let = wrpsym[rn2(sizeof(wrpsym))];
    641 	typ = probtype(let);
    642 typfnd:
    643 	{
    644 		struct obj     *otmp;
    645 		let = objects[typ].oc_olet;
    646 		otmp = mksobj(typ);
    647 		if (heavy)
    648 			otmp->owt += 15;
    649 		if (cnt > 0 && strchr("%?!*)", let) &&
    650 		(cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
    651 			otmp->quan = cnt;
    652 
    653 		if (spe > 3 && spe > otmp->spe)
    654 			spe = 0;
    655 		else if (let == WAND_SYM)
    656 			spe = otmp->spe;
    657 		if (spe == 3 && u.uluck < 0)
    658 			spesgn = -1;
    659 		if (let != WAND_SYM && spesgn == -1)
    660 			spe = -spe;
    661 		if (let == BALL_SYM)
    662 			spe = 0;
    663 		else if (let == AMULET_SYM)
    664 			spe = -1;
    665 		else if (typ == WAN_WISHING && rn2(10))
    666 			spe = (rn2(10) ? -1 : 0);
    667 		otmp->spe = spe;
    668 
    669 		if (spesgn == -1)
    670 			otmp->cursed = 1;
    671 
    672 		return (otmp);
    673 	}
    674 }
    675