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 const char *const gloc_descr
[NUM_GLOCS
][4] = {
48 { "any monsters", "monster", "next monster", "monsters" },
49 { "any items", "item", "next object", "objects" },
50 { "any doors", "door", "next door or doorway", "doors or doorways" },
51 { "any unexplored areas", "unexplored area", "unexplored location",
52 "unexplored locations" },
53 { "anything interesting", "interesting thing", "anything interesting",
54 "anything interesting" }
59 getpos_help_keyxhelp(tmpwin
, k1
, k2
, gloc
)
67 Sprintf(sbuf
, "Use '%s' or '%s' to %s%s%s.",
69 iflags
.getloc_usemenu
? "get a menu of "
70 : "move the cursor to ",
71 gloc_descr
[gloc
][2 + iflags
.getloc_usemenu
],
72 iflags
.getloc_limitview
? " in view" : "");
73 putstr(tmpwin
, 0, sbuf
);
76 /* the response for '?' help request in getpos() */
78 getpos_help(force
, goal
)
83 boolean doing_what_is
;
84 winid tmpwin
= create_nhwindow(NHW_MENU
);
87 "Use '%c', '%c', '%c', '%c' to move the cursor to %s.", /* hjkl */
88 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
, Cmd
.move_E
, goal
);
89 putstr(tmpwin
, 0, sbuf
);
91 "Use 'H', 'J', 'K', 'L' to move the cursor 8 units at a time.");
92 putstr(tmpwin
, 0, "Or enter a background symbol (ex. '<').");
93 Sprintf(sbuf
, "Use '%s' to move the cursor on yourself.",
94 visctrl(Cmd
.spkeys
[NHKF_GETPOS_SELF
]));
95 putstr(tmpwin
, 0, sbuf
);
96 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_MON
) != 0) {
97 getpos_help_keyxhelp(tmpwin
,
98 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MON_NEXT
]),
99 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MON_PREV
]),
102 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_OBJ
) != 0) {
103 getpos_help_keyxhelp(tmpwin
,
104 visctrl(Cmd
.spkeys
[NHKF_GETPOS_OBJ_NEXT
]),
105 visctrl(Cmd
.spkeys
[NHKF_GETPOS_OBJ_PREV
]),
108 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_MAP
) != 0) {
109 /* these are primarily useful when choosing a travel
110 destination for the '_' command */
111 getpos_help_keyxhelp(tmpwin
,
112 visctrl(Cmd
.spkeys
[NHKF_GETPOS_DOOR_NEXT
]),
113 visctrl(Cmd
.spkeys
[NHKF_GETPOS_DOOR_PREV
]),
115 getpos_help_keyxhelp(tmpwin
,
116 visctrl(Cmd
.spkeys
[NHKF_GETPOS_UNEX_NEXT
]),
117 visctrl(Cmd
.spkeys
[NHKF_GETPOS_UNEX_PREV
]),
119 getpos_help_keyxhelp(tmpwin
,
120 visctrl(Cmd
.spkeys
[NHKF_GETPOS_INTERESTING_NEXT
]),
121 visctrl(Cmd
.spkeys
[NHKF_GETPOS_INTERESTING_PREV
]),
124 Sprintf(sbuf
, "Use '%s' to toggle menu listing for possible targets.",
125 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MENU
]));
126 putstr(tmpwin
, 0, sbuf
);
128 "Use '%s' to toggle limiting possible targets to in view only.",
129 visctrl(Cmd
.spkeys
[NHKF_GETPOS_LIMITVIEW
]));
130 putstr(tmpwin
, 0, sbuf
);
131 if (!iflags
.terrainmode
) {
133 if (getpos_hilitefunc
) {
134 Sprintf(sbuf
, "Use '%s' to display valid locations.",
135 visctrl(Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]));
136 putstr(tmpwin
, 0, sbuf
);
138 Sprintf(sbuf
, "Use '%s' to toggle automatic description.",
139 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
140 putstr(tmpwin
, 0, sbuf
);
141 if (iflags
.cmdassist
) { /* assisting the '/' command, I suppose... */
143 (iflags
.getpos_coords
== GPCOORDS_NONE
)
144 ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
145 : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
146 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
148 /* disgusting hack; the alternate selection characters work for any
149 getpos call, but only matter for dowhatis (and doquickwhatis) */
150 doing_what_is
= (goal
== what_is_an_unknown_object
);
152 Sprintf(kbuf
, "'%s' or '%s' or '%s' or '%s'",
153 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
154 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]),
155 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]),
156 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
158 Sprintf(kbuf
, "'%s'", visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
160 Sprintf(sbuf
, "Type a %s when you are at the right place.", kbuf
);
161 putstr(tmpwin
, 0, sbuf
);
164 " '%s' describe current spot, show 'more info', move to another spot.",
165 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
166 putstr(tmpwin
, 0, sbuf
);
168 " '%s' describe current spot,%s move to another spot;",
169 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
170 flags
.help
? " prompt if 'more info'," : "");
171 putstr(tmpwin
, 0, sbuf
);
173 " '%s' describe current spot, move to another spot;",
174 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]));
175 putstr(tmpwin
, 0, sbuf
);
177 " '%s' describe current spot, stop looking at things;",
178 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]));
179 putstr(tmpwin
, 0, sbuf
);
183 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
184 putstr(tmpwin
, 0, "");
185 display_nhwindow(tmpwin
, TRUE
);
186 destroy_nhwindow(tmpwin
);
190 cmp_coord_distu(a
, b
)
196 int dx
, dy
, dist_1
, dist_2
;
200 dist_1
= max(abs(dx
), abs(dy
));
203 dist_2
= max(abs(dx
), abs(dy
));
205 if (dist_1
== dist_2
)
206 return (c1
->y
!= c2
->y
) ? (c1
->y
- c2
->y
) : (c1
->x
- c2
->x
);
208 return dist_1
- dist_2
;
211 #define IS_UNEXPLORED_LOC(x,y) \
213 && glyph_is_cmap(levl[(x)][(y)].glyph) \
214 && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
215 && !levl[(x)][(y)].seenv)
218 gather_locs_interesting(x
,y
, gloc
)
221 /* TODO: if glyph is a pile glyph, convert to ordinary one
222 * in order to keep tail/boulder/rock check simple.
224 int glyph
= glyph_at(x
, y
);
226 if (iflags
.getloc_limitview
&& !cansee(x
,y
))
232 /* unlike '/M', this skips monsters revealed by
233 warning glyphs and remembered unseen ones */
234 return (glyph_is_monster(glyph
)
235 && glyph
!= monnum_to_glyph(PM_LONG_WORM_TAIL
));
237 return (glyph_is_object(glyph
)
238 && glyph
!= objnum_to_glyph(BOULDER
)
239 && glyph
!= objnum_to_glyph(ROCK
));
241 return (glyph_is_cmap(glyph
)
242 && (is_cmap_door(glyph_to_cmap(glyph
))
243 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
244 || glyph_to_cmap(glyph
) == S_ndoor
));
246 return (glyph_is_cmap(glyph
)
247 && (is_cmap_door(glyph_to_cmap(glyph
))
248 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
249 || glyph_to_cmap(glyph
) == S_ndoor
250 || glyph_to_cmap(glyph
) == S_room
251 || glyph_to_cmap(glyph
) == S_darkroom
252 || glyph_to_cmap(glyph
) == S_corr
253 || glyph_to_cmap(glyph
) == S_litcorr
)
254 && (IS_UNEXPLORED_LOC(x
+ 1, y
)
255 || IS_UNEXPLORED_LOC(x
- 1, y
)
256 || IS_UNEXPLORED_LOC(x
, y
+ 1)
257 || IS_UNEXPLORED_LOC(x
, y
- 1)));
258 case GLOC_INTERESTING
:
259 return gather_locs_interesting(x
,y
, GLOC_DOOR
)
260 || !(glyph_is_cmap(glyph
)
261 && (is_cmap_wall(glyph_to_cmap(glyph
))
262 || glyph_to_cmap(glyph
) == S_tree
263 || glyph_to_cmap(glyph
) == S_bars
264 || glyph_to_cmap(glyph
) == S_ice
265 || glyph_to_cmap(glyph
) == S_air
266 || glyph_to_cmap(glyph
) == S_cloud
267 || glyph_to_cmap(glyph
) == S_lava
268 || glyph_to_cmap(glyph
) == S_water
269 || glyph_to_cmap(glyph
) == S_pool
270 || glyph_to_cmap(glyph
) == S_ndoor
271 || glyph_to_cmap(glyph
) == S_room
272 || glyph_to_cmap(glyph
) == S_darkroom
273 || glyph_to_cmap(glyph
) == S_corr
274 || glyph_to_cmap(glyph
) == S_litcorr
));
280 /* gather locations for monsters or objects shown on the map */
282 gather_locs(arr_p
, cnt_p
, gloc
)
290 * We always include the hero's location even if there is no monster
291 * (invisible hero without see invisible) or object (usual case)
292 * displayed there. That way, the count will always be at least 1,
293 * and player has a visual indicator (cursor returns to hero's spot)
294 * highlighting when successive 'm's or 'o's have cycled all the way
295 * through all monsters or objects.
297 * Hero's spot will always sort to array[0] because it will always
298 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
301 for (pass
= 0; pass
< 2; pass
++) {
302 for (x
= 1; x
< COLNO
; x
++)
303 for (y
= 0; y
< ROWNO
; y
++) {
304 if ((x
== u
.ux
&& y
== u
.uy
)
305 || gather_locs_interesting(x
, y
, gloc
)) {
316 if (!pass
) /* end of first pass */
317 *arr_p
= (coord
*) alloc(*cnt_p
* sizeof (coord
));
318 else /* end of second pass */
319 qsort(*arr_p
, *cnt_p
, sizeof (coord
), cmp_coord_distu
);
324 dxdy_to_dist_descr(dx
, dy
, fulldir
)
332 Sprintf(buf
, "here");
333 } else if ((dst
= xytod(dx
, dy
)) != -1) {
334 /* explicit direction; 'one step' is implicit */
335 Sprintf(buf
, "%s", directionname(dst
));
337 const char *dirnames
[4][2] = {
343 /* 9999: protect buf[] against overflow caused by invalid values */
347 Sprintf(eos(buf
), "%d%s%s", abs(dy
), dirnames
[(dy
> 0)][fulldir
],
353 Sprintf(eos(buf
), "%d%s", abs(dx
), dirnames
[2 + (dx
> 0)][fulldir
]);
359 /* coordinate formatting for 'whatis_coord' option */
361 coord_desc(x
, y
, outbuf
, cmode
)
365 static char screen_fmt
[16]; /* [12] suffices: "[%02d,%02d]" */
372 case GPCOORDS_COMFULL
:
373 case GPCOORDS_COMPASS
:
374 /* "east", "3s", "2n,4w" */
377 Sprintf(outbuf
, "(%s)",
378 dxdy_to_dist_descr(dx
, dy
, cmode
== GPCOORDS_COMFULL
));
380 case GPCOORDS_MAP
: /* x,y */
381 /* upper left corner of map is <1,0>;
382 with default COLNO,ROWNO lower right corner is <79,20> */
383 Sprintf(outbuf
, "<%d,%d>", x
, y
);
385 case GPCOORDS_SCREEN
: /* y+2,x */
386 /* for normal map sizes, force a fixed-width formatting so that
387 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
388 than Nx999 or 999xM will still work, but not line up like normal
389 when displayed in a column setting */
391 Sprintf(screen_fmt
, "[%%%sd,%%%sd]",
392 (ROWNO
- 1 + 2 < 100) ? "02" : "03",
393 (COLNO
- 1 < 100) ? "02" : "03");
394 /* map line 0 is screen row 2;
395 map column 0 isn't used, map column 1 is screen column 1 */
396 Sprintf(outbuf
, screen_fmt
, y
+ 2, x
);
403 auto_describe(cx
, cy
)
409 const char *firstmatch
= "unknown";
413 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
414 (void) coord_desc(cx
, cy
, tmpbuf
, iflags
.getpos_coords
);
415 pline("%s%s%s%s", firstmatch
, *tmpbuf
? " " : "", tmpbuf
,
416 (iflags
.getloc_travelmode
&& !is_valid_travelpt(cx
,cy
))
417 ? " (no travel path)" : "");
418 curs(WIN_MAP
, cx
, cy
);
424 getpos_menu(ccp
, fovonly
, gloc
)
434 menu_item
*picks
= (menu_item
*) 0;
437 gather_locs(&garr
, &gcount
, gloc
);
439 if (gcount
< 2) { /* gcount always includes the hero */
440 free((genericptr_t
) garr
);
442 fovonly
? "see" : "detect", gloc_descr
[gloc
][0]);
446 tmpwin
= create_nhwindow(NHW_MENU
);
450 /* gather_locs returns array[0] == you. skip it. */
451 for (i
= 1; i
< gcount
; i
++) {
454 const char *firstmatch
= "unknown";
459 if (do_screen_description(tmpcc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
460 (void) coord_desc(garr
[i
].x
, garr
[i
].y
, tmpbuf
, iflags
.getpos_coords
);
461 Sprintf(fullbuf
, "%s%s%s", firstmatch
, (*tmpbuf
? " " : ""), tmpbuf
);
462 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, fullbuf
,
467 Sprintf(tmpbuf
, "Pick a target %s%s%s",
468 gloc_descr
[gloc
][1], fovonly
? " in view" : "",
469 iflags
.getloc_travelmode
? " for travel" : "");
470 end_menu(tmpwin
, tmpbuf
);
471 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
472 destroy_nhwindow(tmpwin
);
474 ccp
->x
= garr
[picks
->item
.a_int
- 1].x
;
475 ccp
->y
= garr
[picks
->item
.a_int
- 1].y
;
476 free((genericptr_t
) picks
);
478 free((genericptr_t
) garr
);
479 return (pick_cnt
> 0);
483 getpos(ccp
, force
, goal
)
491 } const pick_chars_def
[] = {
492 { NHKF_GETPOS_PICK
, LOOK_TRADITIONAL
},
493 { NHKF_GETPOS_PICK_Q
, LOOK_QUICK
},
494 { NHKF_GETPOS_PICK_O
, LOOK_ONCE
},
495 { NHKF_GETPOS_PICK_V
, LOOK_VERBOSE
}
497 const int mMoOdDxX_def
[] = {
498 NHKF_GETPOS_MON_NEXT
,
499 NHKF_GETPOS_MON_PREV
,
500 NHKF_GETPOS_OBJ_NEXT
,
501 NHKF_GETPOS_OBJ_PREV
,
502 NHKF_GETPOS_DOOR_NEXT
,
503 NHKF_GETPOS_DOOR_PREV
,
504 NHKF_GETPOS_UNEX_NEXT
,
505 NHKF_GETPOS_UNEX_PREV
,
506 NHKF_GETPOS_INTERESTING_NEXT
,
507 NHKF_GETPOS_INTERESTING_PREV
514 boolean msg_given
= TRUE
; /* clear message window by default */
515 boolean show_goal_msg
= FALSE
;
516 boolean hilite_state
= FALSE
;
517 coord
*garr
[NUM_GLOCS
] = DUMMY
;
518 int gcount
[NUM_GLOCS
] = DUMMY
;
519 int gidx
[NUM_GLOCS
] = DUMMY
;
521 for (i
= 0; i
< SIZE(pick_chars_def
); i
++)
522 pick_chars
[i
] = Cmd
.spkeys
[pick_chars_def
[i
].nhkf
];
523 pick_chars
[SIZE(pick_chars_def
)] = '\0';
525 for (i
= 0; i
< SIZE(mMoOdDxX_def
); i
++)
526 mMoOdDxX
[i
] = Cmd
.spkeys
[mMoOdDxX_def
[i
]];
527 mMoOdDxX
[SIZE(mMoOdDxX_def
)] = '\0';
530 goal
= "desired location";
532 pline("(For instructions type a '%s')",
533 visctrl(Cmd
.spkeys
[NHKF_GETPOS_HELP
]));
541 curs(WIN_MAP
, cx
, cy
);
544 lock_mouse_cursor(TRUE
);
548 pline("Move cursor to %s:", goal
);
549 curs(WIN_MAP
, cx
, cy
);
551 show_goal_msg
= FALSE
;
552 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
553 auto_describe(cx
, cy
);
556 c
= nh_poskey(&tx
, &ty
, &sidx
);
559 (*getpos_hilitefunc
)(2);
560 hilite_state
= FALSE
;
561 curs(WIN_MAP
, cx
, cy
);
565 if (iflags
.autodescribe
)
568 if (c
== Cmd
.spkeys
[NHKF_ESC
]) {
570 msg_given
= TRUE
; /* force clear */
577 /* a mouse click event, just assign and return */
582 if ((cp
= index(pick_chars
, c
)) != 0) {
583 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
584 result
= pick_chars_def
[(int) (cp
- pick_chars
)].ret
;
587 for (i
= 0; i
< 8; i
++) {
590 if (Cmd
.dirchars
[i
] == c
) {
591 /* a normal movement letter or digit */
594 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
595 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
596 /* a shifted movement letter or Meta-digit */
602 /* truncate at map edge; diagonal moves complicate this... */
604 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
605 dx
= 1 - cx
; /* so that (cx+dx == 1) */
606 } else if (cx
+ dx
> COLNO
- 1) {
607 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
608 dx
= (COLNO
- 1) - cx
;
611 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
612 dy
= 0 - cy
; /* so that (cy+dy == 0) */
613 } else if (cy
+ dy
> ROWNO
- 1) {
614 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
615 dy
= (ROWNO
- 1) - cy
;
622 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
] || redraw_cmd(c
)) {
623 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
])
624 getpos_help(force
, goal
);
626 docrt(); /* redraw */
627 /* update message window to reflect that we're still targetting */
628 show_goal_msg
= TRUE
;
630 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]
631 && getpos_hilitefunc
) {
633 (*getpos_hilitefunc
)(0);
634 (*getpos_hilitefunc
)(1);
638 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]) {
639 iflags
.autodescribe
= !iflags
.autodescribe
;
640 pline("Automatic description %sis %s.",
641 flags
.verbose
? "of features under cursor " : "",
642 iflags
.autodescribe
? "on" : "off");
643 if (!iflags
.autodescribe
)
644 show_goal_msg
= TRUE
;
647 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_LIMITVIEW
]) {
648 iflags
.getloc_limitview
= !iflags
.getloc_limitview
;
649 for (i
= 0; i
< NUM_GLOCS
; i
++) {
651 free((genericptr_t
) garr
[i
]);
654 gidx
[i
] = gcount
[i
] = 0;
656 pline("%s possible targets to those in sight only.",
657 iflags
.getloc_limitview
? "Limiting" : "Not limiting");
660 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_MENU
]) {
661 iflags
.getloc_usemenu
= !iflags
.getloc_usemenu
;
662 pline("%s a menu to show possible targets.",
663 iflags
.getloc_usemenu
? "Using" : "Not using");
666 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SELF
]) {
667 /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
668 to achieve that except by manually cycling through all spots */
669 for (i
= 0; i
< NUM_GLOCS
; i
++)
674 } else if ((cp
= index(mMoOdDxX
, c
)) != 0) { /* 'm|M', 'o|O', &c */
675 /* nearest or farthest monster or object or door or unexplored */
676 int gtmp
= (int) (cp
- mMoOdDxX
), /* 0..7 */
677 gloc
= gtmp
>> 1; /* 0..3 */
679 if (iflags
.getloc_usemenu
) {
681 if (getpos_menu(&tmpcrd
, iflags
.getloc_limitview
, gloc
)) {
689 gather_locs(&garr
[gloc
], &gcount
[gloc
], gloc
);
690 gidx
[gloc
] = 0; /* garr[][0] is hero's spot */
692 if (!(gtmp
& 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
693 gidx
[gloc
] = (gidx
[gloc
] + 1) % gcount
[gloc
];
694 } else { /* c=='M' || c=='O' || c=='D' || c=='X') */
695 if (--gidx
[gloc
] < 0)
696 gidx
[gloc
] = gcount
[gloc
] - 1;
698 cx
= garr
[gloc
][gidx
[gloc
]].x
;
699 cy
= garr
[gloc
][gidx
[gloc
]].y
;
702 if (!index(quitchars
, c
)) {
703 char matching
[MAXPCHARS
];
704 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
706 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
707 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++) { /* [0] left as 0 */
708 if (IS_DOOR(sidx
) || IS_WALL(sidx
)
709 || sidx
== SDOOR
|| sidx
== SCORR
710 || glyph_to_cmap(k
) == S_room
711 || glyph_to_cmap(k
) == S_darkroom
712 || glyph_to_cmap(k
) == S_corr
713 || glyph_to_cmap(k
) == S_litcorr
)
715 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
716 matching
[sidx
] = (char) ++k
;
719 for (pass
= 0; pass
<= 1; pass
++) {
720 /* pass 0: just past current pos to lower right;
721 pass 1: upper left corner to current pos */
722 lo_y
= (pass
== 0) ? cy
: 0;
723 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
724 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
725 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
726 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
727 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
728 /* first, look at what is currently visible
729 (might be monster) */
730 k
= glyph_at(tx
, ty
);
732 && matching
[glyph_to_cmap(k
)])
734 /* next, try glyph that's remembered here
735 (might be trap or object) */
736 if (level
.flags
.hero_memory
737 /* !terrainmode: don't move to remembered
738 trap or object if not currently shown */
739 && !iflags
.terrainmode
) {
740 k
= levl
[tx
][ty
].glyph
;
742 && matching
[glyph_to_cmap(k
)])
745 /* last, try actual terrain here (shouldn't
746 we be using lastseentyp[][] instead?) */
747 if (levl
[tx
][ty
].seenv
) {
748 k
= back_to_glyph(tx
, ty
);
750 && matching
[glyph_to_cmap(k
)])
757 clear_nhwindow(WIN_MESSAGE
);
764 pline("Can't find dungeon feature '%c'.", c
);
771 Strcpy(note
, "aborted");
773 Sprintf(note
, "use '%c', '%c', '%c', '%c' or '%s'", /* hjkl */
774 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
776 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
777 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
780 } /* k => matching */
785 msg_given
= FALSE
; /* suppress clear */
788 result
= 0; /* not -1 */
796 curs(WIN_MAP
, cx
, cy
);
800 lock_mouse_cursor(FALSE
);
803 clear_nhwindow(WIN_MESSAGE
);
806 for (i
= 0; i
< NUM_GLOCS
; i
++)
808 free((genericptr_t
) garr
[i
]);
809 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
813 /* allocate space for a monster's name; removes old name if there is one */
817 int lth
; /* desired length (caller handles adding 1 for terminator) */
820 /* allocate mextra if necessary; otherwise get rid of old name */
822 mon
->mextra
= newmextra();
824 free_mname(mon
); /* already has mextra, might also have name */
825 MNAME(mon
) = (char *) alloc((unsigned) lth
);
827 /* zero length: the new name is empty; get rid of the old name */
833 /* release a monster's name; retains mextra even if all fields are now null */
838 if (has_mname(mon
)) {
839 free((genericptr_t
) MNAME(mon
));
840 MNAME(mon
) = (char *) 0;
844 /* allocate space for an object's name; removes old name if there is one */
848 int lth
; /* desired length (caller handles adding 1 for terminator) */
851 /* allocate oextra if necessary; otherwise get rid of old name */
853 obj
->oextra
= newoextra();
855 free_oname(obj
); /* already has oextra, might also have name */
856 ONAME(obj
) = (char *) alloc((unsigned) lth
);
858 /* zero length: the new name is empty; get rid of the old name */
864 /* release an object's name; retains oextra even if all fields are now null */
869 if (has_oname(obj
)) {
870 free((genericptr_t
) ONAME(obj
));
871 ONAME(obj
) = (char *) 0;
875 /* safe_oname() always returns a valid pointer to
876 * a string, either the pointer to an object's name
877 * if it has one, or a pointer to an empty string
889 /* historical note: this returns a monster pointer because it used to
890 allocate a new bigger block of memory to hold the monster and its name */
892 christen_monst(mtmp
, name
)
899 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
900 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
903 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
904 buf
[PL_PSIZ
- 1] = '\0';
906 new_mname(mtmp
, lth
); /* removes old name if one is present */
908 Strcpy(MNAME(mtmp
), name
);
912 /* check whether user-supplied name matches or nearly matches an unnameable
913 monster's name; if so, give an alternate reject message for do_mname() */
915 alreadynamed(mtmp
, monnambuf
, usrbuf
)
917 char *monnambuf
, *usrbuf
;
919 char pronounbuf
[10], *p
;
921 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
922 /* catch trying to name "the Oracle" as "Oracle" */
923 || (!strncmpi(monnambuf
, "the ", 4)
924 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
925 /* catch trying to name "invisible Orcus" as "Orcus" */
926 || ((p
= strstri(monnambuf
, "invisible ")) != 0
927 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
928 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
929 || ((p
= strstri(monnambuf
, " of ")) != 0
930 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
931 pline("%s is already called %s.",
932 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
934 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
935 && strstri(monnambuf
, "Juiblex")
936 && !strcmpi(usrbuf
, "Jubilex")) {
937 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
943 /* allow player to assign a name to some chosen monster */
947 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
950 struct monst
*mtmp
= 0;
953 You("would never recognize it anyway.");
958 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
963 if (cx
== u
.ux
&& cy
== u
.uy
) {
964 if (u
.usteed
&& canspotmon(u
.usteed
)) {
967 pline("This %s creature is called %s and cannot be renamed.",
968 beautiful(), plname
);
976 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
977 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
978 || mtmp
->m_ap_type
== M_AP_OBJECT
979 || (mtmp
->minvis
&& !See_invisible
)))) {
980 pline("I see no monster there.");
983 /* special case similar to the one in lookat() */
984 Sprintf(qbuf
, "What do you want to call %s?",
985 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
987 if (!*buf
|| *buf
== '\033')
989 /* strip leading and trailing spaces; unnames monster if all spaces */
990 (void) mungspaces(buf
);
992 /* Unique monsters have their own specific names or titles.
993 * Shopkeepers, temple priests and other minions use alternate
994 * name formatting routines which ignore any user-supplied name.
996 * Don't say the name is being rejected if it happens to match
999 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
1000 if (!alreadynamed(mtmp
, monnambuf
, buf
))
1001 pline("%s doesn't like being called names!", upstart(monnambuf
));
1002 } else if (mtmp
->isshk
1003 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
1004 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
1005 if (!alreadynamed(mtmp
, monnambuf
, buf
))
1006 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
1007 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
1008 if (!alreadynamed(mtmp
, monnambuf
, buf
))
1009 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
1011 (void) christen_monst(mtmp
, buf
);
1015 * This routine changes the address of obj. Be careful not to call it
1016 * when there might be pointers around in unknown places. For now: only
1017 * when obj is in the inventory.
1022 register struct obj
*obj
;
1024 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
1028 /* Do this now because there's no point in even asking for a name */
1029 if (obj
->otyp
== SPE_NOVEL
) {
1030 pline("%s already has a published name.", Ysimple_name2(obj
));
1034 Sprintf(qbuf
, "What do you want to name %s ",
1035 is_plural(obj
) ? "these" : "this");
1036 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
1038 if (!*buf
|| *buf
== '\033')
1040 /* strip leading and trailing spaces; unnames item if all spaces */
1041 (void) mungspaces(buf
);
1044 * We don't violate illiteracy conduct here, although it is
1045 * arguable that we should for anything other than "X". Doing so
1046 * would make attaching player's notes to hero's inventory have an
1047 * in-game effect, which may or may not be the correct thing to do.
1049 * We do violate illiteracy in oname() if player creates Sting or
1050 * Orcrist, clearly being literate (no pun intended...).
1053 /* relax restrictions over proper capitalization for artifacts */
1054 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
1057 if (obj
->oartifact
) {
1058 pline_The("artifact seems to resist the attempt.");
1060 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
1061 /* this used to change one letter, substituting a value
1062 of 'a' through 'y' (due to an off by one error, 'z'
1063 would never be selected) and then force that to
1064 upper case if such was the case of the input;
1065 now, the hand slip scuffs one or two letters as if
1066 the text had been trodden upon, sometimes picking
1067 punctuation instead of an arbitrary letter;
1068 unfortunately, we have to cover the possibility of
1069 it targetting spaces so failing to make any change
1070 (we know that it must eventually target a nonspace
1071 because buf[] matches a valid artifact name) */
1072 Strcpy(bufcpy
, buf
);
1073 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
1074 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
1076 wipeout_text(bufp
, rnd(2), (unsigned) 0);
1077 } while (!strcmp(buf
, bufcpy
));
1078 pline("While engraving, your %s slips.", body_part(HAND
));
1079 display_nhwindow(WIN_MESSAGE
, FALSE
);
1080 You("engrave: \"%s\".", buf
);
1082 obj
= oname(obj
, buf
);
1093 lth
= *name
? (int) (strlen(name
) + 1) : 0;
1094 if (lth
> PL_PSIZ
) {
1096 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
1097 buf
[PL_PSIZ
- 1] = '\0';
1099 /* If named artifact exists in the game, do not create another.
1100 * Also trying to create an artifact shouldn't de-artifact
1101 * it (e.g. Excalibur from prayer). In this case the object
1102 * will retain its current name. */
1103 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
1106 new_oname(obj
, lth
); /* removes old name if one is present */
1108 Strcpy(ONAME(obj
), name
);
1111 artifact_exists(obj
, name
, TRUE
);
1112 if (obj
->oartifact
) {
1113 /* can't dual-wield with artifact as secondary weapon */
1114 if (obj
== uswapwep
)
1116 /* activate warning if you've just named your weapon "Sting" */
1118 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
1119 /* if obj is owned by a shop, increase your bill */
1121 alter_cost(obj
, 0L);
1122 /* violate illiteracy conduct since successfully wrote arti-name */
1123 u
.uconduct
.literate
++;
1130 static NEARDATA
const char callable
[] = {
1131 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
1132 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
1136 objtyp_is_callable(i
)
1139 return (boolean
) (objects
[i
].oc_uname
1140 || (OBJ_DESCR(objects
[i
])
1141 && index(callable
, objects
[i
].oc_class
)));
1144 /* C and #name commands - player can name monster or object or type of obj */
1151 menu_item
*pick_list
= 0;
1152 char ch
, allowall
[2];
1153 /* if player wants a,b,c instead of i,o when looting, do that here too */
1154 boolean abc
= flags
.lootabc
;
1156 win
= create_nhwindow(NHW_MENU
);
1159 any
.a_char
= 'm'; /* group accelerator 'C' */
1160 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
1161 "a monster", MENU_UNSELECTED
);
1163 /* we use y and n as accelerators so that we can accept user's
1164 response keyed to old "name an individual object?" prompt */
1165 any
.a_char
= 'i'; /* group accelerator 'y' */
1166 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
1167 "a particular object in inventory", MENU_UNSELECTED
);
1168 any
.a_char
= 'o'; /* group accelerator 'n' */
1169 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
1170 "the type of an object in inventory", MENU_UNSELECTED
);
1172 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
1173 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
1174 "the type of an object upon the floor", MENU_UNSELECTED
);
1175 any
.a_char
= 'd'; /* group accelerator '\' */
1176 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
1177 "the type of an object on discoveries list", MENU_UNSELECTED
);
1178 any
.a_char
= 'a'; /* group accelerator 'l' */
1179 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
1180 "record an annotation for the current level", MENU_UNSELECTED
);
1181 end_menu(win
, "What do you want to name?");
1182 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
1183 ch
= pick_list
[0].item
.a_char
;
1184 free((genericptr_t
) pick_list
);
1187 destroy_nhwindow(win
);
1193 case 'm': /* name a visible monster */
1196 case 'i': /* name an individual object in inventory */
1197 allowall
[0] = ALL_CLASSES
;
1199 obj
= getobj(allowall
, "name");
1203 case 'o': /* name a type of object in inventory */
1204 obj
= getobj(callable
, "call");
1206 /* behave as if examining it in inventory;
1207 this might set dknown if it was picked up
1208 while blind and the hero can now see */
1212 You("would never recognize another one.");
1214 } else if (!objtyp_is_callable(obj
->otyp
)) {
1215 You("know those as well as you ever will.");
1222 case 'f': /* name a type of object visible on the floor */
1225 case 'd': /* name a type of object on the discoveries list */
1228 case 'a': /* annotate level */
1237 register struct obj
*obj
;
1239 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
1241 register char **str1
;
1244 return; /* probably blind */
1247 otemp
.oextra
= (struct oextra
*) 0;
1249 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
1250 /* kludge, meaning it's sink water */
1251 Sprintf(qbuf
, "Call a stream of %s fluid:",
1252 OBJ_DESCR(objects
[otemp
.otyp
]));
1254 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
1256 if (!*buf
|| *buf
== '\033')
1259 /* clear old name */
1260 str1
= &(objects
[obj
->otyp
].oc_uname
);
1262 free((genericptr_t
) *str1
);
1264 /* strip leading and trailing spaces; uncalls item if all spaces */
1265 (void) mungspaces(buf
);
1267 if (*str1
) { /* had name, so possibly remove from disco[] */
1268 /* strip name first, for the update_inventory() call
1269 from undiscover_object() */
1271 undiscover_object(obj
->otyp
);
1274 *str1
= dupstr(buf
);
1275 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
1285 struct obj
*obj
= 0;
1286 boolean fakeobj
= FALSE
, use_plural
;
1288 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
1289 /* "dot for under/over you" only makes sense when the cursor hasn't
1290 been moved off the hero's '@' yet, but there's no way to adjust
1291 the help text once getpos() has started */
1292 Sprintf(buf
, "object on map (or '.' for one %s you)",
1293 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
1294 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
1296 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1297 obj
= vobj_at(u
.ux
, u
.uy
);
1299 glyph
= glyph_at(cc
.x
, cc
.y
);
1300 if (glyph_is_object(glyph
))
1301 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
1302 /* else 'obj' stays null */
1305 /* "under you" is safe here since there's no object to hide under */
1306 pline("There doesn't seem to be any object %s.",
1307 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
1310 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1311 is a mimic; passing that to xname (directly or via simpleonames)
1312 would yield "glorkum" so we need to handle it explicitly; it will
1313 always fail the Hallucination test and pass the !callable test,
1314 resulting in the "can't be assigned a type name" message */
1315 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
1317 : obj_descr
[STRANGE_OBJECT
].oc_name
);
1318 use_plural
= (obj
->quan
> 1L);
1319 if (Hallucination
) {
1320 const char *unames
[6];
1323 /* straight role name */
1324 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1327 /* random rank title for hero's role */
1328 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
1329 /* random fake monster */
1330 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
1331 /* increased chance for fake monster */
1332 unames
[3] = unames
[2];
1334 unames
[4] = roguename();
1336 unames
[5] = "Wibbly Wobbly";
1337 pline("%s %s to call you \"%s.\"",
1338 The(buf
), use_plural
? "decide" : "decides",
1339 unames
[rn2(SIZE(unames
))]);
1340 } else if (!objtyp_is_callable(obj
->otyp
)) {
1341 pline("%s %s can't be assigned a type name.",
1342 use_plural
? "Those" : "That", buf
);
1343 } else if (!obj
->dknown
) {
1344 You("don't know %s %s well enough to name %s.",
1345 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
1353 static const char *const ghostnames
[] = {
1354 /* these names should have length < PL_NSIZ */
1355 /* Capitalize the names for aesthetics -dgk */
1356 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1357 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1358 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1359 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1360 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1361 "Stephan", "Lance Braccus", "Shadowhawk"
1364 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1368 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
1372 * Monster naming functions:
1373 * x_monnam is the generic monster-naming function.
1374 * seen unseen detected named
1375 * mon_nam: the newt it the invisible orc Fido
1376 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1377 * l_monnam: newt it invisible orc dog called Fido
1378 * Monnam: The newt It The invisible orc Fido
1379 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1380 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1381 * Amonnam: A newt It An invisible orc Fido
1382 * a_monnam: a newt it an invisible orc Fido
1383 * m_monnam: newt xan orc Fido
1384 * y_monnam: your newt your xan your invisible orc Fido
1387 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1388 * options works, since those are special cases.
1391 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
1392 register struct monst
*mtmp
;
1394 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1395 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1397 * If the monster would be referred to as "it" or if the monster has a name
1398 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1399 * and always use no article.
1401 const char *adjective
;
1403 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1404 * EXACT_NAME: combination of all the above
1408 char *buf
= nextmbuf();
1409 struct permonst
*mdat
= mtmp
->data
;
1410 const char *pm_name
= mdat
->mname
;
1411 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
1412 boolean name_at_start
, has_adjectives
;
1415 if (program_state
.gameover
)
1416 suppress
|= SUPPRESS_HALLUCINATION
;
1417 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
1418 article
= ARTICLE_THE
;
1420 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
1421 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
1422 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
1423 && !program_state
.gameover
&& mtmp
!= u
.usteed
1424 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
1425 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
1429 /* unseen monsters, etc. Use "it" */
1435 /* priests and minions: don't even use this function */
1436 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1437 char priestnambuf
[BUFSZ
];
1439 long save_prop
= EHalluc_resistance
;
1440 unsigned save_invis
= mtmp
->minvis
;
1442 /* when true name is wanted, explicitly block Hallucination */
1444 EHalluc_resistance
= 1L;
1447 name
= priestname(mtmp
, priestnambuf
);
1448 EHalluc_resistance
= save_prop
;
1449 mtmp
->minvis
= save_invis
;
1450 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1452 return strcpy(buf
, name
);
1454 /* an "aligned priest" not flagged as a priest or minion should be
1455 "priest" or "priestess" (normally handled by priestname()) */
1456 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1457 pm_name
= mtmp
->female
? "priestess" : "priest";
1458 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1459 pm_name
= "high priestess";
1461 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1462 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1463 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1464 * none of this applies.
1466 if (mtmp
->isshk
&& !do_hallu
) {
1467 if (adjective
&& article
== ARTICLE_THE
) {
1468 /* pathological case: "the angry Asidonhopo the blue dragon"
1470 Strcpy(buf
, "the ");
1471 Strcat(strcat(buf
, adjective
), " ");
1472 Strcat(buf
, shkname(mtmp
));
1475 Strcat(buf
, shkname(mtmp
));
1476 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1478 Strcat(buf
, " the ");
1480 Strcat(buf
, "invisible ");
1481 Strcat(buf
, pm_name
);
1485 /* Put the adjectives in the buffer */
1487 Strcat(strcat(buf
, adjective
), " ");
1489 Strcat(buf
, "invisible ");
1490 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1492 Strcat(buf
, "saddled ");
1494 has_adjectives
= TRUE
;
1496 has_adjectives
= FALSE
;
1498 /* Put the actual monster name or type into the buffer now */
1499 /* Be sure to remember whether the buffer starts with a name */
1502 char *rname
= rndmonnam(&rnamecode
);
1505 name_at_start
= bogon_is_pname(rnamecode
);
1506 } else if (has_mname(mtmp
)) {
1507 char *name
= MNAME(mtmp
);
1509 if (mdat
== &mons
[PM_GHOST
]) {
1510 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1511 name_at_start
= TRUE
;
1512 } else if (called
) {
1513 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1514 name_at_start
= (boolean
) type_is_pname(mdat
);
1515 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1516 /* <name> the <adjective> <invisible> <saddled> <rank> */
1520 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1523 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1525 article
= ARTICLE_NONE
;
1526 name_at_start
= TRUE
;
1529 name_at_start
= TRUE
;
1531 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1534 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1535 (boolean
) mtmp
->female
));
1536 Strcat(buf
, lcase(pbuf
));
1537 name_at_start
= FALSE
;
1539 Strcat(buf
, pm_name
);
1540 name_at_start
= (boolean
) type_is_pname(mdat
);
1543 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1544 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1545 article
= ARTICLE_THE
;
1547 article
= ARTICLE_NONE
;
1548 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1549 article
= ARTICLE_THE
;
1557 Strcpy(buf2
, "your ");
1562 Strcpy(buf2
, "the ");
1579 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1580 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1587 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1588 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1591 /* print the name as if mon_nam() was called, but assume that the player
1592 * can always see the monster--used for probing and for monsters aggravating
1593 * the player with a cursed potion of invisibility
1599 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1600 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1609 register char *bp
= mon_nam(mtmp
);
1619 register char *bp
= noit_mon_nam(mtmp
);
1625 /* monster's own name */
1630 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1633 /* pet name: "your little dog" */
1638 int prefix
, suppression_flag
;
1640 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1641 suppression_flag
= (has_mname(mtmp
)
1642 /* "saddled" is redundant when mounted */
1643 || mtmp
== u
.usteed
)
1647 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1651 Adjmonnam(mtmp
, adj
)
1655 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1656 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1666 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1667 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1674 char *bp
= a_monnam(mtmp
);
1680 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1681 identification of the endgame altars via their attending priests */
1683 distant_monnam(mon
, article
, outbuf
)
1685 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1688 /* high priest(ess)'s identity is concealed on the Astral Plane,
1689 unless you're adjacent (overridden for hallucination which does
1690 its own obfuscation) */
1691 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1692 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1693 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1694 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1696 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1701 /* fake monsters used to be in a hard-coded array, now in a data file */
1708 get_rnd_text(BOGUSMONFILE
, buf
);
1709 /* strip prefix if present */
1710 if (!letter(*mname
)) {
1721 /* return a random monster name, for hallucination */
1726 static char buf
[BUFSZ
];
1729 #define BOGUSMONSIZE 100 /* arbitrary */
1735 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1736 } while (name
< SPECIAL_PM
1737 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1739 if (name
>= SPECIAL_PM
) {
1740 mname
= bogusmon(buf
, code
);
1742 mname
= strcpy(buf
, mons
[name
].mname
);
1748 /* check bogusmon prefix to decide whether it's a personal name */
1750 bogon_is_pname(code
)
1755 return index("-+=", code
) ? TRUE
: FALSE
;
1758 /* name of a Rogue player */
1764 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1765 for (i
= opts
; *i
; i
++)
1766 if (!strncmp("name=", i
, 5)) {
1768 if ((j
= index(i
+ 5, ',')) != 0)
1773 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1777 static NEARDATA
const char *const hcolors
[] = {
1778 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1779 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1780 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1781 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1782 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1783 "strawberry-banana", "peppermint", "romantic", "incandescent",
1784 "octarine", /* Discworld: the Colour of Magic */
1789 const char *colorpref
;
1791 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1795 /* return a random real color unless hallucinating */
1799 int k
= rn2(CLR_MAX
);
1801 return Hallucination
? hcolor((char *) 0)
1802 : (k
== NO_COLOR
) ? "colorless"
1806 static NEARDATA
const char *const hliquids
[] = {
1807 "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
1808 "instant coffee", "tea", "herbal infusion", "liquid rainbow",
1809 "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
1810 "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
1811 "caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
1812 "glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
1813 "sweet vitriol", "grey goo", "pink slime",
1818 const char *liquidpref
;
1820 return (Hallucination
|| !liquidpref
) ? hliquids
[rn2(SIZE(hliquids
))]
1824 /* Aliases for road-runner nemesis
1826 static const char *const coynames
[] = {
1827 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1828 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1829 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1830 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1831 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1832 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1833 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1838 coyotename(mtmp
, buf
)
1843 Sprintf(buf
, "%s - %s",
1844 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1845 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1846 : coynames
[mtmp
->m_id
% (SIZE(coynames
) - 1)]);
1851 /* make sure "The Colour of Magic" remains the first entry in here */
1852 static const char *const sir_Terry_novels
[] = {
1853 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1854 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1855 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1856 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1857 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1858 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1859 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1860 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1861 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1862 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1863 "Raising Steam", "The Shepherd's Crown"
1870 int j
, k
= SIZE(sir_Terry_novels
);
1876 else if (*novidx
>= 0 && *novidx
< k
)
1879 return sir_Terry_novels
[j
];
1883 lookup_novel(lookname
, idx
)
1884 const char *lookname
;
1889 /* Take American or U.K. spelling of this one */
1890 if (!strcmpi(The(lookname
), "The Color of Magic"))
1891 lookname
= sir_Terry_novels
[0];
1893 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1894 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1895 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1898 return sir_Terry_novels
[k
];
1901 /* name not found; if novelidx is already set, override the name */
1902 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1903 return sir_Terry_novels
[*idx
];
1905 return (const char *) 0;