xref: /netbsd-src/games/hack/hack.objnam.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: hack.objnam.c,v 1.5 2001/03/25 20:44:02 jsm Exp $	*/
2 
3 /*
4  * Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985.
5  */
6 
7 #include <sys/cdefs.h>
8 #ifndef lint
9 __RCSID("$NetBSD: hack.objnam.c,v 1.5 2001/03/25 20:44:02 jsm Exp $");
10 #endif				/* not lint */
11 
12 #include <stdlib.h>
13 #include "hack.h"
14 #include "extern.h"
15 #define Sprintf (void) sprintf
16 #define Strcat  (void) strcat
17 #define	Strcpy	(void) strcpy
18 #define	PREFIX	15
19 
20 char           *
21 strprepend(s, pref)
22 	char           *s, *pref;
23 {
24 	int             i = strlen(pref);
25 	if (i > PREFIX) {
26 		pline("WARNING: prefix too short.");
27 		return (s);
28 	}
29 	s -= i;
30 	(void) strncpy(s, pref, i);	/* do not copy trailing 0 */
31 	return (s);
32 }
33 
34 char           *
35 sitoa(a)
36 	int             a;
37 {
38 	static char     buf[13];
39 	Sprintf(buf, (a < 0) ? "%d" : "+%d", a);
40 	return (buf);
41 }
42 
43 char           *
44 typename(otyp)
45 	int             otyp;
46 {
47 	static char     buf[BUFSZ];
48 	struct objclass *ocl = &objects[otyp];
49 	const char     *an = ocl->oc_name;
50 	const char     *dn = ocl->oc_descr;
51 	char           *un = ocl->oc_uname;
52 	int             nn = ocl->oc_name_known;
53 	switch (ocl->oc_olet) {
54 	case POTION_SYM:
55 		Strcpy(buf, "potion");
56 		break;
57 	case SCROLL_SYM:
58 		Strcpy(buf, "scroll");
59 		break;
60 	case WAND_SYM:
61 		Strcpy(buf, "wand");
62 		break;
63 	case RING_SYM:
64 		Strcpy(buf, "ring");
65 		break;
66 	default:
67 		if (nn) {
68 			Strcpy(buf, an);
69 			if (otyp >= TURQUOISE && otyp <= JADE)
70 				Strcat(buf, " stone");
71 			if (un)
72 				Sprintf(eos(buf), " called %s", un);
73 			if (dn)
74 				Sprintf(eos(buf), " (%s)", dn);
75 		} else {
76 			Strcpy(buf, dn ? dn : an);
77 			if (ocl->oc_olet == GEM_SYM)
78 				Strcat(buf, " gem");
79 			if (un)
80 				Sprintf(eos(buf), " called %s", un);
81 		}
82 		return (buf);
83 	}
84 	/* here for ring/scroll/potion/wand */
85 	if (nn)
86 		Sprintf(eos(buf), " of %s", an);
87 	if (un)
88 		Sprintf(eos(buf), " called %s", un);
89 	if (dn)
90 		Sprintf(eos(buf), " (%s)", dn);
91 	return (buf);
92 }
93 
94 char           *
95 xname(obj)
96 	struct obj     *obj;
97 {
98 	static char     bufr[BUFSZ];
99 	char           *buf = &(bufr[PREFIX]);	/* leave room for "17 -3 " */
100 	int             nn = objects[obj->otyp].oc_name_known;
101 	const char     *an = objects[obj->otyp].oc_name;
102 	const char     *dn = objects[obj->otyp].oc_descr;
103 	char           *un = objects[obj->otyp].oc_uname;
104 	int             pl = (obj->quan != 1);
105 	if (!obj->dknown && !Blind)
106 		obj->dknown = 1;/* %% doesnt belong here */
107 	switch (obj->olet) {
108 	case AMULET_SYM:
109 		Strcpy(buf, (obj->spe < 0 && obj->known)
110 		       ? "cheap plastic imitation of the " : "");
111 		Strcat(buf, "Amulet of Yendor");
112 		break;
113 	case TOOL_SYM:
114 		if (!nn) {
115 			Strcpy(buf, dn);
116 			break;
117 		}
118 		Strcpy(buf, an);
119 		break;
120 	case FOOD_SYM:
121 		if (obj->otyp == DEAD_HOMUNCULUS && pl) {
122 			pl = 0;
123 			Strcpy(buf, "dead homunculi");
124 			break;
125 		}
126 		/* fungis ? */
127 		/* fall into next case */
128 	case WEAPON_SYM:
129 		if (obj->otyp == WORM_TOOTH && pl) {
130 			pl = 0;
131 			Strcpy(buf, "worm teeth");
132 			break;
133 		}
134 		if (obj->otyp == CRYSKNIFE && pl) {
135 			pl = 0;
136 			Strcpy(buf, "crysknives");
137 			break;
138 		}
139 		/* fall into next case */
140 	case ARMOR_SYM:
141 	case CHAIN_SYM:
142 	case ROCK_SYM:
143 		Strcpy(buf, an);
144 		break;
145 	case BALL_SYM:
146 		Sprintf(buf, "%sheavy iron ball",
147 		  (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
148 		break;
149 	case POTION_SYM:
150 		if (nn || un || !obj->dknown) {
151 			Strcpy(buf, "potion");
152 			if (pl) {
153 				pl = 0;
154 				Strcat(buf, "s");
155 			}
156 			if (!obj->dknown)
157 				break;
158 			if (un) {
159 				Strcat(buf, " called ");
160 				Strcat(buf, un);
161 			} else {
162 				Strcat(buf, " of ");
163 				Strcat(buf, an);
164 			}
165 		} else {
166 			Strcpy(buf, dn);
167 			Strcat(buf, " potion");
168 		}
169 		break;
170 	case SCROLL_SYM:
171 		Strcpy(buf, "scroll");
172 		if (pl) {
173 			pl = 0;
174 			Strcat(buf, "s");
175 		}
176 		if (!obj->dknown)
177 			break;
178 		if (nn) {
179 			Strcat(buf, " of ");
180 			Strcat(buf, an);
181 		} else if (un) {
182 			Strcat(buf, " called ");
183 			Strcat(buf, un);
184 		} else {
185 			Strcat(buf, " labeled ");
186 			Strcat(buf, dn);
187 		}
188 		break;
189 	case WAND_SYM:
190 		if (!obj->dknown)
191 			Sprintf(buf, "wand");
192 		else if (nn)
193 			Sprintf(buf, "wand of %s", an);
194 		else if (un)
195 			Sprintf(buf, "wand called %s", un);
196 		else
197 			Sprintf(buf, "%s wand", dn);
198 		break;
199 	case RING_SYM:
200 		if (!obj->dknown)
201 			Sprintf(buf, "ring");
202 		else if (nn)
203 			Sprintf(buf, "ring of %s", an);
204 		else if (un)
205 			Sprintf(buf, "ring called %s", un);
206 		else
207 			Sprintf(buf, "%s ring", dn);
208 		break;
209 	case GEM_SYM:
210 		if (!obj->dknown) {
211 			Strcpy(buf, "gem");
212 			break;
213 		}
214 		if (!nn) {
215 			Sprintf(buf, "%s gem", dn);
216 			break;
217 		}
218 		Strcpy(buf, an);
219 		if (obj->otyp >= TURQUOISE && obj->otyp <= JADE)
220 			Strcat(buf, " stone");
221 		break;
222 	default:
223 		Sprintf(buf, "glorkum %c (0%o) %u %d",
224 			obj->olet, obj->olet, obj->otyp, obj->spe);
225 	}
226 	if (pl) {
227 		char           *p;
228 
229 		for (p = buf; *p; p++) {
230 			if (!strncmp(" of ", p, 4)) {
231 				/* pieces of, cloves of, lumps of */
232 				int             c1, c2 = 's';
233 
234 				do {
235 					c1 = c2;
236 					c2 = *p;
237 					*p++ = c1;
238 				} while (c1);
239 				goto nopl;
240 			}
241 		}
242 		p = eos(buf) - 1;
243 		if (*p == 's' || *p == 'z' || *p == 'x' ||
244 		    (*p == 'h' && p[-1] == 's'))
245 			Strcat(buf, "es");	/* boxes */
246 		else if (*p == 'y' && !strchr(vowels, p[-1]))
247 			Strcpy(p, "ies");	/* rubies, zruties */
248 		else
249 			Strcat(buf, "s");
250 	}
251 nopl:
252 	if (obj->onamelth) {
253 		Strcat(buf, " named ");
254 		Strcat(buf, ONAME(obj));
255 	}
256 	return (buf);
257 }
258 
259 char           *
260 doname(obj)
261 	struct obj     *obj;
262 {
263 	char            prefix[PREFIX];
264 	char           *bp = xname(obj);
265 	if (obj->quan != 1)
266 		Sprintf(prefix, "%u ", obj->quan);
267 	else
268 		Strcpy(prefix, "a ");
269 	switch (obj->olet) {
270 	case AMULET_SYM:
271 		if (strncmp(bp, "cheap ", 6))
272 			Strcpy(prefix, "the ");
273 		break;
274 	case ARMOR_SYM:
275 		if (obj->owornmask & W_ARMOR)
276 			Strcat(bp, " (being worn)");
277 		/* fall into next case */
278 	case WEAPON_SYM:
279 		if (obj->known) {
280 			Strcat(prefix, sitoa(obj->spe));
281 			Strcat(prefix, " ");
282 		}
283 		break;
284 	case WAND_SYM:
285 		if (obj->known)
286 			Sprintf(eos(bp), " (%d)", obj->spe);
287 		break;
288 	case RING_SYM:
289 		if (obj->owornmask & W_RINGR)
290 			Strcat(bp, " (on right hand)");
291 		if (obj->owornmask & W_RINGL)
292 			Strcat(bp, " (on left hand)");
293 		if (obj->known && (objects[obj->otyp].bits & SPEC)) {
294 			Strcat(prefix, sitoa(obj->spe));
295 			Strcat(prefix, " ");
296 		}
297 		break;
298 	}
299 	if (obj->owornmask & W_WEP)
300 		Strcat(bp, " (weapon in hand)");
301 	if (obj->unpaid)
302 		Strcat(bp, " (unpaid)");
303 	if (!strcmp(prefix, "a ") && strchr(vowels, *bp))
304 		Strcpy(prefix, "an ");
305 	bp = strprepend(bp, prefix);
306 	return (bp);
307 }
308 
309 /* used only in hack.fight.c (thitu) */
310 void
311 setan(const char *str, char *buf)
312 {
313 	if (strchr(vowels, *str))
314 		Sprintf(buf, "an %s", str);
315 	else
316 		Sprintf(buf, "a %s", str);
317 }
318 
319 char           *
320 aobjnam(otmp, verb)
321 	struct obj     *otmp;
322 	const char           *verb;
323 {
324 	char           *bp = xname(otmp);
325 	char            prefix[PREFIX];
326 	if (otmp->quan != 1) {
327 		Sprintf(prefix, "%u ", otmp->quan);
328 		bp = strprepend(bp, prefix);
329 	}
330 	if (verb) {
331 		/* verb is given in plural (i.e., without trailing s) */
332 		Strcat(bp, " ");
333 		if (otmp->quan != 1)
334 			Strcat(bp, verb);
335 		else if (!strcmp(verb, "are"))
336 			Strcat(bp, "is");
337 		else {
338 			Strcat(bp, verb);
339 			Strcat(bp, "s");
340 		}
341 	}
342 	return (bp);
343 }
344 
345 char           *
346 Doname(obj)
347 	struct obj     *obj;
348 {
349 	char           *s = doname(obj);
350 
351 	if ('a' <= *s && *s <= 'z')
352 		*s -= ('a' - 'A');
353 	return (s);
354 }
355 
356 const char *const wrp[] = {"wand", "ring", "potion", "scroll", "gem"};
357 const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM};
358 
359 struct obj     *
360 readobjnam(bp)
361 	char           *bp;
362 {
363 	char           *p;
364 	int             i;
365 	int             cnt, spe, spesgn, typ, heavy;
366 	char            let;
367 	char           *un, *dn, *an;
368 	/* int the = 0; char *oname = 0; */
369 	cnt = spe = spesgn = typ = heavy = 0;
370 	let = 0;
371 	an = dn = un = 0;
372 	for (p = bp; *p; p++)
373 		if ('A' <= *p && *p <= 'Z')
374 			*p += 'a' - 'A';
375 	if (!strncmp(bp, "the ", 4)) {
376 		/* the = 1; */
377 		bp += 4;
378 	} else if (!strncmp(bp, "an ", 3)) {
379 		cnt = 1;
380 		bp += 3;
381 	} else if (!strncmp(bp, "a ", 2)) {
382 		cnt = 1;
383 		bp += 2;
384 	}
385 	if (!cnt && digit(*bp)) {
386 		cnt = atoi(bp);
387 		while (digit(*bp))
388 			bp++;
389 		while (*bp == ' ')
390 			bp++;
391 	}
392 	if (!cnt)
393 		cnt = 1;	/* %% what with "gems" etc. ? */
394 
395 	if (*bp == '+' || *bp == '-') {
396 		spesgn = (*bp++ == '+') ? 1 : -1;
397 		spe = atoi(bp);
398 		while (digit(*bp))
399 			bp++;
400 		while (*bp == ' ')
401 			bp++;
402 	} else {
403 		p = strrchr(bp, '(');
404 		if (p) {
405 			if (p > bp && p[-1] == ' ')
406 				p[-1] = 0;
407 			else
408 				*p = 0;
409 			p++;
410 			spe = atoi(p);
411 			while (digit(*p))
412 				p++;
413 			if (strcmp(p, ")"))
414 				spe = 0;
415 			else
416 				spesgn = 1;
417 		}
418 	}
419 	/*
420 	 * now we have the actual name, as delivered by xname, say green
421 	 * potions called whisky scrolls labeled "QWERTY" egg dead zruties
422 	 * fortune cookies very heavy iron ball named hoei wand of wishing
423 	 * elven cloak
424 	 */
425 	for (p = bp; *p; p++)
426 		if (!strncmp(p, " named ", 7)) {
427 			*p = 0;
428 			/* oname = p+7; */
429 		}
430 	for (p = bp; *p; p++)
431 		if (!strncmp(p, " called ", 8)) {
432 			*p = 0;
433 			un = p + 8;
434 		}
435 	for (p = bp; *p; p++)
436 		if (!strncmp(p, " labeled ", 9)) {
437 			*p = 0;
438 			dn = p + 9;
439 		}
440 	/* first change to singular if necessary */
441 	if (cnt != 1) {
442 		/* find "cloves of garlic", "worthless pieces of blue glass" */
443 		for (p = bp; *p; p++)
444 			if (!strncmp(p, "s of ", 5)) {
445 				while ((*p = p[1]) != '\0')
446 					p++;
447 				goto sing;
448 			}
449 		/* remove -s or -es (boxes) or -ies (rubies, zruties) */
450 		p = eos(bp);
451 		if (p[-1] == 's') {
452 			if (p[-2] == 'e') {
453 				if (p[-3] == 'i') {
454 					if (!strcmp(p - 7, "cookies"))
455 						goto mins;
456 					Strcpy(p - 3, "y");
457 					goto sing;
458 				}
459 				/* note: cloves / knives from clove / knife */
460 				if (!strcmp(p - 6, "knives")) {
461 					Strcpy(p - 3, "fe");
462 					goto sing;
463 				}
464 				/* note: nurses, axes but boxes */
465 				if (!strcmp(p - 5, "boxes")) {
466 					p[-2] = 0;
467 					goto sing;
468 				}
469 			}
470 	mins:
471 			p[-1] = 0;
472 		} else {
473 			if (!strcmp(p - 9, "homunculi")) {
474 				Strcpy(p - 1, "us");	/* !! makes string
475 							 * longer */
476 				goto sing;
477 			}
478 			if (!strcmp(p - 5, "teeth")) {
479 				Strcpy(p - 5, "tooth");
480 				goto sing;
481 			}
482 			/* here we cannot find the plural suffix */
483 		}
484 	}
485 sing:
486 	if (!strcmp(bp, "amulet of yendor")) {
487 		typ = AMULET_OF_YENDOR;
488 		goto typfnd;
489 	}
490 	p = eos(bp);
491 	if (!strcmp(p - 5, " mail")) {	/* Note: ring mail is not a ring ! */
492 		let = ARMOR_SYM;
493 		an = bp;
494 		goto srch;
495 	}
496 	for (i = 0; i < sizeof(wrpsym); i++) {
497 		int             j = strlen(wrp[i]);
498 		if (!strncmp(bp, wrp[i], j)) {
499 			let = wrpsym[i];
500 			bp += j;
501 			if (!strncmp(bp, " of ", 4))
502 				an = bp + 4;
503 			/* else if(*bp) ?? */
504 			goto srch;
505 		}
506 		if (!strcmp(p - j, wrp[i])) {
507 			let = wrpsym[i];
508 			p -= j;
509 			*p = 0;
510 			if (p[-1] == ' ')
511 				p[-1] = 0;
512 			dn = bp;
513 			goto srch;
514 		}
515 	}
516 	if (!strcmp(p - 6, " stone")) {
517 		p[-6] = 0;
518 		let = GEM_SYM;
519 		an = bp;
520 		goto srch;
521 	}
522 	if (!strcmp(bp, "very heavy iron ball")) {
523 		heavy = 1;
524 		typ = HEAVY_IRON_BALL;
525 		goto typfnd;
526 	}
527 	an = bp;
528 srch:
529 	if (!an && !dn && !un)
530 		goto any;
531 	i = 1;
532 	if (let)
533 		i = bases[letindex(let)];
534 	while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) {
535 		const char           *zn = objects[i].oc_name;
536 
537 		if (!zn)
538 			goto nxti;
539 		if (an && strcmp(an, zn))
540 			goto nxti;
541 		if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
542 			goto nxti;
543 		if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
544 			goto nxti;
545 		typ = i;
546 		goto typfnd;
547 nxti:
548 		i++;
549 	}
550 any:
551 	if (!let)
552 		let = wrpsym[rn2(sizeof(wrpsym))];
553 	typ = probtype(let);
554 typfnd:
555 	{
556 		struct obj     *otmp;
557 		let = objects[typ].oc_olet;
558 		otmp = mksobj(typ);
559 		if (heavy)
560 			otmp->owt += 15;
561 		if (cnt > 0 && strchr("%?!*)", let) &&
562 		(cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
563 			otmp->quan = cnt;
564 
565 		if (spe > 3 && spe > otmp->spe)
566 			spe = 0;
567 		else if (let == WAND_SYM)
568 			spe = otmp->spe;
569 		if (spe == 3 && u.uluck < 0)
570 			spesgn = -1;
571 		if (let != WAND_SYM && spesgn == -1)
572 			spe = -spe;
573 		if (let == BALL_SYM)
574 			spe = 0;
575 		else if (let == AMULET_SYM)
576 			spe = -1;
577 		else if (typ == WAN_WISHING && rn2(10))
578 			spe = (rn2(10) ? -1 : 0);
579 		otmp->spe = spe;
580 
581 		if (spesgn == -1)
582 			otmp->cursed = 1;
583 
584 		return (otmp);
585 	}
586 }
587