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