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