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