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