xref: /netbsd-src/games/hack/hack.objnam.c (revision d5b021c7edb8313eee3804ec3819b28abef1d1a0)
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@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 *
strprepend(char * s,char * pref)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 *
sitoa(int a)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           *
typename(int otyp)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           *
xname(struct obj * obj)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           *
doname(struct obj * obj)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
setan(const char * str,char * buf,size_t bufmax)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           *
aobjnam(struct obj * otmp,const char * verb)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           *
Doname(struct obj * obj)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     *
readobjnam(char * bp)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