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