Not all leaders and nemeses have M2_PNAME set, so they require an extra check to result in the expected behavior.
1033 lines
27 KiB
C
1033 lines
27 KiB
C
/* SCCS Id: @(#)do_name.c 3.4 2002/09/19 */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
#ifdef OVLB
|
|
|
|
STATIC_DCL void FDECL(do_oname, (struct obj *));
|
|
static void FDECL(getpos_help, (BOOLEAN_P,const char *));
|
|
|
|
extern const char what_is_an_unknown_object[]; /* from pager.c */
|
|
|
|
/* the response for '?' help request in getpos() */
|
|
static void
|
|
getpos_help(force, goal)
|
|
boolean force;
|
|
const char *goal;
|
|
{
|
|
char sbuf[BUFSZ];
|
|
boolean doing_what_is;
|
|
winid tmpwin = create_nhwindow(NHW_MENU);
|
|
|
|
Sprintf(sbuf, "Use [%s] to move the cursor to %s.",
|
|
iflags.num_pad ? "2468" : "hjkl", goal);
|
|
putstr(tmpwin, 0, sbuf);
|
|
putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time.");
|
|
putstr(tmpwin, 0, "Or enter a background symbol (ex. <).");
|
|
/* disgusting hack; the alternate selection characters work for any
|
|
getpos call, but they only matter for dowhatis (and doquickwhatis) */
|
|
doing_what_is = (goal == what_is_an_unknown_object);
|
|
Sprintf(sbuf, "Type a .%s when you are at the right place.",
|
|
doing_what_is ? " or , or ; or :" : "");
|
|
putstr(tmpwin, 0, sbuf);
|
|
if (!force)
|
|
putstr(tmpwin, 0, "Type Space or Escape when you're done.");
|
|
putstr(tmpwin, 0, "");
|
|
display_nhwindow(tmpwin, TRUE);
|
|
destroy_nhwindow(tmpwin);
|
|
}
|
|
|
|
int
|
|
getpos(cc, force, goal)
|
|
coord *cc;
|
|
boolean force;
|
|
const char *goal;
|
|
{
|
|
int result = 0;
|
|
int cx, cy, i, c;
|
|
int sidx, tx, ty;
|
|
boolean msg_given = TRUE; /* clear message window by default */
|
|
static const char pick_chars[] = ".,;:";
|
|
const char *cp;
|
|
const char *sdp;
|
|
if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */
|
|
|
|
if (flags.verbose) {
|
|
pline("(For instructions type a ?)");
|
|
msg_given = TRUE;
|
|
}
|
|
cx = cc->x;
|
|
cy = cc->y;
|
|
#ifdef CLIPPING
|
|
cliparound(cx, cy);
|
|
#endif
|
|
curs(WIN_MAP, cx,cy);
|
|
flush_screen(0);
|
|
#ifdef MAC
|
|
lock_mouse_cursor(TRUE);
|
|
#endif
|
|
for (;;) {
|
|
c = nh_poskey(&tx, &ty, &sidx);
|
|
if (c == '\033') {
|
|
cx = cy = -10;
|
|
msg_given = TRUE; /* force clear */
|
|
result = -1;
|
|
break;
|
|
}
|
|
if(c == 0) {
|
|
if (!isok(tx, ty)) continue;
|
|
/* a mouse click event, just assign and return */
|
|
cx = tx;
|
|
cy = ty;
|
|
break;
|
|
}
|
|
if ((cp = index(pick_chars, c)) != 0) {
|
|
/* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */
|
|
result = cp - pick_chars;
|
|
break;
|
|
}
|
|
for (i = 0; i < 8; i++) {
|
|
int dx, dy;
|
|
|
|
if (sdp[i] == c) {
|
|
/* a normal movement letter or digit */
|
|
dx = xdir[i];
|
|
dy = ydir[i];
|
|
} else if (sdir[i] == lowc((char)c)) {
|
|
/* a shifted movement letter */
|
|
dx = 8 * xdir[i];
|
|
dy = 8 * ydir[i];
|
|
} else
|
|
continue;
|
|
|
|
/* truncate at map edge; diagonal moves complicate this... */
|
|
if (cx + dx < 1) {
|
|
dy -= sgn(dy) * (1 - (cx + dx));
|
|
dx = 1 - cx; /* so that (cx+dx == 1) */
|
|
} else if (cx + dx > COLNO-1) {
|
|
dy += sgn(dy) * ((COLNO-1) - (cx + dx));
|
|
dx = (COLNO-1) - cx;
|
|
}
|
|
if (cy + dy < 0) {
|
|
dx -= sgn(dx) * (0 - (cy + dy));
|
|
dy = 0 - cy; /* so that (cy+dy == 0) */
|
|
} else if (cy + dy > ROWNO-1) {
|
|
dx += sgn(dx) * ((ROWNO-1) - (cy + dy));
|
|
dy = (ROWNO-1) - cy;
|
|
}
|
|
cx += dx;
|
|
cy += dy;
|
|
goto nxtc;
|
|
}
|
|
|
|
if(c == '?'){
|
|
getpos_help(force, goal);
|
|
} else {
|
|
if (!index(quitchars, c)) {
|
|
char matching[MAXPCHARS];
|
|
int pass, lo_x, lo_y, hi_x, hi_y, k = 0;
|
|
(void)memset((genericptr_t)matching, 0, sizeof matching);
|
|
for (sidx = 1; sidx < MAXPCHARS; sidx++)
|
|
if (c == defsyms[sidx].sym || c == (int)showsyms[sidx])
|
|
matching[sidx] = (char) ++k;
|
|
if (k) {
|
|
for (pass = 0; pass <= 1; pass++) {
|
|
/* pass 0: just past current pos to lower right;
|
|
pass 1: upper left corner to current pos */
|
|
lo_y = (pass == 0) ? cy : 0;
|
|
hi_y = (pass == 0) ? ROWNO - 1 : cy;
|
|
for (ty = lo_y; ty <= hi_y; ty++) {
|
|
lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1;
|
|
hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1;
|
|
for (tx = lo_x; tx <= hi_x; tx++) {
|
|
k = levl[tx][ty].glyph;
|
|
if (glyph_is_cmap(k) &&
|
|
matching[glyph_to_cmap(k)]) {
|
|
cx = tx, cy = ty;
|
|
if (msg_given) {
|
|
clear_nhwindow(WIN_MESSAGE);
|
|
msg_given = FALSE;
|
|
}
|
|
goto nxtc;
|
|
}
|
|
} /* column */
|
|
} /* row */
|
|
} /* pass */
|
|
pline("Can't find dungeon feature '%c'.", c);
|
|
msg_given = TRUE;
|
|
goto nxtc;
|
|
} else {
|
|
pline("Unknown direction: '%s' (%s).",
|
|
visctrl((char)c),
|
|
!force ? "aborted" :
|
|
iflags.num_pad ? "use 2468 or ." : "use hjkl or .");
|
|
msg_given = TRUE;
|
|
} /* k => matching */
|
|
} /* !quitchars */
|
|
if (force) goto nxtc;
|
|
pline("Done.");
|
|
msg_given = FALSE; /* suppress clear */
|
|
cx = -1;
|
|
cy = 0;
|
|
result = 0; /* not -1 */
|
|
break;
|
|
}
|
|
nxtc: ;
|
|
#ifdef CLIPPING
|
|
cliparound(cx, cy);
|
|
#endif
|
|
curs(WIN_MAP,cx,cy);
|
|
flush_screen(0);
|
|
}
|
|
#ifdef MAC
|
|
lock_mouse_cursor(FALSE);
|
|
#endif
|
|
if (msg_given) clear_nhwindow(WIN_MESSAGE);
|
|
cc->x = cx;
|
|
cc->y = cy;
|
|
return result;
|
|
}
|
|
|
|
struct monst *
|
|
christen_monst(mtmp, name)
|
|
struct monst *mtmp;
|
|
const char *name;
|
|
{
|
|
int lth;
|
|
struct monst *mtmp2;
|
|
char buf[PL_PSIZ];
|
|
|
|
/* dogname & catname are PL_PSIZ arrays; object names have same limit */
|
|
lth = *name ? (int)(strlen(name) + 1) : 0;
|
|
if(lth > PL_PSIZ){
|
|
lth = PL_PSIZ;
|
|
name = strncpy(buf, name, PL_PSIZ - 1);
|
|
buf[PL_PSIZ - 1] = '\0';
|
|
}
|
|
if (lth == mtmp->mnamelth) {
|
|
/* don't need to allocate a new monst struct */
|
|
if (lth) Strcpy(NAME(mtmp), name);
|
|
return mtmp;
|
|
}
|
|
mtmp2 = newmonst(mtmp->mxlth + lth);
|
|
*mtmp2 = *mtmp;
|
|
(void) memcpy((genericptr_t)mtmp2->mextra,
|
|
(genericptr_t)mtmp->mextra, mtmp->mxlth);
|
|
mtmp2->mnamelth = lth;
|
|
if (lth) Strcpy(NAME(mtmp2), name);
|
|
replmon(mtmp,mtmp2);
|
|
return(mtmp2);
|
|
}
|
|
|
|
int
|
|
do_mname()
|
|
{
|
|
char buf[BUFSZ];
|
|
coord cc;
|
|
register int cx,cy;
|
|
register struct monst *mtmp;
|
|
char qbuf[QBUFSZ];
|
|
|
|
if (Hallucination) {
|
|
You("would never recognize it anyway.");
|
|
return 0;
|
|
}
|
|
cc.x = u.ux;
|
|
cc.y = u.uy;
|
|
if (getpos(&cc, FALSE, "the monster you want to name") < 0 ||
|
|
(cx = cc.x) < 0)
|
|
return 0;
|
|
cy = cc.y;
|
|
|
|
if (cx == u.ux && cy == u.uy) {
|
|
#ifdef STEED
|
|
if (u.usteed && canspotmon(u.usteed))
|
|
mtmp = u.usteed;
|
|
else {
|
|
#endif
|
|
pline("This %s creature is called %s and cannot be renamed.",
|
|
ACURR(A_CHA) > 14 ?
|
|
(flags.female ? "beautiful" : "handsome") :
|
|
"ugly",
|
|
plname);
|
|
return(0);
|
|
#ifdef STEED
|
|
}
|
|
#endif
|
|
} else
|
|
mtmp = m_at(cx, cy);
|
|
|
|
if (!mtmp || (!sensemon(mtmp) &&
|
|
(!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected
|
|
|| mtmp->m_ap_type == M_AP_FURNITURE
|
|
|| mtmp->m_ap_type == M_AP_OBJECT
|
|
|| (mtmp->minvis && !See_invisible)))) {
|
|
pline("I see no monster there.");
|
|
return(0);
|
|
}
|
|
/* special case similar to the one in lookat() */
|
|
(void) distant_monnam(mtmp, ARTICLE_THE, buf);
|
|
Sprintf(qbuf, "What do you want to call %s?", buf);
|
|
getlin(qbuf,buf);
|
|
if(!*buf || *buf == '\033') return(0);
|
|
/* strip leading and trailing spaces; unnames monster if all spaces */
|
|
(void)mungspaces(buf);
|
|
|
|
if (mtmp->iswiz || type_is_pname(mtmp->data) ||
|
|
mtmp->data->msound == MS_LEADER ||
|
|
mtmp->data->msound == MS_NEMESIS)
|
|
pline("%s doesn't like being called names!", Monnam(mtmp));
|
|
else (void) christen_monst(mtmp, buf);
|
|
return(0);
|
|
}
|
|
|
|
/*
|
|
* This routine changes the address of obj. Be careful not to call it
|
|
* when there might be pointers around in unknown places. For now: only
|
|
* when obj is in the inventory.
|
|
*/
|
|
STATIC_OVL
|
|
void
|
|
do_oname(obj)
|
|
register struct obj *obj;
|
|
{
|
|
char buf[BUFSZ], qbuf[QBUFSZ];
|
|
const char *aname;
|
|
short objtyp;
|
|
|
|
Sprintf(qbuf, "What do you want to name %s %s?",
|
|
is_plural(obj) ? "these" : "this", xname(obj));
|
|
getlin(qbuf, buf);
|
|
if(!*buf || *buf == '\033') return;
|
|
/* strip leading and trailing spaces; unnames item if all spaces */
|
|
(void)mungspaces(buf);
|
|
|
|
/* relax restrictions over proper capitalization for artifacts */
|
|
if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp)
|
|
Strcpy(buf, aname);
|
|
|
|
if (obj->oartifact) {
|
|
pline_The("artifact seems to resist the attempt.");
|
|
return;
|
|
} else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) {
|
|
int n = rn2((int)strlen(buf));
|
|
register char c1, c2;
|
|
|
|
c1 = lowc(buf[n]);
|
|
do c2 = 'a' + rn2('z'-'a'); while (c1 == c2);
|
|
buf[n] = (buf[n] == c1) ? c2 : highc(c2); /* keep same case */
|
|
pline("While engraving your %s slips.", body_part(HAND));
|
|
display_nhwindow(WIN_MESSAGE, FALSE);
|
|
You("engrave: \"%s\".",buf);
|
|
}
|
|
obj = oname(obj, buf);
|
|
}
|
|
|
|
/*
|
|
* Allocate a new and possibly larger storage space for an obj.
|
|
*/
|
|
struct obj *
|
|
realloc_obj(obj, oextra_size, oextra_src, oname_size, name)
|
|
struct obj *obj;
|
|
int oextra_size; /* storage to allocate for oextra */
|
|
genericptr_t oextra_src;
|
|
int oname_size; /* size of name string + 1 (null terminator) */
|
|
const char *name;
|
|
{
|
|
struct obj *otmp;
|
|
|
|
otmp = newobj(oextra_size + oname_size);
|
|
*otmp = *obj; /* the cobj pointer is copied to otmp */
|
|
if (oextra_size) {
|
|
if (oextra_src)
|
|
(void) memcpy((genericptr_t)otmp->oextra, oextra_src,
|
|
oextra_size);
|
|
} else {
|
|
otmp->oattached = OATTACHED_NOTHING;
|
|
}
|
|
otmp->oxlth = oextra_size;
|
|
|
|
otmp->onamelth = oname_size;
|
|
otmp->timed = 0; /* not timed, yet */
|
|
otmp->lamplit = 0; /* ditto */
|
|
/* __GNUC__ note: if the assignment of otmp->onamelth immediately
|
|
precedes this `if' statement, a gcc bug will miscompile the
|
|
test on vax (`insv' instruction used to store bitfield does
|
|
not set condition codes, but optimizer behaves as if it did).
|
|
gcc-2.7.2.1 finally fixed this. */
|
|
if (oname_size) {
|
|
if (name)
|
|
Strcpy(ONAME(otmp), name);
|
|
}
|
|
|
|
if (obj->owornmask) {
|
|
boolean save_twoweap = u.twoweap;
|
|
/* unwearing the old instance will clear dual-wield mode
|
|
if this object is either of the two weapons */
|
|
setworn((struct obj *)0, obj->owornmask);
|
|
setworn(otmp, otmp->owornmask);
|
|
u.twoweap = save_twoweap;
|
|
}
|
|
|
|
/* replace obj with otmp */
|
|
replace_object(obj, otmp);
|
|
|
|
/* fix ocontainer pointers */
|
|
if (Has_contents(obj)) {
|
|
struct obj *inside;
|
|
|
|
for(inside = obj->cobj; inside; inside = inside->nobj)
|
|
inside->ocontainer = otmp;
|
|
}
|
|
|
|
/* move timers and light sources from obj to otmp */
|
|
if (obj->timed) obj_move_timers(obj, otmp);
|
|
if (obj->lamplit) obj_move_light_source(obj, otmp);
|
|
|
|
/* objects possibly being manipulated by multi-turn occupations
|
|
which have been interrupted but might be subsequently resumed */
|
|
if (obj->oclass == FOOD_CLASS)
|
|
food_substitution(obj, otmp); /* eat food or open tin */
|
|
else if (obj->oclass == SPBOOK_CLASS)
|
|
book_substitution(obj, otmp); /* read spellbook */
|
|
|
|
/* obfree(obj, otmp); now unnecessary: no pointers on bill */
|
|
dealloc_obj(obj); /* let us hope nobody else saved a pointer */
|
|
return otmp;
|
|
}
|
|
|
|
struct obj *
|
|
oname(obj, name)
|
|
struct obj *obj;
|
|
const char *name;
|
|
{
|
|
int lth;
|
|
char buf[PL_PSIZ];
|
|
|
|
lth = *name ? (int)(strlen(name) + 1) : 0;
|
|
if (lth > PL_PSIZ) {
|
|
lth = PL_PSIZ;
|
|
name = strncpy(buf, name, PL_PSIZ - 1);
|
|
buf[PL_PSIZ - 1] = '\0';
|
|
}
|
|
/* If named artifact exists in the game, do not create another.
|
|
* Also trying to create an artifact shouldn't de-artifact
|
|
* it (e.g. Excalibur from prayer). In this case the object
|
|
* will retain its current name. */
|
|
if (obj->oartifact || (lth && exist_artifact(obj->otyp, name)))
|
|
return obj;
|
|
|
|
if (lth == obj->onamelth) {
|
|
/* no need to replace entire object */
|
|
if (lth) Strcpy(ONAME(obj), name);
|
|
} else {
|
|
obj = realloc_obj(obj, obj->oxlth,
|
|
(genericptr_t)obj->oextra, lth, name);
|
|
}
|
|
if (lth) artifact_exists(obj, name, TRUE);
|
|
if (obj->oartifact) {
|
|
/* can't dual-wield with artifact as secondary weapon */
|
|
if (obj == uswapwep) untwoweapon();
|
|
/* activate warning if you've just named your weapon "Sting" */
|
|
if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP);
|
|
}
|
|
if (carried(obj)) update_inventory();
|
|
return obj;
|
|
}
|
|
|
|
static NEARDATA const char callable[] = {
|
|
SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS,
|
|
GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 };
|
|
|
|
int
|
|
ddocall()
|
|
{
|
|
register struct obj *obj;
|
|
#ifdef REDO
|
|
char ch;
|
|
#endif
|
|
char allowall[2];
|
|
|
|
switch(
|
|
#ifdef REDO
|
|
ch =
|
|
#endif
|
|
ynq("Name an individual object?")) {
|
|
case 'q':
|
|
break;
|
|
case 'y':
|
|
#ifdef REDO
|
|
savech(ch);
|
|
#endif
|
|
allowall[0] = ALL_CLASSES; allowall[1] = '\0';
|
|
obj = getobj(allowall, "name");
|
|
if(obj) do_oname(obj);
|
|
break;
|
|
default :
|
|
#ifdef REDO
|
|
savech(ch);
|
|
#endif
|
|
obj = getobj(callable, "call");
|
|
if (obj) {
|
|
if (!obj->dknown) {
|
|
You("would never recognize another one.");
|
|
return 0;
|
|
}
|
|
docall(obj);
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
docall(obj)
|
|
register struct obj *obj;
|
|
{
|
|
char buf[BUFSZ], qbuf[QBUFSZ];
|
|
struct obj otemp;
|
|
register char **str1;
|
|
|
|
if (!obj->dknown) return; /* probably blind */
|
|
otemp = *obj;
|
|
otemp.quan = 1L;
|
|
otemp.onamelth = 0;
|
|
otemp.oxlth = 0;
|
|
if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.corpsenm)
|
|
/* kludge, meaning it's sink water */
|
|
Sprintf(qbuf,"Call a stream of %s fluid:",
|
|
OBJ_DESCR(objects[otemp.otyp]));
|
|
else
|
|
Sprintf(qbuf, "Call %s:", an(xname(&otemp)));
|
|
getlin(qbuf, buf);
|
|
if(!*buf || *buf == '\033')
|
|
return;
|
|
|
|
/* clear old name */
|
|
str1 = &(objects[obj->otyp].oc_uname);
|
|
if(*str1) free((genericptr_t)*str1);
|
|
|
|
/* strip leading and trailing spaces; uncalls item if all spaces */
|
|
(void)mungspaces(buf);
|
|
if (!*buf) {
|
|
if (*str1) { /* had name, so possibly remove from disco[] */
|
|
/* strip name first, for the update_inventory() call
|
|
from undiscover_object() */
|
|
*str1 = (char *)0;
|
|
undiscover_object(obj->otyp);
|
|
}
|
|
} else {
|
|
*str1 = strcpy((char *) alloc((unsigned)strlen(buf)+1), buf);
|
|
discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */
|
|
}
|
|
}
|
|
|
|
#endif /*OVLB*/
|
|
#ifdef OVL0
|
|
|
|
static const char * const ghostnames[] = {
|
|
/* these names should have length < PL_NSIZ */
|
|
/* Capitalize the names for aesthetics -dgk */
|
|
"Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile",
|
|
"Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov",
|
|
"Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert",
|
|
"Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue",
|
|
"Stephan", "Lance Braccus", "Shadowhawk"
|
|
};
|
|
|
|
/* ghost names formerly set by x_monnam(), now by makemon() instead */
|
|
const char *
|
|
rndghostname()
|
|
{
|
|
return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *)plname;
|
|
}
|
|
|
|
/* Monster naming functions:
|
|
* x_monnam is the generic monster-naming function.
|
|
* seen unseen detected named
|
|
* mon_nam: the newt it the invisible orc Fido
|
|
* noit_mon_nam:the newt (as if detected) the invisible orc Fido
|
|
* l_monnam: newt it invisible orc dog called fido
|
|
* Monnam: The newt It The invisible orc Fido
|
|
* noit_Monnam: The newt (as if detected) The invisible orc Fido
|
|
* Adjmonnam: The poor newt It The poor invisible orc The poor Fido
|
|
* Amonnam: A newt It An invisible orc Fido
|
|
* a_monnam: a newt it an invisible orc Fido
|
|
* m_monnam: newt xan orc Fido
|
|
* y_monnam: your newt your xan your invisible orc Fido
|
|
*/
|
|
|
|
/* Bug: if the monster is a priest or shopkeeper, not every one of these
|
|
* options works, since those are special cases.
|
|
*/
|
|
char *
|
|
x_monnam(mtmp, article, adjective, suppress, called)
|
|
register struct monst *mtmp;
|
|
int article;
|
|
/* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
|
|
* ARTICLE_YOUR: "your" on pets, "the" on everything else
|
|
*
|
|
* If the monster would be referred to as "it" or if the monster has a name
|
|
* _and_ there is no adjective, "invisible", "saddled", etc., override this
|
|
* and always use no article.
|
|
*/
|
|
const char *adjective;
|
|
int suppress;
|
|
/* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
|
|
* EXACT_NAME: combination of all the above
|
|
*/
|
|
boolean called;
|
|
{
|
|
#ifdef LINT /* static char buf[BUFSZ]; */
|
|
char buf[BUFSZ];
|
|
#else
|
|
static char buf[BUFSZ];
|
|
#endif
|
|
struct permonst *mdat = mtmp->data;
|
|
boolean do_hallu, do_invis, do_it, do_saddle;
|
|
boolean name_at_start, has_adjectives;
|
|
char *bp;
|
|
|
|
if (program_state.gameover)
|
|
suppress |= SUPPRESS_HALLUCINATION;
|
|
if (article == ARTICLE_YOUR && !mtmp->mtame)
|
|
article = ARTICLE_THE;
|
|
|
|
do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
|
|
do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
|
|
do_it = !canspotmon(mtmp) &&
|
|
article != ARTICLE_YOUR &&
|
|
!program_state.gameover &&
|
|
#ifdef STEED
|
|
mtmp != u.usteed &&
|
|
#endif
|
|
!(u.uswallow && mtmp == u.ustuck) &&
|
|
!(suppress & SUPPRESS_IT);
|
|
do_saddle = !(suppress & SUPPRESS_SADDLE);
|
|
|
|
buf[0] = 0;
|
|
|
|
/* unseen monsters, etc. Use "it" */
|
|
if (do_it) {
|
|
Strcpy(buf, "it");
|
|
return buf;
|
|
}
|
|
|
|
/* priests and minions: don't even use this function */
|
|
if (mtmp->ispriest || mtmp->isminion) {
|
|
char priestnambuf[BUFSZ];
|
|
char *name;
|
|
long save_prop = EHalluc_resistance;
|
|
unsigned save_invis = mtmp->minvis;
|
|
|
|
/* when true name is wanted, explicitly block Hallucination */
|
|
if (!do_hallu) EHalluc_resistance = 1L;
|
|
if (!do_invis) mtmp->minvis = 0;
|
|
name = priestname(mtmp, priestnambuf);
|
|
EHalluc_resistance = save_prop;
|
|
mtmp->minvis = save_invis;
|
|
if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
|
|
name += 4;
|
|
return strcpy(buf, name);
|
|
}
|
|
|
|
/* Shopkeepers: use shopkeeper name. For normal shopkeepers, just
|
|
* "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
|
|
* shopkeeper" or "Asidonhopo the blue dragon". If hallucinating,
|
|
* none of this applies.
|
|
*/
|
|
if (mtmp->isshk && !do_hallu) {
|
|
if (adjective && article == ARTICLE_THE) {
|
|
/* pathological case: "the angry Asidonhopo the blue dragon"
|
|
sounds silly */
|
|
Strcpy(buf, "the ");
|
|
Strcat(strcat(buf, adjective), " ");
|
|
Strcat(buf, shkname(mtmp));
|
|
return buf;
|
|
}
|
|
Strcat(buf, shkname(mtmp));
|
|
if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
|
|
return buf;
|
|
Strcat(buf, " the ");
|
|
if (do_invis)
|
|
Strcat(buf, "invisible ");
|
|
Strcat(buf, mdat->mname);
|
|
return buf;
|
|
}
|
|
|
|
/* Put the adjectives in the buffer */
|
|
if (adjective)
|
|
Strcat(strcat(buf, adjective), " ");
|
|
if (do_invis)
|
|
Strcat(buf, "invisible ");
|
|
#ifdef STEED
|
|
if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) &&
|
|
!Blind && !Hallucination)
|
|
Strcat(buf, "saddled ");
|
|
#endif
|
|
if (buf[0] != 0)
|
|
has_adjectives = TRUE;
|
|
else
|
|
has_adjectives = FALSE;
|
|
|
|
/* Put the actual monster name or type into the buffer now */
|
|
/* Be sure to remember whether the buffer starts with a name */
|
|
if (do_hallu) {
|
|
Strcat(buf, rndmonnam());
|
|
name_at_start = FALSE;
|
|
} else if (mtmp->mnamelth) {
|
|
char *name = NAME(mtmp);
|
|
|
|
if (mdat == &mons[PM_GHOST]) {
|
|
Sprintf(eos(buf), "%s ghost", s_suffix(name));
|
|
name_at_start = TRUE;
|
|
} else if (called) {
|
|
Sprintf(eos(buf), "%s called %s", mdat->mname, name);
|
|
name_at_start = (boolean)type_is_pname(mdat);
|
|
} else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
|
|
/* <name> the <adjective> <invisible> <saddled> <rank> */
|
|
char pbuf[BUFSZ];
|
|
|
|
Strcpy(pbuf, name);
|
|
pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
|
|
if (has_adjectives)
|
|
Strcat(pbuf, buf);
|
|
Strcat(pbuf, bp + 5); /* append the rest of the name */
|
|
Strcpy(buf, pbuf);
|
|
article = ARTICLE_NONE;
|
|
name_at_start = TRUE;
|
|
} else {
|
|
Strcat(buf, name);
|
|
name_at_start = TRUE;
|
|
}
|
|
} else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
|
|
char pbuf[BUFSZ];
|
|
Strcpy(pbuf, rank_of((int)mtmp->m_lev,
|
|
monsndx(mdat),
|
|
(boolean)mtmp->female));
|
|
Strcat(buf, lcase(pbuf));
|
|
name_at_start = FALSE;
|
|
} else {
|
|
Strcat(buf, mdat->mname);
|
|
name_at_start = (boolean)type_is_pname(mdat);
|
|
}
|
|
|
|
if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
|
|
if (mdat == &mons[PM_WIZARD_OF_YENDOR])
|
|
article = ARTICLE_THE;
|
|
else
|
|
article = ARTICLE_NONE;
|
|
} else if ((mons[monsndx(mdat)].geno & G_UNIQ) &&
|
|
article == ARTICLE_A) {
|
|
article = ARTICLE_THE;
|
|
}
|
|
|
|
{
|
|
char buf2[BUFSZ];
|
|
|
|
switch(article) {
|
|
case ARTICLE_YOUR:
|
|
Strcpy(buf2, "your ");
|
|
Strcat(buf2, buf);
|
|
Strcpy(buf, buf2);
|
|
return buf;
|
|
case ARTICLE_THE:
|
|
Strcpy(buf2, "the ");
|
|
Strcat(buf2, buf);
|
|
Strcpy(buf, buf2);
|
|
return buf;
|
|
case ARTICLE_A:
|
|
return(an(buf));
|
|
case ARTICLE_NONE:
|
|
default:
|
|
return buf;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* OVL0 */
|
|
#ifdef OVLB
|
|
|
|
char *
|
|
l_monnam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
return(x_monnam(mtmp, ARTICLE_NONE, (char *)0,
|
|
mtmp->mnamelth ? SUPPRESS_SADDLE : 0, TRUE));
|
|
}
|
|
|
|
#endif /* OVLB */
|
|
#ifdef OVL0
|
|
|
|
char *
|
|
mon_nam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
|
|
mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE));
|
|
}
|
|
|
|
/* print the name as if mon_nam() was called, but assume that the player
|
|
* can always see the monster--used for probing and for monsters aggravating
|
|
* the player with a cursed potion of invisibility
|
|
*/
|
|
char *
|
|
noit_mon_nam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
return(x_monnam(mtmp, ARTICLE_THE, (char *)0,
|
|
mtmp->mnamelth ? (SUPPRESS_SADDLE|SUPPRESS_IT) :
|
|
SUPPRESS_IT, FALSE));
|
|
}
|
|
|
|
char *
|
|
Monnam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
register char *bp = mon_nam(mtmp);
|
|
|
|
*bp = highc(*bp);
|
|
return(bp);
|
|
}
|
|
|
|
char *
|
|
noit_Monnam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
register char *bp = noit_mon_nam(mtmp);
|
|
|
|
*bp = highc(*bp);
|
|
return(bp);
|
|
}
|
|
|
|
/* monster's own name */
|
|
char *
|
|
m_monnam(mtmp)
|
|
struct monst *mtmp;
|
|
{
|
|
return x_monnam(mtmp, ARTICLE_NONE, (char *)0, EXACT_NAME, FALSE);
|
|
}
|
|
|
|
/* pet name: "your little dog" */
|
|
char *
|
|
y_monnam(mtmp)
|
|
struct monst *mtmp;
|
|
{
|
|
int prefix, suppression_flag;
|
|
|
|
prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE;
|
|
suppression_flag = (mtmp->mnamelth
|
|
#ifdef STEED
|
|
/* "saddled" is redundant when mounted */
|
|
|| mtmp == u.usteed
|
|
#endif
|
|
) ? SUPPRESS_SADDLE : 0;
|
|
|
|
return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE);
|
|
}
|
|
|
|
#endif /* OVL0 */
|
|
#ifdef OVLB
|
|
|
|
char *
|
|
Adjmonnam(mtmp, adj)
|
|
register struct monst *mtmp;
|
|
register const char *adj;
|
|
{
|
|
register char *bp = x_monnam(mtmp, ARTICLE_THE, adj,
|
|
mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
|
|
|
|
*bp = highc(*bp);
|
|
return(bp);
|
|
}
|
|
|
|
char *
|
|
a_monnam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
return x_monnam(mtmp, ARTICLE_A, (char *)0,
|
|
mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE);
|
|
}
|
|
|
|
char *
|
|
Amonnam(mtmp)
|
|
register struct monst *mtmp;
|
|
{
|
|
register char *bp = a_monnam(mtmp);
|
|
|
|
*bp = highc(*bp);
|
|
return(bp);
|
|
}
|
|
|
|
/* used for monster ID by the '/', ';', and 'C' commands to block remote
|
|
identification of the endgame altars via their attending priests */
|
|
char *
|
|
distant_monnam(mon, article, outbuf)
|
|
struct monst *mon;
|
|
int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */
|
|
char *outbuf;
|
|
{
|
|
/* high priest(ess)'s identity is concealed on the Astral Plane,
|
|
unless you're adjacent (overridden for hallucination which does
|
|
its own obfuscation) */
|
|
if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination &&
|
|
Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) {
|
|
Strcpy(outbuf, article == ARTICLE_THE ? "the " : "");
|
|
Strcat(outbuf, mon->female ? "high priestess" : "high priest");
|
|
} else {
|
|
Strcpy(outbuf, x_monnam(mon, article, (char *)0, 0, TRUE));
|
|
}
|
|
return outbuf;
|
|
}
|
|
|
|
static const char * const bogusmons[] = {
|
|
"jumbo shrimp", "giant pigmy", "gnu", "killer penguin",
|
|
"giant cockroach", "giant slug", "maggot", "pterodactyl",
|
|
"tyrannosaurus rex", "basilisk", "beholder", "nightmare",
|
|
"efreeti", "marid", "rot grub", "bookworm", "master lichen",
|
|
"shadow", "hologram", "jester", "attorney", "sleazoid",
|
|
"killer tomato", "amazon", "robot", "battlemech",
|
|
"rhinovirus", "harpy", "lion-dog", "rat-ant", "Y2K bug",
|
|
/* misc. */
|
|
"grue", "Christmas-tree monster", "luck sucker", "paskald",
|
|
"brogmoid", "dornbeast", /* Quendor (Zork, &c.) */
|
|
"Ancient Multi-Hued Dragon", "Evil Iggy",
|
|
/* Moria */
|
|
"emu", "kestrel", "xeroc", "venus flytrap",
|
|
/* Rogue */
|
|
"creeping coins", /* Wizardry */
|
|
"hydra", "siren", /* Greek legend */
|
|
"killer bunny", /* Monty Python */
|
|
"rodent of unusual size", /* The Princess Bride */
|
|
"Smokey the bear", /* "Only you can prevent forest fires!" */
|
|
"Luggage", /* Discworld */
|
|
"Ent", /* Lord of the Rings */
|
|
"tangle tree", "nickelpede", "wiggle", /* Xanth */
|
|
"white rabbit", "snark", /* Lewis Carroll */
|
|
"pushmi-pullyu", /* Dr. Doolittle */
|
|
"smurf", /* The Smurfs */
|
|
"tribble", "Klingon", "Borg", /* Star Trek */
|
|
"Ewok", /* Star Wars */
|
|
"Totoro", /* Tonari no Totoro */
|
|
"ohmu", /* Nausicaa */
|
|
"youma", /* Sailor Moon */
|
|
"nyaasu", /* Pokemon (Meowth) */
|
|
"Godzilla", "King Kong", /* monster movies */
|
|
"earthquake beast", /* old L of SH */
|
|
"Invid", /* Robotech */
|
|
"Terminator", /* The Terminator */
|
|
"boomer", /* Bubblegum Crisis */
|
|
"Dalek", /* Dr. Who ("Exterminate!") */
|
|
"microscopic space fleet", "Ravenous Bugblatter Beast of Traal",
|
|
/* HGttG */
|
|
"teenage mutant ninja turtle", /* TMNT */
|
|
"samurai rabbit", /* Usagi Yojimbo */
|
|
"aardvark", /* Cerebus */
|
|
"Audrey II", /* Little Shop of Horrors */
|
|
"witch doctor", "one-eyed one-horned flying purple people eater",
|
|
/* 50's rock 'n' roll */
|
|
"Barney the dinosaur", /* saccharine kiddy TV */
|
|
"Morgoth", /* Angband */
|
|
"Vorlon", /* Babylon 5 */
|
|
"questing beast", /* King Arthur */
|
|
"Predator", /* Movie */
|
|
"mother-in-law" /* common pest */
|
|
};
|
|
|
|
|
|
/* Return a random monster name, for hallucination.
|
|
* KNOWN BUG: May be a proper name (Godzilla, Barney), may not
|
|
* (the Terminator, a Dalek). There's no elegant way to deal
|
|
* with this without radically modifying the calling functions.
|
|
*/
|
|
const char *
|
|
rndmonnam()
|
|
{
|
|
int name;
|
|
|
|
do {
|
|
name = rn1(SPECIAL_PM + SIZE(bogusmons) - LOW_PM, LOW_PM);
|
|
} while (name < SPECIAL_PM &&
|
|
(type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN)));
|
|
|
|
if (name >= SPECIAL_PM) return bogusmons[name - SPECIAL_PM];
|
|
return mons[name].mname;
|
|
}
|
|
|
|
#ifdef REINCARNATION
|
|
const char *
|
|
roguename() /* Name of a Rogue player */
|
|
{
|
|
char *i, *opts;
|
|
|
|
if ((opts = nh_getenv("ROGUEOPTS")) != 0) {
|
|
for (i = opts; *i; i++)
|
|
if (!strncmp("name=",i,5)) {
|
|
char *j;
|
|
if ((j = index(i+5,',')) != 0)
|
|
*j = (char)0;
|
|
return i+5;
|
|
}
|
|
}
|
|
return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold")
|
|
: "Glenn Wichman";
|
|
}
|
|
#endif /* REINCARNATION */
|
|
#endif /* OVLB */
|
|
|
|
#ifdef OVL2
|
|
|
|
static NEARDATA const char * const hcolors[] = {
|
|
"ultraviolet", "infrared", "bluish-orange",
|
|
"reddish-green", "dark white", "light black", "sky blue-pink",
|
|
"salty", "sweet", "sour", "bitter",
|
|
"striped", "spiral", "swirly", "plaid", "checkered", "argyle",
|
|
"paisley", "blotchy", "guernsey-spotted", "polka-dotted",
|
|
"square", "round", "triangular",
|
|
"cabernet", "sangria", "fuchsia", "wisteria",
|
|
"lemon-lime", "strawberry-banana", "peppermint",
|
|
"romantic", "incandescent"
|
|
};
|
|
|
|
const char *
|
|
hcolor(colorpref)
|
|
const char *colorpref;
|
|
{
|
|
return (Hallucination || !colorpref) ?
|
|
hcolors[rn2(SIZE(hcolors))] : colorpref;
|
|
}
|
|
|
|
/* Aliases for road-runner nemesis
|
|
*/
|
|
static const char * const coynames[] = {
|
|
"Carnivorous Vulgaris","Road-Runnerus Digestus",
|
|
"Eatibus Anythingus" ,"Famishus-Famishus",
|
|
"Eatibus Almost Anythingus","Eatius Birdius",
|
|
"Famishius Fantasticus","Eternalii Famishiis",
|
|
"Famishus Vulgarus","Famishius Vulgaris Ingeniusi",
|
|
"Eatius-Slobbius","Hardheadipus Oedipus",
|
|
"Carnivorous Slobbius","Hard-Headipus Ravenus",
|
|
"Evereadii Eatibus","Apetitius Giganticus",
|
|
"Hungrii Flea-Bagius","Overconfidentii Vulgaris",
|
|
"Caninus Nervous Rex","Grotesques Appetitus",
|
|
"Nemesis Riduclii","Canis latrans"
|
|
};
|
|
|
|
char *
|
|
coyotename(mtmp, buf)
|
|
struct monst *mtmp;
|
|
char *buf;
|
|
{
|
|
if (mtmp && buf) {
|
|
Sprintf(buf, "%s - %s",
|
|
x_monnam(mtmp, ARTICLE_NONE, (char *)0, 0, TRUE),
|
|
mtmp->mcan ? coynames[SIZE(coynames)-1] : coynames[rn2(SIZE(coynames)-1)]);
|
|
}
|
|
return buf;
|
|
}
|
|
#endif /* OVL2 */
|
|
|
|
/*do_name.c*/
|