OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / do_name.c
1 /*      SCCS Id: @(#)do_name.c  3.4     2003/01/14      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6
7 #ifdef OVLB
8
9 STATIC_DCL void FDECL(do_oname, (struct obj *));
10 static void FDECL(getpos_help, (BOOLEAN_P,const char *));
11
12 extern const char what_is_an_unknown_object[];          /* from pager.c */
13
14 /* the response for '?' help request in getpos() */
15 static void
16 getpos_help(force, goal)
17 boolean force;
18 const char *goal;
19 {
20     char sbuf[BUFSZ];
21     boolean doing_what_is;
22     winid tmpwin = create_nhwindow(NHW_MENU);
23
24     Sprintf(sbuf, "Use [%s] to move the cursor to %s.",
25             iflags.num_pad ? "2468" : "hjkl", goal);
26     putstr(tmpwin, 0, sbuf);
27     putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
28     putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
29     /* disgusting hack; the alternate selection characters work for any
30        getpos call, but they only matter for dowhatis (and doquickwhatis) */
31     doing_what_is = (goal == what_is_an_unknown_object);
32     Sprintf(sbuf, "Type a .%s when you are at the right place.",
33             doing_what_is ? " or , or ; or :" : "");
34     putstr(tmpwin, 0, sbuf);
35     if (!force)
36         putstr(tmpwin, 0, "Type Space or Escape when you're done.");
37     putstr(tmpwin, 0, "");
38     display_nhwindow(tmpwin, TRUE);
39     destroy_nhwindow(tmpwin);
40 }
41
42 int
43 getpos(cc, force, goal)
44 coord *cc;
45 boolean force;
46 const char *goal;
47 {
48     int result = 0;
49     int cx, cy, i, c;
50     int sidx, tx, ty;
51     boolean msg_given = TRUE;   /* clear message window by default */
52     static const char pick_chars[] = ".,;:";
53     const char *cp;
54     const char *sdp;
55     if(iflags.num_pad) sdp = ndir; else sdp = sdir;     /* DICE workaround */
56
57     if (flags.verbose) {
58         pline("(For instructions type a ?)");
59         msg_given = TRUE;
60     }
61     cx = cc->x;
62     cy = cc->y;
63 #ifdef CLIPPING
64     cliparound(cx, cy);
65 #endif
66     curs(WIN_MAP, cx,cy);
67     flush_screen(0);
68 #ifdef MAC
69     lock_mouse_cursor(TRUE);
70 #endif
71     for (;;) {
72         c = nh_poskey(&tx, &ty, &sidx);
73         if (c == '\033') {
74             cx = cy = -10;
75             msg_given = TRUE;   /* force clear */
76             result = -1;
77             break;
78         }
79         if(c == 0) {
80             if (!isok(tx, ty)) continue;
81             /* a mouse click event, just assign and return */
82             cx = tx;
83             cy = ty;
84             break;
85         }
86         if ((cp = index(pick_chars, c)) != 0) {
87             /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
88             result = cp - pick_chars;
89             break;
90         }
91         for (i = 0; i < 8; i++) {
92             int dx, dy;
93
94             if (sdp[i] == c) {
95                 /* a normal movement letter or digit */
96                 dx = xdir[i];
97                 dy = ydir[i];
98             } else if (sdir[i] == lowc((char)c)) {
99                 /* a shifted movement letter */
100                 dx = 8 * xdir[i];
101                 dy = 8 * ydir[i];
102             } else
103                 continue;
104
105             /* truncate at map edge; diagonal moves complicate this... */
106             if (cx + dx < 1) {
107                 dy -= sgn(dy) * (1 - (cx + dx));
108                 dx = 1 - cx;            /* so that (cx+dx == 1) */
109             } else if (cx + dx > COLNO-1) {
110                 dy += sgn(dy) * ((COLNO-1) - (cx + dx));
111                 dx = (COLNO-1) - cx;
112             }
113             if (cy + dy < 0) {
114                 dx -= sgn(dx) * (0 - (cy + dy));
115                 dy = 0 - cy;            /* so that (cy+dy == 0) */
116             } else if (cy + dy > ROWNO-1) {
117                 dx += sgn(dx) * ((ROWNO-1) - (cy + dy));
118                 dy = (ROWNO-1) - cy;
119             }
120             cx += dx;
121             cy += dy;
122             goto nxtc;
123         }
124
125         if(c == '?'){
126             getpos_help(force, goal);
127         } else {
128             if (!index(quitchars, c)) {
129                 char matching[MAXPCHARS];
130                 int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
131                 (void)memset((genericptr_t)matching, 0, sizeof matching);
132                 for (sidx = 1; sidx < MAXPCHARS; sidx++)
133                     if (c == defsyms[sidx].sym || c == (int)showsyms[sidx])
134                         matching[sidx] = (char) ++k;
135                 if (k) {
136                     for (pass = 0; pass <= 1; pass++) {
137                         /* pass 0: just past current pos to lower right;
138                            pass 1: upper left corner to current pos */
139                         lo_y = (pass == 0) ? cy : 0;
140                         hi_y = (pass == 0) ? ROWNO - 1 : cy;
141                         for (ty = lo_y; ty <= hi_y; ty++) {
142                             lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
143                             hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
144                             for (tx = lo_x; tx <= hi_x; tx++) {
145                                 k = levl[tx][ty].glyph;
146                                 if (glyph_is_cmap(k) &&
147                                         matching[glyph_to_cmap(k)]) {
148                                     cx = tx,  cy = ty;
149                                     if (msg_given) {
150                                         clear_nhwindow(WIN_MESSAGE);
151                                         msg_given = FALSE;
152                                     }
153                                     goto nxtc;
154                                 }
155                             }   /* column */
156                         }       /* row */
157                     }           /* pass */
158                     pline("Can't find dungeon feature '%c'.", c);
159                     msg_given = TRUE;
160                     goto nxtc;
161                 } else {
162                     pline("Unknown direction: '%s' (%s).",
163                           visctrl((char)c),
164                           !force ? "aborted" :
165                           iflags.num_pad ? "use 2468 or ." : "use hjkl or .");
166                     msg_given = TRUE;
167                 } /* k => matching */
168             } /* !quitchars */
169             if (force) goto nxtc;
170             pline("Done.");
171             msg_given = FALSE;  /* suppress clear */
172             cx = -1;
173             cy = 0;
174             result = 0; /* not -1 */
175             break;
176         }
177     nxtc:       ;
178 #ifdef CLIPPING
179         cliparound(cx, cy);
180 #endif
181         curs(WIN_MAP,cx,cy);
182         flush_screen(0);
183     }
184 #ifdef MAC
185     lock_mouse_cursor(FALSE);
186 #endif
187     if (msg_given) clear_nhwindow(WIN_MESSAGE);
188     cc->x = cx;
189     cc->y = cy;
190     return result;
191 }
192
193 struct monst *
194 christen_monst(mtmp, name)
195 struct monst *mtmp;
196 const char *name;
197 {
198         int lth;
199         struct monst *mtmp2;
200         char buf[PL_PSIZ];
201
202         /* dogname & catname are PL_PSIZ arrays; object names have same limit */
203         lth = *name ? (int)(strlen(name) + 1) : 0;
204         if(lth > PL_PSIZ){
205                 lth = PL_PSIZ;
206                 name = strncpy(buf, name, PL_PSIZ - 1);
207                 buf[PL_PSIZ - 1] = '\0';
208         }
209         if (lth == mtmp->mnamelth) {
210                 /* don't need to allocate a new monst struct */
211                 if (lth) Strcpy(NAME(mtmp), name);
212                 return mtmp;
213         }
214         mtmp2 = newmonst(mtmp->mxlth + lth);
215         *mtmp2 = *mtmp;
216         (void) memcpy((genericptr_t)mtmp2->mextra,
217                       (genericptr_t)mtmp->mextra, mtmp->mxlth);
218         mtmp2->mnamelth = lth;
219         if (lth) Strcpy(NAME(mtmp2), name);
220         replmon(mtmp,mtmp2);
221         return(mtmp2);
222 }
223
224 int
225 do_mname()
226 {
227         char buf[BUFSZ];
228         coord cc;
229         register int cx,cy;
230         register struct monst *mtmp;
231         char qbuf[QBUFSZ];
232
233         if (Hallucination) {
234                 You("would never recognize it anyway.");
235                 return 0;
236         }
237         cc.x = u.ux;
238         cc.y = u.uy;
239         if (getpos(&cc, FALSE, "the monster you want to name") < 0 ||
240                         (cx = cc.x) < 0)
241                 return 0;
242         cy = cc.y;
243
244         if (cx == u.ux && cy == u.uy) {
245 #ifdef STEED
246             if (u.usteed && canspotmon(u.usteed))
247                 mtmp = u.usteed;
248             else {
249 #endif
250                 pline("This %s creature is called %s and cannot be renamed.",
251                 ACURR(A_CHA) > 14 ?
252                 (flags.female ? "beautiful" : "handsome") :
253                 "ugly",
254                 plname);
255                 return(0);
256 #ifdef STEED
257             }
258 #endif
259         } else
260             mtmp = m_at(cx, cy);
261
262         if (!mtmp || (!sensemon(mtmp) &&
263                         (!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected
264                         || mtmp->m_ap_type == M_AP_FURNITURE
265                         || mtmp->m_ap_type == M_AP_OBJECT
266                         || (mtmp->minvis && !See_invisible)))) {
267                 pline("I see no monster there.");
268                 return(0);
269         }
270         /* special case similar to the one in lookat() */
271         (void) distant_monnam(mtmp, ARTICLE_THE, buf);
272         Sprintf(qbuf, "What do you want to call %s?", buf);
273         getlin(qbuf,buf);
274         if(!*buf || *buf == '\033') return(0);
275         /* strip leading and trailing spaces; unnames monster if all spaces */
276         (void)mungspaces(buf);
277
278         if (mtmp->data->geno & G_UNIQ)
279             pline("%s doesn't like being called names!", Monnam(mtmp));
280         else
281             (void) christen_monst(mtmp, buf);
282         return(0);
283 }
284
285 /*
286  * This routine changes the address of obj. Be careful not to call it
287  * when there might be pointers around in unknown places. For now: only
288  * when obj is in the inventory.
289  */
290 STATIC_OVL
291 void
292 do_oname(obj)
293 register struct obj *obj;
294 {
295         char buf[BUFSZ], qbuf[QBUFSZ];
296         const char *aname;
297         short objtyp;
298
299         Sprintf(qbuf, "What do you want to name %s %s?",
300                 is_plural(obj) ? "these" : "this", xname(obj));
301         getlin(qbuf, buf);
302         if(!*buf || *buf == '\033')     return;
303         /* strip leading and trailing spaces; unnames item if all spaces */
304         (void)mungspaces(buf);
305
306         /* relax restrictions over proper capitalization for artifacts */
307         if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
308                 Strcpy(buf, aname);
309
310         if (obj->oartifact) {
311                 pline_The("artifact seems to resist the attempt.");
312                 return;
313         } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
314                 int n = rn2((int)strlen(buf));
315                 register char c1, c2;
316
317                 c1 = lowc(buf[n]);
318                 do c2 = 'a' + rn2('z'-'a'); while (c1 == c2);
319                 buf[n] = (buf[n] == c1) ? c2 : highc(c2);  /* keep same case */
320                 pline("While engraving your %s slips.", body_part(HAND));
321                 display_nhwindow(WIN_MESSAGE, FALSE);
322                 You("engrave: \"%s\".",buf);
323         }
324         obj = oname(obj, buf);
325 }
326
327 /*
328  * Allocate a new and possibly larger storage space for an obj.
329  */
330 struct obj *
331 realloc_obj(obj, oextra_size, oextra_src, oname_size, name)
332 struct obj *obj;
333 int oextra_size;                /* storage to allocate for oextra            */
334 genericptr_t oextra_src;
335 int oname_size;                 /* size of name string + 1 (null terminator) */
336 const char *name;
337 {
338         struct obj *otmp;
339
340         otmp = newobj(oextra_size + oname_size);
341         *otmp = *obj;   /* the cobj pointer is copied to otmp */
342         if (oextra_size) {
343             if (oextra_src)
344                 (void) memcpy((genericptr_t)otmp->oextra, oextra_src,
345                                                         oextra_size);
346         } else {
347             otmp->oattached = OATTACHED_NOTHING;
348         }
349         otmp->oxlth = oextra_size;
350
351         otmp->onamelth = oname_size;
352         otmp->timed = 0;        /* not timed, yet */
353         otmp->lamplit = 0;      /* ditto */
354         /* __GNUC__ note:  if the assignment of otmp->onamelth immediately
355            precedes this `if' statement, a gcc bug will miscompile the
356            test on vax (`insv' instruction used to store bitfield does
357            not set condition codes, but optimizer behaves as if it did).
358            gcc-2.7.2.1 finally fixed this. */
359         if (oname_size) {
360             if (name)
361                 Strcpy(ONAME(otmp), name);
362         }
363
364         if (obj->owornmask) {
365                 boolean save_twoweap = u.twoweap;
366                 /* unwearing the old instance will clear dual-wield mode
367                    if this object is either of the two weapons */
368                 setworn((struct obj *)0, obj->owornmask);
369                 setworn(otmp, otmp->owornmask);
370                 u.twoweap = save_twoweap;
371         }
372
373         /* replace obj with otmp */
374         replace_object(obj, otmp);
375
376         /* fix ocontainer pointers */
377         if (Has_contents(obj)) {
378                 struct obj *inside;
379
380                 for(inside = obj->cobj; inside; inside = inside->nobj)
381                         inside->ocontainer = otmp;
382         }
383
384         /* move timers and light sources from obj to otmp */
385         if (obj->timed) obj_move_timers(obj, otmp);
386         if (obj->lamplit) obj_move_light_source(obj, otmp);
387
388         /* objects possibly being manipulated by multi-turn occupations
389            which have been interrupted but might be subsequently resumed */
390         if (obj->oclass == FOOD_CLASS)
391             food_substitution(obj, otmp);       /* eat food or open tin */
392         else if (obj->oclass == SPBOOK_CLASS)
393             book_substitution(obj, otmp);       /* read spellbook */
394
395         /* obfree(obj, otmp);   now unnecessary: no pointers on bill */
396         dealloc_obj(obj);       /* let us hope nobody else saved a pointer */
397         return otmp;
398 }
399
400 struct obj *
401 oname(obj, name)
402 struct obj *obj;
403 const char *name;
404 {
405         int lth;
406         char buf[PL_PSIZ];
407
408         lth = *name ? (int)(strlen(name) + 1) : 0;
409         if (lth > PL_PSIZ) {
410                 lth = PL_PSIZ;
411                 name = strncpy(buf, name, PL_PSIZ - 1);
412                 buf[PL_PSIZ - 1] = '\0';
413         }
414         /* If named artifact exists in the game, do not create another.
415          * Also trying to create an artifact shouldn't de-artifact
416          * it (e.g. Excalibur from prayer). In this case the object
417          * will retain its current name. */
418         if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
419                 return obj;
420
421         if (lth == obj->onamelth) {
422                 /* no need to replace entire object */
423                 if (lth) Strcpy(ONAME(obj), name);
424         } else {
425                 obj = realloc_obj(obj, obj->oxlth,
426                               (genericptr_t)obj->oextra, lth, name);
427         }
428         if (lth) artifact_exists(obj, name, TRUE);
429         if (obj->oartifact) {
430             /* can't dual-wield with artifact as secondary weapon */
431             if (obj == uswapwep) untwoweapon();
432             /* activate warning if you've just named your weapon "Sting" */
433             if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP);
434         }
435         if (carried(obj)) update_inventory();
436         return obj;
437 }
438
439 static NEARDATA const char callable[] = {
440         SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
441         GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 };
442
443 int
444 ddocall()
445 {
446         register struct obj *obj;
447 #ifdef REDO
448         char    ch;
449 #endif
450         char allowall[2];
451
452         switch(
453 #ifdef REDO
454                 ch =
455 #endif
456                 ynq("Name an individual object?")) {
457         case 'q':
458                 break;
459         case 'y':
460 #ifdef REDO
461                 savech(ch);
462 #endif
463                 allowall[0] = ALL_CLASSES; allowall[1] = '\0';
464                 obj = getobj(allowall, "name");
465                 if(obj) do_oname(obj);
466                 break;
467         default :
468 #ifdef REDO
469                 savech(ch);
470 #endif
471                 obj = getobj(callable, "call");
472                 if (obj) {
473                         /* behave as if examining it in inventory;
474                            this might set dknown if it was picked up
475                            while blind and the hero can now see */
476                         (void) xname(obj);
477
478                         if (!obj->dknown) {
479                                 You("would never recognize another one.");
480                                 return 0;
481                         }
482                         docall(obj);
483                 }
484                 break;
485         }
486         return 0;
487 }
488
489 void
490 docall(obj)
491 register struct obj *obj;
492 {
493         char buf[BUFSZ], qbuf[QBUFSZ];
494         struct obj otemp;
495         register char **str1;
496
497         if (!obj->dknown) return; /* probably blind */
498         otemp = *obj;
499         otemp.quan = 1L;
500         otemp.onamelth = 0;
501         otemp.oxlth = 0;
502         if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink)
503             /* kludge, meaning it's sink water */
504             Sprintf(qbuf,"Call a stream of %s fluid:",
505                     OBJ_DESCR(objects[otemp.otyp]));
506         else
507             Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
508         getlin(qbuf, buf);
509         if(!*buf || *buf == '\033')
510                 return;
511
512         /* clear old name */
513         str1 = &(objects[obj->otyp].oc_uname);
514         if(*str1) free((genericptr_t)*str1);
515
516         /* strip leading and trailing spaces; uncalls item if all spaces */
517         (void)mungspaces(buf);
518         if (!*buf) {
519             if (*str1) {        /* had name, so possibly remove from disco[] */
520                 /* strip name first, for the update_inventory() call
521                    from undiscover_object() */
522                 *str1 = (char *)0;
523                 undiscover_object(obj->otyp);
524             }
525         } else {
526             *str1 = strcpy((char *) alloc((unsigned)strlen(buf)+1), buf);
527             discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
528         }
529 }
530
531 #endif /*OVLB*/
532 #ifdef OVL0
533
534 static const char * const ghostnames[] = {
535         /* these names should have length < PL_NSIZ */
536         /* Capitalize the names for aesthetics -dgk */
537         "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile",
538         "Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov",
539         "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert",
540         "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
541         "Stephan", "Lance Braccus", "Shadowhawk"
542 };
543
544 /* ghost names formerly set by x_monnam(), now by makemon() instead */
545 const char *
546 rndghostname()
547 {
548     return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *)plname;
549 }
550
551 /* Monster naming functions:
552  * x_monnam is the generic monster-naming function.
553  *                seen        unseen       detected               named
554  * mon_nam:     the newt        it      the invisible orc       Fido
555  * noit_mon_nam:the newt (as if detected) the invisible orc     Fido
556  * l_monnam:    newt            it      invisible orc           dog called fido
557  * Monnam:      The newt        It      The invisible orc       Fido
558  * noit_Monnam: The newt (as if detected) The invisible orc     Fido
559  * Adjmonnam:   The poor newt   It      The poor invisible orc  The poor Fido
560  * Amonnam:     A newt          It      An invisible orc        Fido
561  * a_monnam:    a newt          it      an invisible orc        Fido
562  * m_monnam:    newt            xan     orc                     Fido
563  * y_monnam:    your newt     your xan  your invisible orc      Fido
564  */
565
566 /* Bug: if the monster is a priest or shopkeeper, not every one of these
567  * options works, since those are special cases.
568  */
569 char *
570 x_monnam(mtmp, article, adjective, suppress, called)
571 register struct monst *mtmp;
572 int article;
573 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
574  * ARTICLE_YOUR: "your" on pets, "the" on everything else
575  *
576  * If the monster would be referred to as "it" or if the monster has a name
577  * _and_ there is no adjective, "invisible", "saddled", etc., override this
578  * and always use no article.
579  */
580 const char *adjective;
581 int suppress;
582 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
583  * EXACT_NAME: combination of all the above
584  */
585 boolean called;
586 {
587 #ifdef LINT     /* static char buf[BUFSZ]; */
588         char buf[BUFSZ];
589 #else
590         static char buf[BUFSZ];
591 #endif
592         struct permonst *mdat = mtmp->data;
593         boolean do_hallu, do_invis, do_it, do_saddle;
594         boolean name_at_start, has_adjectives;
595         char *bp;
596
597         if (program_state.gameover)
598             suppress |= SUPPRESS_HALLUCINATION;
599         if (article == ARTICLE_YOUR && !mtmp->mtame)
600             article = ARTICLE_THE;
601
602         do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
603         do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
604         do_it = !canspotmon(mtmp) && 
605             article != ARTICLE_YOUR &&
606             !program_state.gameover &&
607 #ifdef STEED
608             mtmp != u.usteed &&
609 #endif
610             !(u.uswallow && mtmp == u.ustuck) &&
611             !(suppress & SUPPRESS_IT);
612         do_saddle = !(suppress & SUPPRESS_SADDLE);
613
614         buf[0] = 0;
615
616         /* unseen monsters, etc.  Use "it" */
617         if (do_it) {
618             Strcpy(buf, "it");
619             return buf;
620         }
621
622         /* priests and minions: don't even use this function */
623         if (mtmp->ispriest || mtmp->isminion) {
624             char priestnambuf[BUFSZ];
625             char *name;
626             long save_prop = EHalluc_resistance;
627             unsigned save_invis = mtmp->minvis;
628
629             /* when true name is wanted, explicitly block Hallucination */
630             if (!do_hallu) EHalluc_resistance = 1L;
631             if (!do_invis) mtmp->minvis = 0;
632             name = priestname(mtmp, priestnambuf);
633             EHalluc_resistance = save_prop;
634             mtmp->minvis = save_invis;
635             if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
636                 name += 4;
637             return strcpy(buf, name);
638         }
639
640         /* Shopkeepers: use shopkeeper name.  For normal shopkeepers, just
641          * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
642          * shopkeeper" or "Asidonhopo the blue dragon".  If hallucinating,
643          * none of this applies.
644          */
645         if (mtmp->isshk && !do_hallu) {
646             if (adjective && article == ARTICLE_THE) {
647                 /* pathological case: "the angry Asidonhopo the blue dragon"
648                    sounds silly */
649                 Strcpy(buf, "the ");
650                 Strcat(strcat(buf, adjective), " ");
651                 Strcat(buf, shkname(mtmp));
652                 return buf;
653             }
654             Strcat(buf, shkname(mtmp));
655             if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
656                 return buf;
657             Strcat(buf, " the ");
658             if (do_invis)
659                 Strcat(buf, "invisible ");
660             Strcat(buf, mdat->mname);
661             return buf;
662         }
663
664         /* Put the adjectives in the buffer */
665         if (adjective)
666             Strcat(strcat(buf, adjective), " ");
667         if (do_invis)
668             Strcat(buf, "invisible ");
669 #ifdef STEED
670         if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) &&
671             !Blind && !Hallucination)
672             Strcat(buf, "saddled ");
673 #endif
674         if (buf[0] != 0)
675             has_adjectives = TRUE;
676         else
677             has_adjectives = FALSE;
678
679         /* Put the actual monster name or type into the buffer now */
680         /* Be sure to remember whether the buffer starts with a name */
681         if (do_hallu) {
682             Strcat(buf, rndmonnam());
683             name_at_start = FALSE;
684         } else if (mtmp->mnamelth) {
685             char *name = NAME(mtmp);
686
687             if (mdat == &mons[PM_GHOST]) {
688                 Sprintf(eos(buf), "%s ghost", s_suffix(name));
689                 name_at_start = TRUE;
690             } else if (called) {
691                 Sprintf(eos(buf), "%s called %s", mdat->mname, name);
692                 name_at_start = (boolean)type_is_pname(mdat);
693             } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
694                 /* <name> the <adjective> <invisible> <saddled> <rank> */
695                 char pbuf[BUFSZ];
696
697                 Strcpy(pbuf, name);
698                 pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
699                 if (has_adjectives)
700                     Strcat(pbuf, buf);
701                 Strcat(pbuf, bp + 5);   /* append the rest of the name */
702                 Strcpy(buf, pbuf);
703                 article = ARTICLE_NONE;
704                 name_at_start = TRUE;
705             } else {
706                 Strcat(buf, name);
707                 name_at_start = TRUE;
708             }
709         } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
710             char pbuf[BUFSZ];
711             Strcpy(pbuf, rank_of((int)mtmp->m_lev,
712                                  monsndx(mdat),
713                                  (boolean)mtmp->female));
714             Strcat(buf, lcase(pbuf));
715             name_at_start = FALSE;
716         } else {
717             Strcat(buf, mdat->mname);
718             name_at_start = (boolean)type_is_pname(mdat);
719         }
720
721         if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
722             if (mdat == &mons[PM_WIZARD_OF_YENDOR])
723                 article = ARTICLE_THE;
724             else
725                 article = ARTICLE_NONE;
726         } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
727             article = ARTICLE_THE;
728         }
729
730         {
731             char buf2[BUFSZ];
732
733             switch(article) {
734                 case ARTICLE_YOUR:
735                     Strcpy(buf2, "your ");
736                     Strcat(buf2, buf);
737                     Strcpy(buf, buf2);
738                     return buf;
739                 case ARTICLE_THE:
740                     Strcpy(buf2, "the ");
741                     Strcat(buf2, buf);
742                     Strcpy(buf, buf2);
743                     return buf;
744                 case ARTICLE_A:
745                     return(an(buf));
746                 case ARTICLE_NONE:
747                 default:
748                     return buf;
749             }
750         }
751 }
752
753 #endif /* OVL0 */
754 #ifdef OVLB
755
756 char *
757 l_monnam(mtmp)
758 register struct monst *mtmp;
759 {
760         return(x_monnam(mtmp, ARTICLE_NONE, (char *)0, 
761                 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, TRUE));
762 }
763
764 #endif /* OVLB */
765 #ifdef OVL0
766
767 char *
768 mon_nam(mtmp)
769 register struct monst *mtmp;
770 {
771         return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
772                 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE));
773 }
774
775 /* print the name as if mon_nam() was called, but assume that the player
776  * can always see the monster--used for probing and for monsters aggravating
777  * the player with a cursed potion of invisibility
778  */
779 char *
780 noit_mon_nam(mtmp)
781 register struct monst *mtmp;
782 {
783         return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
784                 mtmp->mnamelth ? (SUPPRESS_SADDLE|SUPPRESS_IT) :
785                     SUPPRESS_IT, FALSE));
786 }
787
788 char *
789 Monnam(mtmp)
790 register struct monst *mtmp;
791 {
792         register char *bp = mon_nam(mtmp);
793
794         *bp = highc(*bp);
795         return(bp);
796 }
797
798 char *
799 noit_Monnam(mtmp)
800 register struct monst *mtmp;
801 {
802         register char *bp = noit_mon_nam(mtmp);
803
804         *bp = highc(*bp);
805         return(bp);
806 }
807
808 /* monster's own name */
809 char *
810 m_monnam(mtmp)
811 struct monst *mtmp;
812 {
813         return x_monnam(mtmp, ARTICLE_NONE, (char *)0, EXACT_NAME, FALSE);
814 }
815
816 /* pet name: "your little dog" */
817 char *
818 y_monnam(mtmp)
819 struct monst *mtmp;
820 {
821         int prefix, suppression_flag;
822
823         prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
824         suppression_flag = (mtmp->mnamelth
825 #ifdef STEED
826                             /* "saddled" is redundant when mounted */
827                             || mtmp == u.usteed
828 #endif
829                             ) ? SUPPRESS_SADDLE : 0;
830
831         return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE);
832 }
833
834 #endif /* OVL0 */
835 #ifdef OVLB
836
837 char *
838 Adjmonnam(mtmp, adj)
839 register struct monst *mtmp;
840 register const char *adj;
841 {
842         register char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
843                 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
844
845         *bp = highc(*bp);
846         return(bp);
847 }
848
849 char *
850 a_monnam(mtmp)
851 register struct monst *mtmp;
852 {
853         return x_monnam(mtmp, ARTICLE_A, (char *)0,
854                 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
855 }
856
857 char *
858 Amonnam(mtmp)
859 register struct monst *mtmp;
860 {
861         register char *bp = a_monnam(mtmp);
862
863         *bp = highc(*bp);
864         return(bp);
865 }
866
867 /* used for monster ID by the '/', ';', and 'C' commands to block remote
868    identification of the endgame altars via their attending priests */
869 char *
870 distant_monnam(mon, article, outbuf)
871 struct monst *mon;
872 int article;    /* only ARTICLE_NONE and ARTICLE_THE are handled here */
873 char *outbuf;
874 {
875     /* high priest(ess)'s identity is concealed on the Astral Plane,
876        unless you're adjacent (overridden for hallucination which does
877        its own obfuscation) */
878     if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination &&
879             Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
880         Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
881         Strcat(outbuf, mon->female ? "high priestess" : "high priest");
882     } else {
883         Strcpy(outbuf, x_monnam(mon, article, (char *)0, 0, TRUE));
884     }
885     return outbuf;
886 }
887
888 static const char * const bogusmons[] = {
889         "jumbo shrimp", "giant pigmy", "gnu", "killer penguin",
890         "giant cockroach", "giant slug", "maggot", "pterodactyl",
891         "tyrannosaurus rex", "basilisk", "beholder", "nightmare",
892         "efreeti", "marid", "rot grub", "bookworm", "master lichen",
893         "shadow", "hologram", "jester", "attorney", "sleazoid",
894         "killer tomato", "amazon", "robot", "battlemech",
895         "rhinovirus", "harpy", "lion-dog", "rat-ant", "Y2K bug",
896                                                 /* misc. */
897         "grue", "Christmas-tree monster", "luck sucker", "paskald",
898         "brogmoid", "dornbeast",                /* Quendor (Zork, &c.) */
899         "Ancient Multi-Hued Dragon", "Evil Iggy",
900                                                 /* Moria */
901         "emu", "kestrel", "xeroc", "venus flytrap",
902                                                 /* Rogue */
903         "creeping coins",                       /* Wizardry */
904         "hydra", "siren",                       /* Greek legend */
905         "killer bunny",                         /* Monty Python */
906         "rodent of unusual size",               /* The Princess Bride */
907         "Smokey the bear",      /* "Only you can prevent forest fires!" */
908         "Luggage",                              /* Discworld */
909         "Ent",                                  /* Lord of the Rings */
910         "tangle tree", "nickelpede", "wiggle",  /* Xanth */
911         "white rabbit", "snark",                /* Lewis Carroll */
912         "pushmi-pullyu",                        /* Dr. Doolittle */
913         "smurf",                                /* The Smurfs */
914         "tribble", "Klingon", "Borg",           /* Star Trek */
915         "Ewok",                                 /* Star Wars */
916         "Totoro",                               /* Tonari no Totoro */
917         "ohmu",                                 /* Nausicaa */
918         "youma",                                /* Sailor Moon */
919         "nyaasu",                               /* Pokemon (Meowth) */
920         "Godzilla", "King Kong",                /* monster movies */
921         "earthquake beast",                     /* old L of SH */
922         "Invid",                                /* Robotech */
923         "Terminator",                           /* The Terminator */
924         "boomer",                               /* Bubblegum Crisis */
925         "Dalek",                                /* Dr. Who ("Exterminate!") */
926         "microscopic space fleet", "Ravenous Bugblatter Beast of Traal",
927                                                 /* HGttG */
928         "teenage mutant ninja turtle",          /* TMNT */
929         "samurai rabbit",                       /* Usagi Yojimbo */
930         "aardvark",                             /* Cerebus */
931         "Audrey II",                            /* Little Shop of Horrors */
932         "witch doctor", "one-eyed one-horned flying purple people eater",
933                                                 /* 50's rock 'n' roll */
934         "Barney the dinosaur",                  /* saccharine kiddy TV */
935         "Morgoth",                              /* Angband */
936         "Vorlon",                               /* Babylon 5 */
937         "questing beast",               /* King Arthur */
938         "Predator",                             /* Movie */
939         "mother-in-law"                         /* common pest */
940 };
941
942
943 /* Return a random monster name, for hallucination.
944  * KNOWN BUG: May be a proper name (Godzilla, Barney), may not
945  * (the Terminator, a Dalek).  There's no elegant way to deal
946  * with this without radically modifying the calling functions.
947  */
948 const char *
949 rndmonnam()
950 {
951         int name;
952
953         do {
954             name = rn1(SPECIAL_PM + SIZE(bogusmons) - LOW_PM, LOW_PM);
955         } while (name < SPECIAL_PM &&
956             (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
957
958         if (name >= SPECIAL_PM) return bogusmons[name - SPECIAL_PM];
959         return mons[name].mname;
960 }
961
962 #ifdef REINCARNATION
963 const char *
964 roguename() /* Name of a Rogue player */
965 {
966         char *i, *opts;
967
968         if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
969                 for (i = opts; *i; i++)
970                         if (!strncmp("name=",i,5)) {
971                                 char *j;
972                                 if ((j = index(i+5,',')) != 0)
973                                         *j = (char)0;
974                                 return i+5;
975                         }
976         }
977         return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
978                 : "Glenn Wichman";
979 }
980 #endif /* REINCARNATION */
981 #endif /* OVLB */
982
983 #ifdef OVL2
984
985 static NEARDATA const char * const hcolors[] = {
986         "ultraviolet", "infrared", "bluish-orange",
987         "reddish-green", "dark white", "light black", "sky blue-pink",
988         "salty", "sweet", "sour", "bitter",
989         "striped", "spiral", "swirly", "plaid", "checkered", "argyle",
990         "paisley", "blotchy", "guernsey-spotted", "polka-dotted",
991         "square", "round", "triangular",
992         "cabernet", "sangria", "fuchsia", "wisteria",
993         "lemon-lime", "strawberry-banana", "peppermint",
994         "romantic", "incandescent"
995 };
996
997 const char *
998 hcolor(colorpref)
999 const char *colorpref;
1000 {
1001         return (Hallucination || !colorpref) ?
1002                 hcolors[rn2(SIZE(hcolors))] : colorpref;
1003 }
1004
1005 /* return a random real color unless hallucinating */
1006 const char *
1007 rndcolor()
1008 {
1009         int k = rn2(CLR_MAX);
1010         return Hallucination ? hcolor((char *)0) : (k == NO_COLOR) ?
1011                 "colorless" : c_obj_colors[k];
1012 }
1013
1014 /* Aliases for road-runner nemesis
1015  */
1016 static const char * const coynames[] = {
1017         "Carnivorous Vulgaris","Road-Runnerus Digestus",
1018         "Eatibus Anythingus"  ,"Famishus-Famishus",
1019         "Eatibus Almost Anythingus","Eatius Birdius",
1020         "Famishius Fantasticus","Eternalii Famishiis",
1021         "Famishus Vulgarus","Famishius Vulgaris Ingeniusi",
1022         "Eatius-Slobbius","Hardheadipus Oedipus",
1023         "Carnivorous Slobbius","Hard-Headipus Ravenus",
1024         "Evereadii Eatibus","Apetitius Giganticus",
1025         "Hungrii Flea-Bagius","Overconfidentii Vulgaris",
1026         "Caninus Nervous Rex","Grotesques Appetitus",
1027         "Nemesis Riduclii","Canis latrans"
1028 };
1029         
1030 char *
1031 coyotename(mtmp, buf)
1032 struct monst *mtmp;
1033 char *buf;
1034 {
1035     if (mtmp && buf) {
1036         Sprintf(buf, "%s - %s",
1037             x_monnam(mtmp, ARTICLE_NONE, (char *)0, 0, TRUE),
1038             mtmp->mcan ? coynames[SIZE(coynames)-1] : coynames[rn2(SIZE(coynames)-1)]);
1039     }
1040     return buf;
1041 }
1042 #endif /* OVL2 */
1043
1044 /*do_name.c*/