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