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*/