1 /* NetHack 3.6 do_name.c $NHDT-Date: 1452064740 2016/01/06 07:19:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */
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
void NDECL(do_mname
);
12 STATIC_DCL boolean
FDECL(alreadynamed
, (struct monst
*, char *, char *));
13 STATIC_DCL
void FDECL(do_oname
, (struct obj
*));
14 STATIC_DCL
void NDECL(namefloorobj
);
15 STATIC_DCL
char *FDECL(bogusmon
, (char *,char *));
17 extern const char what_is_an_unknown_object
[]; /* from pager.c */
21 /* manage a pool of BUFSZ buffers, so callers don't have to */
25 static char NEARDATA bufs
[NUMMBUF
][BUFSZ
];
26 static int bufidx
= 0;
28 bufidx
= (bufidx
+ 1) % NUMMBUF
;
32 /* function for getpos() to highlight desired map locations.
33 * parameter value 0 = initialize, 1 = highlight, 2 = done
35 static void FDECL((*getpos_hilitefunc
), (int)) = (void FDECL((*), (int))) 0;
39 void FDECL((*f
), (int));
41 getpos_hilitefunc
= f
;
44 /* the response for '?' help request in getpos() */
46 getpos_help(force
, goal
)
51 boolean doing_what_is
;
52 winid tmpwin
= create_nhwindow(NHW_MENU
);
54 Sprintf(sbuf
, "Use [%c%c%c%c] to move the cursor to %s.", /* hjkl */
55 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
, Cmd
.move_E
, goal
);
56 putstr(tmpwin
, 0, sbuf
);
57 putstr(tmpwin
, 0, "Use [HJKL] to move the cursor 8 units at a time.");
58 putstr(tmpwin
, 0, "Or enter a background symbol (ex. <).");
59 putstr(tmpwin
, 0, "Use @ to move the cursor on yourself.");
60 putstr(tmpwin
, 0, "Use m or M to move the cursor to next monster.");
61 if (getpos_hilitefunc
)
62 putstr(tmpwin
, 0, "Use $ to display valid locations.");
63 putstr(tmpwin
, 0, "Use # to toggle automatic description.");
64 /* disgusting hack; the alternate selection characters work for any
65 getpos call, but they only matter for dowhatis (and doquickwhatis) */
66 doing_what_is
= (goal
== what_is_an_unknown_object
);
67 Sprintf(sbuf
, "Type a .%s when you are at the right place.",
68 doing_what_is
? " or , or ; or :" : "");
69 putstr(tmpwin
, 0, sbuf
);
71 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
72 putstr(tmpwin
, 0, "");
73 display_nhwindow(tmpwin
, TRUE
);
74 destroy_nhwindow(tmpwin
);
84 int dx
, dy
, dist_1
, dist_2
;
88 dist_1
= dx
* dx
+ dy
* dy
;
91 dist_2
= dx
* dx
+ dy
* dy
;
93 return dist_1
- dist_2
;
97 getpos(ccp
, force
, goal
)
105 boolean msg_given
= TRUE
; /* clear message window by default */
106 boolean show_goal_msg
= FALSE
;
107 static const char pick_chars
[] = ".,;:";
109 boolean hilite_state
= FALSE
;
110 coord
*monarr
= NULL
;
115 goal
= "desired location";
117 pline("(For instructions type a ?)");
125 curs(WIN_MAP
, cx
, cy
);
128 lock_mouse_cursor(TRUE
);
132 pline("Move cursor to %s:", goal
);
133 curs(WIN_MAP
, cx
, cy
);
135 show_goal_msg
= FALSE
;
136 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
140 const char *firstmatch
= NULL
;
144 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
146 curs(WIN_MAP
, cx
, cy
);
151 c
= nh_poskey(&tx
, &ty
, &sidx
);
154 (*getpos_hilitefunc
)(2);
155 hilite_state
= FALSE
;
156 curs(WIN_MAP
, cx
, cy
);
160 if (iflags
.autodescribe
)
165 msg_given
= TRUE
; /* force clear */
172 /* a mouse click event, just assign and return */
177 if ((cp
= index(pick_chars
, c
)) != 0) {
178 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
179 result
= (int) (cp
- pick_chars
);
182 for (i
= 0; i
< 8; i
++) {
185 if (Cmd
.dirchars
[i
] == c
) {
186 /* a normal movement letter or digit */
189 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
190 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
191 /* a shifted movement letter or Meta-digit */
197 /* truncate at map edge; diagonal moves complicate this... */
199 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
200 dx
= 1 - cx
; /* so that (cx+dx == 1) */
201 } else if (cx
+ dx
> COLNO
- 1) {
202 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
203 dx
= (COLNO
- 1) - cx
;
206 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
207 dy
= 0 - cy
; /* so that (cy+dy == 0) */
208 } else if (cy
+ dy
> ROWNO
- 1) {
209 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
210 dy
= (ROWNO
- 1) - cy
;
217 if (c
== '?' || redraw_cmd(c
)) {
219 getpos_help(force
, goal
);
221 docrt(); /* redraw */
222 /* update message window to reflect that we're still targetting */
223 show_goal_msg
= TRUE
;
225 } else if (c
== '$' && getpos_hilitefunc
) {
227 (*getpos_hilitefunc
)(0);
228 (*getpos_hilitefunc
)(1);
232 } else if (c
== '#') {
233 iflags
.autodescribe
= !iflags
.autodescribe
;
234 pline("Automatic description %sis %s.",
235 flags
.verbose
? "of features under cursor " : "",
236 iflags
.autodescribe
? "on" : "off");
237 if (!iflags
.autodescribe
)
238 show_goal_msg
= TRUE
;
241 } else if (c
== '@') {
245 } else if (c
== 'm' || c
== 'M') {
250 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
252 && (mtmp
->mx
!= u
.ux
|| mtmp
->my
!= u
.uy
))
255 /* moncount + 1: always allocate a non-zero amount */
256 monarr
= (coord
*) alloc(sizeof (coord
) * (moncount
+ 1));
258 for (mtmp
= fmon
; mtmp
; mtmp
= mtmp
->nmon
) {
260 && (mtmp
->mx
!= u
.ux
|| mtmp
->my
!= u
.uy
)) {
261 monarr
[monidx
].x
= mtmp
->mx
;
262 monarr
[monidx
].y
= mtmp
->my
;
266 qsort(monarr
, moncount
, sizeof (coord
), cmp_coord_distu
);
267 /* ready for first increment/decrement to change to zero */
268 monidx
= (c
== 'm') ? -1 : 1;
272 monidx
= (monidx
+ 1) % moncount
;
275 monidx
= moncount
- 1;
277 cx
= monarr
[monidx
].x
;
278 cy
= monarr
[monidx
].y
;
282 if (!index(quitchars
, c
)) {
283 char matching
[MAXPCHARS
];
284 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
286 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
287 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++)
288 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
289 matching
[sidx
] = (char) ++k
;
291 for (pass
= 0; pass
<= 1; pass
++) {
292 /* pass 0: just past current pos to lower right;
293 pass 1: upper left corner to current pos */
294 lo_y
= (pass
== 0) ? cy
: 0;
295 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
296 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
297 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
298 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
299 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
300 /* look at dungeon feature, not at
301 * user-visible glyph */
302 k
= back_to_glyph(tx
, ty
);
303 /* uninteresting background glyph */
305 && (IS_DOOR(levl
[tx
][ty
].typ
)
306 || glyph_to_cmap(k
) == S_room
307 || glyph_to_cmap(k
) == S_darkroom
308 || glyph_to_cmap(k
) == S_corr
309 || glyph_to_cmap(k
) == S_litcorr
)) {
310 /* what hero remembers to be at tx,ty */
311 k
= glyph_at(tx
, ty
);
314 && matching
[glyph_to_cmap(k
)]
315 && levl
[tx
][ty
].seenv
316 && (!IS_WALL(levl
[tx
][ty
].typ
))
317 && (levl
[tx
][ty
].typ
!= SDOOR
)
318 && glyph_to_cmap(k
) != S_room
319 && glyph_to_cmap(k
) != S_corr
320 && glyph_to_cmap(k
) != S_litcorr
) {
323 clear_nhwindow(WIN_MESSAGE
);
331 pline("Can't find dungeon feature '%c'.", c
);
338 Strcpy(note
, "aborted");
340 Sprintf(note
, "use %c%c%c%c or .", /* hjkl */
341 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
343 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
346 } /* k => matching */
351 msg_given
= FALSE
; /* suppress clear */
354 result
= 0; /* not -1 */
362 curs(WIN_MAP
, cx
, cy
);
366 lock_mouse_cursor(FALSE
);
369 clear_nhwindow(WIN_MESSAGE
);
373 free((genericptr_t
) monarr
);
374 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
378 /* allocate space for a monster's name; removes old name if there is one */
382 int lth
; /* desired length (caller handles adding 1 for terminator) */
385 /* allocate mextra if necessary; otherwise get rid of old name */
387 mon
->mextra
= newmextra();
389 free_mname(mon
); /* already has mextra, might also have name */
390 MNAME(mon
) = (char *) alloc((unsigned) lth
);
392 /* zero length: the new name is empty; get rid of the old name */
398 /* release a monster's name; retains mextra even if all fields are now null */
403 if (has_mname(mon
)) {
404 free((genericptr_t
) MNAME(mon
));
405 MNAME(mon
) = (char *) 0;
409 /* allocate space for an object's name; removes old name if there is one */
413 int lth
; /* desired length (caller handles adding 1 for terminator) */
416 /* allocate oextra if necessary; otherwise get rid of old name */
418 obj
->oextra
= newoextra();
420 free_oname(obj
); /* already has oextra, might also have name */
421 ONAME(obj
) = (char *) alloc((unsigned) lth
);
423 /* zero length: the new name is empty; get rid of the old name */
429 /* release an object's name; retains oextra even if all fields are now null */
434 if (has_oname(obj
)) {
435 free((genericptr_t
) ONAME(obj
));
436 ONAME(obj
) = (char *) 0;
440 /* safe_oname() always returns a valid pointer to
441 * a string, either the pointer to an object's name
442 * if it has one, or a pointer to an empty string
454 /* historical note: this returns a monster pointer because it used to
455 allocate a new bigger block of memory to hold the monster and its name */
457 christen_monst(mtmp
, name
)
464 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
465 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
468 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
469 buf
[PL_PSIZ
- 1] = '\0';
471 new_mname(mtmp
, lth
); /* removes old name if one is present */
473 Strcpy(MNAME(mtmp
), name
);
477 /* check whether user-supplied name matches or nearly matches an unnameable
478 monster's name; if so, give an alternate reject message for do_mname() */
480 alreadynamed(mtmp
, monnambuf
, usrbuf
)
482 char *monnambuf
, *usrbuf
;
484 char pronounbuf
[10], *p
;
486 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
487 /* catch trying to name "the Oracle" as "Oracle" */
488 || (!strncmpi(monnambuf
, "the ", 4)
489 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
490 /* catch trying to name "invisible Orcus" as "Orcus" */
491 || ((p
= strstri(monnambuf
, "invisible ")) != 0
492 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
493 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
494 || ((p
= strstri(monnambuf
, " of ")) != 0
495 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
496 pline("%s is already called %s.",
497 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
499 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
500 && strstri(monnambuf
, "Juiblex")
501 && !strcmpi(usrbuf
, "Jubilex")) {
502 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
508 /* allow player to assign a name to some chosen monster */
512 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
515 struct monst
*mtmp
= 0;
518 You("would never recognize it anyway.");
523 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
528 if (cx
== u
.ux
&& cy
== u
.uy
) {
529 if (u
.usteed
&& canspotmon(u
.usteed
)) {
532 pline("This %s creature is called %s and cannot be renamed.",
533 beautiful(), plname
);
541 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
542 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
543 || mtmp
->m_ap_type
== M_AP_OBJECT
544 || (mtmp
->minvis
&& !See_invisible
)))) {
545 pline("I see no monster there.");
548 /* special case similar to the one in lookat() */
549 Sprintf(qbuf
, "What do you want to call %s?",
550 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
552 if (!*buf
|| *buf
== '\033')
554 /* strip leading and trailing spaces; unnames monster if all spaces */
555 (void) mungspaces(buf
);
557 /* Unique monsters have their own specific names or titles.
558 * Shopkeepers, temple priests and other minions use alternate
559 * name formatting routines which ignore any user-supplied name.
561 * Don't say the name is being rejected if it happens to match
564 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
565 if (!alreadynamed(mtmp
, monnambuf
, buf
))
566 pline("%s doesn't like being called names!", upstart(monnambuf
));
567 } else if (mtmp
->isshk
568 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
569 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
570 if (!alreadynamed(mtmp
, monnambuf
, buf
))
571 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
572 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
573 if (!alreadynamed(mtmp
, monnambuf
, buf
))
574 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
576 (void) christen_monst(mtmp
, buf
);
580 * This routine changes the address of obj. Be careful not to call it
581 * when there might be pointers around in unknown places. For now: only
582 * when obj is in the inventory.
587 register struct obj
*obj
;
589 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
593 /* Do this now because there's no point in even asking for a name */
594 if (obj
->otyp
== SPE_NOVEL
) {
595 pline("%s already has a published name.", Ysimple_name2(obj
));
599 Sprintf(qbuf
, "What do you want to name %s ",
600 is_plural(obj
) ? "these" : "this");
601 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
603 if (!*buf
|| *buf
== '\033')
605 /* strip leading and trailing spaces; unnames item if all spaces */
606 (void) mungspaces(buf
);
609 * We don't violate illiteracy conduct here, although it is
610 * arguable that we should for anything other than "X". Doing so
611 * would make attaching player's notes to hero's inventory have an
612 * in-game effect, which may or may not be the correct thing to do.
614 * We do violate illiteracy in oname() if player creates Sting or
615 * Orcrist, clearly being literate (no pun intended...).
618 /* relax restrictions over proper capitalization for artifacts */
619 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
622 if (obj
->oartifact
) {
623 pline_The("artifact seems to resist the attempt.");
625 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
626 /* this used to change one letter, substituting a value
627 of 'a' through 'y' (due to an off by one error, 'z'
628 would never be selected) and then force that to
629 upper case if such was the case of the input;
630 now, the hand slip scuffs one or two letters as if
631 the text had been trodden upon, sometimes picking
632 punctuation instead of an arbitrary letter;
633 unfortunately, we have to cover the possibility of
634 it targetting spaces so failing to make any change
635 (we know that it must eventually target a nonspace
636 because buf[] matches a valid artifact name) */
638 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
639 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
641 wipeout_text(bufp
, rnd(2), (unsigned) 0);
642 } while (!strcmp(buf
, bufcpy
));
643 pline("While engraving, your %s slips.", body_part(HAND
));
644 display_nhwindow(WIN_MESSAGE
, FALSE
);
645 You("engrave: \"%s\".", buf
);
647 obj
= oname(obj
, buf
);
658 lth
= *name
? (int) (strlen(name
) + 1) : 0;
661 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
662 buf
[PL_PSIZ
- 1] = '\0';
664 /* If named artifact exists in the game, do not create another.
665 * Also trying to create an artifact shouldn't de-artifact
666 * it (e.g. Excalibur from prayer). In this case the object
667 * will retain its current name. */
668 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
671 new_oname(obj
, lth
); /* removes old name if one is present */
673 Strcpy(ONAME(obj
), name
);
676 artifact_exists(obj
, name
, TRUE
);
677 if (obj
->oartifact
) {
678 /* can't dual-wield with artifact as secondary weapon */
681 /* activate warning if you've just named your weapon "Sting" */
683 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
684 /* if obj is owned by a shop, increase your bill */
687 /* violate illiteracy conduct since successfully wrote arti-name */
688 u
.uconduct
.literate
++;
695 static NEARDATA
const char callable
[] = {
696 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
697 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
701 objtyp_is_callable(i
)
704 return (boolean
) (objects
[i
].oc_uname
705 || (OBJ_DESCR(objects
[i
])
706 && index(callable
, objects
[i
].oc_class
)));
709 /* C and #name commands - player can name monster or object or type of obj */
716 menu_item
*pick_list
= 0;
717 char ch
, allowall
[2];
718 /* if player wants a,b,c instead of i,o when looting, do that here too */
719 boolean abc
= flags
.lootabc
;
721 win
= create_nhwindow(NHW_MENU
);
724 any
.a_char
= 'm'; /* group accelerator 'C' */
725 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
726 "a monster", MENU_UNSELECTED
);
728 /* we use y and n as accelerators so that we can accept user's
729 response keyed to old "name an individual object?" prompt */
730 any
.a_char
= 'i'; /* group accelerator 'y' */
731 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
732 "a particular object in inventory", MENU_UNSELECTED
);
733 any
.a_char
= 'o'; /* group accelerator 'n' */
734 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
735 "the type of an object in inventory", MENU_UNSELECTED
);
737 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
738 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
739 "the type of an object upon the floor", MENU_UNSELECTED
);
740 any
.a_char
= 'd'; /* group accelerator '\' */
741 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
742 "the type of an object on discoveries list", MENU_UNSELECTED
);
743 any
.a_char
= 'a'; /* group accelerator 'l' */
744 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
745 "record an annotation for the current level", MENU_UNSELECTED
);
746 end_menu(win
, "What do you want to name?");
747 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
748 ch
= pick_list
[0].item
.a_char
;
749 free((genericptr_t
) pick_list
);
752 destroy_nhwindow(win
);
758 case 'm': /* name a visible monster */
761 case 'i': /* name an individual object in inventory */
762 allowall
[0] = ALL_CLASSES
;
764 obj
= getobj(allowall
, "name");
768 case 'o': /* name a type of object in inventory */
769 obj
= getobj(callable
, "call");
771 /* behave as if examining it in inventory;
772 this might set dknown if it was picked up
773 while blind and the hero can now see */
777 You("would never recognize another one.");
779 } else if (!objtyp_is_callable(obj
->otyp
)) {
780 You("know those as well as you ever will.");
787 case 'f': /* name a type of object visible on the floor */
790 case 'd': /* name a type of object on the discoveries list */
793 case 'a': /* annotate level */
802 register struct obj
*obj
;
804 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
806 register char **str1
;
809 return; /* probably blind */
812 otemp
.oextra
= (struct oextra
*) 0;
814 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
815 /* kludge, meaning it's sink water */
816 Sprintf(qbuf
, "Call a stream of %s fluid:",
817 OBJ_DESCR(objects
[otemp
.otyp
]));
819 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
821 if (!*buf
|| *buf
== '\033')
825 str1
= &(objects
[obj
->otyp
].oc_uname
);
827 free((genericptr_t
) *str1
);
829 /* strip leading and trailing spaces; uncalls item if all spaces */
830 (void) mungspaces(buf
);
832 if (*str1
) { /* had name, so possibly remove from disco[] */
833 /* strip name first, for the update_inventory() call
834 from undiscover_object() */
836 undiscover_object(obj
->otyp
);
840 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
851 boolean fakeobj
= FALSE
, use_plural
;
853 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
854 /* "dot for under/over you" only makes sense when the cursor hasn't
855 been moved off the hero's '@' yet, but there's no way to adjust
856 the help text once getpos() has started */
857 Sprintf(buf
, "object on map (or '.' for one %s you)",
858 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
859 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
861 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
862 obj
= vobj_at(u
.ux
, u
.uy
);
864 glyph
= glyph_at(cc
.x
, cc
.y
);
865 if (glyph_is_object(glyph
))
866 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
867 /* else 'obj' stays null */
870 /* "under you" is safe here since there's no object to hide under */
871 pline("There doesn't seem to be any object %s.",
872 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
875 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
876 is a mimic; passing that to xname (directly or via simpleonames)
877 would yield "glorkum" so we need to handle it explicitly; it will
878 always fail the Hallucination test and pass the !callable test,
879 resulting in the "can't be assigned a type name" message */
880 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
882 : obj_descr
[STRANGE_OBJECT
].oc_name
);
883 use_plural
= (obj
->quan
> 1L);
885 const char *unames
[6];
888 /* straight role name */
889 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
892 /* random rank title for hero's role */
893 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
894 /* random fake monster */
895 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
896 /* increased chance for fake monster */
897 unames
[3] = unames
[2];
899 unames
[4] = roguename();
901 unames
[5] = "Wibbly Wobbly";
902 pline("%s %s to call you \"%s.\"",
903 The(buf
), use_plural
? "decide" : "decides",
904 unames
[rn2(SIZE(unames
))]);
905 } else if (!objtyp_is_callable(obj
->otyp
)) {
906 pline("%s %s can't be assigned a type name.",
907 use_plural
? "Those" : "That", buf
);
908 } else if (!obj
->dknown
) {
909 You("don't know %s %s well enough to name %s.",
910 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
918 static const char *const ghostnames
[] = {
919 /* these names should have length < PL_NSIZ */
920 /* Capitalize the names for aesthetics -dgk */
921 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
922 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
923 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
924 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
925 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
926 "Stephan", "Lance Braccus", "Shadowhawk"
929 /* ghost names formerly set by x_monnam(), now by makemon() instead */
933 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
937 * Monster naming functions:
938 * x_monnam is the generic monster-naming function.
939 * seen unseen detected named
940 * mon_nam: the newt it the invisible orc Fido
941 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
942 * l_monnam: newt it invisible orc dog called Fido
943 * Monnam: The newt It The invisible orc Fido
944 * noit_Monnam: The newt (as if detected) The invisible orc Fido
945 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
946 * Amonnam: A newt It An invisible orc Fido
947 * a_monnam: a newt it an invisible orc Fido
948 * m_monnam: newt xan orc Fido
949 * y_monnam: your newt your xan your invisible orc Fido
952 /* Bug: if the monster is a priest or shopkeeper, not every one of these
953 * options works, since those are special cases.
956 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
957 register struct monst
*mtmp
;
959 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
960 * ARTICLE_YOUR: "your" on pets, "the" on everything else
962 * If the monster would be referred to as "it" or if the monster has a name
963 * _and_ there is no adjective, "invisible", "saddled", etc., override this
964 * and always use no article.
966 const char *adjective
;
968 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
969 * EXACT_NAME: combination of all the above
973 char *buf
= nextmbuf();
974 struct permonst
*mdat
= mtmp
->data
;
975 const char *pm_name
= mdat
->mname
;
976 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
977 boolean name_at_start
, has_adjectives
;
980 if (program_state
.gameover
)
981 suppress
|= SUPPRESS_HALLUCINATION
;
982 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
983 article
= ARTICLE_THE
;
985 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
986 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
987 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
988 && !program_state
.gameover
&& mtmp
!= u
.usteed
989 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
990 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
994 /* unseen monsters, etc. Use "it" */
1000 /* priests and minions: don't even use this function */
1001 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1002 char priestnambuf
[BUFSZ
];
1004 long save_prop
= EHalluc_resistance
;
1005 unsigned save_invis
= mtmp
->minvis
;
1007 /* when true name is wanted, explicitly block Hallucination */
1009 EHalluc_resistance
= 1L;
1012 name
= priestname(mtmp
, priestnambuf
);
1013 EHalluc_resistance
= save_prop
;
1014 mtmp
->minvis
= save_invis
;
1015 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1017 return strcpy(buf
, name
);
1019 /* an "aligned priest" not flagged as a priest or minion should be
1020 "priest" or "priestess" (normally handled by priestname()) */
1021 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1022 pm_name
= mtmp
->female
? "priestess" : "priest";
1023 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1024 pm_name
= "high priestess";
1026 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1027 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1028 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1029 * none of this applies.
1031 if (mtmp
->isshk
&& !do_hallu
) {
1032 if (adjective
&& article
== ARTICLE_THE
) {
1033 /* pathological case: "the angry Asidonhopo the blue dragon"
1035 Strcpy(buf
, "the ");
1036 Strcat(strcat(buf
, adjective
), " ");
1037 Strcat(buf
, shkname(mtmp
));
1040 Strcat(buf
, shkname(mtmp
));
1041 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1043 Strcat(buf
, " the ");
1045 Strcat(buf
, "invisible ");
1046 Strcat(buf
, pm_name
);
1050 /* Put the adjectives in the buffer */
1052 Strcat(strcat(buf
, adjective
), " ");
1054 Strcat(buf
, "invisible ");
1055 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1057 Strcat(buf
, "saddled ");
1059 has_adjectives
= TRUE
;
1061 has_adjectives
= FALSE
;
1063 /* Put the actual monster name or type into the buffer now */
1064 /* Be sure to remember whether the buffer starts with a name */
1067 char *rname
= rndmonnam(&rnamecode
);
1070 name_at_start
= bogon_is_pname(rnamecode
);
1071 } else if (has_mname(mtmp
)) {
1072 char *name
= MNAME(mtmp
);
1074 if (mdat
== &mons
[PM_GHOST
]) {
1075 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1076 name_at_start
= TRUE
;
1077 } else if (called
) {
1078 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1079 name_at_start
= (boolean
) type_is_pname(mdat
);
1080 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1081 /* <name> the <adjective> <invisible> <saddled> <rank> */
1085 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1088 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1090 article
= ARTICLE_NONE
;
1091 name_at_start
= TRUE
;
1094 name_at_start
= TRUE
;
1096 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1099 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1100 (boolean
) mtmp
->female
));
1101 Strcat(buf
, lcase(pbuf
));
1102 name_at_start
= FALSE
;
1104 Strcat(buf
, pm_name
);
1105 name_at_start
= (boolean
) type_is_pname(mdat
);
1108 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1109 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1110 article
= ARTICLE_THE
;
1112 article
= ARTICLE_NONE
;
1113 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1114 article
= ARTICLE_THE
;
1122 Strcpy(buf2
, "your ");
1127 Strcpy(buf2
, "the ");
1144 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1145 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1152 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1153 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1156 /* print the name as if mon_nam() was called, but assume that the player
1157 * can always see the monster--used for probing and for monsters aggravating
1158 * the player with a cursed potion of invisibility
1164 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1165 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1174 register char *bp
= mon_nam(mtmp
);
1184 register char *bp
= noit_mon_nam(mtmp
);
1190 /* monster's own name */
1195 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1198 /* pet name: "your little dog" */
1203 int prefix
, suppression_flag
;
1205 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1206 suppression_flag
= (has_mname(mtmp
)
1207 /* "saddled" is redundant when mounted */
1208 || mtmp
== u
.usteed
)
1212 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1216 Adjmonnam(mtmp
, adj
)
1220 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1221 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1231 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1232 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1239 char *bp
= a_monnam(mtmp
);
1245 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1246 identification of the endgame altars via their attending priests */
1248 distant_monnam(mon
, article
, outbuf
)
1250 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1253 /* high priest(ess)'s identity is concealed on the Astral Plane,
1254 unless you're adjacent (overridden for hallucination which does
1255 its own obfuscation) */
1256 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1257 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1258 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1259 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1261 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1266 /* fake monsters used to be in a hard-coded array, now in a data file */
1273 get_rnd_text(BOGUSMONFILE
, buf
);
1274 /* strip prefix if present */
1275 if (!letter(*mname
)) {
1286 /* return a random monster name, for hallucination */
1291 static char buf
[BUFSZ
];
1294 #define BOGUSMONSIZE 100 /* arbitrary */
1300 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1301 } while (name
< SPECIAL_PM
1302 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1304 if (name
>= SPECIAL_PM
) {
1305 mname
= bogusmon(buf
, code
);
1307 mname
= strcpy(buf
, mons
[name
].mname
);
1313 /* check bogusmon prefix to decide whether it's a personal name */
1315 bogon_is_pname(code
)
1320 return index("-+=", code
) ? TRUE
: FALSE
;
1323 /* name of a Rogue player */
1329 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1330 for (i
= opts
; *i
; i
++)
1331 if (!strncmp("name=", i
, 5)) {
1333 if ((j
= index(i
+ 5, ',')) != 0)
1338 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1342 static NEARDATA
const char *const hcolors
[] = {
1343 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1344 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1345 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1346 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1347 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1348 "strawberry-banana", "peppermint", "romantic", "incandescent",
1349 "octarine", /* Discworld: the Colour of Magic */
1354 const char *colorpref
;
1356 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1360 /* return a random real color unless hallucinating */
1364 int k
= rn2(CLR_MAX
);
1366 return Hallucination
? hcolor((char *) 0)
1367 : (k
== NO_COLOR
) ? "colorless"
1371 /* Aliases for road-runner nemesis
1373 static const char *const coynames
[] = {
1374 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1375 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1376 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1377 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1378 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1379 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1380 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1385 coyotename(mtmp
, buf
)
1390 Sprintf(buf
, "%s - %s",
1391 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1392 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1393 : coynames
[rn2(SIZE(coynames
) - 1)]);
1398 /* make sure "The Colour of Magic" remains the first entry in here */
1399 static const char *const sir_Terry_novels
[] = {
1400 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1401 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1402 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1403 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1404 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1405 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1406 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1407 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1408 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1409 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1410 "Raising Steam", "The Shepherd's Crown"
1417 int j
, k
= SIZE(sir_Terry_novels
);
1423 else if (*novidx
>= 0 && *novidx
< k
)
1426 return sir_Terry_novels
[j
];
1430 lookup_novel(lookname
, idx
)
1431 const char *lookname
;
1436 /* Take American or U.K. spelling of this one */
1437 if (!strcmpi(The(lookname
), "The Color of Magic"))
1438 lookname
= sir_Terry_novels
[0];
1440 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1441 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1442 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1445 return sir_Terry_novels
[k
];
1448 /* name not found; if novelidx is already set, override the name */
1449 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1450 return sir_Terry_novels
[*idx
];
1452 return (const char *) 0;