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 Sprintf(sbuf
, "Use '%s' for a menu of interesting targets in view.",
92 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MENU_FOV
]));
93 putstr(tmpwin
, 0, sbuf
);
94 Sprintf(sbuf
, "Use '%s' for a menu of all interesting targets.",
95 visctrl(Cmd
.spkeys
[NHKF_GETPOS_MENU
]));
96 putstr(tmpwin
, 0, sbuf
);
97 if (!iflags
.terrainmode
) {
99 if (getpos_hilitefunc
) {
100 Sprintf(sbuf
, "Use '%s' to display valid locations.",
101 visctrl(Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]));
102 putstr(tmpwin
, 0, sbuf
);
104 Sprintf(sbuf
, "Use '%s' to toggle automatic description.",
105 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
106 putstr(tmpwin
, 0, sbuf
);
107 if (iflags
.cmdassist
) { /* assisting the '/' command, I suppose... */
109 (iflags
.getpos_coords
== GPCOORDS_NONE
)
110 ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
111 : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
112 visctrl(Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]));
114 /* disgusting hack; the alternate selection characters work for any
115 getpos call, but only matter for dowhatis (and doquickwhatis) */
116 doing_what_is
= (goal
== what_is_an_unknown_object
);
118 Sprintf(kbuf
, "'%s' or '%s' or '%s' or '%s'",
119 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
120 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]),
121 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]),
122 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
124 Sprintf(kbuf
, "'%s'", visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
126 Sprintf(sbuf
, "Type a %s when you are at the right place.", kbuf
);
127 putstr(tmpwin
, 0, sbuf
);
130 " '%s' describe current spot, show 'more info', move to another spot.",
131 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_V
]));
132 putstr(tmpwin
, 0, sbuf
);
134 " '%s' describe current spot,%s move to another spot;",
135 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]),
136 flags
.help
? " prompt if 'more info'," : "");
137 putstr(tmpwin
, 0, sbuf
);
139 " '%s' describe current spot, move to another spot;",
140 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_Q
]));
141 putstr(tmpwin
, 0, sbuf
);
143 " '%s' describe current spot, stop looking at things;",
144 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK_O
]));
145 putstr(tmpwin
, 0, sbuf
);
149 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
150 putstr(tmpwin
, 0, "");
151 display_nhwindow(tmpwin
, TRUE
);
152 destroy_nhwindow(tmpwin
);
156 cmp_coord_distu(a
, b
)
162 int dx
, dy
, dist_1
, dist_2
;
166 dist_1
= max(abs(dx
), abs(dy
));
169 dist_2
= max(abs(dx
), abs(dy
));
171 if (dist_1
== dist_2
)
172 return (c1
->y
!= c2
->y
) ? (c1
->y
- c2
->y
) : (c1
->x
- c2
->x
);
174 return dist_1
- dist_2
;
190 #define IS_UNEXPLORED_LOC(x,y) \
192 && glyph_is_cmap(levl[(x)][(y)].glyph) \
193 && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
194 && !levl[(x)][(y)].seenv)
197 gather_locs_interesting(x
,y
, gloc
)
200 /* TODO: if glyph is a pile glyph, convert to ordinary one
201 * in order to keep tail/boulder/rock check simple.
203 int glyph
= glyph_at(x
, y
);
208 /* unlike '/M', this skips monsters revealed by
209 warning glyphs and remembered unseen ones */
210 return (glyph_is_monster(glyph
)
211 && glyph
!= monnum_to_glyph(PM_LONG_WORM_TAIL
));
213 return (glyph_is_object(glyph
)
214 && glyph
!= objnum_to_glyph(BOULDER
)
215 && glyph
!= objnum_to_glyph(ROCK
));
217 return (glyph_is_cmap(glyph
)
218 && (is_cmap_door(glyph_to_cmap(glyph
))
219 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
220 || glyph_to_cmap(glyph
) == S_ndoor
));
222 return (glyph_is_cmap(glyph
)
223 && (is_cmap_door(glyph_to_cmap(glyph
))
224 || is_cmap_drawbridge(glyph_to_cmap(glyph
))
225 || glyph_to_cmap(glyph
) == S_ndoor
226 || glyph_to_cmap(glyph
) == S_room
227 || glyph_to_cmap(glyph
) == S_darkroom
228 || glyph_to_cmap(glyph
) == S_corr
229 || glyph_to_cmap(glyph
) == S_litcorr
)
230 && (IS_UNEXPLORED_LOC(x
+ 1, y
)
231 || IS_UNEXPLORED_LOC(x
- 1, y
)
232 || IS_UNEXPLORED_LOC(x
, y
+ 1)
233 || IS_UNEXPLORED_LOC(x
, y
- 1)));
234 case GLOC_INTERESTING_FOV
:
237 case GLOC_INTERESTING
:
238 return gather_locs_interesting(x
,y
, GLOC_DOOR
)
239 || !(glyph_is_cmap(glyph
)
240 && (is_cmap_wall(glyph_to_cmap(glyph
))
241 || glyph_to_cmap(glyph
) == S_tree
242 || glyph_to_cmap(glyph
) == S_bars
243 || glyph_to_cmap(glyph
) == S_ice
244 || glyph_to_cmap(glyph
) == S_air
245 || glyph_to_cmap(glyph
) == S_cloud
246 || glyph_to_cmap(glyph
) == S_lava
247 || glyph_to_cmap(glyph
) == S_water
248 || glyph_to_cmap(glyph
) == S_pool
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
));
259 /* gather locations for monsters or objects shown on the map */
261 gather_locs(arr_p
, cnt_p
, gloc
)
269 * We always include the hero's location even if there is no monster
270 * (invisible hero without see invisible) or object (usual case)
271 * displayed there. That way, the count will always be at least 1,
272 * and player has a visual indicator (cursor returns to hero's spot)
273 * highlighting when successive 'm's or 'o's have cycled all the way
274 * through all monsters or objects.
276 * Hero's spot will always sort to array[0] because it will always
277 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
280 for (pass
= 0; pass
< 2; pass
++) {
281 for (x
= 1; x
< COLNO
; x
++)
282 for (y
= 0; y
< ROWNO
; y
++) {
283 if ((x
== u
.ux
&& y
== u
.uy
)
284 || gather_locs_interesting(x
, y
, gloc
)) {
295 if (!pass
) /* end of first pass */
296 *arr_p
= (coord
*) alloc(*cnt_p
* sizeof (coord
));
297 else /* end of second pass */
298 qsort(*arr_p
, *cnt_p
, sizeof (coord
), cmp_coord_distu
);
303 dxdy_to_dist_descr(dx
, dy
, fulldir
)
311 Sprintf(buf
, "here");
312 } else if ((dst
= xytod(dx
, dy
)) != -1) {
313 /* explicit direction; 'one step' is implicit */
314 Sprintf(buf
, "%s", directionname(dst
));
316 const char *dirnames
[4][2] = {
322 /* 9999: protect buf[] against overflow caused by invalid values */
326 Sprintf(eos(buf
), "%d%s%s", abs(dy
), dirnames
[(dy
> 0)][fulldir
],
332 Sprintf(eos(buf
), "%d%s", abs(dx
), dirnames
[2 + (dx
> 0)][fulldir
]);
338 /* coordinate formatting for 'whatis_coord' option */
340 coord_desc(x
, y
, outbuf
, cmode
)
344 static char screen_fmt
[16]; /* [12] suffices: "[%02d,%02d]" */
351 case GPCOORDS_COMFULL
:
352 case GPCOORDS_COMPASS
:
353 /* "east", "3s", "2n,4w" */
356 Sprintf(outbuf
, "(%s)",
357 dxdy_to_dist_descr(dx
, dy
, cmode
== GPCOORDS_COMFULL
));
359 case GPCOORDS_MAP
: /* x,y */
360 /* upper left corner of map is <1,0>;
361 with default COLNO,ROWNO lower right corner is <79,20> */
362 Sprintf(outbuf
, "<%d,%d>", x
, y
);
364 case GPCOORDS_SCREEN
: /* y+2,x */
365 /* for normal map sizes, force a fixed-width formatting so that
366 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
367 than Nx999 or 999xM will still work, but not line up like normal
368 when displayed in a column setting */
370 Sprintf(screen_fmt
, "[%%%sd,%%%sd]",
371 (ROWNO
- 1 + 2 < 100) ? "02" : "03",
372 (COLNO
- 1 < 100) ? "02" : "03");
373 /* map line 0 is screen row 2;
374 map column 0 isn't used, map column 1 is screen column 1 */
375 Sprintf(outbuf
, screen_fmt
, y
+ 2, x
);
382 auto_describe(cx
, cy
)
388 const char *firstmatch
= "unknown";
392 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
393 (void) coord_desc(cx
, cy
, tmpbuf
, iflags
.getpos_coords
);
394 pline("%s%s%s%s", firstmatch
, *tmpbuf
? " " : "", tmpbuf
,
395 (iflags
.getloc_travelmode
&& !is_valid_travelpt(cx
,cy
))
396 ? " (no travel path)" : "");
397 curs(WIN_MAP
, cx
, cy
);
403 getpos_menu(ccp
, fovonly
)
412 menu_item
*picks
= (menu_item
*) 0;
415 gather_locs(&garr
, &gcount
,
416 fovonly
? GLOC_INTERESTING_FOV
: GLOC_INTERESTING
);
417 if (gcount
< 2) { /* gcount always includes the hero */
418 free((genericptr_t
) garr
);
419 You("cannot %s anything interesting.", fovonly
? "see" : "detect");
423 tmpwin
= create_nhwindow(NHW_MENU
);
427 for (i
= 0; i
< gcount
; i
++) {
430 const char *firstmatch
= "unknown";
435 if (do_screen_description(tmpcc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
436 (void) coord_desc(garr
[i
].x
, garr
[i
].y
, tmpbuf
, iflags
.getpos_coords
);
437 Sprintf(fullbuf
, "%s%s%s", firstmatch
, (*tmpbuf
? " " : ""), tmpbuf
);
438 add_menu(tmpwin
, NO_GLYPH
, &any
, 0, 0, ATR_NONE
, fullbuf
,
443 Sprintf(tmpbuf
, "Pick a target%s%s",
444 fovonly
? " in view" : "",
445 iflags
.getloc_travelmode
? " for travel" : "");
446 end_menu(tmpwin
, tmpbuf
);
447 pick_cnt
= select_menu(tmpwin
, PICK_ONE
, &picks
);
448 destroy_nhwindow(tmpwin
);
450 ccp
->x
= garr
[picks
->item
.a_int
- 1].x
;
451 ccp
->y
= garr
[picks
->item
.a_int
- 1].y
;
452 free((genericptr_t
) picks
);
454 free((genericptr_t
) garr
);
455 return (pick_cnt
> 0);
459 getpos(ccp
, force
, goal
)
467 } const pick_chars_def
[] = {
468 { NHKF_GETPOS_PICK
, LOOK_TRADITIONAL
},
469 { NHKF_GETPOS_PICK_Q
, LOOK_QUICK
},
470 { NHKF_GETPOS_PICK_O
, LOOK_ONCE
},
471 { NHKF_GETPOS_PICK_V
, LOOK_VERBOSE
}
473 const int mMoOdDxX_def
[] = {
474 NHKF_GETPOS_MON_NEXT
,
475 NHKF_GETPOS_MON_PREV
,
476 NHKF_GETPOS_OBJ_NEXT
,
477 NHKF_GETPOS_OBJ_PREV
,
478 NHKF_GETPOS_DOOR_NEXT
,
479 NHKF_GETPOS_DOOR_PREV
,
480 NHKF_GETPOS_UNEX_NEXT
,
481 NHKF_GETPOS_UNEX_PREV
488 boolean msg_given
= TRUE
; /* clear message window by default */
489 boolean show_goal_msg
= FALSE
;
490 boolean hilite_state
= FALSE
;
491 coord
*garr
[NUM_GLOCS
] = DUMMY
;
492 int gcount
[NUM_GLOCS
] = DUMMY
;
493 int gidx
[NUM_GLOCS
] = DUMMY
;
495 for (i
= 0; i
< SIZE(pick_chars_def
); i
++)
496 pick_chars
[i
] = Cmd
.spkeys
[pick_chars_def
[i
].nhkf
];
497 pick_chars
[SIZE(pick_chars_def
)] = '\0';
499 for (i
= 0; i
< SIZE(mMoOdDxX_def
); i
++)
500 mMoOdDxX
[i
] = Cmd
.spkeys
[mMoOdDxX_def
[i
]];
501 mMoOdDxX
[SIZE(mMoOdDxX_def
)] = '\0';
504 goal
= "desired location";
506 pline("(For instructions type a '%s')",
507 visctrl(Cmd
.spkeys
[NHKF_GETPOS_HELP
]));
515 curs(WIN_MAP
, cx
, cy
);
518 lock_mouse_cursor(TRUE
);
522 pline("Move cursor to %s:", goal
);
523 curs(WIN_MAP
, cx
, cy
);
525 show_goal_msg
= FALSE
;
526 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
527 auto_describe(cx
, cy
);
530 c
= nh_poskey(&tx
, &ty
, &sidx
);
533 (*getpos_hilitefunc
)(2);
534 hilite_state
= FALSE
;
535 curs(WIN_MAP
, cx
, cy
);
539 if (iflags
.autodescribe
)
542 if (c
== Cmd
.spkeys
[NHKF_ESC
]) {
544 msg_given
= TRUE
; /* force clear */
551 /* a mouse click event, just assign and return */
556 if ((cp
= index(pick_chars
, c
)) != 0) {
557 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
558 result
= pick_chars_def
[(int) (cp
- pick_chars
)].ret
;
561 for (i
= 0; i
< 8; i
++) {
564 if (Cmd
.dirchars
[i
] == c
) {
565 /* a normal movement letter or digit */
568 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
569 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
570 /* a shifted movement letter or Meta-digit */
576 /* truncate at map edge; diagonal moves complicate this... */
578 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
579 dx
= 1 - cx
; /* so that (cx+dx == 1) */
580 } else if (cx
+ dx
> COLNO
- 1) {
581 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
582 dx
= (COLNO
- 1) - cx
;
585 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
586 dy
= 0 - cy
; /* so that (cy+dy == 0) */
587 } else if (cy
+ dy
> ROWNO
- 1) {
588 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
589 dy
= (ROWNO
- 1) - cy
;
596 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
] || redraw_cmd(c
)) {
597 if (c
== Cmd
.spkeys
[NHKF_GETPOS_HELP
])
598 getpos_help(force
, goal
);
600 docrt(); /* redraw */
601 /* update message window to reflect that we're still targetting */
602 show_goal_msg
= TRUE
;
604 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SHOWVALID
]
605 && getpos_hilitefunc
) {
607 (*getpos_hilitefunc
)(0);
608 (*getpos_hilitefunc
)(1);
612 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_AUTODESC
]) {
613 iflags
.autodescribe
= !iflags
.autodescribe
;
614 pline("Automatic description %sis %s.",
615 flags
.verbose
? "of features under cursor " : "",
616 iflags
.autodescribe
? "on" : "off");
617 if (!iflags
.autodescribe
)
618 show_goal_msg
= TRUE
;
621 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_MENU
]
622 || c
== Cmd
.spkeys
[NHKF_GETPOS_MENU_FOV
]) {
624 if (getpos_menu(&tmpcrd
, (c
== Cmd
.spkeys
[NHKF_GETPOS_MENU_FOV
]))) {
629 } else if (c
== Cmd
.spkeys
[NHKF_GETPOS_SELF
]) {
630 /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
631 to achieve that except by manually cycling through all spots */
632 for (i
= 0; i
< NUM_GLOCS
; i
++)
637 } else if ((cp
= index(mMoOdDxX
, c
)) != 0) { /* 'm|M', 'o|O', &c */
638 /* nearest or farthest monster or object or door or unexplored */
639 int gtmp
= (int) (cp
- mMoOdDxX
), /* 0..7 */
640 gloc
= gtmp
>> 1; /* 0..3 */
643 gather_locs(&garr
[gloc
], &gcount
[gloc
], gloc
);
644 gidx
[gloc
] = 0; /* garr[][0] is hero's spot */
646 if (!(gtmp
& 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
647 gidx
[gloc
] = (gidx
[gloc
] + 1) % gcount
[gloc
];
648 } else { /* c=='M' || c=='O' || c=='D' || c=='X') */
649 if (--gidx
[gloc
] < 0)
650 gidx
[gloc
] = gcount
[gloc
] - 1;
652 cx
= garr
[gloc
][gidx
[gloc
]].x
;
653 cy
= garr
[gloc
][gidx
[gloc
]].y
;
656 if (!index(quitchars
, c
)) {
657 char matching
[MAXPCHARS
];
658 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
660 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
661 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++) { /* [0] left as 0 */
662 if (IS_DOOR(sidx
) || IS_WALL(sidx
)
663 || sidx
== SDOOR
|| sidx
== SCORR
664 || glyph_to_cmap(k
) == S_room
665 || glyph_to_cmap(k
) == S_darkroom
666 || glyph_to_cmap(k
) == S_corr
667 || glyph_to_cmap(k
) == S_litcorr
)
669 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
670 matching
[sidx
] = (char) ++k
;
673 for (pass
= 0; pass
<= 1; pass
++) {
674 /* pass 0: just past current pos to lower right;
675 pass 1: upper left corner to current pos */
676 lo_y
= (pass
== 0) ? cy
: 0;
677 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
678 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
679 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
680 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
681 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
682 /* first, look at what is currently visible
683 (might be monster) */
684 k
= glyph_at(tx
, ty
);
686 && matching
[glyph_to_cmap(k
)])
688 /* next, try glyph that's remembered here
689 (might be trap or object) */
690 if (level
.flags
.hero_memory
691 /* !terrainmode: don't move to remembered
692 trap or object if not currently shown */
693 && !iflags
.terrainmode
) {
694 k
= levl
[tx
][ty
].glyph
;
696 && matching
[glyph_to_cmap(k
)])
699 /* last, try actual terrain here (shouldn't
700 we be using lastseentyp[][] instead?) */
701 if (levl
[tx
][ty
].seenv
) {
702 k
= back_to_glyph(tx
, ty
);
704 && matching
[glyph_to_cmap(k
)])
711 clear_nhwindow(WIN_MESSAGE
);
718 pline("Can't find dungeon feature '%c'.", c
);
725 Strcpy(note
, "aborted");
727 Sprintf(note
, "use '%c', '%c', '%c', '%c' or '%s'", /* hjkl */
728 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
730 visctrl(Cmd
.spkeys
[NHKF_GETPOS_PICK
]));
731 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
734 } /* k => matching */
739 msg_given
= FALSE
; /* suppress clear */
742 result
= 0; /* not -1 */
750 curs(WIN_MAP
, cx
, cy
);
754 lock_mouse_cursor(FALSE
);
757 clear_nhwindow(WIN_MESSAGE
);
760 for (i
= 0; i
< NUM_GLOCS
; i
++)
762 free((genericptr_t
) garr
[i
]);
763 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
767 /* allocate space for a monster's name; removes old name if there is one */
771 int lth
; /* desired length (caller handles adding 1 for terminator) */
774 /* allocate mextra if necessary; otherwise get rid of old name */
776 mon
->mextra
= newmextra();
778 free_mname(mon
); /* already has mextra, might also have name */
779 MNAME(mon
) = (char *) alloc((unsigned) lth
);
781 /* zero length: the new name is empty; get rid of the old name */
787 /* release a monster's name; retains mextra even if all fields are now null */
792 if (has_mname(mon
)) {
793 free((genericptr_t
) MNAME(mon
));
794 MNAME(mon
) = (char *) 0;
798 /* allocate space for an object's name; removes old name if there is one */
802 int lth
; /* desired length (caller handles adding 1 for terminator) */
805 /* allocate oextra if necessary; otherwise get rid of old name */
807 obj
->oextra
= newoextra();
809 free_oname(obj
); /* already has oextra, might also have name */
810 ONAME(obj
) = (char *) alloc((unsigned) lth
);
812 /* zero length: the new name is empty; get rid of the old name */
818 /* release an object's name; retains oextra even if all fields are now null */
823 if (has_oname(obj
)) {
824 free((genericptr_t
) ONAME(obj
));
825 ONAME(obj
) = (char *) 0;
829 /* safe_oname() always returns a valid pointer to
830 * a string, either the pointer to an object's name
831 * if it has one, or a pointer to an empty string
843 /* historical note: this returns a monster pointer because it used to
844 allocate a new bigger block of memory to hold the monster and its name */
846 christen_monst(mtmp
, name
)
853 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
854 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
857 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
858 buf
[PL_PSIZ
- 1] = '\0';
860 new_mname(mtmp
, lth
); /* removes old name if one is present */
862 Strcpy(MNAME(mtmp
), name
);
866 /* check whether user-supplied name matches or nearly matches an unnameable
867 monster's name; if so, give an alternate reject message for do_mname() */
869 alreadynamed(mtmp
, monnambuf
, usrbuf
)
871 char *monnambuf
, *usrbuf
;
873 char pronounbuf
[10], *p
;
875 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
876 /* catch trying to name "the Oracle" as "Oracle" */
877 || (!strncmpi(monnambuf
, "the ", 4)
878 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
879 /* catch trying to name "invisible Orcus" as "Orcus" */
880 || ((p
= strstri(monnambuf
, "invisible ")) != 0
881 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
882 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
883 || ((p
= strstri(monnambuf
, " of ")) != 0
884 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
885 pline("%s is already called %s.",
886 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
888 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
889 && strstri(monnambuf
, "Juiblex")
890 && !strcmpi(usrbuf
, "Jubilex")) {
891 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
897 /* allow player to assign a name to some chosen monster */
901 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
904 struct monst
*mtmp
= 0;
907 You("would never recognize it anyway.");
912 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
917 if (cx
== u
.ux
&& cy
== u
.uy
) {
918 if (u
.usteed
&& canspotmon(u
.usteed
)) {
921 pline("This %s creature is called %s and cannot be renamed.",
922 beautiful(), plname
);
930 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
931 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
932 || mtmp
->m_ap_type
== M_AP_OBJECT
933 || (mtmp
->minvis
&& !See_invisible
)))) {
934 pline("I see no monster there.");
937 /* special case similar to the one in lookat() */
938 Sprintf(qbuf
, "What do you want to call %s?",
939 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
941 if (!*buf
|| *buf
== '\033')
943 /* strip leading and trailing spaces; unnames monster if all spaces */
944 (void) mungspaces(buf
);
946 /* Unique monsters have their own specific names or titles.
947 * Shopkeepers, temple priests and other minions use alternate
948 * name formatting routines which ignore any user-supplied name.
950 * Don't say the name is being rejected if it happens to match
953 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
954 if (!alreadynamed(mtmp
, monnambuf
, buf
))
955 pline("%s doesn't like being called names!", upstart(monnambuf
));
956 } else if (mtmp
->isshk
957 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
958 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
959 if (!alreadynamed(mtmp
, monnambuf
, buf
))
960 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
961 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
962 if (!alreadynamed(mtmp
, monnambuf
, buf
))
963 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
965 (void) christen_monst(mtmp
, buf
);
969 * This routine changes the address of obj. Be careful not to call it
970 * when there might be pointers around in unknown places. For now: only
971 * when obj is in the inventory.
976 register struct obj
*obj
;
978 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
982 /* Do this now because there's no point in even asking for a name */
983 if (obj
->otyp
== SPE_NOVEL
) {
984 pline("%s already has a published name.", Ysimple_name2(obj
));
988 Sprintf(qbuf
, "What do you want to name %s ",
989 is_plural(obj
) ? "these" : "this");
990 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
992 if (!*buf
|| *buf
== '\033')
994 /* strip leading and trailing spaces; unnames item if all spaces */
995 (void) mungspaces(buf
);
998 * We don't violate illiteracy conduct here, although it is
999 * arguable that we should for anything other than "X". Doing so
1000 * would make attaching player's notes to hero's inventory have an
1001 * in-game effect, which may or may not be the correct thing to do.
1003 * We do violate illiteracy in oname() if player creates Sting or
1004 * Orcrist, clearly being literate (no pun intended...).
1007 /* relax restrictions over proper capitalization for artifacts */
1008 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
1011 if (obj
->oartifact
) {
1012 pline_The("artifact seems to resist the attempt.");
1014 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
1015 /* this used to change one letter, substituting a value
1016 of 'a' through 'y' (due to an off by one error, 'z'
1017 would never be selected) and then force that to
1018 upper case if such was the case of the input;
1019 now, the hand slip scuffs one or two letters as if
1020 the text had been trodden upon, sometimes picking
1021 punctuation instead of an arbitrary letter;
1022 unfortunately, we have to cover the possibility of
1023 it targetting spaces so failing to make any change
1024 (we know that it must eventually target a nonspace
1025 because buf[] matches a valid artifact name) */
1026 Strcpy(bufcpy
, buf
);
1027 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
1028 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
1030 wipeout_text(bufp
, rnd(2), (unsigned) 0);
1031 } while (!strcmp(buf
, bufcpy
));
1032 pline("While engraving, your %s slips.", body_part(HAND
));
1033 display_nhwindow(WIN_MESSAGE
, FALSE
);
1034 You("engrave: \"%s\".", buf
);
1036 obj
= oname(obj
, buf
);
1047 lth
= *name
? (int) (strlen(name
) + 1) : 0;
1048 if (lth
> PL_PSIZ
) {
1050 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
1051 buf
[PL_PSIZ
- 1] = '\0';
1053 /* If named artifact exists in the game, do not create another.
1054 * Also trying to create an artifact shouldn't de-artifact
1055 * it (e.g. Excalibur from prayer). In this case the object
1056 * will retain its current name. */
1057 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
1060 new_oname(obj
, lth
); /* removes old name if one is present */
1062 Strcpy(ONAME(obj
), name
);
1065 artifact_exists(obj
, name
, TRUE
);
1066 if (obj
->oartifact
) {
1067 /* can't dual-wield with artifact as secondary weapon */
1068 if (obj
== uswapwep
)
1070 /* activate warning if you've just named your weapon "Sting" */
1072 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
1073 /* if obj is owned by a shop, increase your bill */
1075 alter_cost(obj
, 0L);
1076 /* violate illiteracy conduct since successfully wrote arti-name */
1077 u
.uconduct
.literate
++;
1084 static NEARDATA
const char callable
[] = {
1085 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
1086 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
1090 objtyp_is_callable(i
)
1093 return (boolean
) (objects
[i
].oc_uname
1094 || (OBJ_DESCR(objects
[i
])
1095 && index(callable
, objects
[i
].oc_class
)));
1098 /* C and #name commands - player can name monster or object or type of obj */
1105 menu_item
*pick_list
= 0;
1106 char ch
, allowall
[2];
1107 /* if player wants a,b,c instead of i,o when looting, do that here too */
1108 boolean abc
= flags
.lootabc
;
1110 win
= create_nhwindow(NHW_MENU
);
1113 any
.a_char
= 'm'; /* group accelerator 'C' */
1114 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
1115 "a monster", MENU_UNSELECTED
);
1117 /* we use y and n as accelerators so that we can accept user's
1118 response keyed to old "name an individual object?" prompt */
1119 any
.a_char
= 'i'; /* group accelerator 'y' */
1120 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
1121 "a particular object in inventory", MENU_UNSELECTED
);
1122 any
.a_char
= 'o'; /* group accelerator 'n' */
1123 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
1124 "the type of an object in inventory", MENU_UNSELECTED
);
1126 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
1127 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
1128 "the type of an object upon the floor", MENU_UNSELECTED
);
1129 any
.a_char
= 'd'; /* group accelerator '\' */
1130 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
1131 "the type of an object on discoveries list", MENU_UNSELECTED
);
1132 any
.a_char
= 'a'; /* group accelerator 'l' */
1133 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
1134 "record an annotation for the current level", MENU_UNSELECTED
);
1135 end_menu(win
, "What do you want to name?");
1136 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
1137 ch
= pick_list
[0].item
.a_char
;
1138 free((genericptr_t
) pick_list
);
1141 destroy_nhwindow(win
);
1147 case 'm': /* name a visible monster */
1150 case 'i': /* name an individual object in inventory */
1151 allowall
[0] = ALL_CLASSES
;
1153 obj
= getobj(allowall
, "name");
1157 case 'o': /* name a type of object in inventory */
1158 obj
= getobj(callable
, "call");
1160 /* behave as if examining it in inventory;
1161 this might set dknown if it was picked up
1162 while blind and the hero can now see */
1166 You("would never recognize another one.");
1168 } else if (!objtyp_is_callable(obj
->otyp
)) {
1169 You("know those as well as you ever will.");
1176 case 'f': /* name a type of object visible on the floor */
1179 case 'd': /* name a type of object on the discoveries list */
1182 case 'a': /* annotate level */
1191 register struct obj
*obj
;
1193 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
1195 register char **str1
;
1198 return; /* probably blind */
1201 otemp
.oextra
= (struct oextra
*) 0;
1203 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
1204 /* kludge, meaning it's sink water */
1205 Sprintf(qbuf
, "Call a stream of %s fluid:",
1206 OBJ_DESCR(objects
[otemp
.otyp
]));
1208 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
1210 if (!*buf
|| *buf
== '\033')
1213 /* clear old name */
1214 str1
= &(objects
[obj
->otyp
].oc_uname
);
1216 free((genericptr_t
) *str1
);
1218 /* strip leading and trailing spaces; uncalls item if all spaces */
1219 (void) mungspaces(buf
);
1221 if (*str1
) { /* had name, so possibly remove from disco[] */
1222 /* strip name first, for the update_inventory() call
1223 from undiscover_object() */
1225 undiscover_object(obj
->otyp
);
1228 *str1
= dupstr(buf
);
1229 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
1239 struct obj
*obj
= 0;
1240 boolean fakeobj
= FALSE
, use_plural
;
1242 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
1243 /* "dot for under/over you" only makes sense when the cursor hasn't
1244 been moved off the hero's '@' yet, but there's no way to adjust
1245 the help text once getpos() has started */
1246 Sprintf(buf
, "object on map (or '.' for one %s you)",
1247 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
1248 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
1250 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1251 obj
= vobj_at(u
.ux
, u
.uy
);
1253 glyph
= glyph_at(cc
.x
, cc
.y
);
1254 if (glyph_is_object(glyph
))
1255 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
1256 /* else 'obj' stays null */
1259 /* "under you" is safe here since there's no object to hide under */
1260 pline("There doesn't seem to be any object %s.",
1261 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
1264 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1265 is a mimic; passing that to xname (directly or via simpleonames)
1266 would yield "glorkum" so we need to handle it explicitly; it will
1267 always fail the Hallucination test and pass the !callable test,
1268 resulting in the "can't be assigned a type name" message */
1269 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
1271 : obj_descr
[STRANGE_OBJECT
].oc_name
);
1272 use_plural
= (obj
->quan
> 1L);
1273 if (Hallucination
) {
1274 const char *unames
[6];
1277 /* straight role name */
1278 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1281 /* random rank title for hero's role */
1282 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
1283 /* random fake monster */
1284 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
1285 /* increased chance for fake monster */
1286 unames
[3] = unames
[2];
1288 unames
[4] = roguename();
1290 unames
[5] = "Wibbly Wobbly";
1291 pline("%s %s to call you \"%s.\"",
1292 The(buf
), use_plural
? "decide" : "decides",
1293 unames
[rn2(SIZE(unames
))]);
1294 } else if (!objtyp_is_callable(obj
->otyp
)) {
1295 pline("%s %s can't be assigned a type name.",
1296 use_plural
? "Those" : "That", buf
);
1297 } else if (!obj
->dknown
) {
1298 You("don't know %s %s well enough to name %s.",
1299 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
1307 static const char *const ghostnames
[] = {
1308 /* these names should have length < PL_NSIZ */
1309 /* Capitalize the names for aesthetics -dgk */
1310 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1311 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1312 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1313 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1314 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1315 "Stephan", "Lance Braccus", "Shadowhawk"
1318 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1322 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
1326 * Monster naming functions:
1327 * x_monnam is the generic monster-naming function.
1328 * seen unseen detected named
1329 * mon_nam: the newt it the invisible orc Fido
1330 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1331 * l_monnam: newt it invisible orc dog called Fido
1332 * Monnam: The newt It The invisible orc Fido
1333 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1334 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1335 * Amonnam: A newt It An invisible orc Fido
1336 * a_monnam: a newt it an invisible orc Fido
1337 * m_monnam: newt xan orc Fido
1338 * y_monnam: your newt your xan your invisible orc Fido
1341 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1342 * options works, since those are special cases.
1345 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
1346 register struct monst
*mtmp
;
1348 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1349 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1351 * If the monster would be referred to as "it" or if the monster has a name
1352 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1353 * and always use no article.
1355 const char *adjective
;
1357 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1358 * EXACT_NAME: combination of all the above
1362 char *buf
= nextmbuf();
1363 struct permonst
*mdat
= mtmp
->data
;
1364 const char *pm_name
= mdat
->mname
;
1365 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
1366 boolean name_at_start
, has_adjectives
;
1369 if (program_state
.gameover
)
1370 suppress
|= SUPPRESS_HALLUCINATION
;
1371 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
1372 article
= ARTICLE_THE
;
1374 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
1375 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
1376 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
1377 && !program_state
.gameover
&& mtmp
!= u
.usteed
1378 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
1379 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
1383 /* unseen monsters, etc. Use "it" */
1389 /* priests and minions: don't even use this function */
1390 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1391 char priestnambuf
[BUFSZ
];
1393 long save_prop
= EHalluc_resistance
;
1394 unsigned save_invis
= mtmp
->minvis
;
1396 /* when true name is wanted, explicitly block Hallucination */
1398 EHalluc_resistance
= 1L;
1401 name
= priestname(mtmp
, priestnambuf
);
1402 EHalluc_resistance
= save_prop
;
1403 mtmp
->minvis
= save_invis
;
1404 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1406 return strcpy(buf
, name
);
1408 /* an "aligned priest" not flagged as a priest or minion should be
1409 "priest" or "priestess" (normally handled by priestname()) */
1410 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1411 pm_name
= mtmp
->female
? "priestess" : "priest";
1412 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1413 pm_name
= "high priestess";
1415 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1416 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1417 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1418 * none of this applies.
1420 if (mtmp
->isshk
&& !do_hallu
) {
1421 if (adjective
&& article
== ARTICLE_THE
) {
1422 /* pathological case: "the angry Asidonhopo the blue dragon"
1424 Strcpy(buf
, "the ");
1425 Strcat(strcat(buf
, adjective
), " ");
1426 Strcat(buf
, shkname(mtmp
));
1429 Strcat(buf
, shkname(mtmp
));
1430 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1432 Strcat(buf
, " the ");
1434 Strcat(buf
, "invisible ");
1435 Strcat(buf
, pm_name
);
1439 /* Put the adjectives in the buffer */
1441 Strcat(strcat(buf
, adjective
), " ");
1443 Strcat(buf
, "invisible ");
1444 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1446 Strcat(buf
, "saddled ");
1448 has_adjectives
= TRUE
;
1450 has_adjectives
= FALSE
;
1452 /* Put the actual monster name or type into the buffer now */
1453 /* Be sure to remember whether the buffer starts with a name */
1456 char *rname
= rndmonnam(&rnamecode
);
1459 name_at_start
= bogon_is_pname(rnamecode
);
1460 } else if (has_mname(mtmp
)) {
1461 char *name
= MNAME(mtmp
);
1463 if (mdat
== &mons
[PM_GHOST
]) {
1464 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1465 name_at_start
= TRUE
;
1466 } else if (called
) {
1467 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1468 name_at_start
= (boolean
) type_is_pname(mdat
);
1469 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1470 /* <name> the <adjective> <invisible> <saddled> <rank> */
1474 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1477 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1479 article
= ARTICLE_NONE
;
1480 name_at_start
= TRUE
;
1483 name_at_start
= TRUE
;
1485 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1488 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1489 (boolean
) mtmp
->female
));
1490 Strcat(buf
, lcase(pbuf
));
1491 name_at_start
= FALSE
;
1493 Strcat(buf
, pm_name
);
1494 name_at_start
= (boolean
) type_is_pname(mdat
);
1497 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1498 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1499 article
= ARTICLE_THE
;
1501 article
= ARTICLE_NONE
;
1502 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1503 article
= ARTICLE_THE
;
1511 Strcpy(buf2
, "your ");
1516 Strcpy(buf2
, "the ");
1533 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1534 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1541 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1542 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1545 /* print the name as if mon_nam() was called, but assume that the player
1546 * can always see the monster--used for probing and for monsters aggravating
1547 * the player with a cursed potion of invisibility
1553 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1554 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1563 register char *bp
= mon_nam(mtmp
);
1573 register char *bp
= noit_mon_nam(mtmp
);
1579 /* monster's own name */
1584 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1587 /* pet name: "your little dog" */
1592 int prefix
, suppression_flag
;
1594 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1595 suppression_flag
= (has_mname(mtmp
)
1596 /* "saddled" is redundant when mounted */
1597 || mtmp
== u
.usteed
)
1601 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1605 Adjmonnam(mtmp
, adj
)
1609 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1610 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1620 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1621 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1628 char *bp
= a_monnam(mtmp
);
1634 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1635 identification of the endgame altars via their attending priests */
1637 distant_monnam(mon
, article
, outbuf
)
1639 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1642 /* high priest(ess)'s identity is concealed on the Astral Plane,
1643 unless you're adjacent (overridden for hallucination which does
1644 its own obfuscation) */
1645 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1646 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1647 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1648 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1650 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1655 /* fake monsters used to be in a hard-coded array, now in a data file */
1662 get_rnd_text(BOGUSMONFILE
, buf
);
1663 /* strip prefix if present */
1664 if (!letter(*mname
)) {
1675 /* return a random monster name, for hallucination */
1680 static char buf
[BUFSZ
];
1683 #define BOGUSMONSIZE 100 /* arbitrary */
1689 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1690 } while (name
< SPECIAL_PM
1691 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1693 if (name
>= SPECIAL_PM
) {
1694 mname
= bogusmon(buf
, code
);
1696 mname
= strcpy(buf
, mons
[name
].mname
);
1702 /* check bogusmon prefix to decide whether it's a personal name */
1704 bogon_is_pname(code
)
1709 return index("-+=", code
) ? TRUE
: FALSE
;
1712 /* name of a Rogue player */
1718 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1719 for (i
= opts
; *i
; i
++)
1720 if (!strncmp("name=", i
, 5)) {
1722 if ((j
= index(i
+ 5, ',')) != 0)
1727 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1731 static NEARDATA
const char *const hcolors
[] = {
1732 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1733 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1734 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1735 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1736 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1737 "strawberry-banana", "peppermint", "romantic", "incandescent",
1738 "octarine", /* Discworld: the Colour of Magic */
1743 const char *colorpref
;
1745 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1749 /* return a random real color unless hallucinating */
1753 int k
= rn2(CLR_MAX
);
1755 return Hallucination
? hcolor((char *) 0)
1756 : (k
== NO_COLOR
) ? "colorless"
1760 static NEARDATA
const char *const hliquids
[] = {
1761 "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
1762 "instant coffee", "tea", "herbal infusion", "liquid rainbow",
1763 "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
1764 "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
1765 "caramel sauce", "ink", "aqueous humour", "milk substitute", "fruit juice",
1766 "glowing lava", "gastric acid", "mineral water", "cough syrup", "quicksilver",
1767 "sweet vitriol", "grey goo", "pink slime",
1772 const char *liquidpref
;
1774 return (Hallucination
|| !liquidpref
) ? hliquids
[rn2(SIZE(hliquids
))]
1778 /* Aliases for road-runner nemesis
1780 static const char *const coynames
[] = {
1781 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1782 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1783 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1784 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1785 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1786 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1787 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1792 coyotename(mtmp
, buf
)
1797 Sprintf(buf
, "%s - %s",
1798 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1799 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1800 : coynames
[mtmp
->m_id
% (SIZE(coynames
) - 1)]);
1805 /* make sure "The Colour of Magic" remains the first entry in here */
1806 static const char *const sir_Terry_novels
[] = {
1807 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1808 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1809 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1810 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1811 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1812 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1813 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1814 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1815 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1816 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1817 "Raising Steam", "The Shepherd's Crown"
1824 int j
, k
= SIZE(sir_Terry_novels
);
1830 else if (*novidx
>= 0 && *novidx
< k
)
1833 return sir_Terry_novels
[j
];
1837 lookup_novel(lookname
, idx
)
1838 const char *lookname
;
1843 /* Take American or U.K. spelling of this one */
1844 if (!strcmpi(The(lookname
), "The Color of Magic"))
1845 lookname
= sir_Terry_novels
[0];
1847 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1848 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1849 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1852 return sir_Terry_novels
[k
];
1855 /* name not found; if novelidx is already set, override the name */
1856 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1857 return sir_Terry_novels
[*idx
];
1859 return (const char *) 0;