Use define for iron ball weight increment
[aNetHack.git] / src / do_name.c
blob567720e679a8f09a8a921b5f89817b5ec0579511
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. */
5 #include "hack.h"
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 *,
10 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 */
19 #define NUMMBUF 5
21 /* manage a pool of BUFSZ buffers, so callers don't have to */
22 STATIC_OVL char *
23 nextmbuf()
25 static char NEARDATA bufs[NUMMBUF][BUFSZ];
26 static int bufidx = 0;
28 bufidx = (bufidx + 1) % NUMMBUF;
29 return bufs[bufidx];
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;
37 void
38 getpos_sethilite(f)
39 void FDECL((*f), (int));
41 getpos_hilitefunc = f;
44 /* the response for '?' help request in getpos() */
45 STATIC_OVL void
46 getpos_help(force, goal)
47 boolean force;
48 const char *goal;
50 char sbuf[BUFSZ];
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);
70 if (!force)
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);
77 STATIC_OVL int
78 cmp_coord_distu(a, b)
79 const void *a;
80 const void *b;
82 const coord *c1 = a;
83 const coord *c2 = b;
84 int dx, dy, dist_1, dist_2;
86 dx = u.ux - c1->x;
87 dy = u.uy - c1->y;
88 dist_1 = dx * dx + dy * dy;
89 dx = u.ux - c2->x;
90 dy = u.uy - c2->y;
91 dist_2 = dx * dx + dy * dy;
93 return dist_1 - dist_2;
96 int
97 getpos(ccp, force, goal)
98 coord *ccp;
99 boolean force;
100 const char *goal;
102 int result = 0;
103 int cx, cy, i, c;
104 int sidx, tx, ty;
105 boolean msg_given = TRUE; /* clear message window by default */
106 boolean show_goal_msg = FALSE;
107 static const char pick_chars[] = ".,;:";
108 const char *cp;
109 boolean hilite_state = FALSE;
110 coord *monarr = NULL;
111 int moncount = 0;
112 int monidx = 0;
114 if (!goal)
115 goal = "desired location";
116 if (flags.verbose) {
117 pline("(For instructions type a ?)");
118 msg_given = TRUE;
120 cx = ccp->x;
121 cy = ccp->y;
122 #ifdef CLIPPING
123 cliparound(cx, cy);
124 #endif
125 curs(WIN_MAP, cx, cy);
126 flush_screen(0);
127 #ifdef MAC
128 lock_mouse_cursor(TRUE);
129 #endif
130 for (;;) {
131 if (show_goal_msg) {
132 pline("Move cursor to %s:", goal);
133 curs(WIN_MAP, cx, cy);
134 flush_screen(0);
135 show_goal_msg = FALSE;
136 } else if (iflags.autodescribe && !msg_given && !hilite_state) {
137 coord cc;
138 int sym = 0;
139 char tmpbuf[BUFSZ];
140 const char *firstmatch = NULL;
142 cc.x = cx;
143 cc.y = cy;
144 if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) {
145 pline1(firstmatch);
146 curs(WIN_MAP, cx, cy);
147 flush_screen(0);
151 c = nh_poskey(&tx, &ty, &sidx);
153 if (hilite_state) {
154 (*getpos_hilitefunc)(2);
155 hilite_state = FALSE;
156 curs(WIN_MAP, cx, cy);
157 flush_screen(0);
160 if (iflags.autodescribe)
161 msg_given = FALSE;
163 if (c == '\033') {
164 cx = cy = -10;
165 msg_given = TRUE; /* force clear */
166 result = -1;
167 break;
169 if (c == 0) {
170 if (!isok(tx, ty))
171 continue;
172 /* a mouse click event, just assign and return */
173 cx = tx;
174 cy = ty;
175 break;
177 if ((cp = index(pick_chars, c)) != 0) {
178 /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
179 result = (int) (cp - pick_chars);
180 break;
182 for (i = 0; i < 8; i++) {
183 int dx, dy;
185 if (Cmd.dirchars[i] == c) {
186 /* a normal movement letter or digit */
187 dx = xdir[i];
188 dy = ydir[i];
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 */
192 dx = 8 * xdir[i];
193 dy = 8 * ydir[i];
194 } else
195 continue;
197 /* truncate at map edge; diagonal moves complicate this... */
198 if (cx + dx < 1) {
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;
205 if (cy + dy < 0) {
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;
212 cx += dx;
213 cy += dy;
214 goto nxtc;
217 if (c == '?' || redraw_cmd(c)) {
218 if (c == '?')
219 getpos_help(force, goal);
220 else /* ^R */
221 docrt(); /* redraw */
222 /* update message window to reflect that we're still targetting */
223 show_goal_msg = TRUE;
224 msg_given = TRUE;
225 } else if (c == '$' && getpos_hilitefunc) {
226 if (!hilite_state) {
227 (*getpos_hilitefunc)(0);
228 (*getpos_hilitefunc)(1);
229 hilite_state = TRUE;
231 goto nxtc;
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;
239 msg_given = TRUE;
240 goto nxtc;
241 } else if (c == '@') {
242 cx = u.ux;
243 cy = u.uy;
244 goto nxtc;
245 } else if (c == 'm' || c == 'M') {
246 if (!monarr) {
247 struct monst *mtmp;
249 moncount = 0;
250 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
251 if (canspotmon(mtmp)
252 && (mtmp->mx != u.ux || mtmp->my != u.uy))
253 moncount++;
255 /* moncount + 1: always allocate a non-zero amount */
256 monarr = (coord *) alloc(sizeof (coord) * (moncount + 1));
257 monidx = 0;
258 for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
259 if (canspotmon(mtmp)
260 && (mtmp->mx != u.ux || mtmp->my != u.uy)) {
261 monarr[monidx].x = mtmp->mx;
262 monarr[monidx].y = mtmp->my;
263 monidx++;
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;
270 if (moncount) {
271 if (c == 'm') {
272 monidx = (monidx + 1) % moncount;
273 } else {
274 if (--monidx < 0)
275 monidx = moncount - 1;
277 cx = monarr[monidx].x;
278 cy = monarr[monidx].y;
279 goto nxtc;
281 } else {
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;
290 if (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 */
304 if (glyph_is_cmap(k)
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);
313 if (glyph_is_cmap(k)
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) {
321 cx = tx, cy = ty;
322 if (msg_given) {
323 clear_nhwindow(WIN_MESSAGE);
324 msg_given = FALSE;
326 goto nxtc;
328 } /* column */
329 } /* row */
330 } /* pass */
331 pline("Can't find dungeon feature '%c'.", c);
332 msg_given = TRUE;
333 goto nxtc;
334 } else {
335 char note[QBUFSZ];
337 if (!force)
338 Strcpy(note, "aborted");
339 else
340 Sprintf(note, "use %c%c%c%c or .", /* hjkl */
341 Cmd.move_W, Cmd.move_S, Cmd.move_N,
342 Cmd.move_E);
343 pline("Unknown direction: '%s' (%s).", visctrl((char) c),
344 note);
345 msg_given = TRUE;
346 } /* k => matching */
347 } /* !quitchars */
348 if (force)
349 goto nxtc;
350 pline("Done.");
351 msg_given = FALSE; /* suppress clear */
352 cx = -1;
353 cy = 0;
354 result = 0; /* not -1 */
355 break;
357 nxtc:
359 #ifdef CLIPPING
360 cliparound(cx, cy);
361 #endif
362 curs(WIN_MAP, cx, cy);
363 flush_screen(0);
365 #ifdef MAC
366 lock_mouse_cursor(FALSE);
367 #endif
368 if (msg_given)
369 clear_nhwindow(WIN_MESSAGE);
370 ccp->x = cx;
371 ccp->y = cy;
372 if (monarr)
373 free((genericptr_t) monarr);
374 getpos_hilitefunc = (void FDECL((*), (int))) 0;
375 return result;
378 /* allocate space for a monster's name; removes old name if there is one */
379 void
380 new_mname(mon, lth)
381 struct monst *mon;
382 int lth; /* desired length (caller handles adding 1 for terminator) */
384 if (lth) {
385 /* allocate mextra if necessary; otherwise get rid of old name */
386 if (!mon->mextra)
387 mon->mextra = newmextra();
388 else
389 free_mname(mon); /* already has mextra, might also have name */
390 MNAME(mon) = (char *) alloc((unsigned) lth);
391 } else {
392 /* zero length: the new name is empty; get rid of the old name */
393 if (has_mname(mon))
394 free_mname(mon);
398 /* release a monster's name; retains mextra even if all fields are now null */
399 void
400 free_mname(mon)
401 struct monst *mon;
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 */
410 void
411 new_oname(obj, lth)
412 struct obj *obj;
413 int lth; /* desired length (caller handles adding 1 for terminator) */
415 if (lth) {
416 /* allocate oextra if necessary; otherwise get rid of old name */
417 if (!obj->oextra)
418 obj->oextra = newoextra();
419 else
420 free_oname(obj); /* already has oextra, might also have name */
421 ONAME(obj) = (char *) alloc((unsigned) lth);
422 } else {
423 /* zero length: the new name is empty; get rid of the old name */
424 if (has_oname(obj))
425 free_oname(obj);
429 /* release an object's name; retains oextra even if all fields are now null */
430 void
431 free_oname(obj)
432 struct obj *obj;
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
443 * if it doesn't.
445 const char *
446 safe_oname(obj)
447 struct obj *obj;
449 if (has_oname(obj))
450 return ONAME(obj);
451 return "";
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 */
456 struct monst *
457 christen_monst(mtmp, name)
458 struct monst *mtmp;
459 const char *name;
461 int lth;
462 char buf[PL_PSIZ];
464 /* dogname & catname are PL_PSIZ arrays; object names have same limit */
465 lth = (name && *name) ? ((int) strlen(name) + 1) : 0;
466 if (lth > PL_PSIZ) {
467 lth = PL_PSIZ;
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 */
472 if (lth)
473 Strcpy(MNAME(mtmp), name);
474 return mtmp;
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() */
479 STATIC_OVL boolean
480 alreadynamed(mtmp, monnambuf, usrbuf)
481 struct monst *mtmp;
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);
498 return TRUE;
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);
503 return TRUE;
505 return FALSE;
508 /* allow player to assign a name to some chosen monster */
509 STATIC_OVL void
510 do_mname()
512 char buf[BUFSZ], monnambuf[BUFSZ], qbuf[QBUFSZ];
513 coord cc;
514 int cx, cy;
515 struct monst *mtmp = 0;
517 if (Hallucination) {
518 You("would never recognize it anyway.");
519 return;
521 cc.x = u.ux;
522 cc.y = u.uy;
523 if (getpos(&cc, FALSE, "the monster you want to name") < 0
524 || (cx = cc.x) < 0)
525 return;
526 cy = cc.y;
528 if (cx == u.ux && cy == u.uy) {
529 if (u.usteed && canspotmon(u.usteed)) {
530 mtmp = u.usteed;
531 } else {
532 pline("This %s creature is called %s and cannot be renamed.",
533 beautiful(), plname);
534 return;
536 } else
537 mtmp = m_at(cx, cy);
539 if (!mtmp
540 || (!sensemon(mtmp)
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.");
546 return;
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));
551 getlin(qbuf, buf);
552 if (!*buf || *buf == '\033')
553 return;
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
562 * the existing name.
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);
575 } else
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.
584 STATIC_OVL
585 void
586 do_oname(obj)
587 register struct obj *obj;
589 char *bufp, buf[BUFSZ], bufcpy[BUFSZ], qbuf[QBUFSZ];
590 const char *aname;
591 short objtyp;
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));
596 return;
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");
602 getlin(qbuf, buf);
603 if (!*buf || *buf == '\033')
604 return;
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)
620 Strcpy(buf, aname);
622 if (obj->oartifact) {
623 pline_The("artifact seems to resist the attempt.");
624 return;
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) */
637 Strcpy(bufcpy, buf);
638 /* for "the Foo of Bar", only scuff "Foo of Bar" part */
639 bufp = !strncmpi(bufcpy, "the ", 4) ? (buf + 4) : buf;
640 do {
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);
650 struct obj *
651 oname(obj, name)
652 struct obj *obj;
653 const char *name;
655 int lth;
656 char buf[PL_PSIZ];
658 lth = *name ? (int) (strlen(name) + 1) : 0;
659 if (lth > PL_PSIZ) {
660 lth = PL_PSIZ;
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)))
669 return obj;
671 new_oname(obj, lth); /* removes old name if one is present */
672 if (lth)
673 Strcpy(ONAME(obj), name);
675 if (lth)
676 artifact_exists(obj, name, TRUE);
677 if (obj->oartifact) {
678 /* can't dual-wield with artifact as secondary weapon */
679 if (obj == uswapwep)
680 untwoweapon();
681 /* activate warning if you've just named your weapon "Sting" */
682 if (obj == uwep)
683 set_artifact_intrinsic(obj, TRUE, W_WEP);
684 /* if obj is owned by a shop, increase your bill */
685 if (obj->unpaid)
686 alter_cost(obj, 0L);
687 /* violate illiteracy conduct since successfully wrote arti-name */
688 u.uconduct.literate++;
690 if (carried(obj))
691 update_inventory();
692 return obj;
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
700 boolean
701 objtyp_is_callable(i)
702 int 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 */
711 docallcmd()
713 struct obj *obj;
714 winid win;
715 anything any;
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);
722 start_menu(win);
723 any = zeroany;
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);
727 if (invent) {
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);
750 } else
751 ch = 'q';
752 destroy_nhwindow(win);
754 switch (ch) {
755 default:
756 case 'q':
757 break;
758 case 'm': /* name a visible monster */
759 do_mname();
760 break;
761 case 'i': /* name an individual object in inventory */
762 allowall[0] = ALL_CLASSES;
763 allowall[1] = '\0';
764 obj = getobj(allowall, "name");
765 if (obj)
766 do_oname(obj);
767 break;
768 case 'o': /* name a type of object in inventory */
769 obj = getobj(callable, "call");
770 if (obj) {
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 */
774 (void) xname(obj);
776 if (!obj->dknown) {
777 You("would never recognize another one.");
778 #if 0
779 } else if (!objtyp_is_callable(obj->otyp)) {
780 You("know those as well as you ever will.");
781 #endif
782 } else {
783 docall(obj);
786 break;
787 case 'f': /* name a type of object visible on the floor */
788 namefloorobj();
789 break;
790 case 'd': /* name a type of object on the discoveries list */
791 rename_disco();
792 break;
793 case 'a': /* annotate level */
794 donamelevel();
795 break;
797 return 0;
800 void
801 docall(obj)
802 register struct obj *obj;
804 char buf[BUFSZ], qbuf[QBUFSZ];
805 struct obj otemp;
806 register char **str1;
808 if (!obj->dknown)
809 return; /* probably blind */
810 otemp = *obj;
811 otemp.quan = 1L;
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]));
818 else
819 Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
820 getlin(qbuf, buf);
821 if (!*buf || *buf == '\033')
822 return;
824 /* clear old name */
825 str1 = &(objects[obj->otyp].oc_uname);
826 if (*str1)
827 free((genericptr_t) *str1);
829 /* strip leading and trailing spaces; uncalls item if all spaces */
830 (void) mungspaces(buf);
831 if (!*buf) {
832 if (*str1) { /* had name, so possibly remove from disco[] */
833 /* strip name first, for the update_inventory() call
834 from undiscover_object() */
835 *str1 = (char *) 0;
836 undiscover_object(obj->otyp);
838 } else {
839 *str1 = dupstr(buf);
840 discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
844 STATIC_OVL void
845 namefloorobj()
847 coord cc;
848 int glyph;
849 char buf[BUFSZ];
850 struct obj *obj = 0;
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)
860 return;
861 if (cc.x == u.ux && cc.y == u.uy) {
862 obj = vobj_at(u.ux, u.uy);
863 } else {
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 */
869 if (!obj) {
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");
873 return;
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)
881 ? simpleonames(obj)
882 : obj_descr[STRANGE_OBJECT].oc_name);
883 use_plural = (obj->quan > 1L);
884 if (Hallucination) {
885 const char *unames[6];
886 char tmpbuf[BUFSZ];
888 /* straight role name */
889 unames[0] = ((Upolyd ? u.mfemale : flags.female) && urole.name.f)
890 ? urole.name.f
891 : urole.name.m;
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];
898 /* traditional */
899 unames[4] = roguename();
900 /* silly */
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");
911 } else {
912 docall(obj);
914 if (fakeobj)
915 dealloc_obj(obj);
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 */
930 const char *
931 rndghostname()
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.
955 char *
956 x_monnam(mtmp, article, adjective, suppress, called)
957 register struct monst *mtmp;
958 int article;
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;
967 int suppress;
968 /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
969 * EXACT_NAME: combination of all the above
971 boolean called;
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;
978 char *bp;
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);
992 buf[0] = '\0';
994 /* unseen monsters, etc. Use "it" */
995 if (do_it) {
996 Strcpy(buf, "it");
997 return buf;
1000 /* priests and minions: don't even use this function */
1001 if (mtmp->ispriest || mtmp->isminion) {
1002 char priestnambuf[BUFSZ];
1003 char *name;
1004 long save_prop = EHalluc_resistance;
1005 unsigned save_invis = mtmp->minvis;
1007 /* when true name is wanted, explicitly block Hallucination */
1008 if (!do_hallu)
1009 EHalluc_resistance = 1L;
1010 if (!do_invis)
1011 mtmp->minvis = 0;
1012 name = priestname(mtmp, priestnambuf);
1013 EHalluc_resistance = save_prop;
1014 mtmp->minvis = save_invis;
1015 if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
1016 name += 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"
1034 sounds silly */
1035 Strcpy(buf, "the ");
1036 Strcat(strcat(buf, adjective), " ");
1037 Strcat(buf, shkname(mtmp));
1038 return buf;
1040 Strcat(buf, shkname(mtmp));
1041 if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
1042 return buf;
1043 Strcat(buf, " the ");
1044 if (do_invis)
1045 Strcat(buf, "invisible ");
1046 Strcat(buf, pm_name);
1047 return buf;
1050 /* Put the adjectives in the buffer */
1051 if (adjective)
1052 Strcat(strcat(buf, adjective), " ");
1053 if (do_invis)
1054 Strcat(buf, "invisible ");
1055 if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind
1056 && !Hallucination)
1057 Strcat(buf, "saddled ");
1058 if (buf[0] != 0)
1059 has_adjectives = TRUE;
1060 else
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 */
1065 if (do_hallu) {
1066 char rnamecode;
1067 char *rname = rndmonnam(&rnamecode);
1069 Strcat(buf, rname);
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> */
1082 char pbuf[BUFSZ];
1084 Strcpy(pbuf, name);
1085 pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
1086 if (has_adjectives)
1087 Strcat(pbuf, buf);
1088 Strcat(pbuf, bp + 5); /* append the rest of the name */
1089 Strcpy(buf, pbuf);
1090 article = ARTICLE_NONE;
1091 name_at_start = TRUE;
1092 } else {
1093 Strcat(buf, name);
1094 name_at_start = TRUE;
1096 } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
1097 char pbuf[BUFSZ];
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;
1103 } else {
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;
1111 else
1112 article = ARTICLE_NONE;
1113 } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
1114 article = ARTICLE_THE;
1118 char buf2[BUFSZ];
1120 switch (article) {
1121 case ARTICLE_YOUR:
1122 Strcpy(buf2, "your ");
1123 Strcat(buf2, buf);
1124 Strcpy(buf, buf2);
1125 return buf;
1126 case ARTICLE_THE:
1127 Strcpy(buf2, "the ");
1128 Strcat(buf2, buf);
1129 Strcpy(buf, buf2);
1130 return buf;
1131 case ARTICLE_A:
1132 return an(buf);
1133 case ARTICLE_NONE:
1134 default:
1135 return buf;
1140 char *
1141 l_monnam(mtmp)
1142 struct monst *mtmp;
1144 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0,
1145 (has_mname(mtmp)) ? SUPPRESS_SADDLE : 0, TRUE);
1148 char *
1149 mon_nam(mtmp)
1150 struct monst *mtmp;
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
1160 char *
1161 noit_mon_nam(mtmp)
1162 struct monst *mtmp;
1164 return x_monnam(mtmp, ARTICLE_THE, (char *) 0,
1165 (has_mname(mtmp)) ? (SUPPRESS_SADDLE | SUPPRESS_IT)
1166 : SUPPRESS_IT,
1167 FALSE);
1170 char *
1171 Monnam(mtmp)
1172 struct monst *mtmp;
1174 register char *bp = mon_nam(mtmp);
1176 *bp = highc(*bp);
1177 return bp;
1180 char *
1181 noit_Monnam(mtmp)
1182 struct monst *mtmp;
1184 register char *bp = noit_mon_nam(mtmp);
1186 *bp = highc(*bp);
1187 return bp;
1190 /* monster's own name */
1191 char *
1192 m_monnam(mtmp)
1193 struct monst *mtmp;
1195 return x_monnam(mtmp, ARTICLE_NONE, (char *) 0, EXACT_NAME, FALSE);
1198 /* pet name: "your little dog" */
1199 char *
1200 y_monnam(mtmp)
1201 struct monst *mtmp;
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)
1209 ? SUPPRESS_SADDLE
1210 : 0;
1212 return x_monnam(mtmp, prefix, (char *) 0, suppression_flag, FALSE);
1215 char *
1216 Adjmonnam(mtmp, adj)
1217 struct monst *mtmp;
1218 const char *adj;
1220 char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
1221 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
1223 *bp = highc(*bp);
1224 return bp;
1227 char *
1228 a_monnam(mtmp)
1229 struct monst *mtmp;
1231 return x_monnam(mtmp, ARTICLE_A, (char *) 0,
1232 has_mname(mtmp) ? SUPPRESS_SADDLE : 0, FALSE);
1235 char *
1236 Amonnam(mtmp)
1237 struct monst *mtmp;
1239 char *bp = a_monnam(mtmp);
1241 *bp = highc(*bp);
1242 return bp;
1245 /* used for monster ID by the '/', ';', and 'C' commands to block remote
1246 identification of the endgame altars via their attending priests */
1247 char *
1248 distant_monnam(mon, article, outbuf)
1249 struct monst *mon;
1250 int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
1251 char *outbuf;
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");
1260 } else {
1261 Strcpy(outbuf, x_monnam(mon, article, (char *) 0, 0, TRUE));
1263 return outbuf;
1266 /* fake monsters used to be in a hard-coded array, now in a data file */
1267 STATIC_OVL char *
1268 bogusmon(buf, code)
1269 char *buf, *code;
1271 char *mname = buf;
1273 get_rnd_text(BOGUSMONFILE, buf);
1274 /* strip prefix if present */
1275 if (!letter(*mname)) {
1276 if (code)
1277 *code = *mname;
1278 ++mname;
1279 } else {
1280 if (code)
1281 *code = '\0';
1283 return mname;
1286 /* return a random monster name, for hallucination */
1287 char *
1288 rndmonnam(code)
1289 char *code;
1291 static char buf[BUFSZ];
1292 char *mname;
1293 int name;
1294 #define BOGUSMONSIZE 100 /* arbitrary */
1296 if (code)
1297 *code = '\0';
1299 do {
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);
1306 } else {
1307 mname = strcpy(buf, mons[name].mname);
1309 return mname;
1310 #undef BOGUSMONSIZE
1313 /* check bogusmon prefix to decide whether it's a personal name */
1314 boolean
1315 bogon_is_pname(code)
1316 char code;
1318 if (!code)
1319 return FALSE;
1320 return index("-+=", code) ? TRUE : FALSE;
1323 /* name of a Rogue player */
1324 const char *
1325 roguename()
1327 char *i, *opts;
1329 if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
1330 for (i = opts; *i; i++)
1331 if (!strncmp("name=", i, 5)) {
1332 char *j;
1333 if ((j = index(i + 5, ',')) != 0)
1334 *j = (char) 0;
1335 return i + 5;
1338 return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
1339 : "Glenn Wichman";
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 */
1352 const char *
1353 hcolor(colorpref)
1354 const char *colorpref;
1356 return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))]
1357 : colorpref;
1360 /* return a random real color unless hallucinating */
1361 const char *
1362 rndcolor()
1364 int k = rn2(CLR_MAX);
1366 return Hallucination ? hcolor((char *) 0)
1367 : (k == NO_COLOR) ? "colorless"
1368 : c_obj_colors[k];
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",
1381 "Canis latrans"
1384 char *
1385 coyotename(mtmp, buf)
1386 struct monst *mtmp;
1387 char *buf;
1389 if (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)]);
1395 return buf;
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"
1413 const char *
1414 noveltitle(novidx)
1415 int *novidx;
1417 int j, k = SIZE(sir_Terry_novels);
1419 j = rn2(k);
1420 if (novidx) {
1421 if (*novidx == -1)
1422 *novidx = j;
1423 else if (*novidx >= 0 && *novidx < k)
1424 j = *novidx;
1426 return sir_Terry_novels[j];
1429 const char *
1430 lookup_novel(lookname, idx)
1431 const char *lookname;
1432 int *idx;
1434 int k;
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])) {
1443 if (idx)
1444 *idx = 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;
1455 /*do_name.c*/