Do not run mandoc for lintmanpages if MANPAGES is empty.
[netbsd-mini2440.git] / games / hack / hack.objnam.c
blob172d37db0383b60c1ec5b2d4eafe7946bf9e8ea7
1 /* $NetBSD: hack.objnam.c,v 1.9 2009/06/07 20:13:18 dholland Exp $ */
3 /*
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5 * Amsterdam
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * - Neither the name of the Stichting Centrum voor Wiskunde en
20 * Informatica, nor the names of its contributors may be used to endorse or
21 * promote products derived from this software without specific prior
22 * written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. The name of the author may not be used to endorse or promote products
50 * derived from this software without specific prior written permission.
52 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
55 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.objnam.c,v 1.9 2009/06/07 20:13:18 dholland Exp $");
67 #endif /* not lint */
69 #include <stdlib.h>
70 #include "hack.h"
71 #include "extern.h"
72 #define Snprintf (void) snprintf
73 #define Strcat (void) strcat
74 #define Strcpy (void) strcpy
75 #define PREFIX 15
77 static char *strprepend(char *, char *);
78 static char *sitoa(int);
80 static char *
81 strprepend(char *s, char *pref)
83 int i = strlen(pref);
84 if (i > PREFIX) {
85 pline("WARNING: prefix too short.");
86 return (s);
88 s -= i;
89 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
90 return (s);
93 static char *
94 sitoa(int a)
96 static char buf[13];
97 Snprintf(buf, sizeof(buf), (a < 0) ? "%d" : "+%d", a);
98 return (buf);
101 char *
102 typename(int otyp)
104 static char buf[BUFSZ];
105 size_t bufpos;
106 struct objclass *ocl = &objects[otyp];
107 const char *an = ocl->oc_name;
108 const char *dn = ocl->oc_descr;
109 char *un = ocl->oc_uname;
110 int nn = ocl->oc_name_known;
111 switch (ocl->oc_olet) {
112 case POTION_SYM:
113 Strcpy(buf, "potion");
114 break;
115 case SCROLL_SYM:
116 Strcpy(buf, "scroll");
117 break;
118 case WAND_SYM:
119 Strcpy(buf, "wand");
120 break;
121 case RING_SYM:
122 Strcpy(buf, "ring");
123 break;
124 default:
125 if (nn) {
126 Strcpy(buf, an);
127 if (otyp >= TURQUOISE && otyp <= JADE)
128 Strcat(buf, " stone");
129 if (un) {
130 bufpos = strlen(buf);
131 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
132 " called %s", un);
134 if (dn) {
135 bufpos = strlen(buf);
136 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
137 " (%s)", dn);
139 } else {
140 strlcpy(buf, dn ? dn : an, sizeof(buf));
141 if (ocl->oc_olet == GEM_SYM) {
142 strlcat(buf, " gem", sizeof(buf));
144 if (un) {
145 bufpos = strlen(buf);
146 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
147 " called %s", un);
150 return (buf);
152 /* here for ring/scroll/potion/wand */
153 if (nn) {
154 bufpos = strlen(buf);
155 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " of %s", an);
157 if (un) {
158 bufpos = strlen(buf);
159 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " called %s", un);
161 if (dn) {
162 bufpos = strlen(buf);
163 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " (%s)", dn);
165 return (buf);
168 char *
169 xname(struct obj *obj)
171 static char bufr[BUFSZ];
172 /* caution: doname() and aobjnam() below "know" these sizes */
173 char *buf = &(bufr[PREFIX]); /* leave room for "17 -3 " */
174 size_t bufmax = sizeof(bufr) - PREFIX;
175 int nn = objects[obj->otyp].oc_name_known;
176 const char *an = objects[obj->otyp].oc_name;
177 const char *dn = objects[obj->otyp].oc_descr;
178 char *un = objects[obj->otyp].oc_uname;
179 int pl = (obj->quan != 1);
181 if (!obj->dknown && !Blind)
182 obj->dknown = 1;/* %% doesnt belong here */
183 switch (obj->olet) {
184 case AMULET_SYM:
185 Strcpy(buf, (obj->spe < 0 && obj->known)
186 ? "cheap plastic imitation of the " : "");
187 Strcat(buf, "Amulet of Yendor");
188 break;
189 case TOOL_SYM:
190 if (!nn) {
191 strlcpy(buf, dn, bufmax);
192 break;
194 strlcpy(buf, an, bufmax);
195 break;
196 case FOOD_SYM:
197 if (obj->otyp == DEAD_HOMUNCULUS && pl) {
198 pl = 0;
199 Strcpy(buf, "dead homunculi");
200 break;
202 /* fungis ? */
203 /* fall into next case */
204 case WEAPON_SYM:
205 if (obj->otyp == WORM_TOOTH && pl) {
206 pl = 0;
207 Strcpy(buf, "worm teeth");
208 break;
210 if (obj->otyp == CRYSKNIFE && pl) {
211 pl = 0;
212 Strcpy(buf, "crysknives");
213 break;
215 /* fall into next case */
216 case ARMOR_SYM:
217 case CHAIN_SYM:
218 case ROCK_SYM:
219 strlcpy(buf, an, bufmax);
220 break;
221 case BALL_SYM:
222 Snprintf(buf, bufmax, "%sheavy iron ball",
223 (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
224 break;
225 case POTION_SYM:
226 if (nn || un || !obj->dknown) {
227 Strcpy(buf, "potion");
228 if (pl) {
229 pl = 0;
230 Strcat(buf, "s");
232 if (!obj->dknown)
233 break;
234 if (un) {
235 Strcat(buf, " called ");
236 strlcat(buf, un, bufmax);
237 } else {
238 Strcat(buf, " of ");
239 strlcat(buf, an, bufmax);
241 } else {
242 strlcpy(buf, dn, bufmax);
243 strlcat(buf, " potion", bufmax);
245 break;
246 case SCROLL_SYM:
247 Strcpy(buf, "scroll");
248 if (pl) {
249 pl = 0;
250 Strcat(buf, "s");
252 if (!obj->dknown)
253 break;
254 if (nn) {
255 Strcat(buf, " of ");
256 strlcat(buf, an, bufmax);
257 } else if (un) {
258 Strcat(buf, " called ");
259 strlcat(buf, un, bufmax);
260 } else {
261 Strcat(buf, " labeled ");
262 strlcat(buf, dn, bufmax);
264 break;
265 case WAND_SYM:
266 if (!obj->dknown)
267 Snprintf(buf, bufmax, "wand");
268 else if (nn)
269 Snprintf(buf, bufmax, "wand of %s", an);
270 else if (un)
271 Snprintf(buf, bufmax, "wand called %s", un);
272 else
273 Snprintf(buf, bufmax, "%s wand", dn);
274 break;
275 case RING_SYM:
276 if (!obj->dknown)
277 Snprintf(buf, bufmax, "ring");
278 else if (nn)
279 Snprintf(buf, bufmax, "ring of %s", an);
280 else if (un)
281 Snprintf(buf, bufmax, "ring called %s", un);
282 else
283 Snprintf(buf, bufmax, "%s ring", dn);
284 break;
285 case GEM_SYM:
286 if (!obj->dknown) {
287 Strcpy(buf, "gem");
288 break;
290 if (!nn) {
291 Snprintf(buf, bufmax, "%s gem", dn);
292 break;
294 strlcpy(buf, an, bufmax);
295 if (obj->otyp >= TURQUOISE && obj->otyp <= JADE)
296 strlcat(buf, " stone", bufmax);
297 break;
298 default:
299 Snprintf(buf, bufmax, "glorkum %c (0%o) %u %d",
300 obj->olet, obj->olet, obj->otyp, obj->spe);
302 if (pl) {
303 char *p;
305 for (p = buf; *p; p++) {
306 if (!strncmp(" of ", p, 4)) {
307 /* pieces of, cloves of, lumps of */
308 int c1, c2 = 's';
310 do {
311 c1 = c2;
312 c2 = *p;
313 *p++ = c1;
314 } while (c1);
315 goto nopl;
318 p = eos(buf) - 1;
319 if (*p == 's' || *p == 'z' || *p == 'x' ||
320 (*p == 'h' && p[-1] == 's')) {
321 /* boxes */
322 strlcat(buf, "es", bufmax);
323 } else if (*p == 'y' && !strchr(vowels, p[-1])) {
324 /* rubies, zruties */
325 *p = '\0';
326 strlcat(buf, "ies", bufmax);
327 } else {
328 strlcat(buf, "s", bufmax);
331 nopl:
332 if (obj->onamelth) {
333 strlcat(buf, " named ", bufmax);
334 strlcat(buf, ONAME(obj), bufmax);
336 return (buf);
339 char *
340 doname(struct obj *obj)
342 char prefix[PREFIX];
343 char *bp = xname(obj);
344 size_t bppos, bpmax;
346 /* XXX do this better somehow w/o knowing internals of xname() */
347 bpmax = BUFSZ - PREFIX;
349 if (obj->quan != 1)
350 Snprintf(prefix, sizeof(prefix), "%u ", obj->quan);
351 else
352 Strcpy(prefix, "a ");
353 switch (obj->olet) {
354 case AMULET_SYM:
355 if (strncmp(bp, "cheap ", 6))
356 Strcpy(prefix, "the ");
357 break;
358 case ARMOR_SYM:
359 if (obj->owornmask & W_ARMOR)
360 strlcat(bp, " (being worn)", bpmax);
361 /* fall into next case */
362 case WEAPON_SYM:
363 if (obj->known) {
364 strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
365 strlcat(prefix, " ", sizeof(prefix));
367 break;
368 case WAND_SYM:
369 if (obj->known) {
370 bppos = strlen(bp);
371 Snprintf(bp+bppos, bpmax-bppos, " (%d)", obj->spe);
373 break;
374 case RING_SYM:
375 if (obj->owornmask & W_RINGR)
376 strlcat(bp, " (on right hand)", bpmax);
377 if (obj->owornmask & W_RINGL)
378 strlcat(bp, " (on left hand)", bpmax);
379 if (obj->known && (objects[obj->otyp].bits & SPEC)) {
380 strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
381 strlcat(prefix, " ", sizeof(prefix));
383 break;
385 if (obj->owornmask & W_WEP)
386 strlcat(bp, " (weapon in hand)", bpmax);
387 if (obj->unpaid)
388 strlcat(bp, " (unpaid)", bpmax);
389 if (!strcmp(prefix, "a ") && strchr(vowels, *bp))
390 Strcpy(prefix, "an ");
391 bp = strprepend(bp, prefix);
392 return (bp);
395 /* used only in hack.fight.c (thitu) */
396 void
397 setan(const char *str, char *buf, size_t bufmax)
399 if (strchr(vowels, *str))
400 Snprintf(buf, bufmax, "an %s", str);
401 else
402 Snprintf(buf, bufmax, "a %s", str);
405 char *
406 aobjnam(struct obj *otmp, const char *verb)
408 char *bp = xname(otmp);
409 char prefix[PREFIX];
410 size_t bpmax;
412 /* XXX do this better somehow w/o knowing internals of xname() */
413 bpmax = BUFSZ - PREFIX;
415 if (otmp->quan != 1) {
416 Snprintf(prefix, sizeof(prefix), "%u ", otmp->quan);
417 bp = strprepend(bp, prefix);
419 if (verb) {
420 /* verb is given in plural (i.e., without trailing s) */
421 strlcat(bp, " ", bpmax);
422 if (otmp->quan != 1)
423 strlcat(bp, verb, bpmax);
424 else if (!strcmp(verb, "are"))
425 strlcat(bp, "is", bpmax);
426 else {
427 strlcat(bp, verb, bpmax);
428 strlcat(bp, "s", bpmax);
431 return (bp);
434 char *
435 Doname(struct obj *obj)
437 char *s = doname(obj);
439 if ('a' <= *s && *s <= 'z')
440 *s -= ('a' - 'A');
441 return (s);
444 static const char *const wrp[] = {"wand", "ring", "potion", "scroll", "gem"};
445 static const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM};
447 struct obj *
448 readobjnam(char *bp)
450 char *p;
451 unsigned ii;
452 int i;
453 int cnt, spe, spesgn, typ, heavy;
454 char let;
455 char *un, *dn, *an;
456 /* int the = 0; char *oname = 0; */
457 cnt = spe = spesgn = typ = heavy = 0;
458 let = 0;
459 an = dn = un = 0;
460 for (p = bp; *p; p++)
461 if ('A' <= *p && *p <= 'Z')
462 *p += 'a' - 'A';
463 if (!strncmp(bp, "the ", 4)) {
464 /* the = 1; */
465 bp += 4;
466 } else if (!strncmp(bp, "an ", 3)) {
467 cnt = 1;
468 bp += 3;
469 } else if (!strncmp(bp, "a ", 2)) {
470 cnt = 1;
471 bp += 2;
473 if (!cnt && digit(*bp)) {
474 cnt = atoi(bp);
475 while (digit(*bp))
476 bp++;
477 while (*bp == ' ')
478 bp++;
480 if (!cnt)
481 cnt = 1; /* %% what with "gems" etc. ? */
483 if (*bp == '+' || *bp == '-') {
484 spesgn = (*bp++ == '+') ? 1 : -1;
485 spe = atoi(bp);
486 while (digit(*bp))
487 bp++;
488 while (*bp == ' ')
489 bp++;
490 } else {
491 p = strrchr(bp, '(');
492 if (p) {
493 if (p > bp && p[-1] == ' ')
494 p[-1] = 0;
495 else
496 *p = 0;
497 p++;
498 spe = atoi(p);
499 while (digit(*p))
500 p++;
501 if (strcmp(p, ")"))
502 spe = 0;
503 else
504 spesgn = 1;
508 * now we have the actual name, as delivered by xname, say green
509 * potions called whisky scrolls labeled "QWERTY" egg dead zruties
510 * fortune cookies very heavy iron ball named hoei wand of wishing
511 * elven cloak
513 for (p = bp; *p; p++)
514 if (!strncmp(p, " named ", 7)) {
515 *p = 0;
516 /* oname = p+7; */
518 for (p = bp; *p; p++)
519 if (!strncmp(p, " called ", 8)) {
520 *p = 0;
521 un = p + 8;
523 for (p = bp; *p; p++)
524 if (!strncmp(p, " labeled ", 9)) {
525 *p = 0;
526 dn = p + 9;
528 /* first change to singular if necessary */
529 if (cnt != 1) {
530 /* find "cloves of garlic", "worthless pieces of blue glass" */
531 for (p = bp; *p; p++)
532 if (!strncmp(p, "s of ", 5)) {
533 while ((*p = p[1]) != '\0')
534 p++;
535 goto sing;
537 /* remove -s or -es (boxes) or -ies (rubies, zruties) */
538 p = eos(bp);
539 if (p[-1] == 's') {
540 if (p[-2] == 'e') {
541 if (p[-3] == 'i') {
542 if (!strcmp(p - 7, "cookies"))
543 goto mins;
544 Strcpy(p - 3, "y");
545 goto sing;
547 /* note: cloves / knives from clove / knife */
548 if (!strcmp(p - 6, "knives")) {
549 Strcpy(p - 3, "fe");
550 goto sing;
552 /* note: nurses, axes but boxes */
553 if (!strcmp(p - 5, "boxes")) {
554 p[-2] = 0;
555 goto sing;
558 mins:
559 p[-1] = 0;
560 } else {
561 if (!strcmp(p - 9, "homunculi")) {
562 Strcpy(p - 1, "us"); /* !! makes string
563 * longer */
564 goto sing;
566 if (!strcmp(p - 5, "teeth")) {
567 Strcpy(p - 5, "tooth");
568 goto sing;
570 /* here we cannot find the plural suffix */
573 sing:
574 if (!strcmp(bp, "amulet of yendor")) {
575 typ = AMULET_OF_YENDOR;
576 goto typfnd;
578 p = eos(bp);
579 if (!strcmp(p - 5, " mail")) { /* Note: ring mail is not a ring ! */
580 let = ARMOR_SYM;
581 an = bp;
582 goto srch;
584 for (ii = 0; ii < sizeof(wrpsym); ii++) {
585 int j = strlen(wrp[ii]);
586 if (!strncmp(bp, wrp[ii], j)) {
587 let = wrpsym[ii];
588 bp += j;
589 if (!strncmp(bp, " of ", 4))
590 an = bp + 4;
591 /* else if(*bp) ?? */
592 goto srch;
594 if (!strcmp(p - j, wrp[ii])) {
595 let = wrpsym[ii];
596 p -= j;
597 *p = 0;
598 if (p[-1] == ' ')
599 p[-1] = 0;
600 dn = bp;
601 goto srch;
604 if (!strcmp(p - 6, " stone")) {
605 p[-6] = 0;
606 let = GEM_SYM;
607 an = bp;
608 goto srch;
610 if (!strcmp(bp, "very heavy iron ball")) {
611 heavy = 1;
612 typ = HEAVY_IRON_BALL;
613 goto typfnd;
615 an = bp;
616 srch:
617 if (!an && !dn && !un)
618 goto any;
619 i = 1;
620 if (let)
621 i = bases[letindex(let)];
622 while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) {
623 const char *zn = objects[i].oc_name;
625 if (!zn)
626 goto nxti;
627 if (an && strcmp(an, zn))
628 goto nxti;
629 if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
630 goto nxti;
631 if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
632 goto nxti;
633 typ = i;
634 goto typfnd;
635 nxti:
636 i++;
638 any:
639 if (!let)
640 let = wrpsym[rn2(sizeof(wrpsym))];
641 typ = probtype(let);
642 typfnd:
644 struct obj *otmp;
645 let = objects[typ].oc_olet;
646 otmp = mksobj(typ);
647 if (heavy)
648 otmp->owt += 15;
649 if (cnt > 0 && strchr("%?!*)", let) &&
650 (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
651 otmp->quan = cnt;
653 if (spe > 3 && spe > otmp->spe)
654 spe = 0;
655 else if (let == WAND_SYM)
656 spe = otmp->spe;
657 if (spe == 3 && u.uluck < 0)
658 spesgn = -1;
659 if (let != WAND_SYM && spesgn == -1)
660 spe = -spe;
661 if (let == BALL_SYM)
662 spe = 0;
663 else if (let == AMULET_SYM)
664 spe = -1;
665 else if (typ == WAN_WISHING && rn2(10))
666 spe = (rn2(10) ? -1 : 0);
667 otmp->spe = spe;
669 if (spesgn == -1)
670 otmp->cursed = 1;
672 return (otmp);