1 | /* SCCS Id: @(#)do_name.c 3.3 2000/06/12 */
2 | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 | /* NetHack may be freely redistributed. See license for details. */
4 |
5 | #include "hack.h"
6 |
7 | #ifdef OVLB
8 |
9 | STATIC_DCL void FDECL(do_oname, (struct obj *));
10 | static void FDECL(getpos_help, (BOOLEAN_P,const char *));
11 |
12 | extern const char what_is_an_unknown_object[]; /* from pager.c */
13 |
14 | /* the response for '?' help request in getpos() */
15 | static void
16 | getpos_help(force, goal)
17 | boolean force;
18 | const char *goal;
19 | {
20 | char sbuf[BUFSZ];
21 | boolean doing_what_is;
22 | winid tmpwin = create_nhwindow(NHW_MENU);
23 |
24 | Sprintf(sbuf, "Use [%s] to move the cursor to %s.",
25 | iflags.num_pad ? "2468" : "hjkl", goal);
26 | putstr(tmpwin, 0, sbuf);
27 | putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
28 | putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
29 | /* disgusting hack; the alternate selection characters work for any
30 | getpos call, but they only matter for dowhatis (and doquickwhatis) */
31 | doing_what_is = (goal == what_is_an_unknown_object);
32 | Sprintf(sbuf, "Type a .%s when you are at the right place.",
33 | doing_what_is ? " or , or ; or :" : "");
34 | putstr(tmpwin, 0, sbuf);
35 | if (!force)
36 | putstr(tmpwin, 0, "Type Space or Escape when you're done.");
37 | putstr(tmpwin, 0, "");
38 | display_nhwindow(tmpwin, TRUE);
39 | destroy_nhwindow(tmpwin);
40 | }
41 |
42 | int
43 | getpos(cc, force, goal)
44 | coord *cc;
45 | boolean force;
46 | const char *goal;
47 | {
48 | int result = 0;
49 | int cx, cy, i, c;
50 | int sidx, tx, ty;
51 | boolean msg_given = TRUE; /* clear message window by default */
52 | static const char *pick_chars = ".,;:";
53 | const char *cp;
54 | const char *sdp;
55 | if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
56 |
57 | if (flags.verbose) {
58 | pline("(For instructions type a ?)");
59 | msg_given = TRUE;
60 | }
61 | cx = cc->x;
62 | cy = cc->y;
63 | #ifdef CLIPPING
64 | cliparound(cx, cy);
65 | #endif
66 | curs(WIN_MAP, cx,cy);
67 | flush_screen(0);
68 | #ifdef MAC
69 | lock_mouse_cursor(TRUE);
70 | #endif
71 | for (;;) {
72 | c = nh_poskey(&tx, &ty, &sidx);
73 | if (c == '\033') {
74 | cx = cy = -10;
75 | msg_given = TRUE; /* force clear */
76 | result = -1;
77 | break;
78 | }
79 | if(c == 0) {
80 | if (!isok(tx, ty)) continue;
81 | /* a mouse click event, just assign and return */
82 | cx = tx;
83 | cy = ty;
84 | break;
85 | }
86 | if ((cp = index(pick_chars, c)) != 0) {
87 | /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
88 | result = cp - pick_chars;
89 | break;
90 | }
91 | for (i = 0; i < 8; i++) {
92 | int dx, dy;
93 |
94 | if (sdp[i] == c) {
95 | /* a normal movement letter or digit */
96 | dx = xdir[i];
97 | dy = ydir[i];
98 | } else if (sdir[i] == lowc((char)c)) {
99 | /* a shifted movement letter */
100 | dx = 8 * xdir[i];
101 | dy = 8 * ydir[i];
102 | } else
103 | continue;
104 |
105 | /* truncate at map edge; diagonal moves complicate this... */
106 | if (cx + dx < 1) {
107 | dy -= sgn(dy) * (1 - (cx + dx));
108 | dx = 1 - cx; /* so that (cx+dx == 1) */
109 | } else if (cx + dx > COLNO-1) {
110 | dy += sgn(dy) * ((COLNO-1) - (cx + dx));
111 | dx = (COLNO-1) - cx;
112 | }
113 | if (cy + dy < 0) {
114 | dx -= sgn(dx) * (0 - (cy + dy));
115 | dy = 0 - cy; /* so that (cy+dy == 0) */
116 | } else if (cy + dy > ROWNO-1) {
117 | dx += sgn(dx) * ((ROWNO-1) - (cy + dy));
118 | dy = (ROWNO-1) - cy;
119 | }
120 | cx += dx;
121 | cy += dy;
122 | goto nxtc;
123 | }
124 |
125 | if(c == '?'){
126 | getpos_help(force, goal);
127 | } else {
128 | if (!index(quitchars, c)) {
129 | char matching[MAXPCHARS];
130 | int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
131 | (void)memset((genericptr_t)matching, 0, sizeof matching);
132 | for (sidx = 1; sidx < MAXPCHARS; sidx++)
133 | if (c == defsyms[sidx].sym || c == (int)showsyms[sidx])
134 | matching[sidx] = (char) ++k;
135 | if (k) {
136 | for (pass = 0; pass <= 1; pass++) {
137 | /* pass 0: just past current pos to lower right;
138 | pass 1: upper left corner to current pos */
139 | lo_y = (pass == 0) ? cy : 0;
140 | hi_y = (pass == 0) ? ROWNO - 1 : cy;
141 | for (ty = lo_y; ty <= hi_y; ty++) {
142 | lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
143 | hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
144 | for (tx = lo_x; tx <= hi_x; tx++) {
145 | k = levl[tx][ty].glyph;
146 | if (glyph_is_cmap(k) &&
147 | matching[glyph_to_cmap(k)]) {
148 | cx = tx, cy = ty;
149 | if (msg_given) {
150 | clear_nhwindow(WIN_MESSAGE);
151 | msg_given = FALSE;
152 | }
153 | goto nxtc;
154 | }
155 | } /* column */
156 | } /* row */
157 | } /* pass */
158 | pline("Can't find dungeon feature '%c'", c);
159 | msg_given = TRUE;
160 | goto nxtc;
161 | } else {
162 | pline("Unknown direction: '%s' (%s).",
163 | visctrl((char)c),
164 | !force ? "aborted" :
165 | iflags.num_pad ? "use 2468 or ." : "use hjkl or .");
166 | msg_given = TRUE;
167 | } /* k => matching */
168 | } /* !quitchars */
169 | if (force) goto nxtc;
170 | pline("Done.");
171 | msg_given = FALSE; /* suppress clear */
172 | cx = -1;
173 | cy = 0;
174 | result = 0; /* not -1 */
175 | break;
176 | }
177 | nxtc: ;
178 | #ifdef CLIPPING
179 | cliparound(cx, cy);
180 | #endif
181 | curs(WIN_MAP,cx,cy);
182 | flush_screen(0);
183 | }
184 | #ifdef MAC
185 | lock_mouse_cursor(FALSE);
186 | #endif
187 | if (msg_given) clear_nhwindow(WIN_MESSAGE);
188 | cc->x = cx;
189 | cc->y = cy;
190 | return result;
191 | }
192 |
193 | struct monst *
194 | christen_monst(mtmp, name)
195 | struct monst *mtmp;
196 | const char *name;
197 | {
198 | int lth;
199 | struct monst *mtmp2;
200 | char buf[PL_PSIZ];
201 |
202 | /* dogname & catname are PL_PSIZ arrays; object names have same limit */
203 | lth = *name ? (int)(strlen(name) + 1) : 0;
204 | if(lth > PL_PSIZ){
205 | lth = PL_PSIZ;
206 | name = strncpy(buf, name, PL_PSIZ - 1);
207 | buf[PL_PSIZ - 1] = '\0';
208 | }
209 | if (lth == mtmp->mnamelth) {
210 | /* don't need to allocate a new monst struct */
211 | if (lth) Strcpy(NAME(mtmp), name);
212 | return mtmp;
213 | }
214 | mtmp2 = newmonst(mtmp->mxlth + lth);
215 | *mtmp2 = *mtmp;
216 | (void) memcpy((genericptr_t)mtmp2->mextra,
217 | (genericptr_t)mtmp->mextra, mtmp->mxlth);
218 | mtmp2->mnamelth = lth;
219 | if (lth) Strcpy(NAME(mtmp2), name);
220 | replmon(mtmp,mtmp2);
221 | return(mtmp2);
222 | }
223 |
224 | int
225 | do_mname()
226 | {
227 | char buf[BUFSZ];
228 | coord cc;
229 | register int cx,cy;
230 | register struct monst *mtmp;
231 | char qbuf[QBUFSZ];
232 |
233 | if (Hallucination) {
234 | You("would never recognize it anyway.");
235 | return 0;
236 | }
237 | cc.x = u.ux;
238 | cc.y = u.uy;
239 | if (getpos(&cc, FALSE, "the monster you want to name") < 0 ||
240 | (cx = cc.x) < 0)
241 | return 0;
242 | cy = cc.y;
243 |
244 | if (cx == u.ux && cy == u.uy) {
245 | #ifdef STEED
246 | if (u.usteed && canspotmon(u.usteed))
247 | mtmp = u.usteed;
248 | else {
249 | #endif
250 | pline("This %s creature is called %s and cannot be renamed.",
251 | ACURR(A_CHA) > 14 ?
252 | (flags.female ? "beautiful" : "handsome") :
253 | "ugly",
254 | plname);
255 | return(0);
256 | #ifdef STEED
257 | }
258 | #endif
259 | } else
260 | mtmp = m_at(cx, cy);
261 |
262 | if (!mtmp || (!sensemon(mtmp) &&
263 | (!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected
264 | || mtmp->m_ap_type == M_AP_FURNITURE
265 | || mtmp->m_ap_type == M_AP_OBJECT
266 | || (mtmp->minvis && !See_invisible)))) {
267 | pline("I see no monster there.");
268 | return(0);
269 | }
270 | /* special case similar to the one in lookat() */
271 | if (mtmp->data != &mons[PM_HIGH_PRIEST])
272 | Strcpy(buf, x_monnam(mtmp, ARTICLE_THE, (char *)0, 0, TRUE));
273 | else
274 | Sprintf(buf, "the high priest%s", mtmp->female ? "ess" : "");
275 | Sprintf(qbuf, "What do you want to call %s?", buf);
276 | getlin(qbuf,buf);
277 | if(!*buf || *buf == '\033') return(0);
278 | /* strip leading and trailing spaces; unnames monster if all spaces */
279 | (void)mungspaces(buf);
280 |
281 | if (mtmp->iswiz || type_is_pname(mtmp->data))
282 | pline("%s doesn't like being called names!", Monnam(mtmp));
283 | else (void) christen_monst(mtmp, buf);
284 | return(0);
285 | }
286 |
287 | /*
288 | * This routine changes the address of obj. Be careful not to call it
289 | * when there might be pointers around in unknown places. For now: only
290 | * when obj is in the inventory.
291 | */
292 | STATIC_OVL
293 | void
294 | do_oname(obj)
295 | register struct obj *obj;
296 | {
297 | char buf[BUFSZ], qbuf[QBUFSZ];
298 | const char *aname;
299 | short objtyp;
300 |
301 | Sprintf(qbuf, "What do you want to name %s %s?",
302 | (obj->quan > 1L) ? "these" : "this", xname(obj));
303 | getlin(qbuf, buf);
304 | if(!*buf || *buf == '\033') return;
305 | /* strip leading and trailing spaces; unnames item if all spaces */
306 | (void)mungspaces(buf);
307 |
308 | /* relax restrictions over proper capitalization for artifacts */
309 | if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
310 | Strcpy(buf, aname);
311 |
312 | if (obj->oartifact) {
313 | pline_The("artifact seems to resist the attempt.");
314 | return;
315 | } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
316 | int n = rn2((int)strlen(buf));
317 | register char c1, c2;
318 |
319 | c1 = lowc(buf[n]);
320 | do c2 = 'a' + rn2('z'-'a'); while (c1 == c2);
321 | buf[n] = (buf[n] == c1) ? c2 : highc(c2); /* keep same case */
322 | pline("While engraving your %s slips.", body_part(HAND));
323 | display_nhwindow(WIN_MESSAGE, FALSE);
324 | You("engrave: \"%s\".",buf);
325 | }
326 | obj = oname(obj, buf);
327 | }
328 |
329 | /*
330 | * Allocate a new and possibly larger storage space for an obj.
331 | */
332 | struct obj *
333 | realloc_obj(obj, oextra_size, oextra_src, oname_size, name)
334 | struct obj *obj;
335 | int oextra_size; /* storage to allocate for oextra */
336 | genericptr_t oextra_src;
337 | int oname_size; /* size of name string + 1 (null terminator) */
338 | const char *name;
339 | {
340 | struct obj *otmp;
341 |
342 | otmp = newobj(oextra_size + oname_size);
343 | *otmp = *obj; /* the cobj pointer is copied to otmp */
344 | if (oextra_size) {
345 | if (oextra_src)
346 | (void) memcpy((genericptr_t)otmp->oextra, oextra_src,
347 | oextra_size);
348 | } else {
349 | otmp->oattached = OATTACHED_NOTHING;
350 | }
351 | otmp->oxlth = oextra_size;
352 |
353 | otmp->onamelth = oname_size;
354 | otmp->timed = 0; /* not timed, yet */
355 | otmp->lamplit = 0; /* ditto */
356 | /* __GNUC__ note: if the assignment of otmp->onamelth immediately
357 | precedes this `if' statement, a gcc bug will miscompile the
358 | test on vax (`insv' instruction used to store bitfield does
359 | not set condition codes, but optimizer behaves as if it did).
360 | gcc-2.7.2.1 finally fixed this. */
361 | if (oname_size) {
362 | if (name)
363 | Strcpy(ONAME(otmp), name);
364 | }
365 |
366 | if (obj->owornmask) {
367 | setworn((struct obj *)0, obj->owornmask);
368 | setworn(otmp, otmp->owornmask);
369 | }
370 |
371 | /* replace obj with otmp */
372 | replace_object(obj, otmp);
373 |
374 | /* fix ocontainer pointers */
375 | if (Has_contents(obj)) {
376 | struct obj *inside;
377 |
378 | for(inside = obj->cobj; inside; inside = inside->nobj)
379 | inside->ocontainer = otmp;
380 | }
381 |
382 | /* move timers and light sources from obj to otmp */
383 | if (obj->timed) obj_move_timers(obj, otmp);
384 | if (obj->lamplit) obj_move_light_source(obj, otmp);
385 |
386 | /* objects possibly being manipulated by multi-turn occupations
387 | which have been interrupted but might be subsequently resumed */
388 | if (obj->oclass == FOOD_CLASS)
389 | food_substitution(obj, otmp); /* eat food or open tin */
390 | else if (obj->oclass == SPBOOK_CLASS)
391 | book_substitution(obj, otmp); /* read spellbook */
392 |
393 | /* obfree(obj, otmp); now unnecessary: no pointers on bill */
394 | dealloc_obj(obj); /* let us hope nobody else saved a pointer */
395 | return otmp;
396 | }
397 |
398 | struct obj *
399 | oname(obj, name)
400 | struct obj *obj;
401 | const char *name;
402 | {
403 | int lth;
404 | char buf[PL_PSIZ];
405 |
406 | lth = *name ? (int)(strlen(name) + 1) : 0;
407 | if (lth > PL_PSIZ) {
408 | lth = PL_PSIZ;
409 | name = strncpy(buf, name, PL_PSIZ - 1);
410 | buf[PL_PSIZ - 1] = '\0';
411 | }
412 | /* If named artifact exists in the game, do not create another.
413 | * Also trying to create an artifact shouldn't de-artifact
414 | * it (e.g. Excalibur from prayer). In this case the object
415 | * will retain its current name. */
416 | if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
417 | return obj;
418 |
419 | if (lth == obj->onamelth) {
420 | /* no need to replace entire object */
421 | if (lth) Strcpy(ONAME(obj), name);
422 | } else {
423 | obj = realloc_obj(obj, obj->oxlth,
424 | (genericptr_t)obj->oextra, lth, name);
425 | }
426 | if (lth) artifact_exists(obj, name, TRUE);
427 | if (obj->oartifact && obj == uswapwep) untwoweapon();
428 | if (carried(obj)) update_inventory();
429 | return obj;
430 | }
431 |
432 | static NEARDATA const char callable[] = {
433 | SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
434 | GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 };
435 |
436 | int
437 | ddocall()
438 | {
439 | register struct obj *obj;
440 | #ifdef REDO
441 | char ch;
442 | #endif
443 | char allowall[2];
444 |
445 | switch(
446 | #ifdef REDO
447 | ch =
448 | #endif
449 | ynq("Name an individual object?")) {
450 | case 'q':
451 | break;
452 | case 'y':
453 | #ifdef REDO
454 | savech(ch);
455 | #endif
456 | allowall[0] = ALL_CLASSES; allowall[1] = '\0';
457 | obj = getobj(allowall, "name");
458 | if(obj) do_oname(obj);
459 | break;
460 | default :
461 | #ifdef REDO
462 | savech(ch);
463 | #endif
464 | obj = getobj(callable, "call");
465 | if (obj) {
466 | if (!obj->dknown) {
467 | You("would never recognize another one.");
468 | return 0;
469 | }
470 | docall(obj);
471 | }
472 | break;
473 | }
474 | return 0;
475 | }
476 |
477 | void
478 | docall(obj)
479 | register struct obj *obj;
480 | {
481 | char buf[BUFSZ], qbuf[QBUFSZ];
482 | struct obj otemp;
483 | register char **str1;
484 |
485 | if (!obj->dknown) return; /* probably blind */
486 | otemp = *obj;
487 | otemp.quan = 1L;
488 | otemp.onamelth = 0;
489 | otemp.oxlth = 0;
490 | if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.corpsenm)
491 | /* kludge, meaning it's sink water */
492 | Sprintf(qbuf,"Call a stream of %s fluid:",
493 | OBJ_DESCR(objects[otemp.otyp]));
494 | else
495 | Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
496 | getlin(qbuf, buf);
497 | if(!*buf || *buf == '\033')
498 | return;
499 |
500 | /* clear old name */
501 | str1 = &(objects[obj->otyp].oc_uname);
502 | if(*str1) free((genericptr_t)*str1);
503 |
504 | /* strip leading and trailing spaces; uncalls item if all spaces */
505 | (void)mungspaces(buf);
506 | if (!*buf) {
507 | if (*str1) { /* had name, so possibly remove from disco[] */
508 | /* strip name first, for the update_inventory() call
509 | from undiscover_object() */
510 | *str1 = (char *)0;
511 | undiscover_object(obj->otyp);
512 | }
513 | } else {
514 | *str1 = strcpy((char *) alloc((unsigned)strlen(buf)+1), buf);
515 | discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
516 | }
517 | }
518 |
519 | #endif /*OVLB*/
520 | #ifdef OVL0
521 |
522 | static const char *ghostnames[] = {
523 | /* these names should have length < PL_NSIZ */
524 | /* Capitalize the names for aesthetics -dgk */
525 | "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile",
526 | "Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov",
527 | "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert",
528 | "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
529 | "Stephan", "Lance Braccus", "Shadowhawk"
530 | };
531 |
532 | /* ghost names formerly set by x_monnam(), now by makemon() instead */
533 | const char *
534 | rndghostname()
535 | {
536 | return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *)plname;
537 | }
538 |
539 | /* Monster naming functions:
540 | * x_monnam is the generic monster-naming function.
541 | * seen unseen detected named
542 | * mon_nam: the newt it the invisible orc Fido
543 | * noit_mon_nam:the newt (as if detected) the invisible orc Fido
544 | * l_monnam: newt it invisible orc dog called fido
545 | * Monnam: The newt It The invisible orc Fido
546 | * noit_Monnam: The newt (as if detected) The invisible orc Fido
547 | * Adjmonnam: The poor newt It The poor invisible orc The poor Fido
548 | * Amonnam: A newt It An invisible orc Fido
549 | * a_monnam: a newt it an invisible orc Fido
550 | * m_monnam: newt xan orc Fido
551 | * y_monnam: your newt your xan your invisible orc Fido
552 | */
553 |
554 | /* Bug: if the monster is a priest or shopkeeper, not every one of these
555 | * options works, since those are special cases.
556 | */
557 | char *
558 | x_monnam(mtmp, article, adjective, suppress, called)
559 | register struct monst *mtmp;
560 | int article;
561 | /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
562 | * ARTICLE_YOUR: "your" on pets, "the" on everything else
563 | *
564 | * If the monster would be referred to as "it" or if the monster has a name
565 | * _and_ there is no adjective, "invisible", "saddled", etc., override this
566 | * and always use no article.
567 | */
568 | const char *adjective;
569 | int suppress;
570 | /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
571 | * EXACT_NAME: combination of all the above
572 | */
573 | boolean called;
574 | {
575 | #ifdef LINT /* static char buf[BUFSZ]; */
576 | char buf[BUFSZ];
577 | #else
578 | static char buf[BUFSZ];
579 | #endif
580 | struct permonst *mdat = mtmp->data;
581 | boolean do_hallu, do_invis, do_it, do_saddle;
582 | boolean name_at_start, has_adjectives;
583 |
584 | if (program_state.gameover)
585 | suppress |= SUPPRESS_HALLUCINATION;
586 | if (article == ARTICLE_YOUR && !mtmp->mtame)
587 | article = ARTICLE_THE;
588 |
589 | do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
590 | do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
591 | do_it = !canspotmon(mtmp) &&
592 | article != ARTICLE_YOUR &&
593 | !program_state.gameover &&
594 | #ifdef STEED
595 | mtmp != u.usteed &&
596 | #endif
597 | !(u.uswallow && mtmp == u.ustuck) &&
598 | !(suppress & SUPPRESS_IT);
599 | do_saddle = !(suppress & SUPPRESS_SADDLE);
600 |
601 | buf[0] = 0;
602 |
603 | /* priests and minions: don't even use this function */
604 | if (mtmp->ispriest || mtmp->isminion) {
605 | char priestnambuf[BUFSZ];
606 | char *name;
607 | long save_prop = EHalluc_resistance;
608 | unsigned save_invis = mtmp->minvis;
609 |
610 | /* when true name is wanted, explicitly block Hallucination */
611 | if (!do_hallu) EHalluc_resistance = 1L;
612 | if (!do_invis) mtmp->minvis = 0;
613 | name = priestname(mtmp, priestnambuf);
614 | EHalluc_resistance = save_prop;
615 | mtmp->minvis = save_invis;
616 | if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
617 | name += 4;
618 | return strcpy(buf, name);
619 | }
620 |
621 | /* unseen monsters, etc. Use "it" */
622 | if (do_it) {
623 | Strcpy(buf, "it");
624 | return buf;
625 | }
626 |
627 | /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
628 | * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
629 | * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
630 | * none of this applies.
631 | */
632 | if (mtmp->isshk && !do_hallu) {
633 | if (adjective && article == ARTICLE_THE) {
634 | /* pathological case: "the angry Asidonhopo the blue dragon"
635 | sounds silly */
636 | Strcpy(buf, "the ");
637 | Strcat(strcat(buf, adjective), " ");
638 | Strcat(buf, shkname(mtmp));
639 | return buf;
640 | }
641 | Strcat(buf, shkname(mtmp));
642 | if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
643 | return buf;
644 | Strcat(buf, " the ");
645 | if (do_invis)
646 | Strcat(buf, "invisible ");
647 | Strcat(buf, mdat->mname);
648 | return buf;
649 | }
650 |
651 | /* Put the adjectives in the buffer */
652 | if (adjective)
653 | Strcat(strcat(buf, adjective), " ");
654 | if (do_invis)
655 | Strcat(buf, "invisible ");
656 | #ifdef STEED
657 | if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind)
658 | Strcat(buf, "saddled ");
659 | #endif
660 | if (buf[0] != 0)
661 | has_adjectives = TRUE;
662 | else
663 | has_adjectives = FALSE;
664 |
665 | /* Put the actual monster name or type into the buffer now */
666 | /* Be sure to remember whether the buffer starts with a name */
667 | if (do_hallu) {
668 | Strcat(buf, rndmonnam());
669 | name_at_start = FALSE;
670 | } else if (mtmp->mnamelth) {
671 | char *name = NAME(mtmp);
672 |
673 | if (mdat == &mons[PM_GHOST]) {
674 | Sprintf(eos(buf), "%s ghost", s_suffix(name));
675 | name_at_start = TRUE;
676 | } else if (called) {
677 | Sprintf(eos(buf), "%s called %s", mdat->mname, name);
678 | name_at_start = (boolean)type_is_pname(mdat);
679 | } else {
680 | Strcat(buf, name);
681 | name_at_start = TRUE;
682 | }
683 | } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
684 | char pbuf[BUFSZ];
685 | Strcpy(pbuf, rank_of((int)mtmp->m_lev,
686 | monsndx(mdat),
687 | (boolean)mtmp->female));
688 | Strcat(buf, lcase(pbuf));
689 | name_at_start = FALSE;
690 | } else {
691 | Strcat(buf, mdat->mname);
692 | name_at_start = (boolean)type_is_pname(mdat);
693 | }
694 |
695 | if (name_at_start && !has_adjectives) {
696 | if (mdat == &mons[PM_WIZARD_OF_YENDOR])
697 | article = ARTICLE_THE;
698 | else
699 | article = ARTICLE_NONE;
700 | }
701 |
702 | {
703 | char buf2[BUFSZ];
704 |
705 | switch(article) {
706 | case ARTICLE_YOUR:
707 | Strcpy(buf2, "your ");
708 | Strcat(buf2, buf);
709 | Strcpy(buf, buf2);
710 | return buf;
711 | case ARTICLE_THE:
712 | Strcpy(buf2, "the ");
713 | Strcat(buf2, buf);
714 | Strcpy(buf, buf2);
715 | return buf;
716 | case ARTICLE_A:
717 | return(an(buf));
718 | case ARTICLE_NONE:
719 | default:
720 | return buf;
721 | }
722 | }
723 | }
724 |
725 | #endif /* OVL0 */
726 | #ifdef OVLB
727 |
728 | char *
729 | l_monnam(mtmp)
730 | register struct monst *mtmp;
731 | {
732 | return(x_monnam(mtmp, ARTICLE_NONE, (char *)0,
733 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, TRUE));
734 | }
735 |
736 | #endif /* OVLB */
737 | #ifdef OVL0
738 |
739 | char *
740 | mon_nam(mtmp)
741 | register struct monst *mtmp;
742 | {
743 | return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
744 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE));
745 | }
746 |
747 | /* print the name as if mon_nam() was called, but assume that the player
748 | * can always see the monster--used for probing and for monsters aggravating
749 | * the player with a cursed potion of invisibility
750 | */
751 | char *
752 | noit_mon_nam(mtmp)
753 | register struct monst *mtmp;
754 | {
755 | return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
756 | mtmp->mnamelth ? (SUPPRESS_SADDLE|SUPPRESS_IT) :
757 | SUPPRESS_IT, FALSE));
758 | }
759 |
760 | char *
761 | Monnam(mtmp)
762 | register struct monst *mtmp;
763 | {
764 | register char *bp = mon_nam(mtmp);
765 |
766 | *bp = highc(*bp);
767 | return(bp);
768 | }
769 |
770 | char *
771 | noit_Monnam(mtmp)
772 | register struct monst *mtmp;
773 | {
774 | register char *bp = noit_mon_nam(mtmp);
775 |
776 | *bp = highc(*bp);
777 | return(bp);
778 | }
779 |
780 | /* monster's own name */
781 | char *
782 | m_monnam(mtmp)
783 | struct monst *mtmp;
784 | {
785 | return x_monnam(mtmp, ARTICLE_NONE, (char *)0, EXACT_NAME, FALSE);
786 | }
787 |
788 | /* pet name: "your little dog" */
789 | char *
790 | y_monnam(mtmp)
791 | struct monst *mtmp;
792 | {
793 | return x_monnam(mtmp, ARTICLE_YOUR, (char *)0,
794 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
795 | }
796 |
797 | #endif /* OVL0 */
798 | #ifdef OVLB
799 |
800 | char *
801 | Adjmonnam(mtmp, adj)
802 | register struct monst *mtmp;
803 | register const char *adj;
804 | {
805 | register char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
806 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
807 |
808 | *bp = highc(*bp);
809 | return(bp);
810 | }
811 |
812 | char *
813 | a_monnam(mtmp)
814 | register struct monst *mtmp;
815 | {
816 | return x_monnam(mtmp, ARTICLE_A, (char *)0,
817 | mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
818 | }
819 |
820 | char *
821 | Amonnam(mtmp)
822 | register struct monst *mtmp;
823 | {
824 | register char *bp = a_monnam(mtmp);
825 |
826 | *bp = highc(*bp);
827 | return(bp);
828 | }
829 |
830 | static const char *bogusmons[] = {
831 | "jumbo shrimp", "giant pigmy", "gnu", "killer penguin",
832 | "giant cockroach", "giant slug", "maggot", "pterodactyl",
833 | "tyrannosaurus rex", "basilisk", "beholder", "nightmare",
834 | "efreeti", "marid", "rot grub", "bookworm", "master lichen",
835 | "shadow", "hologram", "jester", "attorney", "sleazoid",
836 | "killer tomato", "amazon", "robot", "battlemech",
837 | "rhinovirus", "harpy", "lion-dog", "rat-ant", "Y2K bug",
838 | /* misc. */
839 | "grue", "Christmas-tree monster", "luck sucker", "paskald",
840 | "brogmoid", "dornbeast", /* Quendor (Zork, &c.) */
841 | "Ancient Multi-Hued Dragon", "Evil Iggy",
842 | /* Moria */
843 | "emu", "kestrel", "xeroc", "venus flytrap",
844 | /* Rogue */
845 | "creeping coins", /* Wizardry */
846 | "hydra", "siren", /* Greek legend */
847 | "killer bunny", /* Monty Python */
848 | "rodent of unusual size", /* The Princess Bride */
849 | "Smokey the bear", /* "Only you can prevent forest fires!" */
850 | "Luggage", /* Discworld */
851 | "Ent", /* Lord of the Rings */
852 | "tangle tree", "nickelpede", "wiggle", /* Xanth */
853 | "white rabbit", "snark", /* Lewis Carroll */
854 | "pushmi-pullyu", /* Dr. Doolittle */
855 | "smurf", /* The Smurfs */
856 | "tribble", "Klingon", "Borg", /* Star Trek */
857 | "Ewok", /* Star Wars */
858 | "Totoro", /* Tonari no Totoro */
859 | "ohmu", /* Nausicaa */
860 | "youma", /* Sailor Moon */
861 | "nyaasu", /* Pokemon (Meowth) */
862 | "Godzilla", "King Kong", /* monster movies */
863 | "earthquake beast", /* old L of SH */
864 | "Invid", /* Robotech */
865 | "Terminator", /* The Terminator */
866 | "boomer", /* Bubblegum Crisis */
867 | "Dalek", /* Dr. Who ("Exterminate!") */
868 | "microscopic space fleet", "Ravenous Bugblatter Beast of Traal",
869 | /* HGttG */
870 | "teenage mutant ninja turtle", /* TMNT */
871 | "samurai rabbit", /* Usagi Yojimbo */
872 | "aardvark", /* Cerebus */
873 | "Audrey II", /* Little Shop of Horrors */
874 | "witch doctor", "one-eyed one-horned flying purple people eater",
875 | /* 50's rock 'n' roll */
876 | "Barney the dinosaur", /* saccharine kiddy TV */
877 | "Morgoth", /* Angband */
878 | "Vorlon", /* Babylon 5 */
879 | "questing beast", /* King Arthur */
880 | "Predator", /* Movie */
881 | "mother-in-law" /* common pest */
882 | };
883 |
884 |
885 | /* Return a random monster name, for hallucination.
886 | * KNOWN BUG: May be a proper name (Godzilla, Barney), may not
887 | * (the Terminator, a Dalek). There's no elegant way to deal
888 | * with this without radically modifying the calling functions.
889 | */
890 | const char *
891 | rndmonnam()
892 | {
893 | int name;
894 |
895 | do {
896 | name = rn1(SPECIAL_PM + SIZE(bogusmons) - LOW_PM, LOW_PM);
897 | } while (name < SPECIAL_PM &&
898 | (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
899 |
900 | if (name >= SPECIAL_PM) return bogusmons[name - SPECIAL_PM];
901 | return mons[name].mname;
902 | }
903 |
904 | const char *pronoun_pairs[][2] = {
905 | {"him", "her"}, {"Him", "Her"}, {"his", "her"}, {"His", "Her"},
906 | {"he", "she"}, {"He", "She"},
907 | {0, 0}
908 | };
909 |
910 | char *
911 | self_pronoun(str, pronoun)
912 | const char *str;
913 | const char *pronoun;
914 | {
915 | static NEARDATA char buf[BUFSZ];
916 | register int i;
917 |
918 | for(i=0; pronoun_pairs[i][0]; i++) {
919 | if(!strncmp(pronoun, pronoun_pairs[i][0], 3)) {
920 | Sprintf(buf, str, pronoun_pairs[i][flags.female]);
921 | return buf;
922 | }
923 | }
924 | impossible("never heard of pronoun %s?", pronoun);
925 | Sprintf(buf, str, pronoun_pairs[i][0]);
926 | return buf;
927 | }
928 |
929 | #ifdef REINCARNATION
930 | const char *
931 | roguename() /* Name of a Rogue player */
932 | {
933 | char *i, *opts;
934 |
935 | if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
936 | for (i = opts; *i; i++)
937 | if (!strncmp("name=",i,5)) {
938 | char *j;
939 | if ((j = index(i+5,',')) != 0)
940 | *j = (char)0;
941 | return i+5;
942 | }
943 | }
944 | return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
945 | : "Glenn Wichman";
946 | }
947 | #endif /* REINCARNATION */
948 | #endif /* OVLB */
949 |
950 | #ifdef OVL2
951 |
952 | static NEARDATA const char *hcolors[] = {
953 | "ultraviolet", "infrared", "bluish-orange",
954 | "reddish-green", "dark white", "light black", "sky blue-pink",
955 | "salty", "sweet", "sour", "bitter",
956 | "striped", "spiral", "swirly", "plaid", "checkered", "argyle",
957 | "paisley", "blotchy", "guernsey-spotted", "polka-dotted",
958 | "square", "round", "triangular",
959 | "cabernet", "sangria", "fuchsia", "wisteria",
960 | "lemon-lime", "strawberry-banana", "peppermint",
961 | "romantic", "incandescent"
962 | };
963 |
964 | const char *
965 | hcolor(colorpref)
966 | const char *colorpref;
967 | {
968 | return (Hallucination || !colorpref) ?
969 | hcolors[rn2(SIZE(hcolors))] : colorpref;
970 | }
971 |
972 | /* Aliases for road-runner nemesis
973 | * See also http://www.geocities.com/EnchantedForest/1141/latin.html
974 | */
975 | static const char *coynames[] = {
976 | "Carnivorous Vulgaris","Road-Runnerus Digestus",
977 | "Eatibus Anythingus" ,"Famishus-Famishus",
978 | "Eatibus Almost Anythingus","Eatius Birdius",
979 | "Famishius Fantasticus","Eternalii Famishiis",
980 | "Famishus Vulgarus","Famishius Vulgaris Ingeniusi",
981 | "Eatius-Slobbius","Hardheadipus Oedipus",
982 | "Carnivorous Slobbius","Hard-Headipus Ravenus",
983 | "Evereadii Eatibus","Apetitius Giganticus",
984 | "Hungrii Flea-Bagius","Overconfidentii Vulgaris",
985 | "Caninus Nervous Rex","Grotesques Appetitus",
986 | "Nemesis Riduclii","Canis latrans"
987 | };
988 |
989 | char *coyotename(buf)
990 | char *buf;
991 | {
992 | if (buf)
993 | Sprintf(buf,
994 | "coyote - %s",
995 | coynames[rn2(SIZE(coynames)-1)]);
996 | return buf;
997 | }
998 | #endif /* OVL2 */
999 |
1000 | /*do_name.c*/