1 /* NetHack 3.6 do_name.c $NHDT-Date: 1582364431 2020/02/22 09:40:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.174 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Pasi Kallinen, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
6 /* JNetHack Copyright */
7 /* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000 */
8 /* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2020 */
9 /* JNetHack may be freely redistributed. See license for details. */
13 STATIC_DCL char *NDECL(nextmbuf);
14 STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *));
15 STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *));
16 STATIC_DCL boolean FDECL(gather_locs_interesting, (int, int, int));
17 STATIC_DCL void FDECL(gather_locs, (coord **, int *, int));
18 STATIC_DCL int FDECL(gloc_filter_floodfill_matcharea, (int, int));
19 STATIC_DCL void FDECL(auto_describe, (int, int));
20 STATIC_DCL void NDECL(do_mname);
21 STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *));
22 STATIC_DCL void FDECL(do_oname, (struct obj *));
23 STATIC_PTR char *FDECL(docall_xname, (struct obj *));
24 STATIC_DCL void NDECL(namefloorobj);
25 STATIC_DCL char *FDECL(bogusmon, (char *,char *));
27 extern const char what_is_an_unknown_object[]; /* from pager.c */
31 /* manage a pool of BUFSZ buffers, so callers don't have to */
35 static char NEARDATA bufs[NUMMBUF][BUFSZ];
36 static int bufidx = 0;
38 bufidx = (bufidx + 1) % NUMMBUF;
42 /* function for getpos() to highlight desired map locations.
43 * parameter value 0 = initialize, 1 = highlight, 2 = done
45 static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0;
46 static boolean FDECL((*getpos_getvalid), (int, int)) =
47 (boolean FDECL((*), (int, int))) 0;
50 getpos_sethilite(gp_hilitef, gp_getvalidf)
51 void FDECL((*gp_hilitef), (int));
52 boolean FDECL((*gp_getvalidf), (int, int));
54 getpos_hilitefunc = gp_hilitef;
55 getpos_getvalid = gp_getvalidf;
61 [2] "use XXX to move the cursor to %s"
63 static const char *const gloc_descr[NUM_GLOCS][4] = {
65 { "any monsters", "monster", "next/previous monster", "monsters" },
66 { "any items", "item", "next/previous object", "objects" },
67 { "any doors", "door", "next/previous door or doorway", "doors or doorways" },
68 { "any unexplored areas", "unexplored area", "unexplored location",
69 "unexplored locations" },
70 { "anything interesting", "interesting thing", "anything interesting",
71 "anything interesting" },
72 { "any valid locations", "valid location", "valid location",
75 { "
\89ö
\95¨", "
\89ö
\95¨", "
\89ö
\95¨
\82Ì
\97×", "
\89ö
\95¨" },
76 { "
\95¨", "
\95¨", "
\95¨
\82Ì
\97×", "
\95¨" },
77 { "
\94à", "
\94à", "
\94à
\82â
\8fo
\93ü
\82è
\8cû
\82Ì
\97×", "
\94à
\82â
\8fo
\93ü
\82è
\8cû" },
78 { "
\96¢
\92T
\8dõ
\95\94\95ª", "
\96¢
\92T
\8dõ
\95\94\95ª", "
\96¢
\92T
\8dõ
\82Ì
\88Ê
\92u", "
\96¢
\92T
\8dõ
\82Ì
\88Ê
\92u" },
79 { "
\8aÖ
\90S
\82Ì
\82 \82é
\82à
\82Ì", "
\8aÖ
\90S
\82Ì
\82 \82é
\82à
\82Ì", "
\8aÖ
\90S
\82Ì
\82 \82é
\82à
\82Ì", "
\8aÖ
\90S
\82Ì
\82 \82é
\82à
\82Ì" },
80 { "
\97L
\8cø
\82È
\88Ê
\92u", "
\97L
\8cø
\82È
\88Ê
\92u", "
\97L
\8cø
\82È
\88Ê
\92u", "
\97L
\8cø
\82È
\88Ê
\92u" },
84 static const char *const gloc_filtertxt[NUM_GFILTER] = {
91 "
\8e\8b\8aE
\82Ì
\92\86\82Ì",
92 "
\82±
\82Ì
\83G
\83\8a\83A
\82Ì"
97 getpos_help_keyxhelp(tmpwin, k1, k2, gloc)
106 Sprintf(sbuf, "Use '%s'/'%s' to %s%s%s.",
108 iflags.getloc_usemenu ? "get a menu of "
109 : "move the cursor to ",
110 gloc_descr[gloc][2 + iflags.getloc_usemenu],
111 gloc_filtertxt[iflags.getloc_filter]);
113 Sprintf(sbuf, "'%s'
\82©'%s'
\82Å%s%s%s
\81D",
115 gloc_filtertxt[iflags.getloc_filter],
116 gloc_descr[gloc][2 + iflags.getloc_usemenu],
117 iflags.getloc_usemenu ? "
\82Ì
\83\81\83j
\83\85\81[
\82ð
\8fo
\82·"
118 : "
\82É
\83J
\81[
\83\
\83\8b\82ð
\93®
\82©
\82·");
120 putstr(tmpwin, 0, sbuf);
123 /* the response for '?' help request in getpos() */
125 getpos_help(force, goal)
130 static const char *const fastmovemode[2] = { "8 units at a time",
131 "skipping same glyphs" };
133 static const char *const fastmovemode[2] = { "
\88ê
\93x
\82É8
\83}
\83X",
134 "
\93¯
\82¶
\92n
\8c`
\82ð
\94ò
\82Î
\82µ
\82Ä" };
137 boolean doing_what_is;
138 winid tmpwin = create_nhwindow(NHW_MENU);
142 "Use '%c', '%c', '%c', '%c' to move the cursor to %s.", /* hjkl */
143 Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
146 "[%c%c%c%c]
\82Å%s
\82Ö
\88Ú
\93®
\82Å
\82«
\82é
\81D",
147 Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E, goal);
149 putstr(tmpwin, 0, sbuf);
152 "Use 'H', 'J', 'K', 'L' to fast-move the cursor, %s.",
153 fastmovemode[iflags.getloc_moveskip]);
156 "'H', 'J', 'K', 'L'
\82Å%s
\88Ú
\93®
\82Å
\82«
\82é
\81D",
157 fastmovemode[iflags.getloc_moveskip]);
159 putstr(tmpwin, 0, sbuf);
161 putstr(tmpwin, 0, "Or enter a background symbol (ex. '<').");
163 putstr(tmpwin, 0, "
\94w
\8ci
\82Ì
\83V
\83\93\83{
\83\8b\82ð
\93ü
\97Í
\82·
\82é
\82Æ
\82»
\82Ì
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é(
\97á
\81F'<')
\81D");
165 Sprintf(sbuf, "Use '%s' to move the cursor on yourself.",
166 visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
168 Sprintf(sbuf, "'%s'
\82Å
\8e©
\95ª
\8e©
\90g
\82Ì
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é
\81D",
169 visctrl(Cmd.spkeys[NHKF_GETPOS_SELF]));
171 putstr(tmpwin, 0, sbuf);
172 if (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0) {
173 getpos_help_keyxhelp(tmpwin,
174 visctrl(Cmd.spkeys[NHKF_GETPOS_MON_NEXT]),
175 visctrl(Cmd.spkeys[NHKF_GETPOS_MON_PREV]),
178 if (!iflags.terrainmode || (iflags.terrainmode & TER_OBJ) != 0) {
179 getpos_help_keyxhelp(tmpwin,
180 visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_NEXT]),
181 visctrl(Cmd.spkeys[NHKF_GETPOS_OBJ_PREV]),
184 if (!iflags.terrainmode || (iflags.terrainmode & TER_MAP) != 0) {
185 /* these are primarily useful when choosing a travel
186 destination for the '_' command */
187 getpos_help_keyxhelp(tmpwin,
188 visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_NEXT]),
189 visctrl(Cmd.spkeys[NHKF_GETPOS_DOOR_PREV]),
191 getpos_help_keyxhelp(tmpwin,
192 visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_NEXT]),
193 visctrl(Cmd.spkeys[NHKF_GETPOS_UNEX_PREV]),
195 getpos_help_keyxhelp(tmpwin,
196 visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_NEXT]),
197 visctrl(Cmd.spkeys[NHKF_GETPOS_INTERESTING_PREV]),
201 Sprintf(sbuf, "Use '%s' to change fast-move mode to %s.",
202 visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]),
203 fastmovemode[!iflags.getloc_moveskip]);
205 Sprintf(sbuf, "'%s'
\82Å
\8d\82\91¬
\88Ú
\93®
\83\82\81[
\83h
\82ð%s
\88Ú
\93®
\82É
\82·
\82é
\81D",
206 visctrl(Cmd.spkeys[NHKF_GETPOS_MOVESKIP]),
207 fastmovemode[!iflags.getloc_moveskip]);
209 putstr(tmpwin, 0, sbuf);
210 if (!iflags.terrainmode || (iflags.terrainmode & TER_DETECT) == 0) {
212 Sprintf(sbuf, "Use '%s' to toggle menu listing for possible targets.",
213 visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
215 Sprintf(sbuf, "'%s'
\82Å
\89Â
\94\
\82È
\83^
\81[
\83Q
\83b
\83g
\82Ì
\83\81\83j
\83\85\81[
\95\
\8e¦
\82ð
\90Ø
\82è
\91Ö
\82¦
\82é
\81D",
216 visctrl(Cmd.spkeys[NHKF_GETPOS_MENU]));
218 putstr(tmpwin, 0, sbuf);
221 "Use '%s' to change the mode of limiting possible targets.",
222 visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
225 "'%s'
\82Å
\90§
\8cÀ
\82³
\82ê
\82½
\89Â
\94\
\82È
\83^
\81[
\83Q
\83b
\83g
\82Ì
\83\82\81[
\83h
\82ð
\90Ø
\82è
\91Ö
\82¦
\82é
\81D",
226 visctrl(Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]));
228 putstr(tmpwin, 0, sbuf);
230 if (!iflags.terrainmode) {
233 if (getpos_getvalid) {
235 Sprintf(sbuf, "Use '%s' or '%s' to move to valid locations.",
236 visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]),
237 visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_PREV]));
239 Sprintf(sbuf, "'%s'
\82©'%s'
\82Å
\90³
\93\96\82È
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é
\81D",
240 visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_NEXT]),
241 visctrl(Cmd.spkeys[NHKF_GETPOS_VALID_PREV]));
243 putstr(tmpwin, 0, sbuf);
245 if (getpos_hilitefunc) {
247 Sprintf(sbuf, "Use '%s' to display valid locations.",
248 visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
250 Sprintf(sbuf, "'%s'
\82Å
\89Â
\94\
\82È
\88Ê
\92u
\82ð
\95\
\8e¦
\82·
\82é
\81D",
251 visctrl(Cmd.spkeys[NHKF_GETPOS_SHOWVALID]));
253 putstr(tmpwin, 0, sbuf);
256 Sprintf(sbuf, "Use '%s' to toggle automatic description.",
257 visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
259 Sprintf(sbuf, "'%s'
\82Å
\90à
\96¾
\82Ì
\8e©
\93®
\95\
\8e¦
\82ð
\90Ø
\82è
\91Ö
\82¦
\82é
\81D",
260 visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
262 putstr(tmpwin, 0, sbuf);
263 if (iflags.cmdassist) { /* assisting the '/' command, I suppose... */
266 (iflags.getpos_coords == GPCOORDS_NONE)
267 ? "(Set 'whatis_coord' option to include coordinates with '%s' text.)"
268 : "(Reset 'whatis_coord' option to omit coordinates from '%s' text.)",
269 visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
272 (iflags.getpos_coords == GPCOORDS_NONE)
273 ? "('%s'
\82É
\8dÀ
\95W
\82ð
\8aÜ
\82Þ
\82É
\82Í'whatis_coord'
\83I
\83v
\83V
\83\87\83\93\82ð
\83I
\83\93\82É
\82·
\82é
\81D)"
274 : "('%s'
\82©
\82ç
\8dÀ
\95W
\82ð
\8f\9c\82
\82É
\82Í'whatis_coord'
\83I
\83v
\83V
\83\87\83\93\82ð
\83I
\83t
\82É
\82·
\82é
\81D)",
275 visctrl(Cmd.spkeys[NHKF_GETPOS_AUTODESC]));
278 /* disgusting hack; the alternate selection characters work for any
279 getpos call, but only matter for dowhatis (and doquickwhatis) */
280 doing_what_is = (goal == what_is_an_unknown_object);
283 Sprintf(kbuf, "'%s' or '%s' or '%s' or '%s'",
284 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
285 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
286 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
287 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
289 Sprintf(kbuf, "'%s'
\82©'%s'
\82©'%s'
\82©'%s'",
290 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
291 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]),
292 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]),
293 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
296 Sprintf(kbuf, "'%s'", visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
299 Sprintf(sbuf, "Type a %s when you are at the right place.", kbuf);
301 Sprintf(sbuf, "[.]%s
\82Å
\8c\88\92è
\81D", kbuf);
303 putstr(tmpwin, 0, sbuf);
307 " '%s' describe current spot, show 'more info', move to another spot.",
308 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
311 " '%s'
\82Í
\8c»
\8dÝ
\82Ì
\88Ê
\92u
\82ð
\90à
\96¾
\82µ
\81A
\92Ç
\89Á
\8fî
\95ñ
\82ð
\95\
\8e¦
\82µ
\81A
\8e\9f\82Ì
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é
\81D",
312 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_V]));
314 putstr(tmpwin, 0, sbuf);
317 " '%s' describe current spot,%s move to another spot;",
318 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
319 flags.help ? " prompt if 'more info'," : "");
322 " '%s'
\82Í
\8c»
\8dÝ
\82Ì
\88Ê
\92u
\82ð
\90à
\96¾
\82µ
\81C%s
\8e\9f\82Ì
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é;",
323 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]),
324 flags.help ? "
\92Ç
\89Á
\8fî
\95ñ
\82ª
\82 \82ê
\82Î
\8am
\94F
\82µ
\81C" : "");
326 putstr(tmpwin, 0, sbuf);
329 " '%s' describe current spot, move to another spot;",
330 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
333 " '%s'
\82Í
\8c»
\8dÝ
\82Ì
\88Ê
\92u
\82ð
\90à
\96¾
\82µ
\81C
\8e\9f\82Ì
\88Ê
\92u
\82É
\88Ú
\93®
\82·
\82é;",
334 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_Q]));
336 putstr(tmpwin, 0, sbuf);
339 " '%s' describe current spot, stop looking at things;",
340 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
343 " '%s'
\82Í
\8c»
\8dÝ
\82Ì
\88Ê
\92u
\82ð
\90à
\96¾
\82µ
\81C
\8c©
\82é
\82Ì
\82ð
\82â
\82ß
\82é;",
344 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK_O]));
346 putstr(tmpwin, 0, sbuf);
351 putstr(tmpwin, 0, "Type Space or Escape when you're done.");
353 putstr(tmpwin, 0, "
\83X
\83y
\81[
\83X
\82Ü
\82½
\82Í
\83G
\83X
\83P
\81[
\83v
\82Å
\8fI
\97¹
\81D");
354 putstr(tmpwin, 0, "");
355 display_nhwindow(tmpwin, TRUE);
356 destroy_nhwindow(tmpwin);
360 cmp_coord_distu(a, b)
366 int dx, dy, dist_1, dist_2;
370 dist_1 = max(abs(dx), abs(dy));
373 dist_2 = max(abs(dx), abs(dy));
375 if (dist_1 == dist_2)
376 return (c1->y != c2->y) ? (c1->y - c2->y) : (c1->x - c2->x);
378 return dist_1 - dist_2;
381 #define IS_UNEXPLORED_LOC(x,y) \
383 && glyph_is_cmap(levl[(x)][(y)].glyph) \
384 && glyph_to_cmap(levl[(x)][(y)].glyph) == S_stone \
385 && !levl[(x)][(y)].seenv)
387 static struct opvar *gloc_filter_map = (struct opvar *) 0;
389 #define GLOC_SAME_AREA(x,y) \
391 && (selection_getpoint((x),(y), gloc_filter_map)))
393 static int gloc_filter_floodfill_match_glyph;
396 gloc_filter_classify_glyph(glyph)
401 if (!glyph_is_cmap(glyph))
404 c = glyph_to_cmap(glyph);
406 if (is_cmap_room(c) || is_cmap_furniture(c))
408 else if (is_cmap_wall(c) || c == S_tree)
410 else if (is_cmap_corr(c))
412 else if (is_cmap_water(c))
414 else if (is_cmap_lava(c))
420 gloc_filter_floodfill_matcharea(x, y)
423 int glyph = back_to_glyph(x, y);
425 if (!levl[x][y].seenv)
428 if (glyph == gloc_filter_floodfill_match_glyph)
431 if (gloc_filter_classify_glyph(glyph)
432 == gloc_filter_classify_glyph(gloc_filter_floodfill_match_glyph))
439 gloc_filter_floodfill(x, y)
442 gloc_filter_floodfill_match_glyph = back_to_glyph(x, y);
444 set_selection_floodfillchk(gloc_filter_floodfill_matcharea);
445 selection_floodfill(gloc_filter_map, x, y, FALSE);
451 if (iflags.getloc_filter == GFILTER_AREA) {
452 if (!gloc_filter_map) {
453 gloc_filter_map = selection_opvar((char *) 0);
455 /* special case: if we're in a doorway, try to figure out which
456 direction we're moving, and use that side of the doorway */
457 if (IS_DOOR(levl[u.ux][u.uy].typ)) {
459 gloc_filter_floodfill(u.ux + u.dx, u.uy + u.dy);
461 /* TODO: maybe add both sides of the doorway? */
464 gloc_filter_floodfill(u.ux, u.uy);
472 if (gloc_filter_map) {
473 opvar_free_x(gloc_filter_map);
474 gloc_filter_map = (struct opvar *) 0;
479 gather_locs_interesting(x, y, gloc)
482 /* TODO: if glyph is a pile glyph, convert to ordinary one
483 * in order to keep tail/boulder/rock check simple.
485 int glyph = glyph_at(x, y);
487 if (iflags.getloc_filter == GFILTER_VIEW && !cansee(x, y))
489 if (iflags.getloc_filter == GFILTER_AREA && !GLOC_SAME_AREA(x, y)
490 && !GLOC_SAME_AREA(x - 1, y) && !GLOC_SAME_AREA(x, y - 1)
491 && !GLOC_SAME_AREA(x + 1, y) && !GLOC_SAME_AREA(x, y + 1))
497 /* unlike '/M', this skips monsters revealed by
498 warning glyphs and remembered unseen ones */
499 return (glyph_is_monster(glyph)
500 && glyph != monnum_to_glyph(PM_LONG_WORM_TAIL));
502 return (glyph_is_object(glyph)
503 && glyph != objnum_to_glyph(BOULDER)
504 && glyph != objnum_to_glyph(ROCK));
506 return (glyph_is_cmap(glyph)
507 && (is_cmap_door(glyph_to_cmap(glyph))
508 || is_cmap_drawbridge(glyph_to_cmap(glyph))
509 || glyph_to_cmap(glyph) == S_ndoor));
511 return (glyph_is_cmap(glyph)
512 && (is_cmap_door(glyph_to_cmap(glyph))
513 || is_cmap_drawbridge(glyph_to_cmap(glyph))
514 || glyph_to_cmap(glyph) == S_ndoor
515 || glyph_to_cmap(glyph) == S_room
516 || glyph_to_cmap(glyph) == S_darkroom
517 || glyph_to_cmap(glyph) == S_corr
518 || glyph_to_cmap(glyph) == S_litcorr)
519 && (IS_UNEXPLORED_LOC(x + 1, y)
520 || IS_UNEXPLORED_LOC(x - 1, y)
521 || IS_UNEXPLORED_LOC(x, y + 1)
522 || IS_UNEXPLORED_LOC(x, y - 1)));
525 return (*getpos_getvalid)(x,y);
527 case GLOC_INTERESTING:
528 return gather_locs_interesting(x,y, GLOC_DOOR)
529 || !(glyph_is_cmap(glyph)
530 && (is_cmap_wall(glyph_to_cmap(glyph))
531 || glyph_to_cmap(glyph) == S_tree
532 || glyph_to_cmap(glyph) == S_bars
533 || glyph_to_cmap(glyph) == S_ice
534 || glyph_to_cmap(glyph) == S_air
535 || glyph_to_cmap(glyph) == S_cloud
536 || glyph_to_cmap(glyph) == S_lava
537 || glyph_to_cmap(glyph) == S_water
538 || glyph_to_cmap(glyph) == S_pool
539 || glyph_to_cmap(glyph) == S_ndoor
540 || glyph_to_cmap(glyph) == S_room
541 || glyph_to_cmap(glyph) == S_darkroom
542 || glyph_to_cmap(glyph) == S_corr
543 || glyph_to_cmap(glyph) == S_litcorr));
549 /* gather locations for monsters or objects shown on the map */
551 gather_locs(arr_p, cnt_p, gloc)
559 * We always include the hero's location even if there is no monster
560 * (invisible hero without see invisible) or object (usual case)
561 * displayed there. That way, the count will always be at least 1,
562 * and player has a visual indicator (cursor returns to hero's spot)
563 * highlighting when successive 'm's or 'o's have cycled all the way
564 * through all monsters or objects.
566 * Hero's spot will always sort to array[0] because it will always
567 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
573 for (pass = 0; pass < 2; pass++) {
574 for (x = 1; x < COLNO; x++)
575 for (y = 0; y < ROWNO; y++) {
576 if ((x == u.ux && y == u.uy)
577 || gather_locs_interesting(x, y, gloc)) {
588 if (!pass) /* end of first pass */
589 *arr_p = (coord *) alloc(*cnt_p * sizeof (coord));
590 else /* end of second pass */
591 qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu);
598 dxdy_to_dist_descr(dx, dy, fulldir)
607 Sprintf(buf, "here");
609 Sprintf(buf, "
\82±
\82±");
610 } else if ((dst = xytod(dx, dy)) != -1) {
611 /* explicit direction; 'one step' is implicit */
612 Sprintf(buf, "%s", directionname(dst));
614 static const char *dirnames[4][2] = {
627 /* 9999: protect buf[] against overflow caused by invalid values */
631 Sprintf(eos(buf), "%d%s%s", abs(dy), dirnames[(dy > 0)][fulldir],
637 Sprintf(eos(buf), "%d%s", abs(dx),
638 dirnames[2 + (dx > 0)][fulldir]);
644 /* coordinate formatting for 'whatis_coord' option */
646 coord_desc(x, y, outbuf, cmode)
650 static char screen_fmt[16]; /* [12] suffices: "[%02d,%02d]" */
657 case GPCOORDS_COMFULL:
658 case GPCOORDS_COMPASS:
659 /* "east", "3s", "2n,4w" */
662 Sprintf(outbuf, "(%s)",
663 dxdy_to_dist_descr(dx, dy, cmode == GPCOORDS_COMFULL));
665 case GPCOORDS_MAP: /* x,y */
666 /* upper left corner of map is <1,0>;
667 with default COLNO,ROWNO lower right corner is <79,20> */
668 Sprintf(outbuf, "<%d,%d>", x, y);
670 case GPCOORDS_SCREEN: /* y+2,x */
671 /* for normal map sizes, force a fixed-width formatting so that
672 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
673 than Nx999 or 999xM will still work, but not line up like normal
674 when displayed in a column setting */
676 Sprintf(screen_fmt, "[%%%sd,%%%sd]",
677 (ROWNO - 1 + 2 < 100) ? "02" : "03",
678 (COLNO - 1 < 100) ? "02" : "03");
679 /* map line 0 is screen row 2;
680 map column 0 isn't used, map column 1 is screen column 1 */
681 Sprintf(outbuf, screen_fmt, y + 2, x);
688 auto_describe(cx, cy)
695 const char *firstmatch = "unknown";
697 const char *firstmatch = "
\95s
\96¾";
701 if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch,
702 (struct permonst **) 0)) {
703 (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords);
705 custompline(SUPPRESS_HISTORY,
706 "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf,
708 && getpos_getvalid && !(*getpos_getvalid)(cx, cy))
710 (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy))
711 ? " (no travel path)" : "");
713 custompline(SUPPRESS_HISTORY,
714 "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf,
716 && getpos_getvalid && !getpos_getvalid(cx, cy))
717 ? " (
\95s
\90³)" : "",
718 (iflags.getloc_travelmode && !is_valid_travelpt(cx, cy))
719 ? " (
\8co
\98H
\82È
\82µ)" : "");
721 curs(WIN_MAP, cx, cy);
727 getpos_menu(ccp, gloc)
736 menu_item *picks = (menu_item *) 0;
739 gather_locs(&garr, &gcount, gloc);
741 if (gcount < 2) { /* gcount always includes the hero */
742 free((genericptr_t) garr);
745 iflags.getloc_filter == GFILTER_VIEW ? "see" : "detect",
746 gloc_descr[gloc][0]);
748 You("%s
\82ð%s
\82±
\82Æ
\82ª
\82Å
\82«
\82È
\82¢
\81D",
750 iflags.getloc_filter == GFILTER_VIEW ? "
\8c©
\82é" : "
\8c©
\82Â
\82¯
\82é");
755 tmpwin = create_nhwindow(NHW_MENU);
759 /* gather_locs returns array[0] == you. skip it. */
760 for (i = 1; i < gcount; i++) {
764 const char *firstmatch = "unknown";
766 const char *firstmatch = "
\95s
\96¾";
772 if (do_screen_description(tmpcc, TRUE, sym, tmpbuf,
773 &firstmatch, (struct permonst **)0)) {
774 (void) coord_desc(garr[i].x, garr[i].y, tmpbuf,
775 iflags.getpos_coords);
776 Sprintf(fullbuf, "%s%s%s", firstmatch,
777 (*tmpbuf ? " " : ""), tmpbuf);
778 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, fullbuf,
784 Sprintf(tmpbuf, "Pick %s%s%s",
785 an(gloc_descr[gloc][1]),
786 gloc_filtertxt[iflags.getloc_filter],
787 iflags.getloc_travelmode ? " for travel destination" : "");
789 Sprintf(tmpbuf, "%s%s
\82Å
\96Ú
\95W
\82Æ
\82·
\82é%s
\82ð
\91I
\91ð
\82µ
\82Ä
\82
\82¾
\82³
\82¢",
790 iflags.getloc_travelmode ? "
\88Ú
\93®
\82Ì
\82½
\82ß
\82É" : "",
791 gloc_filtertxt[iflags.getloc_filter],
792 gloc_descr[gloc][1]);
794 end_menu(tmpwin, tmpbuf);
795 pick_cnt = select_menu(tmpwin, PICK_ONE, &picks);
796 destroy_nhwindow(tmpwin);
798 ccp->x = garr[picks->item.a_int - 1].x;
799 ccp->y = garr[picks->item.a_int - 1].y;
800 free((genericptr_t) picks);
802 free((genericptr_t) garr);
803 return (pick_cnt > 0);
807 getpos(ccp, force, goal)
815 } const pick_chars_def[] = {
816 { NHKF_GETPOS_PICK, LOOK_TRADITIONAL },
817 { NHKF_GETPOS_PICK_Q, LOOK_QUICK },
818 { NHKF_GETPOS_PICK_O, LOOK_ONCE },
819 { NHKF_GETPOS_PICK_V, LOOK_VERBOSE }
821 static const int mMoOdDxX_def[] = {
822 NHKF_GETPOS_MON_NEXT,
823 NHKF_GETPOS_MON_PREV,
824 NHKF_GETPOS_OBJ_NEXT,
825 NHKF_GETPOS_OBJ_PREV,
826 NHKF_GETPOS_DOOR_NEXT,
827 NHKF_GETPOS_DOOR_PREV,
828 NHKF_GETPOS_UNEX_NEXT,
829 NHKF_GETPOS_UNEX_PREV,
830 NHKF_GETPOS_INTERESTING_NEXT,
831 NHKF_GETPOS_INTERESTING_PREV,
832 NHKF_GETPOS_VALID_NEXT,
833 NHKF_GETPOS_VALID_PREV
840 boolean msg_given = TRUE; /* clear message window by default */
841 boolean show_goal_msg = FALSE;
842 boolean hilite_state = FALSE;
843 coord *garr[NUM_GLOCS] = DUMMY;
844 int gcount[NUM_GLOCS] = DUMMY;
845 int gidx[NUM_GLOCS] = DUMMY;
847 for (i = 0; i < SIZE(pick_chars_def); i++)
848 pick_chars[i] = Cmd.spkeys[pick_chars_def[i].nhkf];
849 pick_chars[SIZE(pick_chars_def)] = '\0';
851 for (i = 0; i < SIZE(mMoOdDxX_def); i++)
852 mMoOdDxX[i] = Cmd.spkeys[mMoOdDxX_def[i]];
853 mMoOdDxX[SIZE(mMoOdDxX_def)] = '\0';
857 goal = "desired location";
859 goal = "
\96Ú
\93I
\92n";
862 pline("(For instructions type a '%s')",
863 visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
865 pline("('%s'
\82Å
\83w
\83\8b\83v)",
866 visctrl(Cmd.spkeys[NHKF_GETPOS_HELP]));
875 curs(WIN_MAP, cx, cy);
878 lock_mouse_cursor(TRUE);
883 pline("Move cursor to %s:", goal);
885 pline("
\83J
\81[
\83\
\83\8b\82ð%s
\82É
\93®
\82©
\82µ
\82Ä
\82
\82¾
\82³
\82¢:", goal);
886 curs(WIN_MAP, cx, cy);
888 show_goal_msg = FALSE;
889 } else if (iflags.autodescribe && !msg_given && !hilite_state) {
890 auto_describe(cx, cy);
893 c = nh_poskey(&tx, &ty, &sidx);
896 (*getpos_hilitefunc)(2);
897 hilite_state = FALSE;
898 curs(WIN_MAP, cx, cy);
902 if (iflags.autodescribe)
905 if (c == Cmd.spkeys[NHKF_ESC]) {
907 msg_given = TRUE; /* force clear */
914 /* a mouse click event, just assign and return */
919 if ((cp = index(pick_chars, c)) != 0) {
920 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
921 result = pick_chars_def[(int) (cp - pick_chars)].ret;
924 for (i = 0; i < 8; i++) {
927 if (Cmd.dirchars[i] == c) {
928 /* a normal movement letter or digit */
931 } else if (Cmd.alphadirchars[i] == lowc((char) c)
932 || (Cmd.num_pad && Cmd.dirchars[i] == (c & 0177))) {
933 /* a shifted movement letter or Meta-digit */
934 if (iflags.getloc_moveskip) {
935 /* skip same glyphs */
936 int glyph = glyph_at(cx, cy);
940 while (isok(cx + dx, cy + dy)
941 && glyph == glyph_at(cx + dx, cy + dy)
942 && isok(cx + dx + xdir[i], cy + dy + ydir[i])
943 && glyph == glyph_at(cx + dx + xdir[i],
944 cy + dy + ydir[i])) {
955 /* truncate at map edge; diagonal moves complicate this... */
957 dy -= sgn(dy) * (1 - (cx + dx));
958 dx = 1 - cx; /* so that (cx+dx == 1) */
959 } else if (cx + dx > COLNO - 1) {
960 dy += sgn(dy) * ((COLNO - 1) - (cx + dx));
961 dx = (COLNO - 1) - cx;
964 dx -= sgn(dx) * (0 - (cy + dy));
965 dy = 0 - cy; /* so that (cy+dy == 0) */
966 } else if (cy + dy > ROWNO - 1) {
967 dx += sgn(dx) * ((ROWNO - 1) - (cy + dy));
968 dy = (ROWNO - 1) - cy;
975 if (c == Cmd.spkeys[NHKF_GETPOS_HELP] || redraw_cmd(c)) {
976 if (c == Cmd.spkeys[NHKF_GETPOS_HELP])
977 getpos_help(force, goal);
979 docrt(); /* redraw */
980 /* update message window to reflect that we're still targetting */
981 show_goal_msg = TRUE;
983 } else if (c == Cmd.spkeys[NHKF_GETPOS_SHOWVALID]
984 && getpos_hilitefunc) {
986 (*getpos_hilitefunc)(0);
987 (*getpos_hilitefunc)(1);
991 } else if (c == Cmd.spkeys[NHKF_GETPOS_AUTODESC]) {
992 iflags.autodescribe = !iflags.autodescribe;
994 pline("Automatic description %sis %s.",
995 flags.verbose ? "of features under cursor " : "",
996 iflags.autodescribe ? "on" : "off");
998 pline("%s
\90à
\96¾
\8e©
\93®
\95\
\8e¦
\81F%s",
999 flags.verbose ? "
\83J
\81[
\83\
\83\8b\82Ì
\89º
\82É
\82 \82é
\82à
\82Ì
\82Ì" : "",
1000 iflags.autodescribe ? "
\83I
\83\93" : "
\83I
\83t");
1002 if (!iflags.autodescribe)
1003 show_goal_msg = TRUE;
1006 } else if (c == Cmd.spkeys[NHKF_GETPOS_LIMITVIEW]) {
1007 static const char *const view_filters[NUM_GFILTER] = {
1009 "Not limiting targets",
1010 "Limiting targets to those in sight",
1011 "Limiting targets to those in same area"
1013 "
\83^
\81[
\83Q
\83b
\83g
\82ð
\90§
\8cÀ
\82µ
\82È
\82¢",
1014 "
\8e\8b\8aE
\93à
\82É
\83^
\81[
\83Q
\83b
\83g
\82ð
\90§
\8cÀ
\82·
\82é",
1015 "
\93¯
\82¶
\83G
\83\8a\83A
\82É
\83^
\81[
\83Q
\83b
\83g
\82ð
\90§
\8cÀ
\82·
\82é"
1019 iflags.getloc_filter = (iflags.getloc_filter + 1) % NUM_GFILTER;
1020 for (i = 0; i < NUM_GLOCS; i++) {
1022 free((genericptr_t) garr[i]);
1025 gidx[i] = gcount[i] = 0;
1028 pline("%s.", view_filters[iflags.getloc_filter]);
1030 pline("%s
\81D", view_filters[iflags.getloc_filter]);
1033 } else if (c == Cmd.spkeys[NHKF_GETPOS_MENU]) {
1034 iflags.getloc_usemenu = !iflags.getloc_usemenu;
1036 pline("%s a menu to show possible targets%s.",
1037 iflags.getloc_usemenu ? "Using" : "Not using",
1038 iflags.getloc_usemenu
1039 ? " for 'm|M', 'o|O', 'd|D', and 'x|X'" : "");
1041 pline("
\89Â
\94\
\82È
\83^
\81[
\83Q
\83b
\83g
\82ð
\8c©
\82é
\82Ì
\82É
\83\81\83j
\83\85\81[
\82ð
\8eg%s
\81D%s",
1042 iflags.getloc_usemenu ? "
\82¤" : "
\82í
\82È
\82¢",
1043 iflags.getloc_usemenu
1044 ? "('m|M', 'o|O', 'd|D', 'x|X'
\97p)" : "");
1048 } else if (c == Cmd.spkeys[NHKF_GETPOS_SELF]) {
1049 /* reset 'm&M', 'o&O', &c; otherwise, there's no way for player
1050 to achieve that except by manually cycling through all spots */
1051 for (i = 0; i < NUM_GLOCS; i++)
1056 } else if (c == Cmd.spkeys[NHKF_GETPOS_MOVESKIP]) {
1057 iflags.getloc_moveskip = !iflags.getloc_moveskip;
1059 pline("%skipping over similar terrain when fastmoving the cursor.",
1060 iflags.getloc_moveskip ? "S" : "Not s");
1062 pline("
\83J
\81[
\83\
\83\8b\82ð
\8d\82\91¬
\88Ú
\93®
\82³
\82¹
\82é
\82Æ
\82«
\82É
\8e\97\82½
\82æ
\82¤
\82È
\92n
\8c`
\82ð
\94ò
\82Î%s
\81D",
1063 iflags.getloc_moveskip ? "
\82·" : "
\82³
\82È
\82¢");
1065 } else if ((cp = index(mMoOdDxX, c)) != 0) { /* 'm|M', 'o|O', &c */
1066 /* nearest or farthest monster or object or door or unexplored */
1067 int gtmp = (int) (cp - mMoOdDxX), /* 0..7 */
1068 gloc = gtmp >> 1; /* 0..3 */
1070 if (iflags.getloc_usemenu) {
1073 if (getpos_menu(&tmpcrd, gloc)) {
1081 gather_locs(&garr[gloc], &gcount[gloc], gloc);
1082 gidx[gloc] = 0; /* garr[][0] is hero's spot */
1084 if (!(gtmp & 1)) { /* c=='m' || c=='o' || c=='d' || c=='x') */
1085 gidx[gloc] = (gidx[gloc] + 1) % gcount[gloc];
1086 } else { /* c=='M' || c=='O' || c=='D' || c=='X') */
1087 if (--gidx[gloc] < 0)
1088 gidx[gloc] = gcount[gloc] - 1;
1090 cx = garr[gloc][gidx[gloc]].x;
1091 cy = garr[gloc][gidx[gloc]].y;
1094 if (!index(quitchars, c)) {
1095 char matching[MAXPCHARS];
1096 int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
1098 (void) memset((genericptr_t) matching, 0, sizeof matching);
1099 for (sidx = 1; sidx < MAXPCHARS; sidx++) { /* [0] left as 0 */
1100 if (IS_DOOR(sidx) || IS_WALL(sidx)
1101 || sidx == SDOOR || sidx == SCORR
1102 || glyph_to_cmap(k) == S_room
1103 || glyph_to_cmap(k) == S_darkroom
1104 || glyph_to_cmap(k) == S_corr
1105 || glyph_to_cmap(k) == S_litcorr)
1107 if (c == defsyms[sidx].sym || c == (int) showsyms[sidx])
1108 matching[sidx] = (char) ++k;
1111 for (pass = 0; pass <= 1; pass++) {
1112 /* pass 0: just past current pos to lower right;
1113 pass 1: upper left corner to current pos */
1114 lo_y = (pass == 0) ? cy : 0;
1115 hi_y = (pass == 0) ? ROWNO - 1 : cy;
1116 for (ty = lo_y; ty <= hi_y; ty++) {
1117 lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
1118 hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
1119 for (tx = lo_x; tx <= hi_x; tx++) {
1120 /* first, look at what is currently visible
1121 (might be monster) */
1122 k = glyph_at(tx, ty);
1123 if (glyph_is_cmap(k)
1124 && matching[glyph_to_cmap(k)])
1126 /* next, try glyph that's remembered here
1127 (might be trap or object) */
1128 if (level.flags.hero_memory
1129 /* !terrainmode: don't move to remembered
1130 trap or object if not currently shown */
1131 && !iflags.terrainmode) {
1132 k = levl[tx][ty].glyph;
1133 if (glyph_is_cmap(k)
1134 && matching[glyph_to_cmap(k)])
1137 /* last, try actual terrain here (shouldn't
1138 we be using lastseentyp[][] instead?) */
1139 if (levl[tx][ty].seenv) {
1140 k = back_to_glyph(tx, ty);
1141 if (glyph_is_cmap(k)
1142 && matching[glyph_to_cmap(k)])
1149 clear_nhwindow(WIN_MESSAGE);
1157 pline("Can't find dungeon feature '%c'.", c);
1159 pline("'%c'
\81H", c);
1167 Strcpy(note, "aborted");
1169 Strcpy(note, "
\92\86\92f
\82µ
\82½");
1172 Sprintf(note, "use '%c', '%c', '%c', '%c' or '%s'",
1173 Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E,
1174 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
1176 Sprintf(note, "%c%c%c%c
\82Å
\88Ú
\93®
\81C%s
\82Å
\8fI
\97¹",
1177 Cmd.move_W, Cmd.move_S, Cmd.move_N, Cmd.move_E,
1178 visctrl(Cmd.spkeys[NHKF_GETPOS_PICK]));
1181 pline("Unknown direction: '%s' (%s).", visctrl((char) c),
1183 pline("
\82»
\82Ì
\95û
\8cü
\82Í
\82È
\82¢
\81F'%s' (%s)", visctrl((char) c),
1186 } /* k => matching */
1193 pline("
\88È
\8fã
\81D");
1194 msg_given = FALSE; /* suppress clear */
1197 result = 0; /* not -1 */
1205 curs(WIN_MAP, cx, cy);
1209 lock_mouse_cursor(FALSE);
1212 clear_nhwindow(WIN_MESSAGE);
1215 for (i = 0; i < NUM_GLOCS; i++)
1217 free((genericptr_t) garr[i]);
1218 getpos_hilitefunc = (void FDECL((*), (int))) 0;
1219 getpos_getvalid = (boolean FDECL((*), (int, int))) 0;
1223 /* allocate space for a monster's name; removes old name if there is one */
1227 int lth; /* desired length (caller handles adding 1 for terminator) */
1230 /* allocate mextra if necessary; otherwise get rid of old name */
1232 mon->mextra = newmextra();
1234 free_mname(mon); /* already has mextra, might also have name */
1235 MNAME(mon) = (char *) alloc((unsigned) lth);
1237 /* zero length: the new name is empty; get rid of the old name */
1243 /* release a monster's name; retains mextra even if all fields are now null */
1248 if (has_mname(mon)) {
1249 free((genericptr_t) MNAME(mon));
1250 MNAME(mon) = (char *) 0;
1254 /* allocate space for an object's name; removes old name if there is one */
1258 int lth; /* desired length (caller handles adding 1 for terminator) */
1261 /* allocate oextra if necessary; otherwise get rid of old name */
1263 obj->oextra = newoextra();
1265 free_oname(obj); /* already has oextra, might also have name */
1266 ONAME(obj) = (char *) alloc((unsigned) lth);
1268 /* zero length: the new name is empty; get rid of the old name */
1274 /* release an object's name; retains oextra even if all fields are now null */
1279 if (has_oname(obj)) {
1280 free((genericptr_t) ONAME(obj));
1281 ONAME(obj) = (char *) 0;
1285 /* safe_oname() always returns a valid pointer to
1286 * a string, either the pointer to an object's name
1287 * if it has one, or a pointer to an empty string
1299 /* historical note: this returns a monster pointer because it used to
1300 allocate a new bigger block of memory to hold the monster and its name */
1302 christen_monst(mtmp, name)
1309 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
1310 lth = (name && *name) ? ((int) strlen(name) + 1) : 0;
1311 if (lth > PL_PSIZ) {
1313 if (is_kanji2(buf, lth - 1))
1317 name = strncpy(buf, name, PL_PSIZ - 1);
1318 buf[PL_PSIZ - 1] = '\0';
1320 new_mname(mtmp, lth); /* removes old name if one is present */
1322 Strcpy(MNAME(mtmp), name);
1326 /* check whether user-supplied name matches or nearly matches an unnameable
1327 monster's name; if so, give an alternate reject message for do_mname() */
1329 alreadynamed(mtmp, monnambuf, usrbuf)
1331 char *monnambuf, *usrbuf;
1333 char pronounbuf[10], *p;
1335 if (fuzzymatch(usrbuf, monnambuf, " -_", TRUE)
1336 /* catch trying to name "the Oracle" as "Oracle" */
1337 || (!strncmpi(monnambuf, "the ", 4)
1338 && fuzzymatch(usrbuf, monnambuf + 4, " -_", TRUE))
1339 /* catch trying to name "invisible Orcus" as "Orcus" */
1340 || ((p = strstri(monnambuf, "invisible ")) != 0
1341 && fuzzymatch(usrbuf, p + 10, " -_", TRUE))
1342 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
1343 || ((p = strstri(monnambuf, " of ")) != 0
1344 && fuzzymatch(usrbuf, p + 4, " -_", TRUE))) {
1346 pline("%s is already called %s.",
1347 upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
1349 pline("%s
\82Í
\8aù
\82É%s
\82Æ
\8cÄ
\82Î
\82ê
\82Ä
\82¢
\82é
\81D",
1350 upstart(strcpy(pronounbuf, mhe(mtmp))), monnambuf);
1353 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Í
\8eg
\82í
\82È
\82¢*/
1354 } else if (mtmp->data == &mons[PM_JUIBLEX]
1355 && strstri(monnambuf, "Juiblex")
1356 && !strcmpi(usrbuf, "Jubilex")) {
1357 pline("%s doesn't like being called %s.", upstart(monnambuf), usrbuf);
1364 /* allow player to assign a name to some chosen monster */
1368 char buf[BUFSZ], monnambuf[BUFSZ], qbuf[QBUFSZ];
1371 struct monst *mtmp = 0;
1373 if (Hallucination) {
1375 You("would never recognize it anyway.");
1377 You("
\82»
\82ê
\82ð
\94F
\8e¯
\82Å
\82«
\82È
\82¢
\81D");
1383 if (getpos(&cc, FALSE, "the monster you want to name") < 0
1385 if (getpos(&cc, FALSE, "
\82 \82È
\82½
\82ª
\96¼
\82Ã
\82¯
\82½
\82¢
\89ö
\95¨") < 0
1386 || !isok(cc.x, cc.y))
1388 cx = cc.x, cy = cc.y;
1390 if (cx == u.ux && cy == u.uy) {
1391 if (u.usteed && canspotmon(u.usteed)) {
1395 pline("This %s creature is called %s and cannot be renamed.",
1397 pline("
\82±
\82Ì%s
\90¶
\82«
\95¨
\82Í%s
\82Æ
\8cÄ
\82Î
\82ê
\82Ä
\82¢
\82Ä
\81C
\96¼
\91O
\82Í
\95Ï
\8dX
\82Å
\82«
\82È
\82¢
\81D",
1398 beautiful(), plname);
1402 mtmp = m_at(cx, cy);
1406 && (!(cansee(cx, cy) || see_with_infrared(mtmp))
1407 || mtmp->mundetected || M_AP_TYPE(mtmp) == M_AP_FURNITURE
1408 || M_AP_TYPE(mtmp) == M_AP_OBJECT
1409 || (mtmp->minvis && !See_invisible)))) {
1411 pline("I see no monster there.");
1413 pline("
\82»
\82±
\82É
\89ö
\95¨
\82Í
\82¢
\82È
\82¢
\81D");
1416 /* special case similar to the one in lookat() */
1418 Sprintf(qbuf, "What do you want to call %s?",
1420 Sprintf(qbuf, "%s
\82ð
\89½
\82Æ
\8cÄ
\82Ñ
\82Ü
\82·
\82©
\81H",
1421 distant_monnam(mtmp, ARTICLE_THE, monnambuf));
1424 /* if there's an existing name, make it be the default answer */
1425 if (has_mname(mtmp))
1426 Strcpy(buf, MNAME(mtmp));
1429 if (!*buf || *buf == '\033')
1431 /* strip leading and trailing spaces; unnames monster if all spaces */
1432 (void) mungspaces(buf);
1434 /* Unique monsters have their own specific names or titles.
1435 * Shopkeepers, temple priests and other minions use alternate
1436 * name formatting routines which ignore any user-supplied name.
1438 * Don't say the name is being rejected if it happens to match
1439 * the existing name.
1441 * TODO: should have an alternate message when the attempt is to
1442 * remove existing name without assigning a new one.
1444 if ((mtmp->data->geno & G_UNIQ) && !mtmp->ispriest) {
1445 if (!alreadynamed(mtmp, monnambuf, buf))
1447 pline("%s doesn't like being called names!", upstart(monnambuf));
1449 pline("%s
\82Í
\82 \82¾
\96¼
\82Å
\8cÄ
\82Î
\82ê
\82é
\82Ì
\82ª
\8c\99\82¢
\82È
\82æ
\82¤
\82¾
\81I", Monnam(mtmp));
1450 } else if (mtmp->isshk
1451 && !(Deaf || mtmp->msleeping || !mtmp->mcanmove
1452 || mtmp->data->msound <= MS_ANIMAL)) {
1453 if (!alreadynamed(mtmp, monnambuf, buf))
1455 verbalize("I'm %s, not %s.", shkname(mtmp), buf);
1457 verbalize("
\8e\84\82Í%s
\82¾
\81C%s
\82Å
\82Í
\82È
\82¢
\81D", shkname(mtmp), buf);
1458 } else if (mtmp->ispriest || mtmp->isminion || mtmp->isshk) {
1459 if (!alreadynamed(mtmp, monnambuf, buf))
1461 pline("%s will not accept the name %s.", upstart(monnambuf), buf);
1463 pline("%s
\82Í%s
\82Æ
\82¢
\82¤
\96¼
\91O
\82ð
\8eó
\82¯
\82¢
\82ê
\82È
\82©
\82Á
\82½
\81D", monnambuf, buf);
1465 (void) christen_monst(mtmp, buf);
1468 STATIC_VAR int via_naming = 0;
1471 * This routine used to change the address of 'obj' so be unsafe if not
1472 * used with extreme care. Applying a name to an object no longer
1473 * allocates a replacement object, so that old risk is gone.
1478 register struct obj *obj;
1480 char *bufp, buf[BUFSZ], bufcpy[BUFSZ], qbuf[QBUFSZ];
1484 /* Do this now because there's no point in even asking for a name */
1485 if (obj->otyp == SPE_NOVEL) {
1487 pline("%s already has a published name.", Ysimple_name2(obj));
1489 pline("%s
\82É
\82Í
\82·
\82Å
\82É
\8fo
\94Å
\8e\9e\82Ì
\96¼
\91O
\82ª
\82 \82é
\81D", Ysimple_name2(obj));
1494 Sprintf(qbuf, "What do you want to name %s ",
1495 is_plural(obj) ? "these" : "this");
1496 (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item");
1498 (void) safe_qbuf(qbuf, "", "
\82ð
\89½
\82Æ
\96¼
\82Ã
\82¯
\82Ü
\82·
\82©
\81H", obj, xname,
1499 simpleonames, "
\82»
\82ê");
1503 /* if there's an existing name, make it be the default answer */
1505 Strcpy(buf, ONAME(obj));
1508 if (!*buf || *buf == '\033')
1510 /* strip leading and trailing spaces; unnames item if all spaces */
1511 (void) mungspaces(buf);
1514 * We don't violate illiteracy conduct here, although it is
1515 * arguable that we should for anything other than "X". Doing so
1516 * would make attaching player's notes to hero's inventory have an
1517 * in-game effect, which may or may not be the correct thing to do.
1519 * We do violate illiteracy in oname() if player creates Sting or
1520 * Orcrist, clearly being literate (no pun intended...).
1523 /* relax restrictions over proper capitalization for artifacts */
1524 if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
1527 if (obj->oartifact) {
1529 pline_The("artifact seems to resist the attempt.");
1531 pline("
\90¹
\8aí
\82Í
\96¼
\82Ã
\82¯
\82ð
\8b\91\94Û
\82µ
\82Ä
\82¢
\82é
\82æ
\82¤
\82¾
\81D");
1533 } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
1534 /* this used to change one letter, substituting a value
1535 of 'a' through 'y' (due to an off by one error, 'z'
1536 would never be selected) and then force that to
1537 upper case if such was the case of the input;
1538 now, the hand slip scuffs one or two letters as if
1539 the text had been trodden upon, sometimes picking
1540 punctuation instead of an arbitrary letter;
1541 unfortunately, we have to cover the possibility of
1542 it targetting spaces so failing to make any change
1543 (we know that it must eventually target a nonspace
1544 because buf[] matches a valid artifact name) */
1545 Strcpy(bufcpy, buf);
1546 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
1547 bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf;
1549 wipeout_text(bufp, rn2_on_display_rng(2), (unsigned) 0);
1550 } while (!strcmp(buf, bufcpy));
1552 pline("While engraving, your %s slips.", body_part(HAND));
1554 pline("
\8d\8f\82ñ
\82Å
\82¢
\82é
\8aÔ
\82É%s
\82ª
\8a\8a\82Á
\82Ä
\82µ
\82Ü
\82Á
\82½
\81D", body_part(HAND));
1555 display_nhwindow(WIN_MESSAGE, FALSE);
1557 You("engrave: \"%s\".", buf);
1559 You("
\8d\8f\82ñ
\82¾:
\81u%s
\81v
\81D",buf);
1560 /* violate illiteracy conduct since hero attempted to write
1561 a valid artifact name */
1562 u.uconduct.literate++;
1564 ++via_naming; /* This ought to be an argument rather than a static... */
1565 obj = oname(obj, buf);
1566 --via_naming; /* ...but oname() is used in a lot of places, so defer. */
1577 lth = *name ? (int) (strlen(name) + 1) : 0;
1578 if (lth > PL_PSIZ) {
1581 name = strncpy(buf, name, PL_PSIZ - 1);
1582 buf[PL_PSIZ - 1] = '\0';
1584 if (is_kanji2(name, lth - 1))
1586 name = strncpy(buf, name, lth - 1);
1587 buf[lth - 1] = '\0';
1590 /* If named artifact exists in the game, do not create another.
1591 * Also trying to create an artifact shouldn't de-artifact
1592 * it (e.g. Excalibur from prayer). In this case the object
1593 * will retain its current name. */
1594 if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
1597 new_oname(obj, lth); /* removes old name if one is present */
1599 Strcpy(ONAME(obj), name);
1602 artifact_exists(obj, name, TRUE);
1603 if (obj->oartifact) {
1604 /* can't dual-wield with artifact as secondary weapon */
1605 if (obj == uswapwep)
1607 /* activate warning if you've just named your weapon "Sting" */
1609 set_artifact_intrinsic(obj, TRUE, W_WEP);
1610 /* if obj is owned by a shop, increase your bill */
1612 alter_cost(obj, 0L);
1614 /* violate illiteracy conduct since successfully wrote arti-name */
1615 u.uconduct.literate++;
1623 static NEARDATA const char callable[] = {
1624 SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
1625 GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0
1629 objtyp_is_callable(i)
1632 return (boolean) (objects[i].oc_uname
1633 || (OBJ_DESCR(objects[i])
1634 && index(callable, objects[i].oc_class)));
1637 /* C and #name commands - player can name monster or object or type of obj */
1644 menu_item *pick_list = 0;
1645 char ch, allowall[2];
1646 /* if player wants a,b,c instead of i,o when looting, do that here too */
1647 boolean abc = flags.lootabc;
1649 win = create_nhwindow(NHW_MENU);
1652 any.a_char = 'm'; /* group accelerator 'C' */
1653 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'C', ATR_NONE,
1655 "a monster", MENU_UNSELECTED);
1657 "
\89ö
\95¨", MENU_UNSELECTED);
1659 /* we use y and n as accelerators so that we can accept user's
1660 response keyed to old "name an individual object?" prompt */
1661 any.a_char = 'i'; /* group accelerator 'y' */
1662 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'y', ATR_NONE,
1664 "a particular object in inventory", MENU_UNSELECTED);
1666 "
\8e\9d\82¿
\95¨
\82Ì
\92\86\82Ì
\88ê
\82Â
\82Ì
\83A
\83C
\83e
\83\80", MENU_UNSELECTED);
1667 any.a_char = 'o'; /* group accelerator 'n' */
1668 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'n', ATR_NONE,
1670 "the type of an object in inventory", MENU_UNSELECTED);
1672 "
\8e\9d\82¿
\95¨
\82Ì
\92\86\82Ì
\88ê
\82Â
\82Ì
\83A
\83C
\83e
\83\80\82Ì
\8eí
\97Þ", MENU_UNSELECTED);
1674 any.a_char = 'f'; /* group accelerator ',' (or ':' instead?) */
1675 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, ',', ATR_NONE,
1677 "the type of an object upon the floor", MENU_UNSELECTED);
1679 "
\8f°
\82Ì
\8fã
\82É
\82 \82é
\88ê
\82Â
\82Ì
\83A
\83C
\83e
\83\80\82Ì
\8eí
\97Þ", MENU_UNSELECTED);
1680 any.a_char = 'd'; /* group accelerator '\' */
1681 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, '\\', ATR_NONE,
1683 "the type of an object on discoveries list", MENU_UNSELECTED);
1685 "
\94
\8c©
\95¨
\88ê
\97\97\82É
\82 \82é
\88ê
\82Â
\82Ì
\83A
\83C
\83e
\83\80\82Ì
\8eí
\97Þ", MENU_UNSELECTED);
1686 any.a_char = 'a'; /* group accelerator 'l' */
1687 add_menu(win, NO_GLYPH, &any, abc ? 0 : any.a_char, 'l', ATR_NONE,
1689 "record an annotation for the current level", MENU_UNSELECTED);
1691 "
\8c»
\8dÝ
\82Ì
\8aK
\82É
\91Î
\82·
\82é
\83\81\83\82\82Ì
\8bL
\98^", MENU_UNSELECTED);
1693 end_menu(win, "What do you want to name?");
1695 end_menu(win, "
\82Ç
\82ê
\82É
\96¼
\91O
\82ð
\82Â
\82¯
\82Ü
\82·
\82©
\81H");
1696 if (select_menu(win, PICK_ONE, &pick_list) > 0) {
1697 ch = pick_list[0].item.a_char;
1698 free((genericptr_t) pick_list);
1701 destroy_nhwindow(win);
1707 case 'm': /* name a visible monster */
1710 case 'i': /* name an individual object in inventory */
1711 allowall[0] = ALL_CLASSES;
1713 obj = getobj(allowall, "name");
1717 case 'o': /* name a type of object in inventory */
1718 obj = getobj(callable, "call");
1720 /* behave as if examining it in inventory;
1721 this might set dknown if it was picked up
1722 while blind and the hero can now see */
1727 You("would never recognize another one.");
1729 You("
\91¼
\82É
\94F
\8e¯
\82Å
\82«
\82È
\82¢
\81D");
1731 } else if (!objtyp_is_callable(obj->otyp)) {
1732 You("know those as well as you ever will.");
1739 case 'f': /* name a type of object visible on the floor */
1742 case 'd': /* name a type of object on the discoveries list */
1745 case 'a': /* annotate level */
1752 /* for use by safe_qbuf() */
1760 otemp.oextra = (struct oextra *) 0;
1762 /* in case water is already known, convert "[un]holy water" to "water" */
1763 otemp.blessed = otemp.cursed = 0;
1764 /* remove attributes that are doname() caliber but get formatted
1765 by xname(); most of these fixups aren't really needed because the
1766 relevant type of object isn't callable so won't reach this far */
1767 if (otemp.oclass == WEAPON_CLASS)
1768 otemp.opoisoned = 0; /* not poisoned */
1769 else if (otemp.oclass == POTION_CLASS)
1770 otemp.odiluted = 0; /* not diluted */
1771 else if (otemp.otyp == TOWEL || otemp.otyp == STATUE)
1772 otemp.spe = 0; /* not wet or historic */
1773 else if (otemp.otyp == TIN)
1774 otemp.known = 0; /* suppress tin type (homemade, &c) and mon type */
1775 else if (otemp.otyp == FIGURINE)
1776 otemp.corpsenm = NON_PM; /* suppress mon type */
1777 else if (otemp.otyp == HEAVY_IRON_BALL)
1778 otemp.owt = objects[HEAVY_IRON_BALL].oc_weight; /* not "very heavy" */
1779 else if (otemp.oclass == FOOD_CLASS && otemp.globby)
1780 otemp.owt = 120; /* 6*20, neither a small glob nor a large one */
1782 return an(xname(&otemp));
1789 char buf[BUFSZ], qbuf[QBUFSZ];
1793 return; /* probably blind */
1794 flush_screen(1); /* buffered updates might matter to player's response */
1796 if (obj->oclass == POTION_CLASS && obj->fromsink)
1797 /* kludge, meaning it's sink water */
1799 Sprintf(qbuf, "Call a stream of %s fluid:",
1801 Sprintf(qbuf, "%s
\89t
\91Ì:",
1802 OBJ_DESCR(objects[obj->otyp]));
1805 (void) safe_qbuf(qbuf, "Call ", ":", obj,
1806 docall_xname, simpleonames, "thing");
1808 (void) safe_qbuf(qbuf, "", "
\82É
\89½
\82Æ
\96¼
\91O
\82ð
\95t
\82¯
\82é
\81H", obj,
1809 docall_xname, simpleonames, "
\82±
\82ê");
1811 /* pointer to old name */
1812 str1 = &(objects[obj->otyp].oc_uname);
1815 /* if there's an existing name, make it be the default answer */
1820 if (!*buf || *buf == '\033')
1823 /* clear old name */
1825 free((genericptr_t) *str1);
1827 /* strip leading and trailing spaces; uncalls item if all spaces */
1828 (void) mungspaces(buf);
1830 if (*str1) { /* had name, so possibly remove from disco[] */
1831 /* strip name first, for the update_inventory() call
1832 from undiscover_object() */
1834 undiscover_object(obj->otyp);
1837 *str1 = dupstr(buf);
1838 discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
1848 struct obj *obj = 0;
1850 boolean fakeobj = FALSE, use_plural;
1852 boolean fakeobj = FALSE;
1855 cc.x = u.ux, cc.y = u.uy;
1856 /* "dot for under/over you" only makes sense when the cursor hasn't
1857 been moved off the hero's '@' yet, but there's no way to adjust
1858 the help text once getpos() has started */
1860 Sprintf(buf, "object on map (or '.' for one %s you)",
1861 (u.uundetected && hides_under(youmonst.data)) ? "over" : "under");
1863 Strcpy(buf, "
\92n
\90}
\8fã
\82Ì
\95¨
\91Ì(
\82 \82é
\82¢
\82Í'.'
\82Å
\82 \82È
\82½
\82Ì
\82¢
\82é
\8fê
\8f\8a");
1865 if (getpos(&cc, FALSE, buf) < 0 || cc.x <= 0)
1867 if (cc.x == u.ux && cc.y == u.uy) {
1868 obj = vobj_at(u.ux, u.uy);
1870 glyph = glyph_at(cc.x, cc.y);
1871 if (glyph_is_object(glyph))
1872 fakeobj = object_from_map(glyph, cc.x, cc.y, &obj);
1873 /* else 'obj' stays null */
1876 /* "under you" is safe here since there's no object to hide under */
1878 pline("There doesn't seem to be any object %s.",
1879 (cc.x == u.ux && cc.y == u.uy) ? "under you" : "there");
1881 pline("%s
\82É
\82Í
\89½
\82à
\82È
\82¢
\82æ
\82¤
\82¾
\81D",
1882 (cc.x == u.ux && cc.y == u.uy) ? "
\82 \82È
\82½
\82Ì
\89º" : "
\82»
\82±");
1886 /* note well: 'obj' might be an instance of STRANGE_OBJECT if target
1887 is a mimic; passing that to xname (directly or via simpleonames)
1888 would yield "glorkum" so we need to handle it explicitly; it will
1889 always fail the Hallucination test and pass the !callable test,
1890 resulting in the "can't be assigned a type name" message */
1891 Strcpy(buf, (obj->otyp != STRANGE_OBJECT)
1893 : obj_descr[STRANGE_OBJECT].oc_name);
1895 use_plural = (obj->quan > 1L);
1897 if (Hallucination) {
1898 const char *unames[6];
1901 /* straight role name */
1902 unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
1905 /* random rank title for hero's role
1907 note: the 30 is hardcoded in xlev_to_rank, so should be
1908 hardcoded here too */
1909 unames[1] = rank_of(rn2_on_display_rng(30) + 1,
1910 Role_switch, flags.female);
1911 /* random fake monster */
1912 unames[2] = bogusmon(tmpbuf, (char *) 0);
1913 /* increased chance for fake monster */
1914 unames[3] = unames[2];
1916 unames[4] = roguename();
1919 unames[5] = "Wibbly Wobbly";
1921 unames[5] = "
\82¤
\82ë
\82¤
\82ë";
1923 pline("%s %s to call you \"%s.\"",
1924 The(buf), use_plural ? "decide" : "decides",
1925 unames[rn2_on_display_rng(SIZE(unames))]);
1927 pline("%s
\82Í
\82 \82È
\82½
\82ð
\81u%s
\81v
\82Æ
\8cÄ
\82Ô
\82±
\82Æ
\82É
\8c\88\82ß
\82½
\81D",
1929 unames[rn2_on_display_rng(SIZE(unames))]);
1931 } else if (!objtyp_is_callable(obj->otyp)) {
1933 pline("%s %s can't be assigned a type name.",
1934 use_plural ? "Those" : "That", buf);
1936 pline("%s
\82É
\8eí
\97Þ
\82Ì
\96¼
\91O
\82ð
\8a\84\82è
\93\96\82Ä
\82é
\82±
\82Æ
\82Í
\82Å
\82«
\82È
\82¢
\81D",
1939 } else if (!obj->dknown) {
1941 You("don't know %s %s well enough to name %s.",
1942 use_plural ? "those" : "that", buf, use_plural ? "them" : "it");
1944 You("
\96¼
\91O
\82ð
\95t
\82¯
\82ç
\82ê
\82é
\82Ù
\82Ç%s
\82Ì
\82±
\82Æ
\82ð
\82æ
\82
\92m
\82ç
\82È
\82¢
\81D",
1951 obj->where = OBJ_FREE; /* object_from_map() sets it to OBJ_FLOOR */
1956 static const char *const ghostnames[] = {
1957 /* these names should have length < PL_NSIZ */
1958 /* Capitalize the names for aesthetics -dgk */
1959 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1960 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1961 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1962 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1963 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1964 "Stephan", "Lance Braccus", "Shadowhawk"
1967 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1971 return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *) plname;
1975 * Monster naming functions:
1976 * x_monnam is the generic monster-naming function.
1977 * seen unseen detected named
1978 * mon_nam: the newt it the invisible orc Fido
1979 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1980 * l_monnam: newt it invisible orc dog called Fido
1981 * Monnam: The newt It The invisible orc Fido
1982 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1983 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1984 * Amonnam: A newt It An invisible orc Fido
1985 * a_monnam: a newt it an invisible orc Fido
1986 * m_monnam: newt xan orc Fido
1987 * y_monnam: your newt your xan your invisible orc Fido
1988 * noname_monnam(mon,article):
1989 * article newt art xan art invisible orc art dog
1992 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1993 * options works, since those are special cases.
1996 x_monnam(mtmp, article, adjective, suppress, called)
1997 register struct monst *mtmp;
1999 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
2000 * ARTICLE_YOUR: "your" on pets, "the" on everything else
2002 * If the monster would be referred to as "it" or if the monster has a name
2003 * _and_ there is no adjective, "invisible", "saddled", etc., override this
2004 * and always use no article.
2006 const char *adjective;
2008 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
2009 * EXACT_NAME: combination of all the above
2010 * SUPPRESS_NAME: omit monster's assigned name (unless uniq w/ pname).
2014 char *buf = nextmbuf();
2015 struct permonst *mdat = mtmp->data;
2016 const char *pm_name = mdat->mname;
2017 boolean do_hallu, do_invis, do_it, do_saddle, do_name;
2019 boolean name_at_start, has_adjectives;
2023 if (program_state.gameover)
2024 suppress |= SUPPRESS_HALLUCINATION;
2025 if (article == ARTICLE_YOUR && !mtmp->mtame)
2026 article = ARTICLE_THE;
2028 do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
2029 do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
2030 do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR
2031 && !program_state.gameover && mtmp != u.usteed
2032 && !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT);
2033 do_saddle = !(suppress & SUPPRESS_SADDLE);
2034 do_name = !(suppress & SUPPRESS_NAME) || type_is_pname(mdat);
2038 /* unseen monsters, etc. Use "it" */
2043 Strcpy(buf, "
\89½
\8eÒ
\82©");
2047 /* priests and minions: don't even use this function */
2048 if (mtmp->ispriest || mtmp->isminion) {
2049 char priestnambuf[BUFSZ];
2051 long save_prop = EHalluc_resistance;
2052 unsigned save_invis = mtmp->minvis;
2054 /* when true name is wanted, explicitly block Hallucination */
2056 EHalluc_resistance = 1L;
2059 name = priestname(mtmp, priestnambuf);
2060 EHalluc_resistance = save_prop;
2061 mtmp->minvis = save_invis;
2063 if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
2066 return strcpy(buf, name);
2068 /* an "aligned priest" not flagged as a priest or minion should be
2069 "priest" or "priestess" (normally handled by priestname()) */
2070 if (mdat == &mons[PM_ALIGNED_PRIEST])
2072 pm_name = mtmp->female ? "priestess" : "priest";
2074 pm_name = mtmp->female ? "
\93ò
\91m" : "
\91m
\97µ";
2075 else if (mdat == &mons[PM_HIGH_PRIEST] && mtmp->female)
2077 pm_name = "high priestess";
2079 pm_name = "
\96@
\89¤";
2081 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
2082 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
2083 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
2084 * none of this applies.
2086 if (mtmp->isshk && !do_hallu) {
2088 if (adjective && article == ARTICLE_THE) {
2089 /* pathological case: "the angry Asidonhopo the blue dragon"
2091 Strcpy(buf, "the ");
2092 Strcat(strcat(buf, adjective), " ");
2093 Strcat(buf, shkname(mtmp));
2096 Strcat(buf, shkname(mtmp));
2097 if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
2099 Strcat(buf, " the ");
2101 Strcat(buf, "invisible ");
2102 Strcat(buf, pm_name);
2105 if (mdat == &mons[PM_SHOPKEEPER] && !do_invis){
2106 Strcpy(buf, shkname(mtmp));
2108 Sprintf(buf, "%s
\82Æ
\82¢
\82¤
\96¼
\82Ì%s%s",
2109 shkname(mtmp), do_invis ? "
\8ep
\82Ì
\8c©
\82¦
\82È
\82¢" : "",
2116 /* Put the adjectives in the buffer */
2119 Strcat(strcat(buf, adjective), " ");
2121 Strcat(buf, adjective);
2124 Strcat(buf, "invisible ");
2126 Strcat(buf, "
\8ep
\82Ì
\8c©
\82¦
\82È
\82¢");
2127 if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind
2130 Strcat(buf, "saddled ");
2132 Strcat(buf, "
\88Æ
\82Ì
\82Â
\82¢
\82Ä
\82¢
\82é");
2134 has_adjectives = (buf[0] != '\0');
2137 /* Put the actual monster name or type into the buffer now.
2138 Remember whether the buffer starts with a personal name. */
2141 char *rname = rndmonnam(&rnamecode);
2145 name_at_start = bogon_is_pname(rnamecode);
2147 } else if (do_name && has_mname(mtmp)) {
2148 char *name = MNAME(mtmp);
2150 if (mdat == &mons[PM_GHOST]) {
2152 Sprintf(eos(buf), "%s ghost", s_suffix(name));
2154 Sprintf(buf, "%s
\82Ì
\97H
\97ì", name);
2156 name_at_start = TRUE;
2158 } else if (called) {
2160 Sprintf(eos(buf), "%s called %s", pm_name, name);
2162 Sprintf(eos(buf), "%s
\82Æ
\82¢
\82¤
\96¼
\82Ì%s", name, pm_name);
2164 name_at_start = (boolean) type_is_pname(mdat);
2166 #if 0 /*JP*//*
\92è
\8a¥
\8e\8c\82Ì
\8f\88\97\9d\82Í
\95s
\97v*/
2167 } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
2168 /* <name> the <adjective> <invisible> <saddled> <rank> */
2172 pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
2175 Strcat(pbuf, bp + 5); /* append the rest of the name */
2177 article = ARTICLE_NONE;
2178 name_at_start = TRUE;
2183 name_at_start = TRUE;
2186 } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
2189 Strcpy(pbuf, rank_of((int) mtmp->m_lev, monsndx(mdat),
2190 (boolean) mtmp->female));
2192 Strcat(buf, lcase(pbuf));
2197 name_at_start = FALSE;
2200 Strcat(buf, pm_name);
2202 name_at_start = (boolean) type_is_pname(mdat);
2206 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82É
\8a¥
\8e\8c\82Í
\82È
\82¢*/
2207 if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
2208 if (mdat == &mons[PM_WIZARD_OF_YENDOR])
2209 article = ARTICLE_THE;
2211 article = ARTICLE_NONE;
2212 } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
2213 article = ARTICLE_THE;
2221 Strcpy(buf2, "your ");
2226 Strcpy(buf2, "the ");
2246 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0,
2247 (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE);
2254 return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
2255 (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, FALSE);
2258 /* print the name as if mon_nam() was called, but assume that the player
2259 * can always see the monster--used for probing and for monsters aggravating
2260 * the player with a cursed potion of invisibility
2266 return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
2267 (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT)
2276 register char *bp = mon_nam(mtmp);
2286 register char *bp = noit_mon_nam(mtmp);
2292 /* return "a dog" rather than "Fido", honoring hallucination and visibility */
2294 noname_monnam(mtmp, article)
2298 return x_monnam(mtmp, article, (char *) 0, SUPPRESS_NAME, FALSE);
2301 /* monster's own name -- overrides hallucination and [in]visibility
2302 so shouldn't be used in ordinary messages (mainly for disclosure) */
2307 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, EXACT_NAME, FALSE);
2310 /* pet name: "your little dog" */
2315 int prefix, suppression_flag;
2317 prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
2318 suppression_flag = (has_mname(mtmp)
2319 /* "saddled" is redundant when mounted */
2320 || mtmp == u.usteed)
2324 return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE);
2328 Adjmonnam(mtmp, adj)
2332 char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
2333 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
2343 return x_monnam(mtmp, ARTICLE_A, (char *) 0,
2344 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
2351 char *bp = a_monnam(mtmp);
2357 /* used for monster ID by the '/', ';', and 'C' commands to block remote
2358 identification of the endgame altars via their attending priests */
2360 distant_monnam(mon, article, outbuf)
2362 int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
2365 /* high priest(ess)'s identity is concealed on the Astral Plane,
2366 unless you're adjacent (overridden for hallucination which does
2367 its own obfuscation) */
2368 if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination
2369 && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
2371 Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
2372 Strcat(outbuf, mon->female ? "high priestess" : "high priest");
2374 Strcpy(outbuf, "
\96@
\89¤");
2377 Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE));
2382 /* returns mon_nam(mon) relative to other_mon; normal name unless they're
2383 the same, in which case the reference is to {him|her|it} self */
2385 mon_nam_too(mon, other_mon)
2386 struct monst *mon, *other_mon;
2390 if (mon != other_mon) {
2391 outbuf = mon_nam(mon);
2393 outbuf = nextmbuf();
2395 switch (pronoun_gender(mon, FALSE)) {
2397 Strcpy(outbuf, "himself");
2400 Strcpy(outbuf, "herself");
2403 Strcpy(outbuf, "itself");
2407 Strcpy(outbuf, "
\8e©
\95ª
\8e©
\90g");
2413 /* for debugging messages, where data might be suspect and we aren't
2414 taking what the hero does or doesn't know into consideration */
2416 minimal_monnam(mon, ckloc)
2420 struct permonst *ptr;
2421 char *outbuf = nextmbuf();
2424 Strcpy(outbuf, "[Null monster]");
2425 } else if ((ptr = mon->data) == 0) {
2426 Strcpy(outbuf, "[Null mon->data]");
2427 } else if (ptr < &mons[0]) {
2428 Sprintf(outbuf, "[Invalid mon->data %s < %s]",
2429 fmt_ptr((genericptr_t) mon->data),
2430 fmt_ptr((genericptr_t) &mons[0]));
2431 } else if (ptr >= &mons[NUMMONS]) {
2432 Sprintf(outbuf, "[Invalid mon->data %s >= %s]",
2433 fmt_ptr((genericptr_t) mon->data),
2434 fmt_ptr((genericptr_t) &mons[NUMMONS]));
2435 } else if (ckloc && ptr == &mons[PM_LONG_WORM]
2436 && level.monsters[mon->mx][mon->my] != mon) {
2437 Sprintf(outbuf, "%s <%d,%d>",
2438 mons[PM_LONG_WORM_TAIL].mname, mon->mx, mon->my);
2440 Sprintf(outbuf, "%s%s <%d,%d>",
2441 mon->mtame ? "tame " : mon->mpeaceful ? "peaceful " : "",
2442 mon->data->mname, mon->mx, mon->my);
2443 if (mon->cham != NON_PM)
2444 Sprintf(eos(outbuf), "{%s}", mons[mon->cham].mname);
2449 /* fake monsters used to be in a hard-coded array, now in a data file */
2454 static const char bogon_codes[] = "-_+|="; /* see dat/bonusmon.txt */
2459 /* might fail (return empty buf[]) if the file isn't available */
2460 get_rnd_text(BOGUSMONFILE, buf, rn2_on_display_rng);
2462 Strcpy(buf, "bogon");
2463 } else if (index(bogon_codes, *mname)) { /* strip prefix if present */
2471 /* return a random monster name, for hallucination */
2476 static char buf[BUFSZ];
2479 #define BOGUSMONSIZE 100 /* arbitrary */
2485 name = rn2_on_display_rng(SPECIAL_PM + BOGUSMONSIZE - LOW_PM) + LOW_PM;
2486 } while (name < SPECIAL_PM
2487 && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
2489 if (name >= SPECIAL_PM) {
2490 mname = bogusmon(buf, code);
2492 mname = strcpy(buf, mons[name].mname);
2498 /* check bogusmon prefix to decide whether it's a personal name */
2500 bogon_is_pname(code)
2505 return index("-+=", code) ? TRUE : FALSE;
2508 /* name of a Rogue player */
2514 if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
2515 for (i = opts; *i; i++)
2516 if (!strncmp("name=", i, 5)) {
2518 if ((j = index(i + 5, ',')) != 0)
2523 /*JP:Rogue
\82Ì
\8aJ
\94
\8eÒ
\82Ì
\96¼
\91O*/
2524 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
2528 static NEARDATA const char *const hcolors[] = {
2530 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
2531 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
2532 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
2533 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
2534 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
2535 "strawberry-banana", "peppermint", "romantic", "incandescent",
2536 "octarine", /* Discworld: the Colour of Magic */
2538 "
\8e\87\8aO
\90F
\82Ì", "
\90Ô
\8aO
\90F
\82Ì", "
\90Â
\90F
\82ª
\82©
\82Á
\82½
\83I
\83\8c\83\93\83W
\90F
\82Ì", "
\90Ô
\82Ý
\82ª
\82©
\82Á
\82½
\97Î
\90F
\82Ì", "
\88Ã
\82¢
\94\92\90F
\82Ì",
2539 "
\96¾
\82é
\82¢
\8d\95\82Ì", "
\90\85\90F
\82ª
\82©
\82Á
\82½
\83s
\83\93\83N
\90F
\82Ì", "
\89\96\90h
\82¢", "
\8aÃ
\82¢", "
\82·
\82Á
\82Ï
\82¢", "
\8bê
\82¢",
2540 "
\82µ
\82Ü
\96Í
\97l
\82Ì", "
\82ç
\82¹
\82ñ
\8fó
\82Ì", "
\94g
\8fó
\82Ì", "
\8ai
\8eq
\96Í
\97l
\8fó
\82Ì", "
\83`
\83F
\83b
\83N
\8fó
\82Ì", "
\95ú
\8eË
\8fó
\82Ì", "
\83y
\81[
\83Y
\83\8a\81[
\96Í
\97l
\82Ì",
2541 "
\82µ
\82Ý
\8fó
\82Ì", "
\90Â
\90F
\82Ì
\94Á
\93_
\8fó
\82Ì", "
\93_
\8fó
\82Ì", "
\8el
\8ap
\8c`
\8fó
\82Ì", "
\8aÛ
\8fó
\82Ì",
2542 "
\8eO
\8ap
\8fó
\82Ì", "
\83J
\83x
\83\8b\83l
\90F
\82Ì", "
\83T
\83\93\83O
\83\8a\83A
\90F
\82Ì", "
\91N
\82â
\82©
\82È
\90Ô
\8e\87\90F
\82Ì", "
\93¡
\90F
\82Ì", "
\83\8c\83\82\83\93\83\89\83C
\83\80\90F
\82Ì",
2543 "ä
\95\83o
\83i
\83i
\90F
\82Ì", "
\83y
\83p
\81[
\83~
\83\93\83g
\90F
\82Ì", "
\83\8d\83}
\83\93\83`
\83b
\83N
\82È
\90F
\82Ì", "
\94\92\94M
\90F
\82Ì",
2544 "
\83I
\83N
\83^
\83\8a\83\93\90F
\82Ì",
2550 const char *colorpref;
2552 return (Hallucination || !colorpref)
2553 ? hcolors[rn2_on_display_rng(SIZE(hcolors))]
2557 /* return a random real color unless hallucinating */
2561 int k = rn2(CLR_MAX);
2563 return Hallucination ? hcolor((char *) 0)
2565 : (k == NO_COLOR) ? "colorless"
2567 : (k == NO_COLOR) ? "
\96³
\90F
\82Ì"
2571 static NEARDATA const char *const hliquids[] = {
2573 "yoghurt", "oobleck", "clotted blood", "diluted water", "purified water",
2574 "instant coffee", "tea", "herbal infusion", "liquid rainbow",
2575 "creamy foam", "mulled wine", "bouillon", "nectar", "grog", "flubber",
2576 "ketchup", "slow light", "oil", "vinaigrette", "liquid crystal", "honey",
2577 "caramel sauce", "ink", "aqueous humour", "milk substitute",
2578 "fruit juice", "glowing lava", "gastric acid", "mineral water",
2579 "cough syrup", "quicksilver", "sweet vitriol", "grey goo", "pink slime",
2581 "
\83\88\81[
\83O
\83\8b\83g", "
\83E
\81[
\83u
\83\8c\83b
\83N", "
\8c\8c\8cÐ", "
\8fö
\97¯
\90\85", "
\90¸
\90»
\90\85",
2582 "
\83C
\83\93\83X
\83^
\83\93\83g
\83R
\81[
\83q
\81[", "
\8dg
\92\83", "
\83n
\81[
\83u
\89t", "
\89t
\91Ì
\82Ì
\93ø",
2583 "
\83N
\83\8a\81[
\83~
\81[
\83t
\83H
\81[
\83\80", "
\83z
\83b
\83g
\83\8f\83C
\83\93", "
\83u
\83C
\83\88\83\93", "
\89Ê
\8f`", "
\83O
\83\8d\83b
\83O", "
\83t
\83\89\83o
\81[",
2584 "
\83P
\83`
\83\83\83b
\83v", "
\92á
\91¬
\8cõ", "
\96û", "
\83r
\83l
\83O
\83\8c\83b
\83g
\83\
\81[
\83X", "
\89t
\91Ì
\90\85\8f»", "
\96I
\96¨",
2585 "
\83J
\83\89\83\81\83\8b\83\
\81[
\83X", "
\83C
\83\93\83N", "
\96[
\90\85", "
\91ã
\97p
\93û",
2586 "
\83t
\83\8b\81[
\83c
\83W
\83\85\81[
\83X", "
\97¬
\82ê
\82é
\97n
\8aâ", "
\88Ý
\8e_", "
\83~
\83l
\83\89\83\8b\83E
\83H
\81[
\83^
\81[",
2587 "
\8aP
\8e~
\82ß
\83V
\83\8d\83b
\83v", "
\90\85\8bâ", "
\83W
\83G
\83`
\83\8b\83G
\81[
\83e
\83\8b", "
\83O
\83\8c\83C
\83O
\81[", "
\83s
\83\93\83N
\83X
\83\89\83C
\83\80",
2593 const char *liquidpref;
2595 return (Hallucination || !liquidpref) ? hliquids[rn2(SIZE(hliquids))]
2599 /* Aliases for road-runner nemesis
2601 static const char *const coynames[] = {
2602 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
2603 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
2604 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
2605 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
2606 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
2607 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
2608 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
2613 coyotename(mtmp, buf)
2618 Sprintf(buf, "%s - %s",
2619 x_monnam(mtmp, ARTICLE_NONE, (char *) 0, 0, TRUE),
2620 mtmp->mcan ? coynames[SIZE(coynames) - 1]
2621 : coynames[mtmp->m_id % (SIZE(coynames) - 1)]);
2630 static const char *v[] = { "a", "ai", "og", "u" };
2631 static const char *snd[] = { "gor", "gris", "un", "bane", "ruk",
2632 "oth","ul", "z", "thos","akh","hai" };
2633 int i, iend = rn1(2, 3), vstart = rn2(2);
2637 for (i = 0; i < iend; ++i) {
2638 vstart = 1 - vstart; /* 0 -> 1, 1 -> 0 */
2639 Sprintf(eos(s), "%s%s", (i > 0 && !rn2(30)) ? "-" : "",
2640 vstart ? v[rn2(SIZE(v))] : snd[rn2(SIZE(snd))]);
2647 christen_orc(mtmp, gang, other)
2649 const char *gang, *other;
2652 char buf[BUFSZ], buf2[BUFSZ], *orcname;
2654 orcname = rndorcname(buf2);
2655 sz = (int) strlen(orcname);
2657 sz += (int) (strlen(gang) + sizeof " of " - sizeof "");
2659 sz += (int) strlen(other);
2663 boolean nameit = FALSE;
2665 if (gang && orcname) {
2666 Sprintf(buf, "%s of %s", upstart(orcname),
2667 upstart(strcpy(gbuf, gang)));
2669 } else if (other && orcname) {
2670 Sprintf(buf, "%s%s", upstart(orcname), other);
2674 mtmp = christen_monst(mtmp, buf);
2679 /* make sure "The Colour of Magic" remains the first entry in here */
2680 static const char *const sir_Terry_novels[] = {
2681 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
2682 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
2683 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
2684 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
2685 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
2686 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
2687 "The Last Hero", "The Amazing Maurice and His Educated Rodents",
2688 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
2689 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
2690 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
2691 "Raising Steam", "The Shepherd's Crown"
2698 int j, k = SIZE(sir_Terry_novels);
2704 else if (*novidx >= 0 && *novidx < k)
2707 return sir_Terry_novels[j];
2711 lookup_novel(lookname, idx)
2712 const char *lookname;
2717 /* Take American or U.K. spelling of this one */
2718 if (!strcmpi(The(lookname), "The Color of Magic"))
2719 lookname = sir_Terry_novels[0];
2721 for (k = 0; k < SIZE(sir_Terry_novels); ++k) {
2722 if (!strcmpi(lookname, sir_Terry_novels[k])
2723 || !strcmpi(The(lookname), sir_Terry_novels[k])) {
2726 return sir_Terry_novels[k];
2729 /* name not found; if novelidx is already set, override the name */
2730 if (idx && *idx >= 0 && *idx < SIZE(sir_Terry_novels))
2731 return sir_Terry_novels[*idx];
2733 return (const char *) 0;