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 putstr(tmpwin
, 0, "Use m or M to move the cursor to next monster.");
63 putstr(tmpwin
, 0, "Use o or O to move the cursor to next object.");
64 if (getpos_hilitefunc
)
65 putstr(tmpwin
, 0, "Use $ to display valid locations.");
66 putstr(tmpwin
, 0, "Use # to toggle automatic description.");
67 if (iflags
.cmdassist
) /* assisting the '/' command, I suppose... */
68 putstr(tmpwin
, 0, (iflags
.getpos_coords
== GPCOORDS_NONE
)
69 ? "(Set 'whatis_coord' option to include coordinates with '#' text.)"
70 : "(Reset 'whatis_coord' option to omit coordinates from '#' text.)");
71 /* disgusting hack; the alternate selection characters work for any
72 getpos call, but they only matter for dowhatis (and doquickwhatis) */
73 doing_what_is
= (goal
== what_is_an_unknown_object
);
74 Sprintf(sbuf
, "Type a .%s when you are at the right place.",
75 doing_what_is
? " or , or ; or :" : "");
76 putstr(tmpwin
, 0, sbuf
);
79 " : describe current spot, show 'more info', move to another spot.");
80 Sprintf(sbuf
, " . describe current spot,%s move to another spot;",
81 flags
.help
? " prompt if 'more info'," : "");
82 putstr(tmpwin
, 0, sbuf
);
83 putstr(tmpwin
, 0, " , describe current spot, move to another spot;");
85 " ; describe current spot, stop looking at things;");
88 putstr(tmpwin
, 0, "Type Space or Escape when you're done.");
89 putstr(tmpwin
, 0, "");
90 display_nhwindow(tmpwin
, TRUE
);
91 destroy_nhwindow(tmpwin
);
101 int dx
, dy
, dist_1
, dist_2
;
105 dist_1
= max(abs(dx
), abs(dy
));
108 dist_2
= max(abs(dx
), abs(dy
));
110 if (dist_1
== dist_2
)
111 return (c1
->y
!= c2
->y
) ? (c1
->y
- c2
->y
) : (c1
->x
- c2
->x
);
113 return dist_1
- dist_2
;
116 /* gather locations for monsters or objects shown on the map */
118 gather_locs(arr_p
, cnt_p
, do_mons
)
123 int x
, y
, pass
, glyph
, idx
,
124 tail
= (do_mons
? monnum_to_glyph(PM_LONG_WORM_TAIL
) : 0),
125 boulder
= (!do_mons
? objnum_to_glyph(BOULDER
) : 0),
126 rock
= (!do_mons
? objnum_to_glyph(ROCK
) : 0);
129 * We always include the hero's location even if there is no monster
130 * (invisible hero without see invisible) or object (usual case)
131 * displayed there. That way, the count will always be at least 1,
132 * and player has a visual indicator (cursor returns to hero's spot)
133 * highlighting when successive 'm's or 'o's have cycled all the way
134 * through all monsters or objects.
136 * Hero's spot will always sort to array[0] because it will always
137 * be the shortest distance (namely, 0 units) away from <u.ux,u.uy>.
140 for (pass
= 0; pass
< 2; pass
++) {
141 for (x
= 1; x
< COLNO
; x
++)
142 for (y
= 0; y
< ROWNO
; y
++) {
143 /* TODO: if glyph is a pile glyph, convert to ordinary one
144 * in order to keep tail/boulder/rock check simple.
146 glyph
= glyph_at(x
, y
);
147 /* unlike '/M', this skips monsters revealed by
148 warning glyphs and remembered invisible ones */
149 if ((x
== u
.ux
&& y
== u
.uy
)
150 || (do_mons
? (glyph_is_monster(glyph
) && glyph
!= tail
)
151 : (glyph_is_object(glyph
)
152 && glyph
!= boulder
&& glyph
!= rock
))) {
163 if (!pass
) /* end of first pass */
164 *arr_p
= (coord
*) alloc(*cnt_p
* sizeof (coord
));
165 else /* end of second pass */
166 qsort(*arr_p
, *cnt_p
, sizeof (coord
), cmp_coord_distu
);
171 dxdy_to_dist_descr(dx
, dy
)
174 /* [12] suffices, but guard against long translation for direction-name */
179 Sprintf(buf
, "here");
180 } else if ((dst
= xytod(dx
, dy
)) != -1) {
181 /* explicit direction; 'one step' is implicit */
182 Sprintf(buf
, "%s", directionname(dst
));
185 /* 9999: protect buf[] against overflow caused by invalid values */
189 Sprintf(eos(buf
), "%d%c%s", abs(dy
), (dy
> 0) ? 's' : 'n',
195 Sprintf(eos(buf
), "%d%c", abs(dx
), (dx
> 0) ? 'e' : 'w');
201 /* coordinate formatting for 'whatis_coord' option */
203 coord_desc(x
, y
, outbuf
, cmode
)
207 static char screen_fmt
[16]; /* [12] suffices: "[%02d,%02d]" */
214 case GPCOORDS_COMPASS
:
215 /* "east", "3s", "2n,4w" */
218 Sprintf(outbuf
, "(%s)", dxdy_to_dist_descr(dx
, dy
));
220 case GPCOORDS_MAP
: /* x,y */
221 /* upper left corner of map is <1,0>;
222 with default COLNO,ROWNO lower right corner is <79,20> */
223 Sprintf(outbuf
, "<%d,%d>", x
, y
);
225 case GPCOORDS_SCREEN
: /* y+2,x */
226 /* for normal map sizes, force a fixed-width formatting so that
227 /m, /M, /o, and /O output lines up cleanly; map sizes bigger
228 than Nx999 or 999xM will still work, but not line up like normal
229 when displayed in a column setting */
231 Sprintf(screen_fmt
, "[%%%sd,%%%sd]",
232 (ROWNO
- 1 + 2 < 100) ? "02" : "03",
233 (COLNO
- 1 < 100) ? "02" : "03");
234 /* map line 0 is screen row 2;
235 map column 0 isn't used, map column 1 is screen column 1 */
236 Sprintf(outbuf
, screen_fmt
, y
+ 2, x
);
243 auto_describe(cx
, cy
)
249 const char *firstmatch
= "unknown";
253 if (do_screen_description(cc
, TRUE
, sym
, tmpbuf
, &firstmatch
)) {
254 (void) coord_desc(cx
, cy
, tmpbuf
, iflags
.getpos_coords
);
255 pline("%s%s%s", firstmatch
, *tmpbuf
? " " : "", tmpbuf
);
256 curs(WIN_MAP
, cx
, cy
);
262 getpos(ccp
, force
, goal
)
270 boolean msg_given
= TRUE
; /* clear message window by default */
271 boolean show_goal_msg
= FALSE
;
272 static const char pick_chars
[] = ".,;:";
274 boolean hilite_state
= FALSE
;
275 coord
*monarr
= (coord
*) 0, *objarr
= (coord
*) 0;
276 int moncount
= 0, monidx
= 0, objcount
= 0, objidx
= 0;
279 goal
= "desired location";
281 pline("(For instructions type a ?)");
289 curs(WIN_MAP
, cx
, cy
);
292 lock_mouse_cursor(TRUE
);
296 pline("Move cursor to %s:", goal
);
297 curs(WIN_MAP
, cx
, cy
);
299 show_goal_msg
= FALSE
;
300 } else if (iflags
.autodescribe
&& !msg_given
&& !hilite_state
) {
301 auto_describe(cx
, cy
);
304 c
= nh_poskey(&tx
, &ty
, &sidx
);
307 (*getpos_hilitefunc
)(2);
308 hilite_state
= FALSE
;
309 curs(WIN_MAP
, cx
, cy
);
313 if (iflags
.autodescribe
)
318 msg_given
= TRUE
; /* force clear */
325 /* a mouse click event, just assign and return */
330 if ((cp
= index(pick_chars
, c
)) != 0) {
331 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
332 result
= (int) (cp
- pick_chars
);
335 for (i
= 0; i
< 8; i
++) {
338 if (Cmd
.dirchars
[i
] == c
) {
339 /* a normal movement letter or digit */
342 } else if (Cmd
.alphadirchars
[i
] == lowc((char) c
)
343 || (Cmd
.num_pad
&& Cmd
.dirchars
[i
] == (c
& 0177))) {
344 /* a shifted movement letter or Meta-digit */
350 /* truncate at map edge; diagonal moves complicate this... */
352 dy
-= sgn(dy
) * (1 - (cx
+ dx
));
353 dx
= 1 - cx
; /* so that (cx+dx == 1) */
354 } else if (cx
+ dx
> COLNO
- 1) {
355 dy
+= sgn(dy
) * ((COLNO
- 1) - (cx
+ dx
));
356 dx
= (COLNO
- 1) - cx
;
359 dx
-= sgn(dx
) * (0 - (cy
+ dy
));
360 dy
= 0 - cy
; /* so that (cy+dy == 0) */
361 } else if (cy
+ dy
> ROWNO
- 1) {
362 dx
+= sgn(dx
) * ((ROWNO
- 1) - (cy
+ dy
));
363 dy
= (ROWNO
- 1) - cy
;
370 if (c
== '?' || redraw_cmd(c
)) {
372 getpos_help(force
, goal
);
374 docrt(); /* redraw */
375 /* update message window to reflect that we're still targetting */
376 show_goal_msg
= TRUE
;
378 } else if (c
== '$' && getpos_hilitefunc
) {
380 (*getpos_hilitefunc
)(0);
381 (*getpos_hilitefunc
)(1);
385 } else if (c
== '#') {
386 iflags
.autodescribe
= !iflags
.autodescribe
;
387 pline("Automatic description %sis %s.",
388 flags
.verbose
? "of features under cursor " : "",
389 iflags
.autodescribe
? "on" : "off");
390 if (!iflags
.autodescribe
)
391 show_goal_msg
= TRUE
;
394 } else if (c
== '@') { /* return to hero's spot */
395 /* reset 'm','M' and 'o','O'; otherwise, there's no way for player
396 to achieve that except by manually cycling through all spots */
401 } else if (c
== 'm' || c
== 'M') { /* nearest or farthest monster */
403 gather_locs(&monarr
, &moncount
, TRUE
);
404 monidx
= 0; /* monarr[0] is hero's spot */
407 monidx
= (monidx
+ 1) % moncount
;
410 monidx
= moncount
- 1;
412 cx
= monarr
[monidx
].x
;
413 cy
= monarr
[monidx
].y
;
415 } else if (c
== 'o' || c
== 'O') { /* nearest or farthest object */
417 gather_locs(&objarr
, &objcount
, FALSE
);
418 objidx
= 0; /* objarr[0] is hero's spot */
421 objidx
= (objidx
+ 1) % objcount
;
424 objidx
= objcount
- 1;
426 cx
= objarr
[objidx
].x
;
427 cy
= objarr
[objidx
].y
;
430 if (!index(quitchars
, c
)) {
431 char matching
[MAXPCHARS
];
432 int pass
, lo_x
, lo_y
, hi_x
, hi_y
, k
= 0;
434 (void) memset((genericptr_t
) matching
, 0, sizeof matching
);
435 for (sidx
= 1; sidx
< MAXPCHARS
; sidx
++)
436 if (c
== defsyms
[sidx
].sym
|| c
== (int) showsyms
[sidx
])
437 matching
[sidx
] = (char) ++k
;
439 for (pass
= 0; pass
<= 1; pass
++) {
440 /* pass 0: just past current pos to lower right;
441 pass 1: upper left corner to current pos */
442 lo_y
= (pass
== 0) ? cy
: 0;
443 hi_y
= (pass
== 0) ? ROWNO
- 1 : cy
;
444 for (ty
= lo_y
; ty
<= hi_y
; ty
++) {
445 lo_x
= (pass
== 0 && ty
== lo_y
) ? cx
+ 1 : 1;
446 hi_x
= (pass
== 1 && ty
== hi_y
) ? cx
: COLNO
- 1;
447 for (tx
= lo_x
; tx
<= hi_x
; tx
++) {
448 /* look at dungeon feature, not at
449 * user-visible glyph */
450 k
= back_to_glyph(tx
, ty
);
451 /* uninteresting background glyph */
453 && (IS_DOOR(levl
[tx
][ty
].typ
)
454 || glyph_to_cmap(k
) == S_room
455 || glyph_to_cmap(k
) == S_darkroom
456 || glyph_to_cmap(k
) == S_corr
457 || glyph_to_cmap(k
) == S_litcorr
)) {
458 /* what hero remembers to be at tx,ty */
459 k
= glyph_at(tx
, ty
);
462 && matching
[glyph_to_cmap(k
)]
463 && levl
[tx
][ty
].seenv
464 && (!IS_WALL(levl
[tx
][ty
].typ
))
465 && (levl
[tx
][ty
].typ
!= SDOOR
)
466 && glyph_to_cmap(k
) != S_room
467 && glyph_to_cmap(k
) != S_corr
468 && glyph_to_cmap(k
) != S_litcorr
) {
471 clear_nhwindow(WIN_MESSAGE
);
479 pline("Can't find dungeon feature '%c'.", c
);
486 Strcpy(note
, "aborted");
488 Sprintf(note
, "use %c%c%c%c or .", /* hjkl */
489 Cmd
.move_W
, Cmd
.move_S
, Cmd
.move_N
,
491 pline("Unknown direction: '%s' (%s).", visctrl((char) c
),
494 } /* k => matching */
499 msg_given
= FALSE
; /* suppress clear */
502 result
= 0; /* not -1 */
510 curs(WIN_MAP
, cx
, cy
);
514 lock_mouse_cursor(FALSE
);
517 clear_nhwindow(WIN_MESSAGE
);
521 free((genericptr_t
) monarr
);
523 free((genericptr_t
) objarr
);
524 getpos_hilitefunc
= (void FDECL((*), (int))) 0;
528 /* allocate space for a monster's name; removes old name if there is one */
532 int lth
; /* desired length (caller handles adding 1 for terminator) */
535 /* allocate mextra if necessary; otherwise get rid of old name */
537 mon
->mextra
= newmextra();
539 free_mname(mon
); /* already has mextra, might also have name */
540 MNAME(mon
) = (char *) alloc((unsigned) lth
);
542 /* zero length: the new name is empty; get rid of the old name */
548 /* release a monster's name; retains mextra even if all fields are now null */
553 if (has_mname(mon
)) {
554 free((genericptr_t
) MNAME(mon
));
555 MNAME(mon
) = (char *) 0;
559 /* allocate space for an object's name; removes old name if there is one */
563 int lth
; /* desired length (caller handles adding 1 for terminator) */
566 /* allocate oextra if necessary; otherwise get rid of old name */
568 obj
->oextra
= newoextra();
570 free_oname(obj
); /* already has oextra, might also have name */
571 ONAME(obj
) = (char *) alloc((unsigned) lth
);
573 /* zero length: the new name is empty; get rid of the old name */
579 /* release an object's name; retains oextra even if all fields are now null */
584 if (has_oname(obj
)) {
585 free((genericptr_t
) ONAME(obj
));
586 ONAME(obj
) = (char *) 0;
590 /* safe_oname() always returns a valid pointer to
591 * a string, either the pointer to an object's name
592 * if it has one, or a pointer to an empty string
604 /* historical note: this returns a monster pointer because it used to
605 allocate a new bigger block of memory to hold the monster and its name */
607 christen_monst(mtmp
, name
)
614 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
615 lth
= (name
&& *name
) ? ((int) strlen(name
) + 1) : 0;
618 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
619 buf
[PL_PSIZ
- 1] = '\0';
621 new_mname(mtmp
, lth
); /* removes old name if one is present */
623 Strcpy(MNAME(mtmp
), name
);
627 /* check whether user-supplied name matches or nearly matches an unnameable
628 monster's name; if so, give an alternate reject message for do_mname() */
630 alreadynamed(mtmp
, monnambuf
, usrbuf
)
632 char *monnambuf
, *usrbuf
;
634 char pronounbuf
[10], *p
;
636 if (fuzzymatch(usrbuf
, monnambuf
, " -_", TRUE
)
637 /* catch trying to name "the Oracle" as "Oracle" */
638 || (!strncmpi(monnambuf
, "the ", 4)
639 && fuzzymatch(usrbuf
, monnambuf
+ 4, " -_", TRUE
))
640 /* catch trying to name "invisible Orcus" as "Orcus" */
641 || ((p
= strstri(monnambuf
, "invisible ")) != 0
642 && fuzzymatch(usrbuf
, p
+ 10, " -_", TRUE
))
643 /* catch trying to name "the {priest,Angel} of Crom" as "Crom" */
644 || ((p
= strstri(monnambuf
, " of ")) != 0
645 && fuzzymatch(usrbuf
, p
+ 4, " -_", TRUE
))) {
646 pline("%s is already called %s.",
647 upstart(strcpy(pronounbuf
, mhe(mtmp
))), monnambuf
);
649 } else if (mtmp
->data
== &mons
[PM_JUIBLEX
]
650 && strstri(monnambuf
, "Juiblex")
651 && !strcmpi(usrbuf
, "Jubilex")) {
652 pline("%s doesn't like being called %s.", upstart(monnambuf
), usrbuf
);
658 /* allow player to assign a name to some chosen monster */
662 char buf
[BUFSZ
], monnambuf
[BUFSZ
], qbuf
[QBUFSZ
];
665 struct monst
*mtmp
= 0;
668 You("would never recognize it anyway.");
673 if (getpos(&cc
, FALSE
, "the monster you want to name") < 0
678 if (cx
== u
.ux
&& cy
== u
.uy
) {
679 if (u
.usteed
&& canspotmon(u
.usteed
)) {
682 pline("This %s creature is called %s and cannot be renamed.",
683 beautiful(), plname
);
691 && (!(cansee(cx
, cy
) || see_with_infrared(mtmp
))
692 || mtmp
->mundetected
|| mtmp
->m_ap_type
== M_AP_FURNITURE
693 || mtmp
->m_ap_type
== M_AP_OBJECT
694 || (mtmp
->minvis
&& !See_invisible
)))) {
695 pline("I see no monster there.");
698 /* special case similar to the one in lookat() */
699 Sprintf(qbuf
, "What do you want to call %s?",
700 distant_monnam(mtmp
, ARTICLE_THE
, monnambuf
));
702 if (!*buf
|| *buf
== '\033')
704 /* strip leading and trailing spaces; unnames monster if all spaces */
705 (void) mungspaces(buf
);
707 /* Unique monsters have their own specific names or titles.
708 * Shopkeepers, temple priests and other minions use alternate
709 * name formatting routines which ignore any user-supplied name.
711 * Don't say the name is being rejected if it happens to match
714 if ((mtmp
->data
->geno
& G_UNIQ
) && !mtmp
->ispriest
) {
715 if (!alreadynamed(mtmp
, monnambuf
, buf
))
716 pline("%s doesn't like being called names!", upstart(monnambuf
));
717 } else if (mtmp
->isshk
718 && !(Deaf
|| mtmp
->msleeping
|| !mtmp
->mcanmove
719 || mtmp
->data
->msound
<= MS_ANIMAL
)) {
720 if (!alreadynamed(mtmp
, monnambuf
, buf
))
721 verbalize("I'm %s, not %s.", shkname(mtmp
), buf
);
722 } else if (mtmp
->ispriest
|| mtmp
->isminion
|| mtmp
->isshk
) {
723 if (!alreadynamed(mtmp
, monnambuf
, buf
))
724 pline("%s will not accept the name %s.", upstart(monnambuf
), buf
);
726 (void) christen_monst(mtmp
, buf
);
730 * This routine changes the address of obj. Be careful not to call it
731 * when there might be pointers around in unknown places. For now: only
732 * when obj is in the inventory.
737 register struct obj
*obj
;
739 char *bufp
, buf
[BUFSZ
], bufcpy
[BUFSZ
], qbuf
[QBUFSZ
];
743 /* Do this now because there's no point in even asking for a name */
744 if (obj
->otyp
== SPE_NOVEL
) {
745 pline("%s already has a published name.", Ysimple_name2(obj
));
749 Sprintf(qbuf
, "What do you want to name %s ",
750 is_plural(obj
) ? "these" : "this");
751 (void) safe_qbuf(qbuf
, qbuf
, "?", obj
, xname
, simpleonames
, "item");
753 if (!*buf
|| *buf
== '\033')
755 /* strip leading and trailing spaces; unnames item if all spaces */
756 (void) mungspaces(buf
);
759 * We don't violate illiteracy conduct here, although it is
760 * arguable that we should for anything other than "X". Doing so
761 * would make attaching player's notes to hero's inventory have an
762 * in-game effect, which may or may not be the correct thing to do.
764 * We do violate illiteracy in oname() if player creates Sting or
765 * Orcrist, clearly being literate (no pun intended...).
768 /* relax restrictions over proper capitalization for artifacts */
769 if ((aname
= artifact_name(buf
, &objtyp
)) != 0 && objtyp
== obj
->otyp
)
772 if (obj
->oartifact
) {
773 pline_The("artifact seems to resist the attempt.");
775 } else if (restrict_name(obj
, buf
) || exist_artifact(obj
->otyp
, buf
)) {
776 /* this used to change one letter, substituting a value
777 of 'a' through 'y' (due to an off by one error, 'z'
778 would never be selected) and then force that to
779 upper case if such was the case of the input;
780 now, the hand slip scuffs one or two letters as if
781 the text had been trodden upon, sometimes picking
782 punctuation instead of an arbitrary letter;
783 unfortunately, we have to cover the possibility of
784 it targetting spaces so failing to make any change
785 (we know that it must eventually target a nonspace
786 because buf[] matches a valid artifact name) */
788 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
789 bufp
= !strncmpi(bufcpy
, "the ", 4) ? (buf
+ 4) : buf
;
791 wipeout_text(bufp
, rnd(2), (unsigned) 0);
792 } while (!strcmp(buf
, bufcpy
));
793 pline("While engraving, your %s slips.", body_part(HAND
));
794 display_nhwindow(WIN_MESSAGE
, FALSE
);
795 You("engrave: \"%s\".", buf
);
797 obj
= oname(obj
, buf
);
808 lth
= *name
? (int) (strlen(name
) + 1) : 0;
811 name
= strncpy(buf
, name
, PL_PSIZ
- 1);
812 buf
[PL_PSIZ
- 1] = '\0';
814 /* If named artifact exists in the game, do not create another.
815 * Also trying to create an artifact shouldn't de-artifact
816 * it (e.g. Excalibur from prayer). In this case the object
817 * will retain its current name. */
818 if (obj
->oartifact
|| (lth
&& exist_artifact(obj
->otyp
, name
)))
821 new_oname(obj
, lth
); /* removes old name if one is present */
823 Strcpy(ONAME(obj
), name
);
826 artifact_exists(obj
, name
, TRUE
);
827 if (obj
->oartifact
) {
828 /* can't dual-wield with artifact as secondary weapon */
831 /* activate warning if you've just named your weapon "Sting" */
833 set_artifact_intrinsic(obj
, TRUE
, W_WEP
);
834 /* if obj is owned by a shop, increase your bill */
837 /* violate illiteracy conduct since successfully wrote arti-name */
838 u
.uconduct
.literate
++;
845 static NEARDATA
const char callable
[] = {
846 SCROLL_CLASS
, POTION_CLASS
, WAND_CLASS
, RING_CLASS
, AMULET_CLASS
,
847 GEM_CLASS
, SPBOOK_CLASS
, ARMOR_CLASS
, TOOL_CLASS
, 0
851 objtyp_is_callable(i
)
854 return (boolean
) (objects
[i
].oc_uname
855 || (OBJ_DESCR(objects
[i
])
856 && index(callable
, objects
[i
].oc_class
)));
859 /* C and #name commands - player can name monster or object or type of obj */
866 menu_item
*pick_list
= 0;
867 char ch
, allowall
[2];
868 /* if player wants a,b,c instead of i,o when looting, do that here too */
869 boolean abc
= flags
.lootabc
;
871 win
= create_nhwindow(NHW_MENU
);
874 any
.a_char
= 'm'; /* group accelerator 'C' */
875 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'C', ATR_NONE
,
876 "a monster", MENU_UNSELECTED
);
878 /* we use y and n as accelerators so that we can accept user's
879 response keyed to old "name an individual object?" prompt */
880 any
.a_char
= 'i'; /* group accelerator 'y' */
881 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'y', ATR_NONE
,
882 "a particular object in inventory", MENU_UNSELECTED
);
883 any
.a_char
= 'o'; /* group accelerator 'n' */
884 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'n', ATR_NONE
,
885 "the type of an object in inventory", MENU_UNSELECTED
);
887 any
.a_char
= 'f'; /* group accelerator ',' (or ':' instead?) */
888 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, ',', ATR_NONE
,
889 "the type of an object upon the floor", MENU_UNSELECTED
);
890 any
.a_char
= 'd'; /* group accelerator '\' */
891 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, '\\', ATR_NONE
,
892 "the type of an object on discoveries list", MENU_UNSELECTED
);
893 any
.a_char
= 'a'; /* group accelerator 'l' */
894 add_menu(win
, NO_GLYPH
, &any
, abc
? 0 : any
.a_char
, 'l', ATR_NONE
,
895 "record an annotation for the current level", MENU_UNSELECTED
);
896 end_menu(win
, "What do you want to name?");
897 if (select_menu(win
, PICK_ONE
, &pick_list
) > 0) {
898 ch
= pick_list
[0].item
.a_char
;
899 free((genericptr_t
) pick_list
);
902 destroy_nhwindow(win
);
908 case 'm': /* name a visible monster */
911 case 'i': /* name an individual object in inventory */
912 allowall
[0] = ALL_CLASSES
;
914 obj
= getobj(allowall
, "name");
918 case 'o': /* name a type of object in inventory */
919 obj
= getobj(callable
, "call");
921 /* behave as if examining it in inventory;
922 this might set dknown if it was picked up
923 while blind and the hero can now see */
927 You("would never recognize another one.");
929 } else if (!objtyp_is_callable(obj
->otyp
)) {
930 You("know those as well as you ever will.");
937 case 'f': /* name a type of object visible on the floor */
940 case 'd': /* name a type of object on the discoveries list */
943 case 'a': /* annotate level */
952 register struct obj
*obj
;
954 char buf
[BUFSZ
], qbuf
[QBUFSZ
];
956 register char **str1
;
959 return; /* probably blind */
962 otemp
.oextra
= (struct oextra
*) 0;
964 if (objects
[otemp
.otyp
].oc_class
== POTION_CLASS
&& otemp
.fromsink
)
965 /* kludge, meaning it's sink water */
966 Sprintf(qbuf
, "Call a stream of %s fluid:",
967 OBJ_DESCR(objects
[otemp
.otyp
]));
969 Sprintf(qbuf
, "Call %s:", an(xname(&otemp
)));
971 if (!*buf
|| *buf
== '\033')
975 str1
= &(objects
[obj
->otyp
].oc_uname
);
977 free((genericptr_t
) *str1
);
979 /* strip leading and trailing spaces; uncalls item if all spaces */
980 (void) mungspaces(buf
);
982 if (*str1
) { /* had name, so possibly remove from disco[] */
983 /* strip name first, for the update_inventory() call
984 from undiscover_object() */
986 undiscover_object(obj
->otyp
);
990 discover_object(obj
->otyp
, FALSE
, TRUE
); /* possibly add to disco[] */
1000 struct obj
*obj
= 0;
1001 boolean fakeobj
= FALSE
, use_plural
;
1003 cc
.x
= u
.ux
, cc
.y
= u
.uy
;
1004 /* "dot for under/over you" only makes sense when the cursor hasn't
1005 been moved off the hero's '@' yet, but there's no way to adjust
1006 the help text once getpos() has started */
1007 Sprintf(buf
, "object on map (or '.' for one %s you)",
1008 (u
.uundetected
&& hides_under(youmonst
.data
)) ? "over" : "under");
1009 if (getpos(&cc
, FALSE
, buf
) < 0 || cc
.x
<= 0)
1011 if (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) {
1012 obj
= vobj_at(u
.ux
, u
.uy
);
1014 glyph
= glyph_at(cc
.x
, cc
.y
);
1015 if (glyph_is_object(glyph
))
1016 fakeobj
= object_from_map(glyph
, cc
.x
, cc
.y
, &obj
);
1017 /* else 'obj' stays null */
1020 /* "under you" is safe here since there's no object to hide under */
1021 pline("There doesn't seem to be any object %s.",
1022 (cc
.x
== u
.ux
&& cc
.y
== u
.uy
) ? "under you" : "there");
1025 /* note well: 'obj' might be as instance of STRANGE_OBJECT if target
1026 is a mimic; passing that to xname (directly or via simpleonames)
1027 would yield "glorkum" so we need to handle it explicitly; it will
1028 always fail the Hallucination test and pass the !callable test,
1029 resulting in the "can't be assigned a type name" message */
1030 Strcpy(buf
, (obj
->otyp
!= STRANGE_OBJECT
)
1032 : obj_descr
[STRANGE_OBJECT
].oc_name
);
1033 use_plural
= (obj
->quan
> 1L);
1034 if (Hallucination
) {
1035 const char *unames
[6];
1038 /* straight role name */
1039 unames
[0] = ((Upolyd
? u
.mfemale
: flags
.female
) && urole
.name
.f
)
1042 /* random rank title for hero's role */
1043 unames
[1] = rank_of(rnd(30), Role_switch
, flags
.female
);
1044 /* random fake monster */
1045 unames
[2] = bogusmon(tmpbuf
, (char *) 0);
1046 /* increased chance for fake monster */
1047 unames
[3] = unames
[2];
1049 unames
[4] = roguename();
1051 unames
[5] = "Wibbly Wobbly";
1052 pline("%s %s to call you \"%s.\"",
1053 The(buf
), use_plural
? "decide" : "decides",
1054 unames
[rn2(SIZE(unames
))]);
1055 } else if (!objtyp_is_callable(obj
->otyp
)) {
1056 pline("%s %s can't be assigned a type name.",
1057 use_plural
? "Those" : "That", buf
);
1058 } else if (!obj
->dknown
) {
1059 You("don't know %s %s well enough to name %s.",
1060 use_plural
? "those" : "that", buf
, use_plural
? "them" : "it");
1068 static const char *const ghostnames
[] = {
1069 /* these names should have length < PL_NSIZ */
1070 /* Capitalize the names for aesthetics -dgk */
1071 "Adri", "Andries", "Andreas", "Bert", "David", "Dirk",
1072 "Emile", "Frans", "Fred", "Greg", "Hether", "Jay",
1073 "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin",
1074 "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron",
1075 "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
1076 "Stephan", "Lance Braccus", "Shadowhawk"
1079 /* ghost names formerly set by x_monnam(), now by makemon() instead */
1083 return rn2(7) ? ghostnames
[rn2(SIZE(ghostnames
))] : (const char *) plname
;
1087 * Monster naming functions:
1088 * x_monnam is the generic monster-naming function.
1089 * seen unseen detected named
1090 * mon_nam: the newt it the invisible orc Fido
1091 * noit_mon_nam:the newt (as if detected) the invisible orc Fido
1092 * l_monnam: newt it invisible orc dog called Fido
1093 * Monnam: The newt It The invisible orc Fido
1094 * noit_Monnam: The newt (as if detected) The invisible orc Fido
1095 * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
1096 * Amonnam: A newt It An invisible orc Fido
1097 * a_monnam: a newt it an invisible orc Fido
1098 * m_monnam: newt xan orc Fido
1099 * y_monnam: your newt your xan your invisible orc Fido
1102 /* Bug: if the monster is a priest or shopkeeper, not every one of these
1103 * options works, since those are special cases.
1106 x_monnam(mtmp
, article
, adjective
, suppress
, called
)
1107 register struct monst
*mtmp
;
1109 /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
1110 * ARTICLE_YOUR: "your" on pets, "the" on everything else
1112 * If the monster would be referred to as "it" or if the monster has a name
1113 * _and_ there is no adjective, "invisible", "saddled", etc., override this
1114 * and always use no article.
1116 const char *adjective
;
1118 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
1119 * EXACT_NAME: combination of all the above
1123 char *buf
= nextmbuf();
1124 struct permonst
*mdat
= mtmp
->data
;
1125 const char *pm_name
= mdat
->mname
;
1126 boolean do_hallu
, do_invis
, do_it
, do_saddle
;
1127 boolean name_at_start
, has_adjectives
;
1130 if (program_state
.gameover
)
1131 suppress
|= SUPPRESS_HALLUCINATION
;
1132 if (article
== ARTICLE_YOUR
&& !mtmp
->mtame
)
1133 article
= ARTICLE_THE
;
1135 do_hallu
= Hallucination
&& !(suppress
& SUPPRESS_HALLUCINATION
);
1136 do_invis
= mtmp
->minvis
&& !(suppress
& SUPPRESS_INVISIBLE
);
1137 do_it
= !canspotmon(mtmp
) && article
!= ARTICLE_YOUR
1138 && !program_state
.gameover
&& mtmp
!= u
.usteed
1139 && !(u
.uswallow
&& mtmp
== u
.ustuck
) && !(suppress
& SUPPRESS_IT
);
1140 do_saddle
= !(suppress
& SUPPRESS_SADDLE
);
1144 /* unseen monsters, etc. Use "it" */
1150 /* priests and minions: don't even use this function */
1151 if (mtmp
->ispriest
|| mtmp
->isminion
) {
1152 char priestnambuf
[BUFSZ
];
1154 long save_prop
= EHalluc_resistance
;
1155 unsigned save_invis
= mtmp
->minvis
;
1157 /* when true name is wanted, explicitly block Hallucination */
1159 EHalluc_resistance
= 1L;
1162 name
= priestname(mtmp
, priestnambuf
);
1163 EHalluc_resistance
= save_prop
;
1164 mtmp
->minvis
= save_invis
;
1165 if (article
== ARTICLE_NONE
&& !strncmp(name
, "the ", 4))
1167 return strcpy(buf
, name
);
1169 /* an "aligned priest" not flagged as a priest or minion should be
1170 "priest" or "priestess" (normally handled by priestname()) */
1171 if (mdat
== &mons
[PM_ALIGNED_PRIEST
])
1172 pm_name
= mtmp
->female
? "priestess" : "priest";
1173 else if (mdat
== &mons
[PM_HIGH_PRIEST
] && mtmp
->female
)
1174 pm_name
= "high priestess";
1176 /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
1177 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
1178 * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
1179 * none of this applies.
1181 if (mtmp
->isshk
&& !do_hallu
) {
1182 if (adjective
&& article
== ARTICLE_THE
) {
1183 /* pathological case: "the angry Asidonhopo the blue dragon"
1185 Strcpy(buf
, "the ");
1186 Strcat(strcat(buf
, adjective
), " ");
1187 Strcat(buf
, shkname(mtmp
));
1190 Strcat(buf
, shkname(mtmp
));
1191 if (mdat
== &mons
[PM_SHOPKEEPER
] && !do_invis
)
1193 Strcat(buf
, " the ");
1195 Strcat(buf
, "invisible ");
1196 Strcat(buf
, pm_name
);
1200 /* Put the adjectives in the buffer */
1202 Strcat(strcat(buf
, adjective
), " ");
1204 Strcat(buf
, "invisible ");
1205 if (do_saddle
&& (mtmp
->misc_worn_check
& W_SADDLE
) && !Blind
1207 Strcat(buf
, "saddled ");
1209 has_adjectives
= TRUE
;
1211 has_adjectives
= FALSE
;
1213 /* Put the actual monster name or type into the buffer now */
1214 /* Be sure to remember whether the buffer starts with a name */
1217 char *rname
= rndmonnam(&rnamecode
);
1220 name_at_start
= bogon_is_pname(rnamecode
);
1221 } else if (has_mname(mtmp
)) {
1222 char *name
= MNAME(mtmp
);
1224 if (mdat
== &mons
[PM_GHOST
]) {
1225 Sprintf(eos(buf
), "%s ghost", s_suffix(name
));
1226 name_at_start
= TRUE
;
1227 } else if (called
) {
1228 Sprintf(eos(buf
), "%s called %s", pm_name
, name
);
1229 name_at_start
= (boolean
) type_is_pname(mdat
);
1230 } else if (is_mplayer(mdat
) && (bp
= strstri(name
, " the ")) != 0) {
1231 /* <name> the <adjective> <invisible> <saddled> <rank> */
1235 pbuf
[bp
- name
+ 5] = '\0'; /* adjectives right after " the " */
1238 Strcat(pbuf
, bp
+ 5); /* append the rest of the name */
1240 article
= ARTICLE_NONE
;
1241 name_at_start
= TRUE
;
1244 name_at_start
= TRUE
;
1246 } else if (is_mplayer(mdat
) && !In_endgame(&u
.uz
)) {
1249 Strcpy(pbuf
, rank_of((int) mtmp
->m_lev
, monsndx(mdat
),
1250 (boolean
) mtmp
->female
));
1251 Strcat(buf
, lcase(pbuf
));
1252 name_at_start
= FALSE
;
1254 Strcat(buf
, pm_name
);
1255 name_at_start
= (boolean
) type_is_pname(mdat
);
1258 if (name_at_start
&& (article
== ARTICLE_YOUR
|| !has_adjectives
)) {
1259 if (mdat
== &mons
[PM_WIZARD_OF_YENDOR
])
1260 article
= ARTICLE_THE
;
1262 article
= ARTICLE_NONE
;
1263 } else if ((mdat
->geno
& G_UNIQ
) && article
== ARTICLE_A
) {
1264 article
= ARTICLE_THE
;
1272 Strcpy(buf2
, "your ");
1277 Strcpy(buf2
, "the ");
1294 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0,
1295 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, TRUE
);
1302 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1303 (has_mname(mtmp
)) ? SUPPRESS_SADDLE
: 0, FALSE
);
1306 /* print the name as if mon_nam() was called, but assume that the player
1307 * can always see the monster--used for probing and for monsters aggravating
1308 * the player with a cursed potion of invisibility
1314 return x_monnam(mtmp
, ARTICLE_THE
, (char *) 0,
1315 (has_mname(mtmp
)) ? (SUPPRESS_SADDLE
| SUPPRESS_IT
)
1324 register char *bp
= mon_nam(mtmp
);
1334 register char *bp
= noit_mon_nam(mtmp
);
1340 /* monster's own name */
1345 return x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, EXACT_NAME
, FALSE
);
1348 /* pet name: "your little dog" */
1353 int prefix
, suppression_flag
;
1355 prefix
= mtmp
->mtame
? ARTICLE_YOUR
: ARTICLE_THE
;
1356 suppression_flag
= (has_mname(mtmp
)
1357 /* "saddled" is redundant when mounted */
1358 || mtmp
== u
.usteed
)
1362 return x_monnam(mtmp
, prefix
, (char *) 0, suppression_flag
, FALSE
);
1366 Adjmonnam(mtmp
, adj
)
1370 char *bp
= x_monnam(mtmp
, ARTICLE_THE
, adj
,
1371 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1381 return x_monnam(mtmp
, ARTICLE_A
, (char *) 0,
1382 has_mname(mtmp
) ? SUPPRESS_SADDLE
: 0, FALSE
);
1389 char *bp
= a_monnam(mtmp
);
1395 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1396 identification of the endgame altars via their attending priests */
1398 distant_monnam(mon
, article
, outbuf
)
1400 int article
; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1403 /* high priest(ess)'s identity is concealed on the Astral Plane,
1404 unless you're adjacent (overridden for hallucination which does
1405 its own obfuscation) */
1406 if (mon
->data
== &mons
[PM_HIGH_PRIEST
] && !Hallucination
1407 && Is_astralevel(&u
.uz
) && distu(mon
->mx
, mon
->my
) > 2) {
1408 Strcpy(outbuf
, article
== ARTICLE_THE
? "the " : "");
1409 Strcat(outbuf
, mon
->female
? "high priestess" : "high priest");
1411 Strcpy(outbuf
, x_monnam(mon
, article
, (char *) 0, 0, TRUE
));
1416 /* fake monsters used to be in a hard-coded array, now in a data file */
1423 get_rnd_text(BOGUSMONFILE
, buf
);
1424 /* strip prefix if present */
1425 if (!letter(*mname
)) {
1436 /* return a random monster name, for hallucination */
1441 static char buf
[BUFSZ
];
1444 #define BOGUSMONSIZE 100 /* arbitrary */
1450 name
= rn1(SPECIAL_PM
+ BOGUSMONSIZE
- LOW_PM
, LOW_PM
);
1451 } while (name
< SPECIAL_PM
1452 && (type_is_pname(&mons
[name
]) || (mons
[name
].geno
& G_NOGEN
)));
1454 if (name
>= SPECIAL_PM
) {
1455 mname
= bogusmon(buf
, code
);
1457 mname
= strcpy(buf
, mons
[name
].mname
);
1463 /* check bogusmon prefix to decide whether it's a personal name */
1465 bogon_is_pname(code
)
1470 return index("-+=", code
) ? TRUE
: FALSE
;
1473 /* name of a Rogue player */
1479 if ((opts
= nh_getenv("ROGUEOPTS")) != 0) {
1480 for (i
= opts
; *i
; i
++)
1481 if (!strncmp("name=", i
, 5)) {
1483 if ((j
= index(i
+ 5, ',')) != 0)
1488 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1492 static NEARDATA
const char *const hcolors
[] = {
1493 "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white",
1494 "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter",
1495 "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley",
1496 "blotchy", "guernsey-spotted", "polka-dotted", "square", "round",
1497 "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime",
1498 "strawberry-banana", "peppermint", "romantic", "incandescent",
1499 "octarine", /* Discworld: the Colour of Magic */
1504 const char *colorpref
;
1506 return (Hallucination
|| !colorpref
) ? hcolors
[rn2(SIZE(hcolors
))]
1510 /* return a random real color unless hallucinating */
1514 int k
= rn2(CLR_MAX
);
1516 return Hallucination
? hcolor((char *) 0)
1517 : (k
== NO_COLOR
) ? "colorless"
1521 /* Aliases for road-runner nemesis
1523 static const char *const coynames
[] = {
1524 "Carnivorous Vulgaris", "Road-Runnerus Digestus", "Eatibus Anythingus",
1525 "Famishus-Famishus", "Eatibus Almost Anythingus", "Eatius Birdius",
1526 "Famishius Fantasticus", "Eternalii Famishiis", "Famishus Vulgarus",
1527 "Famishius Vulgaris Ingeniusi", "Eatius-Slobbius", "Hardheadipus Oedipus",
1528 "Carnivorous Slobbius", "Hard-Headipus Ravenus", "Evereadii Eatibus",
1529 "Apetitius Giganticus", "Hungrii Flea-Bagius", "Overconfidentii Vulgaris",
1530 "Caninus Nervous Rex", "Grotesques Appetitus", "Nemesis Ridiculii",
1535 coyotename(mtmp
, buf
)
1540 Sprintf(buf
, "%s - %s",
1541 x_monnam(mtmp
, ARTICLE_NONE
, (char *) 0, 0, TRUE
),
1542 mtmp
->mcan
? coynames
[SIZE(coynames
) - 1]
1543 : coynames
[rn2(SIZE(coynames
) - 1)]);
1548 /* make sure "The Colour of Magic" remains the first entry in here */
1549 static const char *const sir_Terry_novels
[] = {
1550 "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort",
1551 "Sourcery", "Wyrd Sisters", "Pyramids", "Guards! Guards!", "Eric",
1552 "Moving Pictures", "Reaper Man", "Witches Abroad", "Small Gods",
1553 "Lords and Ladies", "Men at Arms", "Soul Music", "Interesting Times",
1554 "Maskerade", "Feet of Clay", "Hogfather", "Jingo", "The Last Continent",
1555 "Carpe Jugulum", "The Fifth Elephant", "The Truth", "Thief of Time",
1556 "The Last Hero", "The Amazing Maurice and his Educated Rodents",
1557 "Night Watch", "The Wee Free Men", "Monstrous Regiment",
1558 "A Hat Full of Sky", "Going Postal", "Thud!", "Wintersmith",
1559 "Making Money", "Unseen Academicals", "I Shall Wear Midnight", "Snuff",
1560 "Raising Steam", "The Shepherd's Crown"
1567 int j
, k
= SIZE(sir_Terry_novels
);
1573 else if (*novidx
>= 0 && *novidx
< k
)
1576 return sir_Terry_novels
[j
];
1580 lookup_novel(lookname
, idx
)
1581 const char *lookname
;
1586 /* Take American or U.K. spelling of this one */
1587 if (!strcmpi(The(lookname
), "The Color of Magic"))
1588 lookname
= sir_Terry_novels
[0];
1590 for (k
= 0; k
< SIZE(sir_Terry_novels
); ++k
) {
1591 if (!strcmpi(lookname
, sir_Terry_novels
[k
])
1592 || !strcmpi(The(lookname
), sir_Terry_novels
[k
])) {
1595 return sir_Terry_novels
[k
];
1598 /* name not found; if novelidx is already set, override the name */
1599 if (idx
&& *idx
>= 0 && *idx
< SIZE(sir_Terry_novels
))
1600 return sir_Terry_novels
[*idx
];
1602 return (const char *) 0;