Home | History | Annotate | Line # | Download | only in hack
hack.objnam.c revision 1.5
      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