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