use of #terrain while underwater
[aNetHack.git] / src / do_name.c
blob1570e41bfb4df6e541dd482e3879d4dd2b928d89
1 /* NetHack 3.6 do_name.c $NHDT-Date: 1452669022 2016/01/13 07:10:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
7 STATIC_DCL char *NDECL(nextmbuf);
8 STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *));
9 STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *,
10 const void *));
11 STATIC_DCL void FDECL(gather_locs, (coord **, int *, BOOLEAN_P));
12 STATIC_DCL void FDECL(auto_describe, (int, int));
13 STATIC_DCL void NDECL(do_mname);
14 STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *));
15 STATIC_DCL void FDECL(do_oname, (struct obj *));
16 STATIC_DCL void NDECL(namefloorobj);
17 STATIC_DCL char *FDECL(bogusmon, (char *,char *));
19 extern const char what_is_an_unknown_object[]; /* from pager.c */
21 #define NUMMBUF 5
23 /* manage a pool of BUFSZ buffers, so callers don't have to */
24 STATIC_OVL char *
25 nextmbuf()
27 static char NEARDATA bufs[NUMMBUF][BUFSZ];
28 static int bufidx = 0;
30 bufidx = (bufidx + 1) % NUMMBUF;
31 return bufs[bufidx];
34 /* function for getpos() to highlight desired map locations.
35 * parameter value 0 = initialize, 1 = highlight, 2 = done
37 static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0;
39 void
40 getpos_sethilite(f)
41 void FDECL((*f), (int));
43 getpos_hilitefunc = f;
46 /* the response for '?' help request in getpos() */
47 STATIC_OVL void
48 getpos_help(force, goal)
49 boolean force;
50 const char *goal;
52 char sbuf[BUFSZ];
53 boolean doing_what_is;
54 winid tmpwin = create_nhwindow(NHW_MENU);
56 Sprintf(sbuf, "Use [%c%c%c%c] to move the cursor to %s.", /* hjkl */
57 Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
58 putstr(tmpwin, 0, sbuf);
59 putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
60 putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
61 putstr(tmpwin, 0, "Use @ to move the cursor on yourself.");
62 if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)
63 putstr(tmpwin, 0, "Use m or M to move the cursor to next monster.");
64 if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0)
65 putstr(tmpwin, 0, "Use o or O to move the cursor to next object.");
66 if (!iflags.terrainmode) {
67 if (getpos_hilitefunc)
68 putstr(tmpwin, 0, "Use $ to display valid locations.");
69 putstr(tmpwin, 0, "Use # to toggle automatic description.");
70 if (iflags.cmdassist) /* assisting the '/' command, I suppose... */
71 putstr(tmpwin, 0,
72 (iflags.getpos_coords == GPCOORDS_NONE)
73 ? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
74 : "(Reset 'whatis_coord' option to omit coordinates from '#' text.)");
75 /* disgusting hack; the alternate selection characters work for any
76 getpos call, but only matter for dowhatis (and doquickwhatis) */
77 doing_what_is = (goal == what_is_an_unknown_object);
78 Sprintf(sbuf, "Type a .%s when you are at the right place.",
79 doing_what_is ? " or , or ; or :" : "");
80 putstr(tmpwin, 0, sbuf);
81 if (doing_what_is) {
82 putstr(tmpwin, 0,
83 " : describe current spot, show 'more info', move to another spot.");
84 Sprintf(sbuf,
85 " . describe current spot,%s move to another spot;",
86 flags.help ? " prompt if 'more info'," : "");
87 putstr(tmpwin, 0, sbuf);
88 putstr(tmpwin, 0,
89 " , describe current spot, move to another spot;");
90 putstr(tmpwin, 0,
91 " ; describe current spot, stop looking at things;");
94 if (!force)
95 putstr(tmpwin, 0, "Type Space or Escape when you're done.");
96 putstr(tmpwin, 0, "");
97 display_nhwindow(tmpwin, TRUE);
98 destroy_nhwindow(tmpwin);
101 STATIC_OVL int
102 cmp_coord_distu(a, b)
103 const void *a;
104 const void *b;
106 const coord *c1 = a;
107 const coord *c2 = b;
108 int dx, dy, dist_1, dist_2;
110 dx = u.ux - c1->x;
111 dy = u.uy - c1->y;
112 dist_1 = max(abs(dx), abs(dy));
113 dx = u.ux - c2->x;
114 dy = u.uy - c2->y;
115 dist_2 = max(abs(dx), abs(dy));
117 if (dist_1 == dist_2)
118 return (c1->y != c2->y) ? (c1->y - c2->y) : (c1->x - c2->x);
120 return dist_1 - dist_2;
123 /* gather locations for monsters or objects shown on the map */
124 STATIC_OVL void
125 gather_locs(arr_p, cnt_p, do_mons)
126 coord **arr_p;
127 int *cnt_p;
128 boolean do_mons;
130 int x, y, pass, glyph, idx,
131 tail = (do_mons ? monnum_to_glyph(PM_LONG_WORM_TAIL) : 0),
132 boulder = (!do_mons ? objnum_to_glyph(BOULDER) : 0),
133 rock = (!do_mons ? objnum_to_glyph(ROCK) : 0);
136 * We always include the hero's location even if there is no monster
137 * (invisible hero without see invisible) or object (usual case)
138 * displayed there. That way, the count will always be at least 1,
139 * and player has a visual indicator (cursor returns to hero's spot)
140 * highlighting when successive 'm's or 'o's have cycled all the way
141 * through all monsters or objects.
143 * Hero's spot will always sort to array[0] because it will always
144 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
146 *cnt_p = idx = 0;
147 for (pass = 0; pass < 2; pass++) {
148 for (x = 1; x < COLNO; x++)
149 for (y = 0; y < ROWNO; y++) {
150 /* TODO: if glyph is a pile glyph, convert to ordinary one
151 * in order to keep tail/boulder/rock check simple.
153 glyph = glyph_at(x, y);
154 /* unlike '/M', this skips monsters revealed by
155 warning glyphs and remembered invisible ones */
156 if ((x == u.ux && y == u.uy)
157 || (do_mons ? (glyph_is_monster(glyph) && glyph != tail)
158 : (glyph_is_object(glyph)
159 && glyph != boulder && glyph != rock))) {
160 if (!pass) {
161 ++*cnt_p;
162 } else {
163 (*arr_p)[idx].x = x;
164 (*arr_p)[idx].y = y;
165 ++idx;
170 if (!pass) /* end of first pass */
171 *arr_p = (coord *) alloc(*cnt_p * sizeof (coord));
172 else /* end of second pass */
173 qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu);
174 } /* pass */
177 char *
178 dxdy_to_dist_descr(dx, dy)
179 int dx, dy;
181 /* [12] suffices, but guard against long translation for direction-name */
182 static char buf[20];
183 int dst;
185 if (!dx && !dy) {
186 Sprintf(buf, "here");
187 } else if ((dst = xytod(dx, dy)) != -1) {
188 /* explicit direction; 'one step' is implicit */
189 Sprintf(buf, "%s", directionname(dst));
190 } else {
191 buf[0] = '\0';
192 /* 9999: protect buf[] against overflow caused by invalid values */
193 if (dy) {
194 if (abs(dy) > 9999)
195 dy = sgn(dy) * 9999;
196 Sprintf(eos(buf), "%d%c%s", abs(dy), (dy > 0) ? 's' : 'n',
197 dx ? "," : "");
199 if (dx) {
200 if (abs(dx) > 9999)
201 dx = sgn(dx) * 9999;
202 Sprintf(eos(buf), "%d%c", abs(dx), (dx > 0) ? 'e' : 'w');
205 return buf;
208 /* coordinate formatting for 'whatis_coord' option */
209 char *
210 coord_desc(x, y, outbuf, cmode)
211 int x, y;
212 char *outbuf, cmode;
214 static char screen_fmt[16]; /* [12] suffices: "[%02d,%02d]" */
215 int dx, dy;
217 outbuf[0] = '\0';
218 switch (cmode) {
219 default:
220 break;
221 case GPCOORDS_COMPASS:
222 /* "east", "3s", "2n,4w" */
223 dx = x - u.ux;
224 dy = y - u.uy;
225 Sprintf(outbuf, "(%s)", dxdy_to_dist_descr(dx, dy));
226 break;
227 case GPCOORDS_MAP: /* x,y */
228 /* upper left corner of map is <1,0>;
229 with default COLNO,ROWNO lower right corner is <79,20> */
230 Sprintf(outbuf, "<%d,%d>", x, y);
231 break;
232 case GPCOORDS_SCREEN: /* y+2,x */
233 /* for normal map sizes, force a fixed-width formatting so that
234 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
235 than Nx999 or 999xM will still work, but not line up like normal
236 when displayed in a column setting */
237 if (!*screen_fmt)
238 Sprintf(screen_fmt, "[%%%sd,%%%sd]",
239 (ROWNO - 1 + 2 < 100) ? "02" : "03",
240 (COLNO - 1 < 100) ? "02" : "03");
241 /* map line 0 is screen row 2;
242 map column 0 isn't used, map column 1 is screen column 1 */
243 Sprintf(outbuf, screen_fmt, y + 2, x);
244 break;
246 return outbuf;
249 STATIC_OVL void
250 auto_describe(cx, cy)
251 int cx, cy;
253 coord cc;
254 int sym = 0;
255 char tmpbuf[BUFSZ];
256 const char *firstmatch = "unknown";
258 cc.x = cx;
259 cc.y = cy;
260 if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) {
261 (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords);
262 pline("%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf);
263 curs(WIN_MAP, cx, cy);
264 flush_screen(0);
269 getpos(ccp, force, goal)
270 coord *ccp;
271 boolean force;
272 const char *goal;
274 int result = 0;
275 int cx, cy, i, c;
276 int sidx, tx, ty;
277 boolean msg_given = TRUE; /* clear message window by default */
278 boolean show_goal_msg = FALSE;
279 static const char pick_chars[] = ".,;:";
280 const char *cp;
281 boolean hilite_state = FALSE;
282 coord *monarr = (coord *) 0, *objarr = (coord *) 0;
283 int moncount = 0, monidx = 0, objcount = 0, objidx = 0;
285 if (!goal)
286 goal = "desired location";
287 if (flags.verbose) {
288 pline("(For instructions type a ?)");
289 msg_given = TRUE;
291 cx = ccp->x;
292 cy = ccp->y;
293 #ifdef CLIPPING
294 cliparound(cx, cy);
295 #endif
296 curs(WIN_MAP, cx, cy);
297 flush_screen(0);
298 #ifdef MAC
299 lock_mouse_cursor(TRUE);
300 #endif
301 for (;;) {
302 if (show_goal_msg) {
303 pline("Move cursor to %s:", goal);
304 curs(WIN_MAP, cx, cy);
305 flush_screen(0);
306 show_goal_msg = FALSE;
307 } else if (iflags.autodescribe && !msg_given && !hilite_state) {
308 auto_describe(cx, cy);
311 c = nh_poskey(&tx, &ty, &sidx);
313 if (hilite_state) {
314 (*getpos_hilitefunc)(2);
315 hilite_state = FALSE;
316 curs(WIN_MAP, cx, cy);
317 flush_screen(0);
320 if (iflags.autodescribe)
321 msg_given = FALSE;
323 if (c == '\033') {
324 cx = cy = -10;
325 msg_given = TRUE; /* force clear */
326 result = -1;
327 break;
329 if (c == 0) {
330 if (!isok(tx, ty))
331 continue;
332 /* a mouse click event, just assign and return */
333 cx = tx;
334 cy = ty;
335 break;
337 if ((cp = index(pick_chars, c)) != 0) {
338 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
339 result = (int) (cp - pick_chars);
340 break;
342 for (i = 0; i < 8; i++) {
343 int dx, dy;
345 if (Cmd.dirchars[i] == c) {
346 /* a normal movement letter or digit */
347 dx = xdir[i];
348 dy = ydir[i];
349 } else if (Cmd.alphadirchars[i] == lowc((char) c)
350 || (Cmd.num_pad && Cmd.dirchars[i] == (c & 0177))) {
351 /* a shifted movement letter or Meta-digit */
352 dx = 8 * xdir[i];
353 dy = 8 * ydir[i];
354 } else
355 continue;
357 /* truncate at map edge; diagonal moves complicate this... */
358 if (cx + dx < 1) {
359 dy -= sgn(dy) * (1 - (cx + dx));
360 dx = 1 - cx; /* so that (cx+dx == 1) */
361 } else if (cx + dx > COLNO - 1) {
362 dy += sgn(dy) * ((COLNO - 1) - (cx + dx));
363 dx = (COLNO - 1) - cx;
365 if (cy + dy < 0) {
366 dx -= sgn(dx) * (0 - (cy + dy));
367 dy = 0 - cy; /* so that (cy+dy == 0) */
368 } else if (cy + dy > ROWNO - 1) {
369 dx += sgn(dx) * ((ROWNO - 1) - (cy + dy));
370 dy = (ROWNO - 1) - cy;
372 cx += dx;
373 cy += dy;
374 goto nxtc;
377 if (c == '?' || redraw_cmd(c)) {
378 if (c == '?')
379 getpos_help(force, goal);
380 else /* ^R */
381 docrt(); /* redraw */
382 /* update message window to reflect that we're still targetting */
383 show_goal_msg = TRUE;
384 msg_given = TRUE;
385 } else if (c == '$' && getpos_hilitefunc) {
386 if (!hilite_state) {
387 (*getpos_hilitefunc)(0);
388 (*getpos_hilitefunc)(1);
389 hilite_state = TRUE;
391 goto nxtc;
392 } else if (c == '#') {
393 iflags.autodescribe = !iflags.autodescribe;
394 pline("Automatic description %sis %s.",
395 flags.verbose ? "of features under cursor " : "",
396 iflags.autodescribe ? "on" : "off");
397 if (!iflags.autodescribe)
398 show_goal_msg = TRUE;
399 msg_given = TRUE;
400 goto nxtc;
401 } else if (c == '@') { /* return to hero's spot */
402 /* reset 'm','M' and 'o','O'; otherwise, there's no way for player
403 to achieve that except by manually cycling through all spots */
404 monidx = objidx = 0;
405 cx = u.ux;
406 cy = u.uy;
407 goto nxtc;
408 } else if (c == 'm' || c == 'M') { /* nearest or farthest monster */
409 if (!monarr) {
410 gather_locs(&monarr, &moncount, TRUE);
411 monidx = 0; /* monarr[0] is hero's spot */
413 if (c == 'm') {
414 monidx = (monidx + 1) % moncount;
415 } else {
416 if (--monidx < 0)
417 monidx = moncount - 1;
419 cx = monarr[monidx].x;
420 cy = monarr[monidx].y;
421 goto nxtc;
422 } else if (c == 'o' || c == 'O') { /* nearest or farthest object */
423 if (!objarr) {
424 gather_locs(&objarr, &objcount, FALSE);
425 objidx = 0; /* objarr[0] is hero's spot */
427 if (c == 'o') {
428 objidx = (objidx + 1) % objcount;
429 } else {
430 if (--objidx < 0)
431 objidx = objcount - 1;
433 cx = objarr[objidx].x;
434 cy = objarr[objidx].y;
435 goto nxtc;
436 } else {
437 if (!index(quitchars, c)) {
438 char matching[MAXPCHARS];
439 int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
441 (void) memset((genericptr_t) matching, 0, sizeof matching);
442 for (sidx = 1; sidx < MAXPCHARS; sidx++)
443 if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
444 matching[sidx] = (char) ++k;
445 if (k) {
446 for (pass = 0; pass <= 1; pass++) {
447 /* pass 0: just past current pos to lower right;
448 pass 1: upper left corner to current pos */
449 lo_y = (pass == 0) ? cy : 0;
450 hi_y = (pass == 0) ? ROWNO - 1 : cy;
451 for (ty = lo_y; ty <= hi_y; ty++) {
452 lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
453 hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
454 for (tx = lo_x; tx <= hi_x; tx++) {
455 /* look at dungeon feature, not at
456 user-visible glyph */
457 k = back_to_glyph(tx, ty);
458 /* uninteresting background glyph */
459 if (glyph_is_cmap(k)
460 && (IS_DOOR(levl[tx][ty].typ)
461 || glyph_to_cmap(k) == S_room
462 || glyph_to_cmap(k) == S_darkroom
463 || glyph_to_cmap(k) == S_corr
464 || glyph_to_cmap(k) == S_litcorr)) {
465 /* what hero remembers to be at tx,ty */
466 k = glyph_at(tx, ty);
468 if (glyph_is_cmap(k)
469 && matching[glyph_to_cmap(k)]
470 && (levl[tx][ty].seenv
471 || iflags.terrainmode)
472 && !IS_WALL(levl[tx][ty].typ)
473 && levl[tx][ty].typ != SDOOR
474 && glyph_to_cmap(k) != S_room
475 && glyph_to_cmap(k) != S_corr
476 && glyph_to_cmap(k) != S_litcorr) {
477 cx = tx, cy = ty;
478 if (msg_given) {
479 clear_nhwindow(WIN_MESSAGE);
480 msg_given = FALSE;
482 goto nxtc;
484 } /* column */
485 } /* row */
486 } /* pass */
487 pline("Can't find dungeon feature '%c'.", c);
488 msg_given = TRUE;
489 goto nxtc;
490 } else {
491 char note[QBUFSZ];
493 if (!force)
494 Strcpy(note, "aborted");
495 else
496 Sprintf(note, "use %c%c%c%c or .", /* hjkl */
497 Cmd.move_W, Cmd.move_S, Cmd.move_N,
498 Cmd.move_E);
499 pline("Unknown direction: '%s' (%s).", visctrl((char) c),
500 note);
501 msg_given = TRUE;
502 } /* k => matching */
503 } /* !quitchars */
504 if (force)
505 goto nxtc;
506 if (!iflags.terrainmode) {
507 pline("Done.");
508 msg_given = FALSE; /* suppress clear */
510 cx = -1;
511 cy = 0;
512 result = 0; /* not -1 */
513 break;
515 nxtc:
517 #ifdef CLIPPING
518 cliparound(cx, cy);
519 #endif
520 curs(WIN_MAP, cx, cy);
521 flush_screen(0);
523 #ifdef MAC
524 lock_mouse_cursor(FALSE);
525 #endif
526 if (msg_given)
527 clear_nhwindow(WIN_MESSAGE);
528 ccp->x = cx;
529 ccp->y = cy;
530 if (monarr)
531 free((genericptr_t) monarr);
532 if (objarr)
533 free((genericptr_t) objarr);
534 getpos_hilitefunc = (void FDECL((*), (int))) 0;
535 return result;
538 /* allocate space for a monster's name; removes old name if there is one */
539 void
540 new_mname(mon, lth)
541 struct monst *mon;
542 int lth; /* desired length (caller handles adding 1 for terminator) */
544 if (lth) {
545 /* allocate mextra if necessary; otherwise get rid of old name */
546 if (!mon->mextra)
547 mon->mextra = newmextra();
548 else
549 free_mname(mon); /* already has mextra, might also have name */
550 MNAME(mon) = (char *) alloc((unsigned) lth);
551 } else {
552 /* zero length: the new name is empty; get rid of the old name */
553 if (has_mname(mon))
554 free_mname(mon);
558 /* release a monster's name; retains mextra even if all fields are now null */
559 void
560 free_mname(mon)
561 struct monst *mon;
563 if (has_mname(mon)) {
564 free((genericptr_t) MNAME(mon));
565 MNAME(mon) = (char *) 0;
569 /* allocate space for an object's name; removes old name if there is one */
570 void
571 new_oname(obj, lth)
572 struct obj *obj;
573 int lth; /* desired length (caller handles adding 1 for terminator) */
575 if (lth) {
576 /* allocate oextra if necessary; otherwise get rid of old name */
577 if (!obj->oextra)
578 obj->oextra = newoextra();
579 else
580 free_oname(obj); /* already has oextra, might also have name */
581 ONAME(obj) = (char *) alloc((unsigned) lth);
582 } else {
583 /* zero length: the new name is empty; get rid of the old name */
584 if (has_oname(obj))
585 free_oname(obj);
589 /* release an object's name; retains oextra even if all fields are now null */
590 void
591 free_oname(obj)
592 struct obj *obj;
594 if (has_oname(obj)) {
595 free((genericptr_t) ONAME(obj));
596 ONAME(obj) = (char *) 0;
600 /* safe_oname() always returns a valid pointer to
601 * a string, either the pointer to an object's name
602 * if it has one, or a pointer to an empty string
603 * if it doesn't.
605 const char *
606 safe_oname(obj)
607 struct obj *obj;
609 if (has_oname(obj))
610 return ONAME(obj);
611 return "";
614 /* historical note: this returns a monster pointer because it used to
615 allocate a new bigger block of memory to hold the monster and its name */
616 struct monst *
617 christen_monst(mtmp, name)
618 struct monst *mtmp;
619 const char *name;
621 int lth;
622 char buf[PL_PSIZ];
624 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
625 lth = (name && *name) ? ((int) strlen(name) + 1) : 0;
626 if (lth > PL_PSIZ) {
627 lth = PL_PSIZ;
628 name = strncpy(buf, name, PL_PSIZ - 1);
629 buf[PL_PSIZ - 1] = '\0';
631 new_mname(mtmp, lth); /* removes old name if one is present */
632 if (lth)
633 Strcpy(MNAME(mtmp), name);
634 return mtmp;
637 /* check whether user-supplied name matches or nearly matches an unnameable
638 monster's name; if so, give an alternate reject message for do_mname() */
639 STATIC_OVL boolean
640 alreadynamed(mtmp, monnambuf, usrbuf)
641 struct monst *mtmp;
642 char *monnambuf, *usrbuf;
644 char pronounbuf[10], *p;
646 if (fuzzymatch(usrbuf, monnambuf, " -_", TRUE)
647 /* catch trying to name "the Oracle" as "Oracle" */
648 || (!strncmpi(monnambuf, "the ", 4)
649 && fuzzymatch(usrbuf, monnambuf + 4, " -_", TRUE))
650 /* catch trying to name "invisible Orcus" as "Orcus" */
651 || ((p = strstri(monnambuf, "invisible ")) != 0
652 && fuzzymatch(usrbuf, p + 10, " -_", TRUE))
653 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
654 || ((p = strstri(monnambuf, " of ")) != 0
655 && fuzzymatch(usrbuf, p + 4, " -_", TRUE))) {
656 pline("%s is already called %s.",
657 upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
658 return TRUE;
659 } else if (mtmp->data == &mons[PM_JUIBLEX]
660 && strstri(monnambuf, "Juiblex")
661 && !strcmpi(usrbuf, "Jubilex")) {
662 pline("%s doesn't like being called %s.", upstart(monnambuf), usrbuf);
663 return TRUE;
665 return FALSE;
668 /* allow player to assign a name to some chosen monster */
669 STATIC_OVL void
670 do_mname()
672 char buf[BUFSZ], monnambuf[BUFSZ], qbuf[QBUFSZ];
673 coord cc;
674 int cx, cy;
675 struct monst *mtmp = 0;
677 if (Hallucination) {
678 You("would never recognize it anyway.");
679 return;
681 cc.x = u.ux;
682 cc.y = u.uy;
683 if (getpos(&cc, FALSE, "the monster you want to name") < 0
684 || (cx = cc.x) < 0)
685 return;
686 cy = cc.y;
688 if (cx == u.ux && cy == u.uy) {
689 if (u.usteed && canspotmon(u.usteed)) {
690 mtmp = u.usteed;
691 } else {
692 pline("This %s creature is called %s and cannot be renamed.",
693 beautiful(), plname);
694 return;
696 } else
697 mtmp = m_at(cx, cy);
699 if (!mtmp
700 || (!sensemon(mtmp)
701 && (!(cansee(cx, cy) || see_with_infrared(mtmp))
702 || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE
703 || mtmp->m_ap_type == M_AP_OBJECT
704 || (mtmp->minvis && !See_invisible)))) {
705 pline("I see no monster there.");
706 return;
708 /* special case similar to the one in lookat() */
709 Sprintf(qbuf, "What do you want to call %s?",
710 distant_monnam(mtmp, ARTICLE_THE, monnambuf));
711 getlin(qbuf, buf);
712 if (!*buf || *buf == '\033')
713 return;
714 /* strip leading and trailing spaces; unnames monster if all spaces */
715 (void) mungspaces(buf);
717 /* Unique monsters have their own specific names or titles.
718 * Shopkeepers, temple priests and other minions use alternate
719 * name formatting routines which ignore any user-supplied name.
721 * Don't say the name is being rejected if it happens to match
722 * the existing name.
724 if ((mtmp->data->geno & G_UNIQ) && !mtmp->ispriest) {
725 if (!alreadynamed(mtmp, monnambuf, buf))
726 pline("%s doesn't like being called names!", upstart(monnambuf));
727 } else if (mtmp->isshk
728 && !(Deaf || mtmp->msleeping || !mtmp->mcanmove
729 || mtmp->data->msound <= MS_ANIMAL)) {
730 if (!alreadynamed(mtmp, monnambuf, buf))
731 verbalize("I'm %s, not %s.", shkname(mtmp), buf);
732 } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) {
733 if (!alreadynamed(mtmp, monnambuf, buf))
734 pline("%s will not accept the name %s.", upstart(monnambuf), buf);
735 } else
736 (void) christen_monst(mtmp, buf);
740 * This routine changes the address of obj. Be careful not to call it
741 * when there might be pointers around in unknown places. For now: only
742 * when obj is in the inventory.
744 STATIC_OVL
745 void
746 do_oname(obj)
747 register struct obj *obj;
749 char *bufp, buf[BUFSZ], bufcpy[BUFSZ], qbuf[QBUFSZ];
750 const char *aname;
751 short objtyp;
753 /* Do this now because there's no point in even asking for a name */
754 if (obj->otyp == SPE_NOVEL) {
755 pline("%s already has a published name.", Ysimple_name2(obj));
756 return;
759 Sprintf(qbuf, "What do you want to name %s ",
760 is_plural(obj) ? "these" : "this");
761 (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item");
762 getlin(qbuf, buf);
763 if (!*buf || *buf == '\033')
764 return;
765 /* strip leading and trailing spaces; unnames item if all spaces */
766 (void) mungspaces(buf);
769 * We don't violate illiteracy conduct here, although it is
770 * arguable that we should for anything other than "X". Doing so
771 * would make attaching player's notes to hero's inventory have an
772 * in-game effect, which may or may not be the correct thing to do.
774 * We do violate illiteracy in oname() if player creates Sting or
775 * Orcrist, clearly being literate (no pun intended...).
778 /* relax restrictions over proper capitalization for artifacts */
779 if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
780 Strcpy(buf, aname);
782 if (obj->oartifact) {
783 pline_The("artifact seems to resist the attempt.");
784 return;
785 } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
786 /* this used to change one letter, substituting a value
787 of 'a' through 'y' (due to an off by one error, 'z'
788 would never be selected) and then force that to
789 upper case if such was the case of the input;
790 now, the hand slip scuffs one or two letters as if
791 the text had been trodden upon, sometimes picking
792 punctuation instead of an arbitrary letter;
793 unfortunately, we have to cover the possibility of
794 it targetting spaces so failing to make any change
795 (we know that it must eventually target a nonspace
796 because buf[] matches a valid artifact name) */
797 Strcpy(bufcpy, buf);
798 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
799 bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf;
800 do {
801 wipeout_text(bufp, rnd(2), (unsigned) 0);
802 } while (!strcmp(buf, bufcpy));
803 pline("While engraving, your %s slips.", body_part(HAND));
804 display_nhwindow(WIN_MESSAGE, FALSE);
805 You("engrave: \"%s\".", buf);
807 obj = oname(obj, buf);
810 struct obj *
811 oname(obj, name)
812 struct obj *obj;
813 const char *name;
815 int lth;
816 char buf[PL_PSIZ];
818 lth = *name ? (int) (strlen(name) + 1) : 0;
819 if (lth > PL_PSIZ) {
820 lth = PL_PSIZ;
821 name = strncpy(buf, name, PL_PSIZ - 1);
822 buf[PL_PSIZ - 1] = '\0';
824 /* If named artifact exists in the game, do not create another.
825 * Also trying to create an artifact shouldn't de-artifact
826 * it (e.g. Excalibur from prayer). In this case the object
827 * will retain its current name. */
828 if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
829 return obj;
831 new_oname(obj, lth); /* removes old name if one is present */
832 if (lth)
833 Strcpy(ONAME(obj), name);
835 if (lth)
836 artifact_exists(obj, name, TRUE);
837 if (obj->oartifact) {
838 /* can't dual-wield with artifact as secondary weapon */
839 if (obj == uswapwep)
840 untwoweapon();
841 /* activate warning if you've just named your weapon "Sting" */
842 if (obj == uwep)
843 set_artifact_intrinsic(obj, TRUE, W_WEP);
844 /* if obj is owned by a shop, increase your bill */
845 if (obj->unpaid)
846 alter_cost(obj, 0L);
847 /* violate illiteracy conduct since successfully wrote arti-name */
848 u.uconduct.literate++;
850 if (carried(obj))
851 update_inventory();
852 return obj;
855 static NEARDATA const char callable[] = {
856 SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
857 GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0
860 boolean
861 objtyp_is_callable(i)
862 int i;
864 return (boolean) (objects[i].oc_uname
865 || (OBJ_DESCR(objects[i])
866 && index(callable, objects[i].oc_class)));
869 /* C and #name commands - player can name monster or object or type of obj */
871 docallcmd()
873 struct obj *obj;
874 winid win;
875 anything any;
876 menu_item *pick_list = 0;
877 char ch, allowall[2];
878 /* if player wants a,b,c instead of i,o when looting, do that here too */
879 boolean abc = flags.lootabc;
881 win = create_nhwindow(NHW_MENU);
882 start_menu(win);
883 any = zeroany;
884 any.a_char = 'm'; /* group accelerator 'C' */
885 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'C', ATR_NONE,
886 "a monster", MENU_UNSELECTED);
887 if (invent) {
888 /* we use y and n as accelerators so that we can accept user's
889 response keyed to old "name an individual object?" prompt */
890 any.a_char = 'i'; /* group accelerator 'y' */
891 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'y', ATR_NONE,
892 "a particular object in inventory", MENU_UNSELECTED);
893 any.a_char = 'o'; /* group accelerator 'n' */
894 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'n', ATR_NONE,
895 "the type of an object in inventory", MENU_UNSELECTED);
897 any.a_char = 'f'; /* group accelerator ',' (or ':' instead?) */
898 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, ',', ATR_NONE,
899 "the type of an object upon the floor", MENU_UNSELECTED);
900 any.a_char = 'd'; /* group accelerator '\' */
901 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, '\\', ATR_NONE,
902 "the type of an object on discoveries list", MENU_UNSELECTED);
903 any.a_char = 'a'; /* group accelerator 'l' */
904 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'l', ATR_NONE,
905 "record an annotation for the current level", MENU_UNSELECTED);
906 end_menu(win, "What do you want to name?");
907 if (select_menu(win, PICK_ONE, &pick_list) > 0) {
908 ch = pick_list[0].item.a_char;
909 free((genericptr_t) pick_list);
910 } else
911 ch = 'q';
912 destroy_nhwindow(win);
914 switch (ch) {
915 default:
916 case 'q':
917 break;
918 case 'm': /* name a visible monster */
919 do_mname();
920 break;
921 case 'i': /* name an individual object in inventory */
922 allowall[0] = ALL_CLASSES;
923 allowall[1] = '\0';
924 obj = getobj(allowall, "name");
925 if (obj)
926 do_oname(obj);
927 break;
928 case 'o': /* name a type of object in inventory */
929 obj = getobj(callable, "call");
930 if (obj) {
931 /* behave as if examining it in inventory;
932 this might set dknown if it was picked up
933 while blind and the hero can now see */
934 (void) xname(obj);
936 if (!obj->dknown) {
937 You("would never recognize another one.");
938 #if 0
939 } else if (!objtyp_is_callable(obj->otyp)) {
940 You("know those as well as you ever will.");
941 #endif
942 } else {
943 docall(obj);
946 break;
947 case 'f': /* name a type of object visible on the floor */
948 namefloorobj();
949 break;
950 case 'd': /* name a type of object on the discoveries list */
951 rename_disco();
952 break;
953 case 'a': /* annotate level */
954 donamelevel();
955 break;
957 return 0;
960 void
961 docall(obj)
962 register struct obj *obj;
964 char buf[BUFSZ], qbuf[QBUFSZ];
965 struct obj otemp;
966 register char **str1;
968 if (!obj->dknown)
969 return; /* probably blind */
970 otemp = *obj;
971 otemp.quan = 1L;
972 otemp.oextra = (struct oextra *) 0;
974 if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink)
975 /* kludge, meaning it's sink water */
976 Sprintf(qbuf, "Call a stream of %s fluid:",
977 OBJ_DESCR(objects[otemp.otyp]));
978 else
979 Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
980 getlin(qbuf, buf);
981 if (!*buf || *buf == '\033')
982 return;
984 /* clear old name */
985 str1 = &(objects[obj->otyp].oc_uname);
986 if (*str1)
987 free((genericptr_t) *str1);
989 /* strip leading and trailing spaces; uncalls item if all spaces */
990 (void) mungspaces(buf);
991 if (!*buf) {
992 if (*str1) { /* had name, so possibly remove from disco[] */
993 /* strip name first, for the update_inventory() call
994 from undiscover_object() */
995 *str1 = (char *) 0;
996 undiscover_object(obj->otyp);
998 } else {
999 *str1 = dupstr(buf);
1000 discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
1004 STATIC_OVL void
1005 namefloorobj()
1007 coord cc;
1008 int glyph;
1009 char buf[BUFSZ];
1010 struct obj *obj = 0;
1011 boolean fakeobj = FALSE, use_plural;
1013 cc.x = u.ux, cc.y = u.uy;
1014 /* "dot for under/over you" only makes sense when the cursor hasn't
1015 been moved off the hero's '@' yet, but there's no way to adjust
1016 the help text once getpos() has started */
1017 Sprintf(buf, "object on map (or '.' for one %s you)",
1018 (u.uundetected && hides_under(youmonst.data)) ? "over" : "under");
1019 if (getpos(&cc, FALSE, buf) < 0 || cc.x <= 0)
1020 return;
1021 if (cc.x == u.ux && cc.y == u.uy) {
1022 obj = vobj_at(u.ux, u.uy);
1023 } else {
1024 glyph = glyph_at(cc.x, cc.y);
1025 if (glyph_is_object(glyph))
1026 fakeobj = object_from_map(glyph, cc.x, cc.y, &obj);
1027 /* else 'obj' stays null */
1029 if (!obj) {
1030 /* "under you" is safe here since there's no object to hide under */
1031 pline("There doesn't seem to be any object %s.",
1032 (cc.x == u.ux && cc.y == u.uy) ? "under you" : "there");
1033 return;
1035 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1036 is a mimic; passing that to xname (directly or via simpleonames)
1037 would yield "glorkum" so we need to handle it explicitly; it will
1038 always fail the Hallucination test and pass the !callable test,
1039 resulting in the "can't be assigned a type name" message */
1040 Strcpy(buf, (obj->otyp != STRANGE_OBJECT)
1041 ? simpleonames(obj)
1042 : obj_descr[STRANGE_OBJECT].oc_name);
1043 use_plural = (obj->quan > 1L);
1044 if (Hallucination) {
1045 const char *unames[6];
1046 char tmpbuf[BUFSZ];
1048 /* straight role name */
1049 unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
1050 ? urole.name.f
1051 : urole.name.m;
1052 /* random rank title for hero's role */
1053 unames[1] = rank_of(rnd(30), Role_switch, flags.female);
1054 /* random fake monster */
1055 unames[2] = bogusmon(tmpbuf, (char *) 0);
1056 /* increased chance for fake monster */
1057 unames[3] = unames[2];
1058 /* traditional */
1059 unames[4] = roguename();
1060 /* silly */
1061 unames[5] = "Wibbly Wobbly";
1062 pline("%s %s to call you \"%s.\"",
1063 The(buf), use_plural ? "decide" : "decides",
1064 unames[rn2(SIZE(unames))]);
1065 } else if (!objtyp_is_callable(obj->otyp)) {
1066 pline("%s %s can't be assigned a type name.",
1067 use_plural ? "Those" : "That", buf);
1068 } else if (!obj->dknown) {
1069 You("don't know %s %s well enough to name %s.",
1070 use_plural ? "those" : "that", buf, use_plural ? "them" : "it");
1071 } else {
1072 docall(obj);
1074 if (fakeobj)
1075 dealloc_obj(obj);
1078 static const char *const ghostnames[] = {
1079 /* these names should have length < PL_NSIZ */
1080 /* Capitalize the names for aesthetics -dgk */
1081 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1082 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1083 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1084 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1085 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1086 "Stephan", "Lance Braccus", "Shadowhawk"
1089 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1090 const char *
1091 rndghostname()
1093 return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *) plname;
1097 * Monster naming functions:
1098 * x_monnam is the generic monster-naming function.
1099 * seen unseen detected named
1100 * mon_nam: the newt it the invisible orc Fido
1101 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1102 * l_monnam: newt it invisible orc dog called Fido
1103 * Monnam: The newt It The invisible orc Fido
1104 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1105 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1106 * Amonnam: A newt It An invisible orc Fido
1107 * a_monnam: a newt it an invisible orc Fido
1108 * m_monnam: newt xan orc Fido
1109 * y_monnam: your newt your xan your invisible orc Fido
1112 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1113 * options works, since those are special cases.
1115 char *
1116 x_monnam(mtmp, article, adjective, suppress, called)
1117 register struct monst *mtmp;
1118 int article;
1119 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1120 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1122 * If the monster would be referred to as "it" or if the monster has a name
1123 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1124 * and always use no article.
1126 const char *adjective;
1127 int suppress;
1128 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1129 * EXACT_NAME: combination of all the above
1131 boolean called;
1133 char *buf = nextmbuf();
1134 struct permonst *mdat = mtmp->data;
1135 const char *pm_name = mdat->mname;
1136 boolean do_hallu, do_invis, do_it, do_saddle;
1137 boolean name_at_start, has_adjectives;
1138 char *bp;
1140 if (program_state.gameover)
1141 suppress |= SUPPRESS_HALLUCINATION;
1142 if (article == ARTICLE_YOUR && !mtmp->mtame)
1143 article = ARTICLE_THE;
1145 do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
1146 do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
1147 do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR
1148 && !program_state.gameover && mtmp != u.usteed
1149 && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT);
1150 do_saddle = !(suppress & SUPPRESS_SADDLE);
1152 buf[0] = '\0';
1154 /* unseen monsters, etc. Use "it" */
1155 if (do_it) {
1156 Strcpy(buf, "it");
1157 return buf;
1160 /* priests and minions: don't even use this function */
1161 if (mtmp->ispriest || mtmp->isminion) {
1162 char priestnambuf[BUFSZ];
1163 char *name;
1164 long save_prop = EHalluc_resistance;
1165 unsigned save_invis = mtmp->minvis;
1167 /* when true name is wanted, explicitly block Hallucination */
1168 if (!do_hallu)
1169 EHalluc_resistance = 1L;
1170 if (!do_invis)
1171 mtmp->minvis = 0;
1172 name = priestname(mtmp, priestnambuf);
1173 EHalluc_resistance = save_prop;
1174 mtmp->minvis = save_invis;
1175 if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
1176 name += 4;
1177 return strcpy(buf, name);
1179 /* an "aligned priest" not flagged as a priest or minion should be
1180 "priest" or "priestess" (normally handled by priestname()) */
1181 if (mdat == &mons[PM_ALIGNED_PRIEST])
1182 pm_name = mtmp->female ? "priestess" : "priest";
1183 else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female)
1184 pm_name = "high priestess";
1186 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1187 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1188 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1189 * none of this applies.
1191 if (mtmp->isshk && !do_hallu) {
1192 if (adjective && article == ARTICLE_THE) {
1193 /* pathological case: "the angry Asidonhopo the blue dragon"
1194 sounds silly */
1195 Strcpy(buf, "the ");
1196 Strcat(strcat(buf, adjective), " ");
1197 Strcat(buf, shkname(mtmp));
1198 return buf;
1200 Strcat(buf, shkname(mtmp));
1201 if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
1202 return buf;
1203 Strcat(buf, " the ");
1204 if (do_invis)
1205 Strcat(buf, "invisible ");
1206 Strcat(buf, pm_name);
1207 return buf;
1210 /* Put the adjectives in the buffer */
1211 if (adjective)
1212 Strcat(strcat(buf, adjective), " ");
1213 if (do_invis)
1214 Strcat(buf, "invisible ");
1215 if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind
1216 && !Hallucination)
1217 Strcat(buf, "saddled ");
1218 if (buf[0] != 0)
1219 has_adjectives = TRUE;
1220 else
1221 has_adjectives = FALSE;
1223 /* Put the actual monster name or type into the buffer now */
1224 /* Be sure to remember whether the buffer starts with a name */
1225 if (do_hallu) {
1226 char rnamecode;
1227 char *rname = rndmonnam(&rnamecode);
1229 Strcat(buf, rname);
1230 name_at_start = bogon_is_pname(rnamecode);
1231 } else if (has_mname(mtmp)) {
1232 char *name = MNAME(mtmp);
1234 if (mdat == &mons[PM_GHOST]) {
1235 Sprintf(eos(buf), "%s ghost", s_suffix(name));
1236 name_at_start = TRUE;
1237 } else if (called) {
1238 Sprintf(eos(buf), "%s called %s", pm_name, name);
1239 name_at_start = (boolean) type_is_pname(mdat);
1240 } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
1241 /* <name> the <adjective> <invisible> <saddled> <rank> */
1242 char pbuf[BUFSZ];
1244 Strcpy(pbuf, name);
1245 pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
1246 if (has_adjectives)
1247 Strcat(pbuf, buf);
1248 Strcat(pbuf, bp + 5); /* append the rest of the name */
1249 Strcpy(buf, pbuf);
1250 article = ARTICLE_NONE;
1251 name_at_start = TRUE;
1252 } else {
1253 Strcat(buf, name);
1254 name_at_start = TRUE;
1256 } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
1257 char pbuf[BUFSZ];
1259 Strcpy(pbuf, rank_of((int) mtmp->m_lev, monsndx(mdat),
1260 (boolean) mtmp->female));
1261 Strcat(buf, lcase(pbuf));
1262 name_at_start = FALSE;
1263 } else {
1264 Strcat(buf, pm_name);
1265 name_at_start = (boolean) type_is_pname(mdat);
1268 if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
1269 if (mdat == &mons[PM_WIZARD_OF_YENDOR])
1270 article = ARTICLE_THE;
1271 else
1272 article = ARTICLE_NONE;
1273 } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
1274 article = ARTICLE_THE;
1278 char buf2[BUFSZ];
1280 switch (article) {
1281 case ARTICLE_YOUR:
1282 Strcpy(buf2, "your ");
1283 Strcat(buf2, buf);
1284 Strcpy(buf, buf2);
1285 return buf;
1286 case ARTICLE_THE:
1287 Strcpy(buf2, "the ");
1288 Strcat(buf2, buf);
1289 Strcpy(buf, buf2);
1290 return buf;
1291 case ARTICLE_A:
1292 return an(buf);
1293 case ARTICLE_NONE:
1294 default:
1295 return buf;
1300 char *
1301 l_monnam(mtmp)
1302 struct monst *mtmp;
1304 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0,
1305 (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE);
1308 char *
1309 mon_nam(mtmp)
1310 struct monst *mtmp;
1312 return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
1313 (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE);
1316 /* print the name as if mon_nam() was called, but assume that the player
1317 * can always see the monster--used for probing and for monsters aggravating
1318 * the player with a cursed potion of invisibility
1320 char *
1321 noit_mon_nam(mtmp)
1322 struct monst *mtmp;
1324 return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
1325 (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT)
1326 : SUPPRESS_IT,
1327 FALSE);
1330 char *
1331 Monnam(mtmp)
1332 struct monst *mtmp;
1334 register char *bp = mon_nam(mtmp);
1336 *bp = highc(*bp);
1337 return bp;
1340 char *
1341 noit_Monnam(mtmp)
1342 struct monst *mtmp;
1344 register char *bp = noit_mon_nam(mtmp);
1346 *bp = highc(*bp);
1347 return bp;
1350 /* monster's own name */
1351 char *
1352 m_monnam(mtmp)
1353 struct monst *mtmp;
1355 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, EXACT_NAME, FALSE);
1358 /* pet name: "your little dog" */
1359 char *
1360 y_monnam(mtmp)
1361 struct monst *mtmp;
1363 int prefix, suppression_flag;
1365 prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
1366 suppression_flag = (has_mname(mtmp)
1367 /* "saddled" is redundant when mounted */
1368 || mtmp == u.usteed)
1369 ? SUPPRESS_SADDLE
1370 : 0;
1372 return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE);
1375 char *
1376 Adjmonnam(mtmp, adj)
1377 struct monst *mtmp;
1378 const char *adj;
1380 char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
1381 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
1383 *bp = highc(*bp);
1384 return bp;
1387 char *
1388 a_monnam(mtmp)
1389 struct monst *mtmp;
1391 return x_monnam(mtmp, ARTICLE_A, (char *) 0,
1392 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
1395 char *
1396 Amonnam(mtmp)
1397 struct monst *mtmp;
1399 char *bp = a_monnam(mtmp);
1401 *bp = highc(*bp);
1402 return bp;
1405 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1406 identification of the endgame altars via their attending priests */
1407 char *
1408 distant_monnam(mon, article, outbuf)
1409 struct monst *mon;
1410 int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1411 char *outbuf;
1413 /* high priest(ess)'s identity is concealed on the Astral Plane,
1414 unless you're adjacent (overridden for hallucination which does
1415 its own obfuscation) */
1416 if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination
1417 && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
1418 Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
1419 Strcat(outbuf, mon->female ? "high priestess" : "high priest");
1420 } else {
1421 Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE));
1423 return outbuf;
1426 /* fake monsters used to be in a hard-coded array, now in a data file */
1427 STATIC_OVL char *
1428 bogusmon(buf, code)
1429 char *buf, *code;
1431 char *mname = buf;
1433 get_rnd_text(BOGUSMONFILE, buf);
1434 /* strip prefix if present */
1435 if (!letter(*mname)) {
1436 if (code)
1437 *code = *mname;
1438 ++mname;
1439 } else {
1440 if (code)
1441 *code = '\0';
1443 return mname;
1446 /* return a random monster name, for hallucination */
1447 char *
1448 rndmonnam(code)
1449 char *code;
1451 static char buf[BUFSZ];
1452 char *mname;
1453 int name;
1454 #define BOGUSMONSIZE 100 /* arbitrary */
1456 if (code)
1457 *code = '\0';
1459 do {
1460 name = rn1(SPECIAL_PM + BOGUSMONSIZE - LOW_PM, LOW_PM);
1461 } while (name < SPECIAL_PM
1462 && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
1464 if (name >= SPECIAL_PM) {
1465 mname = bogusmon(buf, code);
1466 } else {
1467 mname = strcpy(buf, mons[name].mname);
1469 return mname;
1470 #undef BOGUSMONSIZE
1473 /* check bogusmon prefix to decide whether it's a personal name */
1474 boolean
1475 bogon_is_pname(code)
1476 char code;
1478 if (!code)
1479 return FALSE;
1480 return index("-+=", code) ? TRUE : FALSE;
1483 /* name of a Rogue player */
1484 const char *
1485 roguename()
1487 char *i, *opts;
1489 if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
1490 for (i = opts; *i; i++)
1491 if (!strncmp("name=", i, 5)) {
1492 char *j;
1493 if ((j = index(i + 5, ',')) != 0)
1494 *j = (char) 0;
1495 return i + 5;
1498 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1499 : "Glenn Wichman";
1502 static NEARDATA const char *const hcolors[] = {
1503 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1504 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1505 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1506 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1507 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1508 "strawberry-banana", "peppermint", "romantic", "incandescent",
1509 "octarine", /* Discworld: the Colour of Magic */
1512 const char *
1513 hcolor(colorpref)
1514 const char *colorpref;
1516 return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))]
1517 : colorpref;
1520 /* return a random real color unless hallucinating */
1521 const char *
1522 rndcolor()
1524 int k = rn2(CLR_MAX);
1526 return Hallucination ? hcolor((char *) 0)
1527 : (k == NO_COLOR) ? "colorless"
1528 : c_obj_colors[k];
1531 /* Aliases for road-runner nemesis
1533 static const char *const coynames[] = {
1534 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1535 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1536 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1537 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1538 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1539 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1540 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1541 "Canis latrans"
1544 char *
1545 coyotename(mtmp, buf)
1546 struct monst *mtmp;
1547 char *buf;
1549 if (mtmp && buf) {
1550 Sprintf(buf, "%s - %s",
1551 x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
1552 mtmp->mcan ? coynames[SIZE(coynames) - 1]
1553 : coynames[rn2(SIZE(coynames) - 1)]);
1555 return buf;
1558 /* make sure "The Colour of Magic" remains the first entry in here */
1559 static const char *const sir_Terry_novels[] = {
1560 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1561 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1562 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1563 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1564 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1565 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1566 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1567 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1568 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1569 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1570 "Raising Steam", "The Shepherd's Crown"
1573 const char *
1574 noveltitle(novidx)
1575 int *novidx;
1577 int j, k = SIZE(sir_Terry_novels);
1579 j = rn2(k);
1580 if (novidx) {
1581 if (*novidx == -1)
1582 *novidx = j;
1583 else if (*novidx >= 0 && *novidx < k)
1584 j = *novidx;
1586 return sir_Terry_novels[j];
1589 const char *
1590 lookup_novel(lookname, idx)
1591 const char *lookname;
1592 int *idx;
1594 int k;
1596 /* Take American or U.K. spelling of this one */
1597 if (!strcmpi(The(lookname), "The Color of Magic"))
1598 lookname = sir_Terry_novels[0];
1600 for (k = 0; k < SIZE(sir_Terry_novels); ++k) {
1601 if (!strcmpi(lookname, sir_Terry_novels[k])
1602 || !strcmpi(The(lookname), sir_Terry_novels[k])) {
1603 if (idx)
1604 *idx = k;
1605 return sir_Terry_novels[k];
1608 /* name not found; if novelidx is already set, override the name */
1609 if (idx && *idx >= 0 && *idx < SIZE(sir_Terry_novels))
1610 return sir_Terry_novels[*idx];
1612 return (const char *) 0;
1615 /*do_name.c*/