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