]> git.cameronkatri.com Git - bsdgames-darwin.git/blob - hack/hack.objnam.c
don't use char values for functions that can return -1; chars are not always
[bsdgames-darwin.git] / hack / hack.objnam.c
1 /* $NetBSD: hack.objnam.c,v 1.9 2009/06/07 20:13:18 dholland Exp $ */
2
3 /*
4 * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5 * Amsterdam
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
10 * met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
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.
18 *
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.
23 *
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.
35 */
36
37 /*
38 * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39 * All rights reserved.
40 *
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.
51 *
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.
62 */
63
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 */
68
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
76
77 char *
78 strprepend(char *s, char *pref)
79 {
80 int i = strlen(pref);
81 if (i > PREFIX) {
82 pline("WARNING: prefix too short.");
83 return (s);
84 }
85 s -= i;
86 (void) strncpy(s, pref, i); /* do not copy trailing 0 */
87 return (s);
88 }
89
90 char *
91 sitoa(int a)
92 {
93 static char buf[13];
94 Snprintf(buf, sizeof(buf), (a < 0) ? "%d" : "+%d", a);
95 return (buf);
96 }
97
98 char *
99 typename(int otyp)
100 {
101 static char buf[BUFSZ];
102 size_t bufpos;
103 struct objclass *ocl = &objects[otyp];
104 const char *an = ocl->oc_name;
105 const char *dn = ocl->oc_descr;
106 char *un = ocl->oc_uname;
107 int nn = ocl->oc_name_known;
108 switch (ocl->oc_olet) {
109 case POTION_SYM:
110 Strcpy(buf, "potion");
111 break;
112 case SCROLL_SYM:
113 Strcpy(buf, "scroll");
114 break;
115 case WAND_SYM:
116 Strcpy(buf, "wand");
117 break;
118 case RING_SYM:
119 Strcpy(buf, "ring");
120 break;
121 default:
122 if (nn) {
123 Strcpy(buf, an);
124 if (otyp >= TURQUOISE && otyp <= JADE)
125 Strcat(buf, " stone");
126 if (un) {
127 bufpos = strlen(buf);
128 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
129 " called %s", un);
130 }
131 if (dn) {
132 bufpos = strlen(buf);
133 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
134 " (%s)", dn);
135 }
136 } else {
137 strlcpy(buf, dn ? dn : an, sizeof(buf));
138 if (ocl->oc_olet == GEM_SYM) {
139 strlcat(buf, " gem", sizeof(buf));
140 }
141 if (un) {
142 bufpos = strlen(buf);
143 Snprintf(buf+bufpos, sizeof(buf)-bufpos,
144 " called %s", un);
145 }
146 }
147 return (buf);
148 }
149 /* here for ring/scroll/potion/wand */
150 if (nn) {
151 bufpos = strlen(buf);
152 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " of %s", an);
153 }
154 if (un) {
155 bufpos = strlen(buf);
156 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " called %s", un);
157 }
158 if (dn) {
159 bufpos = strlen(buf);
160 Snprintf(buf+bufpos, sizeof(buf)-bufpos, " (%s)", dn);
161 }
162 return (buf);
163 }
164
165 char *
166 xname(struct obj *obj)
167 {
168 static char bufr[BUFSZ];
169 /* caution: doname() and aobjnam() below "know" these sizes */
170 char *buf = &(bufr[PREFIX]); /* leave room for "17 -3 " */
171 size_t bufmax = sizeof(bufr) - PREFIX;
172 int nn = objects[obj->otyp].oc_name_known;
173 const char *an = objects[obj->otyp].oc_name;
174 const char *dn = objects[obj->otyp].oc_descr;
175 char *un = objects[obj->otyp].oc_uname;
176 int pl = (obj->quan != 1);
177
178 if (!obj->dknown && !Blind)
179 obj->dknown = 1;/* %% doesnt belong here */
180 switch (obj->olet) {
181 case AMULET_SYM:
182 Strcpy(buf, (obj->spe < 0 && obj->known)
183 ? "cheap plastic imitation of the " : "");
184 Strcat(buf, "Amulet of Yendor");
185 break;
186 case TOOL_SYM:
187 if (!nn) {
188 strlcpy(buf, dn, bufmax);
189 break;
190 }
191 strlcpy(buf, an, bufmax);
192 break;
193 case FOOD_SYM:
194 if (obj->otyp == DEAD_HOMUNCULUS && pl) {
195 pl = 0;
196 Strcpy(buf, "dead homunculi");
197 break;
198 }
199 /* fungis ? */
200 /* fall into next case */
201 case WEAPON_SYM:
202 if (obj->otyp == WORM_TOOTH && pl) {
203 pl = 0;
204 Strcpy(buf, "worm teeth");
205 break;
206 }
207 if (obj->otyp == CRYSKNIFE && pl) {
208 pl = 0;
209 Strcpy(buf, "crysknives");
210 break;
211 }
212 /* fall into next case */
213 case ARMOR_SYM:
214 case CHAIN_SYM:
215 case ROCK_SYM:
216 strlcpy(buf, an, bufmax);
217 break;
218 case BALL_SYM:
219 Snprintf(buf, bufmax, "%sheavy iron ball",
220 (obj->owt > objects[obj->otyp].oc_weight) ? "very " : "");
221 break;
222 case POTION_SYM:
223 if (nn || un || !obj->dknown) {
224 Strcpy(buf, "potion");
225 if (pl) {
226 pl = 0;
227 Strcat(buf, "s");
228 }
229 if (!obj->dknown)
230 break;
231 if (un) {
232 Strcat(buf, " called ");
233 strlcat(buf, un, bufmax);
234 } else {
235 Strcat(buf, " of ");
236 strlcat(buf, an, bufmax);
237 }
238 } else {
239 strlcpy(buf, dn, bufmax);
240 strlcat(buf, " potion", bufmax);
241 }
242 break;
243 case SCROLL_SYM:
244 Strcpy(buf, "scroll");
245 if (pl) {
246 pl = 0;
247 Strcat(buf, "s");
248 }
249 if (!obj->dknown)
250 break;
251 if (nn) {
252 Strcat(buf, " of ");
253 strlcat(buf, an, bufmax);
254 } else if (un) {
255 Strcat(buf, " called ");
256 strlcat(buf, un, bufmax);
257 } else {
258 Strcat(buf, " labeled ");
259 strlcat(buf, dn, bufmax);
260 }
261 break;
262 case WAND_SYM:
263 if (!obj->dknown)
264 Snprintf(buf, bufmax, "wand");
265 else if (nn)
266 Snprintf(buf, bufmax, "wand of %s", an);
267 else if (un)
268 Snprintf(buf, bufmax, "wand called %s", un);
269 else
270 Snprintf(buf, bufmax, "%s wand", dn);
271 break;
272 case RING_SYM:
273 if (!obj->dknown)
274 Snprintf(buf, bufmax, "ring");
275 else if (nn)
276 Snprintf(buf, bufmax, "ring of %s", an);
277 else if (un)
278 Snprintf(buf, bufmax, "ring called %s", un);
279 else
280 Snprintf(buf, bufmax, "%s ring", dn);
281 break;
282 case GEM_SYM:
283 if (!obj->dknown) {
284 Strcpy(buf, "gem");
285 break;
286 }
287 if (!nn) {
288 Snprintf(buf, bufmax, "%s gem", dn);
289 break;
290 }
291 strlcpy(buf, an, bufmax);
292 if (obj->otyp >= TURQUOISE && obj->otyp <= JADE)
293 strlcat(buf, " stone", bufmax);
294 break;
295 default:
296 Snprintf(buf, bufmax, "glorkum %c (0%o) %u %d",
297 obj->olet, obj->olet, obj->otyp, obj->spe);
298 }
299 if (pl) {
300 char *p;
301
302 for (p = buf; *p; p++) {
303 if (!strncmp(" of ", p, 4)) {
304 /* pieces of, cloves of, lumps of */
305 int c1, c2 = 's';
306
307 do {
308 c1 = c2;
309 c2 = *p;
310 *p++ = c1;
311 } while (c1);
312 goto nopl;
313 }
314 }
315 p = eos(buf) - 1;
316 if (*p == 's' || *p == 'z' || *p == 'x' ||
317 (*p == 'h' && p[-1] == 's')) {
318 /* boxes */
319 strlcat(buf, "es", bufmax);
320 } else if (*p == 'y' && !strchr(vowels, p[-1])) {
321 /* rubies, zruties */
322 *p = '\0';
323 strlcat(buf, "ies", bufmax);
324 } else {
325 strlcat(buf, "s", bufmax);
326 }
327 }
328 nopl:
329 if (obj->onamelth) {
330 strlcat(buf, " named ", bufmax);
331 strlcat(buf, ONAME(obj), bufmax);
332 }
333 return (buf);
334 }
335
336 char *
337 doname(struct obj *obj)
338 {
339 char prefix[PREFIX];
340 char *bp = xname(obj);
341 size_t bppos, bpmax;
342
343 /* XXX do this better somehow w/o knowing internals of xname() */
344 bpmax = BUFSZ - PREFIX;
345
346 if (obj->quan != 1)
347 Snprintf(prefix, sizeof(prefix), "%u ", obj->quan);
348 else
349 Strcpy(prefix, "a ");
350 switch (obj->olet) {
351 case AMULET_SYM:
352 if (strncmp(bp, "cheap ", 6))
353 Strcpy(prefix, "the ");
354 break;
355 case ARMOR_SYM:
356 if (obj->owornmask & W_ARMOR)
357 strlcat(bp, " (being worn)", bpmax);
358 /* fall into next case */
359 case WEAPON_SYM:
360 if (obj->known) {
361 strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
362 strlcat(prefix, " ", sizeof(prefix));
363 }
364 break;
365 case WAND_SYM:
366 if (obj->known) {
367 bppos = strlen(bp);
368 Snprintf(bp+bppos, bpmax-bppos, " (%d)", obj->spe);
369 }
370 break;
371 case RING_SYM:
372 if (obj->owornmask & W_RINGR)
373 strlcat(bp, " (on right hand)", bpmax);
374 if (obj->owornmask & W_RINGL)
375 strlcat(bp, " (on left hand)", bpmax);
376 if (obj->known && (objects[obj->otyp].bits & SPEC)) {
377 strlcat(prefix, sitoa(obj->spe), sizeof(prefix));
378 strlcat(prefix, " ", sizeof(prefix));
379 }
380 break;
381 }
382 if (obj->owornmask & W_WEP)
383 strlcat(bp, " (weapon in hand)", bpmax);
384 if (obj->unpaid)
385 strlcat(bp, " (unpaid)", bpmax);
386 if (!strcmp(prefix, "a ") && strchr(vowels, *bp))
387 Strcpy(prefix, "an ");
388 bp = strprepend(bp, prefix);
389 return (bp);
390 }
391
392 /* used only in hack.fight.c (thitu) */
393 void
394 setan(const char *str, char *buf, size_t bufmax)
395 {
396 if (strchr(vowels, *str))
397 Snprintf(buf, bufmax, "an %s", str);
398 else
399 Snprintf(buf, bufmax, "a %s", str);
400 }
401
402 char *
403 aobjnam(struct obj *otmp, const char *verb)
404 {
405 char *bp = xname(otmp);
406 char prefix[PREFIX];
407 size_t bpmax;
408
409 /* XXX do this better somehow w/o knowing internals of xname() */
410 bpmax = BUFSZ - PREFIX;
411
412 if (otmp->quan != 1) {
413 Snprintf(prefix, sizeof(prefix), "%u ", otmp->quan);
414 bp = strprepend(bp, prefix);
415 }
416 if (verb) {
417 /* verb is given in plural (i.e., without trailing s) */
418 strlcat(bp, " ", bpmax);
419 if (otmp->quan != 1)
420 strlcat(bp, verb, bpmax);
421 else if (!strcmp(verb, "are"))
422 strlcat(bp, "is", bpmax);
423 else {
424 strlcat(bp, verb, bpmax);
425 strlcat(bp, "s", bpmax);
426 }
427 }
428 return (bp);
429 }
430
431 char *
432 Doname(struct obj *obj)
433 {
434 char *s = doname(obj);
435
436 if ('a' <= *s && *s <= 'z')
437 *s -= ('a' - 'A');
438 return (s);
439 }
440
441 const char *const wrp[] = {"wand", "ring", "potion", "scroll", "gem"};
442 const char wrpsym[] = {WAND_SYM, RING_SYM, POTION_SYM, SCROLL_SYM, GEM_SYM};
443
444 struct obj *
445 readobjnam(char *bp)
446 {
447 char *p;
448 unsigned ii;
449 int i;
450 int cnt, spe, spesgn, typ, heavy;
451 char let;
452 char *un, *dn, *an;
453 /* int the = 0; char *oname = 0; */
454 cnt = spe = spesgn = typ = heavy = 0;
455 let = 0;
456 an = dn = un = 0;
457 for (p = bp; *p; p++)
458 if ('A' <= *p && *p <= 'Z')
459 *p += 'a' - 'A';
460 if (!strncmp(bp, "the ", 4)) {
461 /* the = 1; */
462 bp += 4;
463 } else if (!strncmp(bp, "an ", 3)) {
464 cnt = 1;
465 bp += 3;
466 } else if (!strncmp(bp, "a ", 2)) {
467 cnt = 1;
468 bp += 2;
469 }
470 if (!cnt && digit(*bp)) {
471 cnt = atoi(bp);
472 while (digit(*bp))
473 bp++;
474 while (*bp == ' ')
475 bp++;
476 }
477 if (!cnt)
478 cnt = 1; /* %% what with "gems" etc. ? */
479
480 if (*bp == '+' || *bp == '-') {
481 spesgn = (*bp++ == '+') ? 1 : -1;
482 spe = atoi(bp);
483 while (digit(*bp))
484 bp++;
485 while (*bp == ' ')
486 bp++;
487 } else {
488 p = strrchr(bp, '(');
489 if (p) {
490 if (p > bp && p[-1] == ' ')
491 p[-1] = 0;
492 else
493 *p = 0;
494 p++;
495 spe = atoi(p);
496 while (digit(*p))
497 p++;
498 if (strcmp(p, ")"))
499 spe = 0;
500 else
501 spesgn = 1;
502 }
503 }
504 /*
505 * now we have the actual name, as delivered by xname, say green
506 * potions called whisky scrolls labeled "QWERTY" egg dead zruties
507 * fortune cookies very heavy iron ball named hoei wand of wishing
508 * elven cloak
509 */
510 for (p = bp; *p; p++)
511 if (!strncmp(p, " named ", 7)) {
512 *p = 0;
513 /* oname = p+7; */
514 }
515 for (p = bp; *p; p++)
516 if (!strncmp(p, " called ", 8)) {
517 *p = 0;
518 un = p + 8;
519 }
520 for (p = bp; *p; p++)
521 if (!strncmp(p, " labeled ", 9)) {
522 *p = 0;
523 dn = p + 9;
524 }
525 /* first change to singular if necessary */
526 if (cnt != 1) {
527 /* find "cloves of garlic", "worthless pieces of blue glass" */
528 for (p = bp; *p; p++)
529 if (!strncmp(p, "s of ", 5)) {
530 while ((*p = p[1]) != '\0')
531 p++;
532 goto sing;
533 }
534 /* remove -s or -es (boxes) or -ies (rubies, zruties) */
535 p = eos(bp);
536 if (p[-1] == 's') {
537 if (p[-2] == 'e') {
538 if (p[-3] == 'i') {
539 if (!strcmp(p - 7, "cookies"))
540 goto mins;
541 Strcpy(p - 3, "y");
542 goto sing;
543 }
544 /* note: cloves / knives from clove / knife */
545 if (!strcmp(p - 6, "knives")) {
546 Strcpy(p - 3, "fe");
547 goto sing;
548 }
549 /* note: nurses, axes but boxes */
550 if (!strcmp(p - 5, "boxes")) {
551 p[-2] = 0;
552 goto sing;
553 }
554 }
555 mins:
556 p[-1] = 0;
557 } else {
558 if (!strcmp(p - 9, "homunculi")) {
559 Strcpy(p - 1, "us"); /* !! makes string
560 * longer */
561 goto sing;
562 }
563 if (!strcmp(p - 5, "teeth")) {
564 Strcpy(p - 5, "tooth");
565 goto sing;
566 }
567 /* here we cannot find the plural suffix */
568 }
569 }
570 sing:
571 if (!strcmp(bp, "amulet of yendor")) {
572 typ = AMULET_OF_YENDOR;
573 goto typfnd;
574 }
575 p = eos(bp);
576 if (!strcmp(p - 5, " mail")) { /* Note: ring mail is not a ring ! */
577 let = ARMOR_SYM;
578 an = bp;
579 goto srch;
580 }
581 for (ii = 0; ii < sizeof(wrpsym); ii++) {
582 int j = strlen(wrp[ii]);
583 if (!strncmp(bp, wrp[ii], j)) {
584 let = wrpsym[ii];
585 bp += j;
586 if (!strncmp(bp, " of ", 4))
587 an = bp + 4;
588 /* else if(*bp) ?? */
589 goto srch;
590 }
591 if (!strcmp(p - j, wrp[ii])) {
592 let = wrpsym[ii];
593 p -= j;
594 *p = 0;
595 if (p[-1] == ' ')
596 p[-1] = 0;
597 dn = bp;
598 goto srch;
599 }
600 }
601 if (!strcmp(p - 6, " stone")) {
602 p[-6] = 0;
603 let = GEM_SYM;
604 an = bp;
605 goto srch;
606 }
607 if (!strcmp(bp, "very heavy iron ball")) {
608 heavy = 1;
609 typ = HEAVY_IRON_BALL;
610 goto typfnd;
611 }
612 an = bp;
613 srch:
614 if (!an && !dn && !un)
615 goto any;
616 i = 1;
617 if (let)
618 i = bases[letindex(let)];
619 while (i <= NROFOBJECTS && (!let || objects[i].oc_olet == let)) {
620 const char *zn = objects[i].oc_name;
621
622 if (!zn)
623 goto nxti;
624 if (an && strcmp(an, zn))
625 goto nxti;
626 if (dn && (!(zn = objects[i].oc_descr) || strcmp(dn, zn)))
627 goto nxti;
628 if (un && (!(zn = objects[i].oc_uname) || strcmp(un, zn)))
629 goto nxti;
630 typ = i;
631 goto typfnd;
632 nxti:
633 i++;
634 }
635 any:
636 if (!let)
637 let = wrpsym[rn2(sizeof(wrpsym))];
638 typ = probtype(let);
639 typfnd:
640 {
641 struct obj *otmp;
642 let = objects[typ].oc_olet;
643 otmp = mksobj(typ);
644 if (heavy)
645 otmp->owt += 15;
646 if (cnt > 0 && strchr("%?!*)", let) &&
647 (cnt < 4 || (let == WEAPON_SYM && typ <= ROCK && cnt < 20)))
648 otmp->quan = cnt;
649
650 if (spe > 3 && spe > otmp->spe)
651 spe = 0;
652 else if (let == WAND_SYM)
653 spe = otmp->spe;
654 if (spe == 3 && u.uluck < 0)
655 spesgn = -1;
656 if (let != WAND_SYM && spesgn == -1)
657 spe = -spe;
658 if (let == BALL_SYM)
659 spe = 0;
660 else if (let == AMULET_SYM)
661 spe = -1;
662 else if (typ == WAN_WISHING && rn2(10))
663 spe = (rn2(10) ? -1 : 0);
664 otmp->spe = spe;
665
666 if (spesgn == -1)
667 otmp->cursed = 1;
668
669 return (otmp);
670 }
671 }