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. */
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 *,
11 STATIC_DCL boolean
FDECL(gather_locs_interesting
, (int, int, int));
12 STATIC_DCL
void FDECL(gather_locs
, (coord
**, int *, int));
13 STATIC_DCL
void FDECL(auto_describe
, (int, int));
14 STATIC_DCL
void NDECL(do_mname
);
15 STATIC_DCL boolean
FDECL(alreadynamed
, (struct monst
*, char *, char *));
16 STATIC_DCL
void FDECL(do_oname
, (struct obj
*));
17 STATIC_DCL
void NDECL(namefloorobj
);
18 STATIC_DCL
char *FDECL(bogusmon
, (char *,char *));
20 extern const char what_is_an_unknown_object
[]; /* from pager.c */
24 /* manage a pool of BUFSZ buffers, so callers don't have to */
28 static char NEARDATA bufs
[NUMMBUF
][BUFSZ
];
29 static int bufidx
= 0;
31 bufidx
= (bufidx
+ 1) % NUMMBUF
;
35 /* function for getpos() to highlight desired map locations.
36 * parameter value 0 = initialize, 1 = highlight, 2 = done
38 static void FDECL((*getpos_hilitefunc
), (int)) = (void FDECL((*), (int))) 0;
42 void FDECL((*f
), (int));
44 getpos_hilitefunc
= f
;
47 /* the response for '?' help request in getpos() */
49 getpos_help(force
, goal
)
54 boolean doing_what_is
;
55 winid tmpwin
= create_nhwindow(NHW_MENU
);
57 Sprintf(sbuf
, "Use '%c', '%c', '%c', '%c' to move the cursor to %s.", /* hjkl */
58 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
, Cmd
.move_E
, goal
);
59 putstr(tmpwin
, 0, sbuf
);
60 putstr(tmpwin
, 0, "Use 'H', 'J', 'K', 'L' to move the cursor 8 units at a time.");
61 putstr(tmpwin
, 0, "Or enter a background symbol (ex. '<').");
62 Sprintf(sbuf
, "Use '%s' to move the cursor on yourself.",
63 visctrl(Cmd
.spkeys
[NHKF_GETPOS_SELF
]));
64 putstr(tmpwin
, 0, sbuf
);
65 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_MON
) != 0) {
66 Sprintf(sbuf
, "Use '%s' or '%s' to move the cursor to next monster.",
67 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MON_NEXT
]),
68 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MON_PREV
]));
69 putstr(tmpwin
, 0, sbuf
);
71 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_OBJ
) != 0) {
72 Sprintf(sbuf
, "Use '%s' or '%s' to move the cursor to next object.",
73 visctrl(Cmd
.spkeys
[NHKF_GETPOS_OBJ_NEXT
]),
74 visctrl(Cmd
.spkeys
[NHKF_GETPOS_OBJ_PREV
]));
75 putstr(tmpwin
, 0, sbuf
);
77 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_MAP
) != 0) {
78 /* both of these are primarily useful when choosing a travel
79 destination for the '_' command */
81 "Use '%s' or '%s' to move the cursor to next door or doorway.",
82 visctrl(Cmd
.spkeys
[NHKF_GETPOS_DOOR_NEXT
]),
83 visctrl(Cmd
.spkeys
[NHKF_GETPOS_DOOR_PREV
]));
84 putstr(tmpwin
, 0, sbuf
);
86 "Use '%s' or '%s' to move the cursor to unexplored location.",
87 visctrl(Cmd
.spkeys
[NHKF_GETPOS_UNEX_NEXT
]),
88 visctrl(Cmd
.spkeys
[NHKF_GETPOS_UNEX_PREV
]));
89 putstr(tmpwin
, 0, sbuf
);
91 if (!iflags
.terrainmode
) {
93 if (getpos_hilitefunc
) {
94 Sprintf(sbuf
, "Use '%s' to display valid locations.",
95 visctrl(Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]));
96 putstr(tmpwin
, 0, sbuf
);
98 Sprintf(sbuf
, "Use '%s' to toggle automatic description.",
99 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
100 putstr(tmpwin
, 0, sbuf
);
101 if (iflags
.cmdassist
) { /* assisting the '/' command, I suppose... */
103 (iflags
.getpos_coords
== GPCOORDS_NONE
)
104 ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
105 : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
106 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
108 /* disgusting hack; the alternate selection characters work for any
109 getpos call, but only matter for dowhatis (and doquickwhatis) */
110 doing_what_is
= (goal
== what_is_an_unknown_object
);
112 Sprintf(kbuf
, "'%s' or '%s' or '%s' or '%s'",
113 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
114 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]),
115 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]),
116 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
118 Sprintf(kbuf
, "'%s'", visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
120 Sprintf(sbuf
, "Type a %s when you are at the right place.", kbuf
);
121 putstr(tmpwin
, 0, sbuf
);
124 " '%s' describe current spot, show 'more info', move to another spot.",
125 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
126 putstr(tmpwin
, 0, sbuf
);
128 " '%s' describe current spot,%s move to another spot;",
129 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
130 flags
.help
? " prompt if 'more info'," : "");
131 putstr(tmpwin
, 0, sbuf
);
133 " '%s' describe current spot, move to another spot;",
134 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]));
135 putstr(tmpwin
, 0, sbuf
);
137 " '%s' describe current spot, stop looking at things;",
138 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]));
139 putstr(tmpwin
, 0, sbuf
);
143 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
144 putstr(tmpwin
, 0, "");
145 display_nhwindow(tmpwin
, TRUE
);
146 destroy_nhwindow(tmpwin
);
150 cmp_coord_distu(a
, b
)
156 int dx
, dy
, dist_1
, dist_2
;
160 dist_1
= max(abs(dx
), abs(dy
));
163 dist_2
= max(abs(dx
), abs(dy
));
165 if (dist_1
== dist_2
)
166 return (c1
->y
!= c2
->y
) ? (c1
->y
- c2
->y
) : (c1
->x
- c2
->x
);
168 return dist_1
- dist_2
;
181 #define IS_UNEXPLORED_LOC(x,y) \
183 && glyph_is_cmap(levl[(x)][(y)].glyph) \
184 && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
185 && !levl[(x)][(y)].seenv)
188 gather_locs_interesting(x
,y
, gloc
)
191 /* TODO: if glyph is a pile glyph, convert to ordinary one
192 * in order to keep tail/boulder/rock check simple.
194 int glyph
= glyph_at(x
, y
);
199 /* unlike '/M', this skips monsters revealed by
200 warning glyphs and remembered unseen ones */
201 return (glyph_is_monster(glyph
)
202 && glyph
!= monnum_to_glyph(PM_LONG_WORM_TAIL
));
204 return (glyph_is_object(glyph
)
205 && glyph
!= objnum_to_glyph(BOULDER
)
206 && glyph
!= objnum_to_glyph(ROCK
));
208 return (glyph_is_cmap(glyph
)
209 && (is_cmap_door(glyph_to_cmap(glyph
))
210 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
211 || glyph_to_cmap(glyph
) == S_ndoor
));
213 return (glyph_is_cmap(glyph
)
214 && (is_cmap_door(glyph_to_cmap(glyph
))
215 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
216 || glyph_to_cmap(glyph
) == S_ndoor
217 || glyph_to_cmap(glyph
) == S_room
218 || glyph_to_cmap(glyph
) == S_darkroom
219 || glyph_to_cmap(glyph
) == S_corr
220 || glyph_to_cmap(glyph
) == S_litcorr
)
221 && (IS_UNEXPLORED_LOC(x
+ 1, y
)
222 || IS_UNEXPLORED_LOC(x
- 1, y
)
223 || IS_UNEXPLORED_LOC(x
, y
+ 1)
224 || IS_UNEXPLORED_LOC(x
, y
- 1)));
230 /* gather locations for monsters or objects shown on the map */
232 gather_locs(arr_p
, cnt_p
, gloc
)
240 * We always include the hero's location even if there is no monster
241 * (invisible hero without see invisible) or object (usual case)
242 * displayed there. That way, the count will always be at least 1,
243 * and player has a visual indicator (cursor returns to hero's spot)
244 * highlighting when successive 'm's or 'o's have cycled all the way
245 * through all monsters or objects.
247 * Hero's spot will always sort to array[0] because it will always
248 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
251 for (pass
= 0; pass
< 2; pass
++) {
252 for (x
= 1; x
< COLNO
; x
++)
253 for (y
= 0; y
< ROWNO
; y
++) {
254 if ((x
== u
.ux
&& y
== u
.uy
)
255 || gather_locs_interesting(x
, y
, gloc
)) {
266 if (!pass
) /* end of first pass */
267 *arr_p
= (coord
*) alloc(*cnt_p
* sizeof (coord
));
268 else /* end of second pass */
269 qsort(*arr_p
, *cnt_p
, sizeof (coord
), cmp_coord_distu
);
274 dxdy_to_dist_descr(dx
, dy
, fulldir
)
282 Sprintf(buf
, "here");
283 } else if ((dst
= xytod(dx
, dy
)) != -1) {
284 /* explicit direction; 'one step' is implicit */
285 Sprintf(buf
, "%s", directionname(dst
));
287 const char *dirnames
[4][2] = {
293 /* 9999: protect buf[] against overflow caused by invalid values */
297 Sprintf(eos(buf
), "%d%s%s", abs(dy
), dirnames
[(dy
> 0)][fulldir
],
303 Sprintf(eos(buf
), "%d%s", abs(dx
), dirnames
[2 + (dx
> 0)][fulldir
]);
309 /* coordinate formatting for 'whatis_coord' option */
311 coord_desc(x
, y
, outbuf
, cmode
)
315 static char screen_fmt
[16]; /* [12] suffices: "[%02d,%02d]" */
322 case GPCOORDS_COMFULL
:
323 case GPCOORDS_COMPASS
:
324 /* "east", "3s", "2n,4w" */
327 Sprintf(outbuf
, "(%s)",
328 dxdy_to_dist_descr(dx
, dy
, cmode
== GPCOORDS_COMFULL
));
330 case GPCOORDS_MAP
: /* x,y */
331 /* upper left corner of map is <1,0>;
332 with default COLNO,ROWNO lower right corner is <79,20> */
333 Sprintf(outbuf
, "<%d,%d>", x
, y
);
335 case GPCOORDS_SCREEN
: /* y+2,x */
336 /* for normal map sizes, force a fixed-width formatting so that
337 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
338 than Nx999 or 999xM will still work, but not line up like normal
339 when displayed in a column setting */
341 Sprintf(screen_fmt
, "[%%%sd,%%%sd]",
342 (ROWNO
- 1 + 2 < 100) ? "02" : "03",
343 (COLNO
- 1 < 100) ? "02" : "03");
344 /* map line 0 is screen row 2;
345 map column 0 isn't used, map column 1 is screen column 1 */
346 Sprintf(outbuf
, screen_fmt
, y
+ 2, x
);
353 auto_describe(cx
, cy
)
359 const char *firstmatch
= "unknown";
363 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
364 (void) coord_desc(cx
, cy
, tmpbuf
, iflags
.getpos_coords
);
365 pline("%s%s%s%s", firstmatch
, *tmpbuf
? " " : "", tmpbuf
,
366 (iflags
.getloc_travelmode
&& !is_valid_travelpt(cx
,cy
))
367 ? " (no travel path)" : "");
368 curs(WIN_MAP
, cx
, cy
);
374 getpos(ccp
, force
, goal
)
382 } const pick_chars_def
[] = {
383 { NHKF_GETPOS_PICK
, LOOK_TRADITIONAL
},
384 { NHKF_GETPOS_PICK_Q
, LOOK_QUICK
},
385 { NHKF_GETPOS_PICK_O
, LOOK_ONCE
},
386 { NHKF_GETPOS_PICK_V
, LOOK_VERBOSE
}
388 const int mMoOdDxX_def
[] = {
389 NHKF_GETPOS_MON_NEXT
,
390 NHKF_GETPOS_MON_PREV
,
391 NHKF_GETPOS_OBJ_NEXT
,
392 NHKF_GETPOS_OBJ_PREV
,
393 NHKF_GETPOS_DOOR_NEXT
,
394 NHKF_GETPOS_DOOR_PREV
,
395 NHKF_GETPOS_UNEX_NEXT
,
396 NHKF_GETPOS_UNEX_PREV
403 boolean msg_given
= TRUE
; /* clear message window by default */
404 boolean show_goal_msg
= FALSE
;
405 boolean hilite_state
= FALSE
;
406 coord
*garr
[NUM_GLOCS
] = DUMMY
;
407 int gcount
[NUM_GLOCS
] = DUMMY
;
408 int gidx
[NUM_GLOCS
] = DUMMY
;
410 for (i
= 0; i
< SIZE(pick_chars_def
); i
++)
411 pick_chars
[i
] = Cmd
.spkeys
[pick_chars_def
[i
].nhkf
];
412 pick_chars
[SIZE(pick_chars_def
)] = '\0';
414 for (i
= 0; i
< SIZE(mMoOdDxX_def
); i
++)
415 mMoOdDxX
[i
] = Cmd
.spkeys
[mMoOdDxX_def
[i
]];
416 mMoOdDxX
[SIZE(mMoOdDxX_def
)] = '\0';
419 goal
= "desired location";
421 pline("(For instructions type a '%s')",
422 visctrl(Cmd
.spkeys
[NHKF_GETPOS_HELP
]));
430 curs(WIN_MAP
, cx
, cy
);
433 lock_mouse_cursor(TRUE
);
437 pline("Move cursor to %s:", goal
);
438 curs(WIN_MAP
, cx
, cy
);
440 show_goal_msg
= FALSE
;
441 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
442 auto_describe(cx
, cy
);
445 c
= nh_poskey(&tx
, &ty
, &sidx
);
448 (*getpos_hilitefunc
)(2);
449 hilite_state
= FALSE
;
450 curs(WIN_MAP
, cx
, cy
);
454 if (iflags
.autodescribe
)
457 if (c
== Cmd
.spkeys
[NHKF_ESC
]) {
459 msg_given
= TRUE
; /* force clear */
466 /* a mouse click event, just assign and return */
471 if ((cp
= index(pick_chars
, c
)) != 0) {
472 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
473 result
= pick_chars_def
[(int) (cp
- pick_chars
)].ret
;
476 for (i
= 0; i
< 8; i
++) {
479 if (Cmd
.dirchars
[i
] == c
) {
480 /* a normal movement letter or digit */
483 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
484 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
485 /* a shifted movement letter or Meta-digit */
491 /* truncate at map edge; diagonal moves complicate this... */
493 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
494 dx
= 1 - cx
; /* so that (cx+dx == 1) */
495 } else if (cx
+ dx
> COLNO
- 1) {
496 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
497 dx
= (COLNO
- 1) - cx
;
500 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
501 dy
= 0 - cy
; /* so that (cy+dy == 0) */
502 } else if (cy
+ dy
> ROWNO
- 1) {
503 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
504 dy
= (ROWNO
- 1) - cy
;
511 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
] || redraw_cmd(c
)) {
512 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
])
513 getpos_help(force
, goal
);
515 docrt(); /* redraw */
516 /* update message window to reflect that we're still targetting */
517 show_goal_msg
= TRUE
;
519 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]
520 && getpos_hilitefunc
) {
522 (*getpos_hilitefunc
)(0);
523 (*getpos_hilitefunc
)(1);
527 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]) {
528 iflags
.autodescribe
= !iflags
.autodescribe
;
529 pline("Automatic description %sis %s.",
530 flags
.verbose
? "of features under cursor " : "",
531 iflags
.autodescribe
? "on" : "off");
532 if (!iflags
.autodescribe
)
533 show_goal_msg
= TRUE
;
536 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SELF
]) {
537 /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
538 to achieve that except by manually cycling through all spots */
539 for (i
= 0; i
< NUM_GLOCS
; i
++)
544 } else if ((cp
= index(mMoOdDxX
, c
)) != 0) { /* 'm|M', 'o|O', &c */
545 /* nearest or farthest monster or object or door or unexplored */
546 int gtmp
= (int) (cp
- mMoOdDxX
), /* 0..7 */
547 gloc
= gtmp
>> 1; /* 0..3 */
550 gather_locs(&garr
[gloc
], &gcount
[gloc
], gloc
);
551 gidx
[gloc
] = 0; /* garr[][0] is hero's spot */
553 if (!(gtmp
& 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
554 gidx
[gloc
] = (gidx
[gloc
] + 1) % gcount
[gloc
];
555 } else { /* c=='M' || c=='O' || c=='D' || c=='X') */
556 if (--gidx
[gloc
] < 0)
557 gidx
[gloc
] = gcount
[gloc
] - 1;
559 cx
= garr
[gloc
][gidx
[gloc
]].x
;
560 cy
= garr
[gloc
][gidx
[gloc
]].y
;
563 if (!index(quitchars
, c
)) {
564 char matching
[MAXPCHARS
];
565 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
567 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
568 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++) { /* [0] left as 0 */
569 if (IS_DOOR(sidx
) || IS_WALL(sidx
)
570 || sidx
== SDOOR
|| sidx
== SCORR
571 || glyph_to_cmap(k
) == S_room
572 || glyph_to_cmap(k
) == S_darkroom
573 || glyph_to_cmap(k
) == S_corr
574 || glyph_to_cmap(k
) == S_litcorr
)
576 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
577 matching
[sidx
] = (char) ++k
;
580 for (pass
= 0; pass
<= 1; pass
++) {
581 /* pass 0: just past current pos to lower right;
582 pass 1: upper left corner to current pos */
583 lo_y
= (pass
== 0) ? cy
: 0;
584 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
585 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
586 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
587 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
588 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
589 /* first, look at what is currently visible
590 (might be monster) */
591 k
= glyph_at(tx
, ty
);
593 && matching
[glyph_to_cmap(k
)])
595 /* next, try glyph that's remembered here
596 (might be trap or object) */
597 if (level
.flags
.hero_memory
598 /* !terrainmode: don't move to remembered
599 trap or object if not currently shown */
600 && !iflags
.terrainmode
) {
601 k
= levl
[tx
][ty
].glyph
;
603 && matching
[glyph_to_cmap(k
)])
606 /* last, try actual terrain here (shouldn't
607 we be using lastseentyp[][] instead?) */
608 if (levl
[tx
][ty
].seenv
) {
609 k
= back_to_glyph(tx
, ty
);
611 && matching
[glyph_to_cmap(k
)])
618 clear_nhwindow(WIN_MESSAGE
);
625 pline("Can't find dungeon feature '%c'.", c
);
632 Strcpy(note
, "aborted");
634 Sprintf(note
, "use '%c', '%c', '%c', '%c' or '%s'", /* hjkl */
635 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
637 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
638 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
641 } /* k => matching */
646 msg_given
= FALSE
; /* suppress clear */
649 result
= 0; /* not -1 */
657 curs(WIN_MAP
, cx
, cy
);
661 lock_mouse_cursor(FALSE
);
664 clear_nhwindow(WIN_MESSAGE
);
667 for (i
= 0; i
< NUM_GLOCS
; i
++)
669 free((genericptr_t
) garr
[i
]);
670 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
674 /* allocate space for a monster's name; removes old name if there is one */
678 int lth
; /* desired length (caller handles adding 1 for terminator) */
681 /* allocate mextra if necessary; otherwise get rid of old name */
683 mon
->mextra
= newmextra();
685 free_mname(mon
); /* already has mextra, might also have name */
686 MNAME(mon
) = (char *) alloc((unsigned) lth
);
688 /* zero length: the new name is empty; get rid of the old name */
694 /* release a monster's name; retains mextra even if all fields are now null */
699 if (has_mname(mon
)) {
700 free((genericptr_t
) MNAME(mon
));
701 MNAME(mon
) = (char *) 0;
705 /* allocate space for an object's name; removes old name if there is one */
709 int lth
; /* desired length (caller handles adding 1 for terminator) */
712 /* allocate oextra if necessary; otherwise get rid of old name */
714 obj
->oextra
= newoextra();
716 free_oname(obj
); /* already has oextra, might also have name */
717 ONAME(obj
) = (char *) alloc((unsigned) lth
);
719 /* zero length: the new name is empty; get rid of the old name */
725 /* release an object's name; retains oextra even if all fields are now null */
730 if (has_oname(obj
)) {
731 free((genericptr_t
) ONAME(obj
));
732 ONAME(obj
) = (char *) 0;
736 /* safe_oname() always returns a valid pointer to
737 * a string, either the pointer to an object's name
738 * if it has one, or a pointer to an empty string
750 /* historical note: this returns a monster pointer because it used to
751 allocate a new bigger block of memory to hold the monster and its name */
753 christen_monst(mtmp
, name
)
760 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
761 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
764 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
765 buf
[PL_PSIZ
- 1] = '\0';
767 new_mname(mtmp
, lth
); /* removes old name if one is present */
769 Strcpy(MNAME(mtmp
), name
);
773 /* check whether user-supplied name matches or nearly matches an unnameable
774 monster's name; if so, give an alternate reject message for do_mname() */
776 alreadynamed(mtmp
, monnambuf
, usrbuf
)
778 char *monnambuf
, *usrbuf
;
780 char pronounbuf
[10], *p
;
782 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
783 /* catch trying to name "the Oracle" as "Oracle" */
784 || (!strncmpi(monnambuf
, "the ", 4)
785 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
786 /* catch trying to name "invisible Orcus" as "Orcus" */
787 || ((p
= strstri(monnambuf
, "invisible ")) != 0
788 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
789 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
790 || ((p
= strstri(monnambuf
, " of ")) != 0
791 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
792 pline("%s is already called %s.",
793 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
795 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
796 && strstri(monnambuf
, "Juiblex")
797 && !strcmpi(usrbuf
, "Jubilex")) {
798 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
804 /* allow player to assign a name to some chosen monster */
808 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
811 struct monst
*mtmp
= 0;
814 You("would never recognize it anyway.");
819 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
824 if (cx
== u
.ux
&& cy
== u
.uy
) {
825 if (u
.usteed
&& canspotmon(u
.usteed
)) {
828 pline("This %s creature is called %s and cannot be renamed.",
829 beautiful(), plname
);
837 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
838 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
839 || mtmp
->m_ap_type
== M_AP_OBJECT
840 || (mtmp
->minvis
&& !See_invisible
)))) {
841 pline("I see no monster there.");
844 /* special case similar to the one in lookat() */
845 Sprintf(qbuf
, "What do you want to call %s?",
846 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
848 if (!*buf
|| *buf
== '\033')
850 /* strip leading and trailing spaces; unnames monster if all spaces */
851 (void) mungspaces(buf
);
853 /* Unique monsters have their own specific names or titles.
854 * Shopkeepers, temple priests and other minions use alternate
855 * name formatting routines which ignore any user-supplied name.
857 * Don't say the name is being rejected if it happens to match
860 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
861 if (!alreadynamed(mtmp
, monnambuf
, buf
))
862 pline("%s doesn't like being called names!", upstart(monnambuf
));
863 } else if (mtmp
->isshk
864 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
865 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
866 if (!alreadynamed(mtmp
, monnambuf
, buf
))
867 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
868 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
869 if (!alreadynamed(mtmp
, monnambuf
, buf
))
870 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
872 (void) christen_monst(mtmp
, buf
);
876 * This routine changes the address of obj. Be careful not to call it
877 * when there might be pointers around in unknown places. For now: only
878 * when obj is in the inventory.
883 register struct obj
*obj
;
885 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
889 /* Do this now because there's no point in even asking for a name */
890 if (obj
->otyp
== SPE_NOVEL
) {
891 pline("%s already has a published name.", Ysimple_name2(obj
));
895 Sprintf(qbuf
, "What do you want to name %s ",
896 is_plural(obj
) ? "these" : "this");
897 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
899 if (!*buf
|| *buf
== '\033')
901 /* strip leading and trailing spaces; unnames item if all spaces */
902 (void) mungspaces(buf
);
905 * We don't violate illiteracy conduct here, although it is
906 * arguable that we should for anything other than "X". Doing so
907 * would make attaching player's notes to hero's inventory have an
908 * in-game effect, which may or may not be the correct thing to do.
910 * We do violate illiteracy in oname() if player creates Sting or
911 * Orcrist, clearly being literate (no pun intended...).
914 /* relax restrictions over proper capitalization for artifacts */
915 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
918 if (obj
->oartifact
) {
919 pline_The("artifact seems to resist the attempt.");
921 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
922 /* this used to change one letter, substituting a value
923 of 'a' through 'y' (due to an off by one error, 'z'
924 would never be selected) and then force that to
925 upper case if such was the case of the input;
926 now, the hand slip scuffs one or two letters as if
927 the text had been trodden upon, sometimes picking
928 punctuation instead of an arbitrary letter;
929 unfortunately, we have to cover the possibility of
930 it targetting spaces so failing to make any change
931 (we know that it must eventually target a nonspace
932 because buf[] matches a valid artifact name) */
934 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
935 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
937 wipeout_text(bufp
, rnd(2), (unsigned) 0);
938 } while (!strcmp(buf
, bufcpy
));
939 pline("While engraving, your %s slips.", body_part(HAND
));
940 display_nhwindow(WIN_MESSAGE
, FALSE
);
941 You("engrave: \"%s\".", buf
);
943 obj
= oname(obj
, buf
);
954 lth
= *name
? (int) (strlen(name
) + 1) : 0;
957 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
958 buf
[PL_PSIZ
- 1] = '\0';
960 /* If named artifact exists in the game, do not create another.
961 * Also trying to create an artifact shouldn't de-artifact
962 * it (e.g. Excalibur from prayer). In this case the object
963 * will retain its current name. */
964 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
967 new_oname(obj
, lth
); /* removes old name if one is present */
969 Strcpy(ONAME(obj
), name
);
972 artifact_exists(obj
, name
, TRUE
);
973 if (obj
->oartifact
) {
974 /* can't dual-wield with artifact as secondary weapon */
977 /* activate warning if you've just named your weapon "Sting" */
979 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
980 /* if obj is owned by a shop, increase your bill */
983 /* violate illiteracy conduct since successfully wrote arti-name */
984 u
.uconduct
.literate
++;
991 static NEARDATA
const char callable
[] = {
992 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
993 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
997 objtyp_is_callable(i
)
1000 return (boolean
) (objects
[i
].oc_uname
1001 || (OBJ_DESCR(objects
[i
])
1002 && index(callable
, objects
[i
].oc_class
)));
1005 /* C and #name commands - player can name monster or object or type of obj */
1012 menu_item
*pick_list
= 0;
1013 char ch
, allowall
[2];
1014 /* if player wants a,b,c instead of i,o when looting, do that here too */
1015 boolean abc
= flags
.lootabc
;
1017 win
= create_nhwindow(NHW_MENU
);
1020 any
.a_char
= 'm'; /* group accelerator 'C' */
1021 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
1022 "a monster", MENU_UNSELECTED
);
1024 /* we use y and n as accelerators so that we can accept user's
1025 response keyed to old "name an individual object?" prompt */
1026 any
.a_char
= 'i'; /* group accelerator 'y' */
1027 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
1028 "a particular object in inventory", MENU_UNSELECTED
);
1029 any
.a_char
= 'o'; /* group accelerator 'n' */
1030 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
1031 "the type of an object in inventory", MENU_UNSELECTED
);
1033 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
1034 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
1035 "the type of an object upon the floor", MENU_UNSELECTED
);
1036 any
.a_char
= 'd'; /* group accelerator '\' */
1037 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
1038 "the type of an object on discoveries list", MENU_UNSELECTED
);
1039 any
.a_char
= 'a'; /* group accelerator 'l' */
1040 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
1041 "record an annotation for the current level", MENU_UNSELECTED
);
1042 end_menu(win
, "What do you want to name?");
1043 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
1044 ch
= pick_list
[0].item
.a_char
;
1045 free((genericptr_t
) pick_list
);
1048 destroy_nhwindow(win
);
1054 case 'm': /* name a visible monster */
1057 case 'i': /* name an individual object in inventory */
1058 allowall
[0] = ALL_CLASSES
;
1060 obj
= getobj(allowall
, "name");
1064 case 'o': /* name a type of object in inventory */
1065 obj
= getobj(callable
, "call");
1067 /* behave as if examining it in inventory;
1068 this might set dknown if it was picked up
1069 while blind and the hero can now see */
1073 You("would never recognize another one.");
1075 } else if (!objtyp_is_callable(obj
->otyp
)) {
1076 You("know those as well as you ever will.");
1083 case 'f': /* name a type of object visible on the floor */
1086 case 'd': /* name a type of object on the discoveries list */
1089 case 'a': /* annotate level */
1098 register struct obj
*obj
;
1100 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
1102 register char **str1
;
1105 return; /* probably blind */
1108 otemp
.oextra
= (struct oextra
*) 0;
1110 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
1111 /* kludge, meaning it's sink water */
1112 Sprintf(qbuf
, "Call a stream of %s fluid:",
1113 OBJ_DESCR(objects
[otemp
.otyp
]));
1115 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
1117 if (!*buf
|| *buf
== '\033')
1120 /* clear old name */
1121 str1
= &(objects
[obj
->otyp
].oc_uname
);
1123 free((genericptr_t
) *str1
);
1125 /* strip leading and trailing spaces; uncalls item if all spaces */
1126 (void) mungspaces(buf
);
1128 if (*str1
) { /* had name, so possibly remove from disco[] */
1129 /* strip name first, for the update_inventory() call
1130 from undiscover_object() */
1132 undiscover_object(obj
->otyp
);
1135 *str1
= dupstr(buf
);
1136 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
1146 struct obj
*obj
= 0;
1147 boolean fakeobj
= FALSE
, use_plural
;
1149 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
1150 /* "dot for under/over you" only makes sense when the cursor hasn't
1151 been moved off the hero's '@' yet, but there's no way to adjust
1152 the help text once getpos() has started */
1153 Sprintf(buf
, "object on map (or '.' for one %s you)",
1154 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
1155 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
1157 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1158 obj
= vobj_at(u
.ux
, u
.uy
);
1160 glyph
= glyph_at(cc
.x
, cc
.y
);
1161 if (glyph_is_object(glyph
))
1162 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
1163 /* else 'obj' stays null */
1166 /* "under you" is safe here since there's no object to hide under */
1167 pline("There doesn't seem to be any object %s.",
1168 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
1171 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1172 is a mimic; passing that to xname (directly or via simpleonames)
1173 would yield "glorkum" so we need to handle it explicitly; it will
1174 always fail the Hallucination test and pass the !callable test,
1175 resulting in the "can't be assigned a type name" message */
1176 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
1178 : obj_descr
[STRANGE_OBJECT
].oc_name
);
1179 use_plural
= (obj
->quan
> 1L);
1180 if (Hallucination
) {
1181 const char *unames
[6];
1184 /* straight role name */
1185 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1188 /* random rank title for hero's role */
1189 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
1190 /* random fake monster */
1191 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
1192 /* increased chance for fake monster */
1193 unames
[3] = unames
[2];
1195 unames
[4] = roguename();
1197 unames
[5] = "Wibbly Wobbly";
1198 pline("%s %s to call you \"%s.\"",
1199 The(buf
), use_plural
? "decide" : "decides",
1200 unames
[rn2(SIZE(unames
))]);
1201 } else if (!objtyp_is_callable(obj
->otyp
)) {
1202 pline("%s %s can't be assigned a type name.",
1203 use_plural
? "Those" : "That", buf
);
1204 } else if (!obj
->dknown
) {
1205 You("don't know %s %s well enough to name %s.",
1206 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
1214 static const char *const ghostnames
[] = {
1215 /* these names should have length < PL_NSIZ */
1216 /* Capitalize the names for aesthetics -dgk */
1217 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1218 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1219 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1220 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1221 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1222 "Stephan", "Lance Braccus", "Shadowhawk"
1225 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1229 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
1233 * Monster naming functions:
1234 * x_monnam is the generic monster-naming function.
1235 * seen unseen detected named
1236 * mon_nam: the newt it the invisible orc Fido
1237 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1238 * l_monnam: newt it invisible orc dog called Fido
1239 * Monnam: The newt It The invisible orc Fido
1240 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1241 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1242 * Amonnam: A newt It An invisible orc Fido
1243 * a_monnam: a newt it an invisible orc Fido
1244 * m_monnam: newt xan orc Fido
1245 * y_monnam: your newt your xan your invisible orc Fido
1248 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1249 * options works, since those are special cases.
1252 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
1253 register struct monst
*mtmp
;
1255 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1256 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1258 * If the monster would be referred to as "it" or if the monster has a name
1259 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1260 * and always use no article.
1262 const char *adjective
;
1264 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1265 * EXACT_NAME: combination of all the above
1269 char *buf
= nextmbuf();
1270 struct permonst
*mdat
= mtmp
->data
;
1271 const char *pm_name
= mdat
->mname
;
1272 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
1273 boolean name_at_start
, has_adjectives
;
1276 if (program_state
.gameover
)
1277 suppress
|= SUPPRESS_HALLUCINATION
;
1278 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
1279 article
= ARTICLE_THE
;
1281 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
1282 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
1283 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
1284 && !program_state
.gameover
&& mtmp
!= u
.usteed
1285 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
1286 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
1290 /* unseen monsters, etc. Use "it" */
1296 /* priests and minions: don't even use this function */
1297 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1298 char priestnambuf
[BUFSZ
];
1300 long save_prop
= EHalluc_resistance
;
1301 unsigned save_invis
= mtmp
->minvis
;
1303 /* when true name is wanted, explicitly block Hallucination */
1305 EHalluc_resistance
= 1L;
1308 name
= priestname(mtmp
, priestnambuf
);
1309 EHalluc_resistance
= save_prop
;
1310 mtmp
->minvis
= save_invis
;
1311 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1313 return strcpy(buf
, name
);
1315 /* an "aligned priest" not flagged as a priest or minion should be
1316 "priest" or "priestess" (normally handled by priestname()) */
1317 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1318 pm_name
= mtmp
->female
? "priestess" : "priest";
1319 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1320 pm_name
= "high priestess";
1322 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1323 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1324 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1325 * none of this applies.
1327 if (mtmp
->isshk
&& !do_hallu
) {
1328 if (adjective
&& article
== ARTICLE_THE
) {
1329 /* pathological case: "the angry Asidonhopo the blue dragon"
1331 Strcpy(buf
, "the ");
1332 Strcat(strcat(buf
, adjective
), " ");
1333 Strcat(buf
, shkname(mtmp
));
1336 Strcat(buf
, shkname(mtmp
));
1337 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1339 Strcat(buf
, " the ");
1341 Strcat(buf
, "invisible ");
1342 Strcat(buf
, pm_name
);
1346 /* Put the adjectives in the buffer */
1348 Strcat(strcat(buf
, adjective
), " ");
1350 Strcat(buf
, "invisible ");
1351 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1353 Strcat(buf
, "saddled ");
1355 has_adjectives
= TRUE
;
1357 has_adjectives
= FALSE
;
1359 /* Put the actual monster name or type into the buffer now */
1360 /* Be sure to remember whether the buffer starts with a name */
1363 char *rname
= rndmonnam(&rnamecode
);
1366 name_at_start
= bogon_is_pname(rnamecode
);
1367 } else if (has_mname(mtmp
)) {
1368 char *name
= MNAME(mtmp
);
1370 if (mdat
== &mons
[PM_GHOST
]) {
1371 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1372 name_at_start
= TRUE
;
1373 } else if (called
) {
1374 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1375 name_at_start
= (boolean
) type_is_pname(mdat
);
1376 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1377 /* <name> the <adjective> <invisible> <saddled> <rank> */
1381 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1384 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1386 article
= ARTICLE_NONE
;
1387 name_at_start
= TRUE
;
1390 name_at_start
= TRUE
;
1392 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1395 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1396 (boolean
) mtmp
->female
));
1397 Strcat(buf
, lcase(pbuf
));
1398 name_at_start
= FALSE
;
1400 Strcat(buf
, pm_name
);
1401 name_at_start
= (boolean
) type_is_pname(mdat
);
1404 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1405 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1406 article
= ARTICLE_THE
;
1408 article
= ARTICLE_NONE
;
1409 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1410 article
= ARTICLE_THE
;
1418 Strcpy(buf2
, "your ");
1423 Strcpy(buf2
, "the ");
1440 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1441 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1448 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1449 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1452 /* print the name as if mon_nam() was called, but assume that the player
1453 * can always see the monster--used for probing and for monsters aggravating
1454 * the player with a cursed potion of invisibility
1460 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1461 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1470 register char *bp
= mon_nam(mtmp
);
1480 register char *bp
= noit_mon_nam(mtmp
);
1486 /* monster's own name */
1491 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1494 /* pet name: "your little dog" */
1499 int prefix
, suppression_flag
;
1501 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1502 suppression_flag
= (has_mname(mtmp
)
1503 /* "saddled" is redundant when mounted */
1504 || mtmp
== u
.usteed
)
1508 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1512 Adjmonnam(mtmp
, adj
)
1516 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1517 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1527 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1528 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1535 char *bp
= a_monnam(mtmp
);
1541 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1542 identification of the endgame altars via their attending priests */
1544 distant_monnam(mon
, article
, outbuf
)
1546 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1549 /* high priest(ess)'s identity is concealed on the Astral Plane,
1550 unless you're adjacent (overridden for hallucination which does
1551 its own obfuscation) */
1552 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1553 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1554 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1555 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1557 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1562 /* fake monsters used to be in a hard-coded array, now in a data file */
1569 get_rnd_text(BOGUSMONFILE
, buf
);
1570 /* strip prefix if present */
1571 if (!letter(*mname
)) {
1582 /* return a random monster name, for hallucination */
1587 static char buf
[BUFSZ
];
1590 #define BOGUSMONSIZE 100 /* arbitrary */
1596 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1597 } while (name
< SPECIAL_PM
1598 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1600 if (name
>= SPECIAL_PM
) {
1601 mname
= bogusmon(buf
, code
);
1603 mname
= strcpy(buf
, mons
[name
].mname
);
1609 /* check bogusmon prefix to decide whether it's a personal name */
1611 bogon_is_pname(code
)
1616 return index("-+=", code
) ? TRUE
: FALSE
;
1619 /* name of a Rogue player */
1625 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1626 for (i
= opts
; *i
; i
++)
1627 if (!strncmp("name=", i
, 5)) {
1629 if ((j
= index(i
+ 5, ',')) != 0)
1634 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1638 static NEARDATA
const char *const hcolors
[] = {
1639 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1640 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1641 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1642 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1643 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1644 "strawberry-banana", "peppermint", "romantic", "incandescent",
1645 "octarine", /* Discworld: the Colour of Magic */
1650 const char *colorpref
;
1652 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1656 /* return a random real color unless hallucinating */
1660 int k
= rn2(CLR_MAX
);
1662 return Hallucination
? hcolor((char *) 0)
1663 : (k
== NO_COLOR
) ? "colorless"
1667 static NEARDATA
const char *const hliquids
[] = {
1668 "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
1669 "instant coffee", "tea", "herbal infusion", "liquid rainbow",
1670 "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
1671 "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
1672 "caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
1673 "glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
1674 "sweet vitriol", "grey goo", "pink slime",
1679 const char *liquidpref
;
1681 return (Hallucination
|| !liquidpref
) ? hliquids
[rn2(SIZE(hliquids
))]
1685 /* Aliases for road-runner nemesis
1687 static const char *const coynames
[] = {
1688 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1689 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1690 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1691 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1692 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1693 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1694 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1699 coyotename(mtmp
, buf
)
1704 Sprintf(buf
, "%s - %s",
1705 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1706 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1707 : coynames
[mtmp
->m_id
% (SIZE(coynames
) - 1)]);
1712 /* make sure "The Colour of Magic" remains the first entry in here */
1713 static const char *const sir_Terry_novels
[] = {
1714 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1715 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1716 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1717 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1718 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1719 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1720 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1721 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1722 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1723 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1724 "Raising Steam", "The Shepherd's Crown"
1731 int j
, k
= SIZE(sir_Terry_novels
);
1737 else if (*novidx
>= 0 && *novidx
< k
)
1740 return sir_Terry_novels
[j
];
1744 lookup_novel(lookname
, idx
)
1745 const char *lookname
;
1750 /* Take American or U.K. spelling of this one */
1751 if (!strcmpi(The(lookname
), "The Color of Magic"))
1752 lookname
= sir_Terry_novels
[0];
1754 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1755 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1756 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1759 return sir_Terry_novels
[k
];
1762 /* name not found; if novelidx is already set, override the name */
1763 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1764 return sir_Terry_novels
[*idx
];
1766 return (const char *) 0;