1 /* NetHack 3.6 do_name.c $NHDT-Date: 1452669022 2016/01/13 07:10:22 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.90 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
7 STATIC_DCL
char *NDECL(nextmbuf
);
8 STATIC_DCL
void FDECL(getpos_help
, (BOOLEAN_P
, const char *));
9 STATIC_DCL
int FDECL(CFDECLSPEC cmp_coord_distu
, (const void *,
11 STATIC_DCL
void FDECL(gather_locs
, (coord
**, int *, BOOLEAN_P
));
12 STATIC_DCL
void FDECL(auto_describe
, (int, int));
13 STATIC_DCL
void NDECL(do_mname
);
14 STATIC_DCL boolean
FDECL(alreadynamed
, (struct monst
*, char *, char *));
15 STATIC_DCL
void FDECL(do_oname
, (struct obj
*));
16 STATIC_DCL
void NDECL(namefloorobj
);
17 STATIC_DCL
char *FDECL(bogusmon
, (char *,char *));
19 extern const char what_is_an_unknown_object
[]; /* from pager.c */
23 /* manage a pool of BUFSZ buffers, so callers don't have to */
27 static char NEARDATA bufs
[NUMMBUF
][BUFSZ
];
28 static int bufidx
= 0;
30 bufidx
= (bufidx
+ 1) % NUMMBUF
;
34 /* function for getpos() to highlight desired map locations.
35 * parameter value 0 = initialize, 1 = highlight, 2 = done
37 static void FDECL((*getpos_hilitefunc
), (int)) = (void FDECL((*), (int))) 0;
41 void FDECL((*f
), (int));
43 getpos_hilitefunc
= f
;
46 /* the response for '?' help request in getpos() */
48 getpos_help(force
, goal
)
53 boolean doing_what_is
;
54 winid tmpwin
= create_nhwindow(NHW_MENU
);
56 Sprintf(sbuf
, "Use [%c%c%c%c] to move the cursor to %s.", /* hjkl */
57 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
, Cmd
.move_E
, goal
);
58 putstr(tmpwin
, 0, sbuf
);
59 putstr(tmpwin
, 0, "Use [HJKL] to move the cursor 8 units at a time.");
60 putstr(tmpwin
, 0, "Or enter a background symbol (ex. <).");
61 putstr(tmpwin
, 0, "Use @ to move the cursor on yourself.");
62 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_MON
) != 0)
63 putstr(tmpwin
, 0, "Use m or M to move the cursor to next monster.");
64 if (!iflags
.terrainmode
|| (iflags
.terrainmode
& TER_OBJ
) != 0)
65 putstr(tmpwin
, 0, "Use o or O to move the cursor to next object.");
66 if (!iflags
.terrainmode
) {
67 if (getpos_hilitefunc
)
68 putstr(tmpwin
, 0, "Use $ to display valid locations.");
69 putstr(tmpwin
, 0, "Use # to toggle automatic description.");
70 if (iflags
.cmdassist
) /* assisting the '/' command, I suppose... */
72 (iflags
.getpos_coords
== GPCOORDS_NONE
)
73 ? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
74 : "(Reset 'whatis_coord' option to omit coordinates from '#' text.)");
75 /* disgusting hack; the alternate selection characters work for any
76 getpos call, but only matter for dowhatis (and doquickwhatis) */
77 doing_what_is
= (goal
== what_is_an_unknown_object
);
78 Sprintf(sbuf
, "Type a .%s when you are at the right place.",
79 doing_what_is
? " or , or ; or :" : "");
80 putstr(tmpwin
, 0, sbuf
);
83 " : describe current spot, show 'more info', move to another spot.");
85 " . describe current spot,%s move to another spot;",
86 flags
.help
? " prompt if 'more info'," : "");
87 putstr(tmpwin
, 0, sbuf
);
89 " , describe current spot, move to another spot;");
91 " ; describe current spot, stop looking at things;");
95 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
96 putstr(tmpwin
, 0, "");
97 display_nhwindow(tmpwin
, TRUE
);
98 destroy_nhwindow(tmpwin
);
102 cmp_coord_distu(a
, b
)
108 int dx
, dy
, dist_1
, dist_2
;
112 dist_1
= max(abs(dx
), abs(dy
));
115 dist_2
= max(abs(dx
), abs(dy
));
117 if (dist_1
== dist_2
)
118 return (c1
->y
!= c2
->y
) ? (c1
->y
- c2
->y
) : (c1
->x
- c2
->x
);
120 return dist_1
- dist_2
;
123 /* gather locations for monsters or objects shown on the map */
125 gather_locs(arr_p
, cnt_p
, do_mons
)
130 int x
, y
, pass
, glyph
, idx
,
131 tail
= (do_mons
? monnum_to_glyph(PM_LONG_WORM_TAIL
) : 0),
132 boulder
= (!do_mons
? objnum_to_glyph(BOULDER
) : 0),
133 rock
= (!do_mons
? objnum_to_glyph(ROCK
) : 0);
136 * We always include the hero's location even if there is no monster
137 * (invisible hero without see invisible) or object (usual case)
138 * displayed there. That way, the count will always be at least 1,
139 * and player has a visual indicator (cursor returns to hero's spot)
140 * highlighting when successive 'm's or 'o's have cycled all the way
141 * through all monsters or objects.
143 * Hero's spot will always sort to array[0] because it will always
144 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
147 for (pass
= 0; pass
< 2; pass
++) {
148 for (x
= 1; x
< COLNO
; x
++)
149 for (y
= 0; y
< ROWNO
; y
++) {
150 /* TODO: if glyph is a pile glyph, convert to ordinary one
151 * in order to keep tail/boulder/rock check simple.
153 glyph
= glyph_at(x
, y
);
154 /* unlike '/M', this skips monsters revealed by
155 warning glyphs and remembered invisible ones */
156 if ((x
== u
.ux
&& y
== u
.uy
)
157 || (do_mons
? (glyph_is_monster(glyph
) && glyph
!= tail
)
158 : (glyph_is_object(glyph
)
159 && glyph
!= boulder
&& glyph
!= rock
))) {
170 if (!pass
) /* end of first pass */
171 *arr_p
= (coord
*) alloc(*cnt_p
* sizeof (coord
));
172 else /* end of second pass */
173 qsort(*arr_p
, *cnt_p
, sizeof (coord
), cmp_coord_distu
);
178 dxdy_to_dist_descr(dx
, dy
)
181 /* [12] suffices, but guard against long translation for direction-name */
186 Sprintf(buf
, "here");
187 } else if ((dst
= xytod(dx
, dy
)) != -1) {
188 /* explicit direction; 'one step' is implicit */
189 Sprintf(buf
, "%s", directionname(dst
));
192 /* 9999: protect buf[] against overflow caused by invalid values */
196 Sprintf(eos(buf
), "%d%c%s", abs(dy
), (dy
> 0) ? 's' : 'n',
202 Sprintf(eos(buf
), "%d%c", abs(dx
), (dx
> 0) ? 'e' : 'w');
208 /* coordinate formatting for 'whatis_coord' option */
210 coord_desc(x
, y
, outbuf
, cmode
)
214 static char screen_fmt
[16]; /* [12] suffices: "[%02d,%02d]" */
221 case GPCOORDS_COMPASS
:
222 /* "east", "3s", "2n,4w" */
225 Sprintf(outbuf
, "(%s)", dxdy_to_dist_descr(dx
, dy
));
227 case GPCOORDS_MAP
: /* x,y */
228 /* upper left corner of map is <1,0>;
229 with default COLNO,ROWNO lower right corner is <79,20> */
230 Sprintf(outbuf
, "<%d,%d>", x
, y
);
232 case GPCOORDS_SCREEN
: /* y+2,x */
233 /* for normal map sizes, force a fixed-width formatting so that
234 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
235 than Nx999 or 999xM will still work, but not line up like normal
236 when displayed in a column setting */
238 Sprintf(screen_fmt
, "[%%%sd,%%%sd]",
239 (ROWNO
- 1 + 2 < 100) ? "02" : "03",
240 (COLNO
- 1 < 100) ? "02" : "03");
241 /* map line 0 is screen row 2;
242 map column 0 isn't used, map column 1 is screen column 1 */
243 Sprintf(outbuf
, screen_fmt
, y
+ 2, x
);
250 auto_describe(cx
, cy
)
256 const char *firstmatch
= "unknown";
260 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
261 (void) coord_desc(cx
, cy
, tmpbuf
, iflags
.getpos_coords
);
262 pline("%s%s%s", firstmatch
, *tmpbuf
? " " : "", tmpbuf
);
263 curs(WIN_MAP
, cx
, cy
);
269 getpos(ccp
, force
, goal
)
277 boolean msg_given
= TRUE
; /* clear message window by default */
278 boolean show_goal_msg
= FALSE
;
279 static const char pick_chars
[] = ".,;:";
281 boolean hilite_state
= FALSE
;
282 coord
*monarr
= (coord
*) 0, *objarr
= (coord
*) 0;
283 int moncount
= 0, monidx
= 0, objcount
= 0, objidx
= 0;
286 goal
= "desired location";
288 pline("(For instructions type a ?)");
296 curs(WIN_MAP
, cx
, cy
);
299 lock_mouse_cursor(TRUE
);
303 pline("Move cursor to %s:", goal
);
304 curs(WIN_MAP
, cx
, cy
);
306 show_goal_msg
= FALSE
;
307 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
308 auto_describe(cx
, cy
);
311 c
= nh_poskey(&tx
, &ty
, &sidx
);
314 (*getpos_hilitefunc
)(2);
315 hilite_state
= FALSE
;
316 curs(WIN_MAP
, cx
, cy
);
320 if (iflags
.autodescribe
)
325 msg_given
= TRUE
; /* force clear */
332 /* a mouse click event, just assign and return */
337 if ((cp
= index(pick_chars
, c
)) != 0) {
338 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
339 result
= (int) (cp
- pick_chars
);
342 for (i
= 0; i
< 8; i
++) {
345 if (Cmd
.dirchars
[i
] == c
) {
346 /* a normal movement letter or digit */
349 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
350 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
351 /* a shifted movement letter or Meta-digit */
357 /* truncate at map edge; diagonal moves complicate this... */
359 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
360 dx
= 1 - cx
; /* so that (cx+dx == 1) */
361 } else if (cx
+ dx
> COLNO
- 1) {
362 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
363 dx
= (COLNO
- 1) - cx
;
366 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
367 dy
= 0 - cy
; /* so that (cy+dy == 0) */
368 } else if (cy
+ dy
> ROWNO
- 1) {
369 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
370 dy
= (ROWNO
- 1) - cy
;
377 if (c
== '?' || redraw_cmd(c
)) {
379 getpos_help(force
, goal
);
381 docrt(); /* redraw */
382 /* update message window to reflect that we're still targetting */
383 show_goal_msg
= TRUE
;
385 } else if (c
== '$' && getpos_hilitefunc
) {
387 (*getpos_hilitefunc
)(0);
388 (*getpos_hilitefunc
)(1);
392 } else if (c
== '#') {
393 iflags
.autodescribe
= !iflags
.autodescribe
;
394 pline("Automatic description %sis %s.",
395 flags
.verbose
? "of features under cursor " : "",
396 iflags
.autodescribe
? "on" : "off");
397 if (!iflags
.autodescribe
)
398 show_goal_msg
= TRUE
;
401 } else if (c
== '@') { /* return to hero's spot */
402 /* reset 'm','M' and 'o','O'; otherwise, there's no way for player
403 to achieve that except by manually cycling through all spots */
408 } else if (c
== 'm' || c
== 'M') { /* nearest or farthest monster */
410 gather_locs(&monarr
, &moncount
, TRUE
);
411 monidx
= 0; /* monarr[0] is hero's spot */
414 monidx
= (monidx
+ 1) % moncount
;
417 monidx
= moncount
- 1;
419 cx
= monarr
[monidx
].x
;
420 cy
= monarr
[monidx
].y
;
422 } else if (c
== 'o' || c
== 'O') { /* nearest or farthest object */
424 gather_locs(&objarr
, &objcount
, FALSE
);
425 objidx
= 0; /* objarr[0] is hero's spot */
428 objidx
= (objidx
+ 1) % objcount
;
431 objidx
= objcount
- 1;
433 cx
= objarr
[objidx
].x
;
434 cy
= objarr
[objidx
].y
;
437 if (!index(quitchars
, c
)) {
438 char matching
[MAXPCHARS
];
439 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
441 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
442 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++)
443 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
444 matching
[sidx
] = (char) ++k
;
446 for (pass
= 0; pass
<= 1; pass
++) {
447 /* pass 0: just past current pos to lower right;
448 pass 1: upper left corner to current pos */
449 lo_y
= (pass
== 0) ? cy
: 0;
450 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
451 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
452 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
453 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
454 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
455 /* look at dungeon feature, not at
456 user-visible glyph */
457 k
= back_to_glyph(tx
, ty
);
458 /* uninteresting background glyph */
460 && (IS_DOOR(levl
[tx
][ty
].typ
)
461 || glyph_to_cmap(k
) == S_room
462 || glyph_to_cmap(k
) == S_darkroom
463 || glyph_to_cmap(k
) == S_corr
464 || glyph_to_cmap(k
) == S_litcorr
)) {
465 /* what hero remembers to be at tx,ty */
466 k
= glyph_at(tx
, ty
);
469 && matching
[glyph_to_cmap(k
)]
470 && (levl
[tx
][ty
].seenv
471 || iflags
.terrainmode
)
472 && !IS_WALL(levl
[tx
][ty
].typ
)
473 && levl
[tx
][ty
].typ
!= SDOOR
474 && glyph_to_cmap(k
) != S_room
475 && glyph_to_cmap(k
) != S_corr
476 && glyph_to_cmap(k
) != S_litcorr
) {
479 clear_nhwindow(WIN_MESSAGE
);
487 pline("Can't find dungeon feature '%c'.", c
);
494 Strcpy(note
, "aborted");
496 Sprintf(note
, "use %c%c%c%c or .", /* hjkl */
497 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
499 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
502 } /* k => matching */
506 if (!iflags
.terrainmode
) {
508 msg_given
= FALSE
; /* suppress clear */
512 result
= 0; /* not -1 */
520 curs(WIN_MAP
, cx
, cy
);
524 lock_mouse_cursor(FALSE
);
527 clear_nhwindow(WIN_MESSAGE
);
531 free((genericptr_t
) monarr
);
533 free((genericptr_t
) objarr
);
534 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
538 /* allocate space for a monster's name; removes old name if there is one */
542 int lth
; /* desired length (caller handles adding 1 for terminator) */
545 /* allocate mextra if necessary; otherwise get rid of old name */
547 mon
->mextra
= newmextra();
549 free_mname(mon
); /* already has mextra, might also have name */
550 MNAME(mon
) = (char *) alloc((unsigned) lth
);
552 /* zero length: the new name is empty; get rid of the old name */
558 /* release a monster's name; retains mextra even if all fields are now null */
563 if (has_mname(mon
)) {
564 free((genericptr_t
) MNAME(mon
));
565 MNAME(mon
) = (char *) 0;
569 /* allocate space for an object's name; removes old name if there is one */
573 int lth
; /* desired length (caller handles adding 1 for terminator) */
576 /* allocate oextra if necessary; otherwise get rid of old name */
578 obj
->oextra
= newoextra();
580 free_oname(obj
); /* already has oextra, might also have name */
581 ONAME(obj
) = (char *) alloc((unsigned) lth
);
583 /* zero length: the new name is empty; get rid of the old name */
589 /* release an object's name; retains oextra even if all fields are now null */
594 if (has_oname(obj
)) {
595 free((genericptr_t
) ONAME(obj
));
596 ONAME(obj
) = (char *) 0;
600 /* safe_oname() always returns a valid pointer to
601 * a string, either the pointer to an object's name
602 * if it has one, or a pointer to an empty string
614 /* historical note: this returns a monster pointer because it used to
615 allocate a new bigger block of memory to hold the monster and its name */
617 christen_monst(mtmp
, name
)
624 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
625 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
628 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
629 buf
[PL_PSIZ
- 1] = '\0';
631 new_mname(mtmp
, lth
); /* removes old name if one is present */
633 Strcpy(MNAME(mtmp
), name
);
637 /* check whether user-supplied name matches or nearly matches an unnameable
638 monster's name; if so, give an alternate reject message for do_mname() */
640 alreadynamed(mtmp
, monnambuf
, usrbuf
)
642 char *monnambuf
, *usrbuf
;
644 char pronounbuf
[10], *p
;
646 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
647 /* catch trying to name "the Oracle" as "Oracle" */
648 || (!strncmpi(monnambuf
, "the ", 4)
649 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
650 /* catch trying to name "invisible Orcus" as "Orcus" */
651 || ((p
= strstri(monnambuf
, "invisible ")) != 0
652 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
653 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
654 || ((p
= strstri(monnambuf
, " of ")) != 0
655 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
656 pline("%s is already called %s.",
657 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
659 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
660 && strstri(monnambuf
, "Juiblex")
661 && !strcmpi(usrbuf
, "Jubilex")) {
662 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
668 /* allow player to assign a name to some chosen monster */
672 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
675 struct monst
*mtmp
= 0;
678 You("would never recognize it anyway.");
683 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
688 if (cx
== u
.ux
&& cy
== u
.uy
) {
689 if (u
.usteed
&& canspotmon(u
.usteed
)) {
692 pline("This %s creature is called %s and cannot be renamed.",
693 beautiful(), plname
);
701 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
702 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
703 || mtmp
->m_ap_type
== M_AP_OBJECT
704 || (mtmp
->minvis
&& !See_invisible
)))) {
705 pline("I see no monster there.");
708 /* special case similar to the one in lookat() */
709 Sprintf(qbuf
, "What do you want to call %s?",
710 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
712 if (!*buf
|| *buf
== '\033')
714 /* strip leading and trailing spaces; unnames monster if all spaces */
715 (void) mungspaces(buf
);
717 /* Unique monsters have their own specific names or titles.
718 * Shopkeepers, temple priests and other minions use alternate
719 * name formatting routines which ignore any user-supplied name.
721 * Don't say the name is being rejected if it happens to match
724 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
725 if (!alreadynamed(mtmp
, monnambuf
, buf
))
726 pline("%s doesn't like being called names!", upstart(monnambuf
));
727 } else if (mtmp
->isshk
728 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
729 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
730 if (!alreadynamed(mtmp
, monnambuf
, buf
))
731 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
732 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
733 if (!alreadynamed(mtmp
, monnambuf
, buf
))
734 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
736 (void) christen_monst(mtmp
, buf
);
740 * This routine changes the address of obj. Be careful not to call it
741 * when there might be pointers around in unknown places. For now: only
742 * when obj is in the inventory.
747 register struct obj
*obj
;
749 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
753 /* Do this now because there's no point in even asking for a name */
754 if (obj
->otyp
== SPE_NOVEL
) {
755 pline("%s already has a published name.", Ysimple_name2(obj
));
759 Sprintf(qbuf
, "What do you want to name %s ",
760 is_plural(obj
) ? "these" : "this");
761 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
763 if (!*buf
|| *buf
== '\033')
765 /* strip leading and trailing spaces; unnames item if all spaces */
766 (void) mungspaces(buf
);
769 * We don't violate illiteracy conduct here, although it is
770 * arguable that we should for anything other than "X". Doing so
771 * would make attaching player's notes to hero's inventory have an
772 * in-game effect, which may or may not be the correct thing to do.
774 * We do violate illiteracy in oname() if player creates Sting or
775 * Orcrist, clearly being literate (no pun intended...).
778 /* relax restrictions over proper capitalization for artifacts */
779 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
782 if (obj
->oartifact
) {
783 pline_The("artifact seems to resist the attempt.");
785 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
786 /* this used to change one letter, substituting a value
787 of 'a' through 'y' (due to an off by one error, 'z'
788 would never be selected) and then force that to
789 upper case if such was the case of the input;
790 now, the hand slip scuffs one or two letters as if
791 the text had been trodden upon, sometimes picking
792 punctuation instead of an arbitrary letter;
793 unfortunately, we have to cover the possibility of
794 it targetting spaces so failing to make any change
795 (we know that it must eventually target a nonspace
796 because buf[] matches a valid artifact name) */
798 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
799 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
801 wipeout_text(bufp
, rnd(2), (unsigned) 0);
802 } while (!strcmp(buf
, bufcpy
));
803 pline("While engraving, your %s slips.", body_part(HAND
));
804 display_nhwindow(WIN_MESSAGE
, FALSE
);
805 You("engrave: \"%s\".", buf
);
807 obj
= oname(obj
, buf
);
818 lth
= *name
? (int) (strlen(name
) + 1) : 0;
821 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
822 buf
[PL_PSIZ
- 1] = '\0';
824 /* If named artifact exists in the game, do not create another.
825 * Also trying to create an artifact shouldn't de-artifact
826 * it (e.g. Excalibur from prayer). In this case the object
827 * will retain its current name. */
828 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
831 new_oname(obj
, lth
); /* removes old name if one is present */
833 Strcpy(ONAME(obj
), name
);
836 artifact_exists(obj
, name
, TRUE
);
837 if (obj
->oartifact
) {
838 /* can't dual-wield with artifact as secondary weapon */
841 /* activate warning if you've just named your weapon "Sting" */
843 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
844 /* if obj is owned by a shop, increase your bill */
847 /* violate illiteracy conduct since successfully wrote arti-name */
848 u
.uconduct
.literate
++;
855 static NEARDATA
const char callable
[] = {
856 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
857 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
861 objtyp_is_callable(i
)
864 return (boolean
) (objects
[i
].oc_uname
865 || (OBJ_DESCR(objects
[i
])
866 && index(callable
, objects
[i
].oc_class
)));
869 /* C and #name commands - player can name monster or object or type of obj */
876 menu_item
*pick_list
= 0;
877 char ch
, allowall
[2];
878 /* if player wants a,b,c instead of i,o when looting, do that here too */
879 boolean abc
= flags
.lootabc
;
881 win
= create_nhwindow(NHW_MENU
);
884 any
.a_char
= 'm'; /* group accelerator 'C' */
885 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
886 "a monster", MENU_UNSELECTED
);
888 /* we use y and n as accelerators so that we can accept user's
889 response keyed to old "name an individual object?" prompt */
890 any
.a_char
= 'i'; /* group accelerator 'y' */
891 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
892 "a particular object in inventory", MENU_UNSELECTED
);
893 any
.a_char
= 'o'; /* group accelerator 'n' */
894 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
895 "the type of an object in inventory", MENU_UNSELECTED
);
897 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
898 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
899 "the type of an object upon the floor", MENU_UNSELECTED
);
900 any
.a_char
= 'd'; /* group accelerator '\' */
901 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
902 "the type of an object on discoveries list", MENU_UNSELECTED
);
903 any
.a_char
= 'a'; /* group accelerator 'l' */
904 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
905 "record an annotation for the current level", MENU_UNSELECTED
);
906 end_menu(win
, "What do you want to name?");
907 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
908 ch
= pick_list
[0].item
.a_char
;
909 free((genericptr_t
) pick_list
);
912 destroy_nhwindow(win
);
918 case 'm': /* name a visible monster */
921 case 'i': /* name an individual object in inventory */
922 allowall
[0] = ALL_CLASSES
;
924 obj
= getobj(allowall
, "name");
928 case 'o': /* name a type of object in inventory */
929 obj
= getobj(callable
, "call");
931 /* behave as if examining it in inventory;
932 this might set dknown if it was picked up
933 while blind and the hero can now see */
937 You("would never recognize another one.");
939 } else if (!objtyp_is_callable(obj
->otyp
)) {
940 You("know those as well as you ever will.");
947 case 'f': /* name a type of object visible on the floor */
950 case 'd': /* name a type of object on the discoveries list */
953 case 'a': /* annotate level */
962 register struct obj
*obj
;
964 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
966 register char **str1
;
969 return; /* probably blind */
972 otemp
.oextra
= (struct oextra
*) 0;
974 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
975 /* kludge, meaning it's sink water */
976 Sprintf(qbuf
, "Call a stream of %s fluid:",
977 OBJ_DESCR(objects
[otemp
.otyp
]));
979 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
981 if (!*buf
|| *buf
== '\033')
985 str1
= &(objects
[obj
->otyp
].oc_uname
);
987 free((genericptr_t
) *str1
);
989 /* strip leading and trailing spaces; uncalls item if all spaces */
990 (void) mungspaces(buf
);
992 if (*str1
) { /* had name, so possibly remove from disco[] */
993 /* strip name first, for the update_inventory() call
994 from undiscover_object() */
996 undiscover_object(obj
->otyp
);
1000 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
1010 struct obj
*obj
= 0;
1011 boolean fakeobj
= FALSE
, use_plural
;
1013 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
1014 /* "dot for under/over you" only makes sense when the cursor hasn't
1015 been moved off the hero's '@' yet, but there's no way to adjust
1016 the help text once getpos() has started */
1017 Sprintf(buf
, "object on map (or '.' for one %s you)",
1018 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
1019 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
1021 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1022 obj
= vobj_at(u
.ux
, u
.uy
);
1024 glyph
= glyph_at(cc
.x
, cc
.y
);
1025 if (glyph_is_object(glyph
))
1026 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
1027 /* else 'obj' stays null */
1030 /* "under you" is safe here since there's no object to hide under */
1031 pline("There doesn't seem to be any object %s.",
1032 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
1035 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1036 is a mimic; passing that to xname (directly or via simpleonames)
1037 would yield "glorkum" so we need to handle it explicitly; it will
1038 always fail the Hallucination test and pass the !callable test,
1039 resulting in the "can't be assigned a type name" message */
1040 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
1042 : obj_descr
[STRANGE_OBJECT
].oc_name
);
1043 use_plural
= (obj
->quan
> 1L);
1044 if (Hallucination
) {
1045 const char *unames
[6];
1048 /* straight role name */
1049 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1052 /* random rank title for hero's role */
1053 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
1054 /* random fake monster */
1055 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
1056 /* increased chance for fake monster */
1057 unames
[3] = unames
[2];
1059 unames
[4] = roguename();
1061 unames
[5] = "Wibbly Wobbly";
1062 pline("%s %s to call you \"%s.\"",
1063 The(buf
), use_plural
? "decide" : "decides",
1064 unames
[rn2(SIZE(unames
))]);
1065 } else if (!objtyp_is_callable(obj
->otyp
)) {
1066 pline("%s %s can't be assigned a type name.",
1067 use_plural
? "Those" : "That", buf
);
1068 } else if (!obj
->dknown
) {
1069 You("don't know %s %s well enough to name %s.",
1070 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
1078 static const char *const ghostnames
[] = {
1079 /* these names should have length < PL_NSIZ */
1080 /* Capitalize the names for aesthetics -dgk */
1081 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1082 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1083 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1084 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1085 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1086 "Stephan", "Lance Braccus", "Shadowhawk"
1089 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1093 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
1097 * Monster naming functions:
1098 * x_monnam is the generic monster-naming function.
1099 * seen unseen detected named
1100 * mon_nam: the newt it the invisible orc Fido
1101 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1102 * l_monnam: newt it invisible orc dog called Fido
1103 * Monnam: The newt It The invisible orc Fido
1104 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1105 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1106 * Amonnam: A newt It An invisible orc Fido
1107 * a_monnam: a newt it an invisible orc Fido
1108 * m_monnam: newt xan orc Fido
1109 * y_monnam: your newt your xan your invisible orc Fido
1112 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1113 * options works, since those are special cases.
1116 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
1117 register struct monst
*mtmp
;
1119 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1120 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1122 * If the monster would be referred to as "it" or if the monster has a name
1123 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1124 * and always use no article.
1126 const char *adjective
;
1128 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1129 * EXACT_NAME: combination of all the above
1133 char *buf
= nextmbuf();
1134 struct permonst
*mdat
= mtmp
->data
;
1135 const char *pm_name
= mdat
->mname
;
1136 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
1137 boolean name_at_start
, has_adjectives
;
1140 if (program_state
.gameover
)
1141 suppress
|= SUPPRESS_HALLUCINATION
;
1142 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
1143 article
= ARTICLE_THE
;
1145 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
1146 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
1147 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
1148 && !program_state
.gameover
&& mtmp
!= u
.usteed
1149 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
1150 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
1154 /* unseen monsters, etc. Use "it" */
1160 /* priests and minions: don't even use this function */
1161 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1162 char priestnambuf
[BUFSZ
];
1164 long save_prop
= EHalluc_resistance
;
1165 unsigned save_invis
= mtmp
->minvis
;
1167 /* when true name is wanted, explicitly block Hallucination */
1169 EHalluc_resistance
= 1L;
1172 name
= priestname(mtmp
, priestnambuf
);
1173 EHalluc_resistance
= save_prop
;
1174 mtmp
->minvis
= save_invis
;
1175 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1177 return strcpy(buf
, name
);
1179 /* an "aligned priest" not flagged as a priest or minion should be
1180 "priest" or "priestess" (normally handled by priestname()) */
1181 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1182 pm_name
= mtmp
->female
? "priestess" : "priest";
1183 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1184 pm_name
= "high priestess";
1186 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1187 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1188 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1189 * none of this applies.
1191 if (mtmp
->isshk
&& !do_hallu
) {
1192 if (adjective
&& article
== ARTICLE_THE
) {
1193 /* pathological case: "the angry Asidonhopo the blue dragon"
1195 Strcpy(buf
, "the ");
1196 Strcat(strcat(buf
, adjective
), " ");
1197 Strcat(buf
, shkname(mtmp
));
1200 Strcat(buf
, shkname(mtmp
));
1201 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1203 Strcat(buf
, " the ");
1205 Strcat(buf
, "invisible ");
1206 Strcat(buf
, pm_name
);
1210 /* Put the adjectives in the buffer */
1212 Strcat(strcat(buf
, adjective
), " ");
1214 Strcat(buf
, "invisible ");
1215 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1217 Strcat(buf
, "saddled ");
1219 has_adjectives
= TRUE
;
1221 has_adjectives
= FALSE
;
1223 /* Put the actual monster name or type into the buffer now */
1224 /* Be sure to remember whether the buffer starts with a name */
1227 char *rname
= rndmonnam(&rnamecode
);
1230 name_at_start
= bogon_is_pname(rnamecode
);
1231 } else if (has_mname(mtmp
)) {
1232 char *name
= MNAME(mtmp
);
1234 if (mdat
== &mons
[PM_GHOST
]) {
1235 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1236 name_at_start
= TRUE
;
1237 } else if (called
) {
1238 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1239 name_at_start
= (boolean
) type_is_pname(mdat
);
1240 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1241 /* <name> the <adjective> <invisible> <saddled> <rank> */
1245 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1248 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1250 article
= ARTICLE_NONE
;
1251 name_at_start
= TRUE
;
1254 name_at_start
= TRUE
;
1256 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1259 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1260 (boolean
) mtmp
->female
));
1261 Strcat(buf
, lcase(pbuf
));
1262 name_at_start
= FALSE
;
1264 Strcat(buf
, pm_name
);
1265 name_at_start
= (boolean
) type_is_pname(mdat
);
1268 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1269 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1270 article
= ARTICLE_THE
;
1272 article
= ARTICLE_NONE
;
1273 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1274 article
= ARTICLE_THE
;
1282 Strcpy(buf2
, "your ");
1287 Strcpy(buf2
, "the ");
1304 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1305 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1312 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1313 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1316 /* print the name as if mon_nam() was called, but assume that the player
1317 * can always see the monster--used for probing and for monsters aggravating
1318 * the player with a cursed potion of invisibility
1324 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1325 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1334 register char *bp
= mon_nam(mtmp
);
1344 register char *bp
= noit_mon_nam(mtmp
);
1350 /* monster's own name */
1355 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1358 /* pet name: "your little dog" */
1363 int prefix
, suppression_flag
;
1365 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1366 suppression_flag
= (has_mname(mtmp
)
1367 /* "saddled" is redundant when mounted */
1368 || mtmp
== u
.usteed
)
1372 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1376 Adjmonnam(mtmp
, adj
)
1380 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1381 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1391 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1392 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1399 char *bp
= a_monnam(mtmp
);
1405 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1406 identification of the endgame altars via their attending priests */
1408 distant_monnam(mon
, article
, outbuf
)
1410 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1413 /* high priest(ess)'s identity is concealed on the Astral Plane,
1414 unless you're adjacent (overridden for hallucination which does
1415 its own obfuscation) */
1416 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1417 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1418 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1419 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1421 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1426 /* fake monsters used to be in a hard-coded array, now in a data file */
1433 get_rnd_text(BOGUSMONFILE
, buf
);
1434 /* strip prefix if present */
1435 if (!letter(*mname
)) {
1446 /* return a random monster name, for hallucination */
1451 static char buf
[BUFSZ
];
1454 #define BOGUSMONSIZE 100 /* arbitrary */
1460 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1461 } while (name
< SPECIAL_PM
1462 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1464 if (name
>= SPECIAL_PM
) {
1465 mname
= bogusmon(buf
, code
);
1467 mname
= strcpy(buf
, mons
[name
].mname
);
1473 /* check bogusmon prefix to decide whether it's a personal name */
1475 bogon_is_pname(code
)
1480 return index("-+=", code
) ? TRUE
: FALSE
;
1483 /* name of a Rogue player */
1489 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1490 for (i
= opts
; *i
; i
++)
1491 if (!strncmp("name=", i
, 5)) {
1493 if ((j
= index(i
+ 5, ',')) != 0)
1498 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1502 static NEARDATA
const char *const hcolors
[] = {
1503 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1504 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1505 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1506 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1507 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1508 "strawberry-banana", "peppermint", "romantic", "incandescent",
1509 "octarine", /* Discworld: the Colour of Magic */
1514 const char *colorpref
;
1516 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1520 /* return a random real color unless hallucinating */
1524 int k
= rn2(CLR_MAX
);
1526 return Hallucination
? hcolor((char *) 0)
1527 : (k
== NO_COLOR
) ? "colorless"
1531 /* Aliases for road-runner nemesis
1533 static const char *const coynames
[] = {
1534 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1535 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1536 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1537 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1538 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1539 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1540 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1545 coyotename(mtmp
, buf
)
1550 Sprintf(buf
, "%s - %s",
1551 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1552 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1553 : coynames
[rn2(SIZE(coynames
) - 1)]);
1558 /* make sure "The Colour of Magic" remains the first entry in here */
1559 static const char *const sir_Terry_novels
[] = {
1560 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1561 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1562 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1563 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1564 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1565 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1566 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1567 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1568 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1569 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1570 "Raising Steam", "The Shepherd's Crown"
1577 int j
, k
= SIZE(sir_Terry_novels
);
1583 else if (*novidx
>= 0 && *novidx
< k
)
1586 return sir_Terry_novels
[j
];
1590 lookup_novel(lookname
, idx
)
1591 const char *lookname
;
1596 /* Take American or U.K. spelling of this one */
1597 if (!strcmpi(The(lookname
), "The Color of Magic"))
1598 lookname
= sir_Terry_novels
[0];
1600 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1601 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1602 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1605 return sir_Terry_novels
[k
];
1608 /* name not found; if novelidx is already set, override the name */
1609 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1610 return sir_Terry_novels
[*idx
];
1612 return (const char *) 0;