1/* SCCS Id: @(#)wizard.c 3.4 2003/02/18 */ 2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ 3/* NetHack may be freely redistributed. See license for details. */ 4 5/* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */ 6/* - heavily modified to give the wiz balls. (genat!mike) */ 7/* - dewimped and given some maledictions. -3. */ 8/* - generalized for 3.1 (mike@bullns.on01.bull.ca) */ 9 10#include "hack.h" 11#include "qtext.h" 12#include "epri.h" 13 14extern const int monstr[]; 15 16#ifdef OVLB 17 18STATIC_DCL short FDECL(which_arti, (int)); 19STATIC_DCL boolean FDECL(mon_has_arti, (struct monst *,SHORT_P)); 20STATIC_DCL struct monst *FDECL(other_mon_has_arti, (struct monst *,SHORT_P)); 21STATIC_DCL struct obj *FDECL(on_ground, (SHORT_P)); 22STATIC_DCL boolean FDECL(you_have, (int)); 23STATIC_DCL long FDECL(target_on, (int,struct monst *)); 24STATIC_DCL long FDECL(strategy, (struct monst *)); 25 26static NEARDATA const int nasties[] = { 27 PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON, 28 PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM, 29 PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD, 30 PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON, 31 PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT, 32 PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER, 33 PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING, 34 PM_OLOG_HAI, PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, 35 PM_DISENCHANTER 36 }; 37 38static NEARDATA const unsigned wizapp[] = { 39 PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE, 40 PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK, 41 PM_XORN, PM_XAN, PM_COCKATRICE, 42 PM_FLOATING_EYE, 43 PM_GUARDIAN_NAGA, 44 PM_TRAPPER 45}; 46 47#endif /* OVLB */ 48#ifdef OVL0 49 50/* If you've found the Amulet, make the Wizard appear after some time */ 51/* Also, give hints about portal locations, if amulet is worn/wielded -dlc */ 52void 53amulet() 54{ 55 struct monst *mtmp; 56 struct trap *ttmp; 57 struct obj *amu; 58 59#if 0 /* caller takes care of this check */ 60 if (!u.uhave.amulet) 61 return; 62#endif 63 if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) || 64 ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR)) 65 && !rn2(15)) { 66 for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { 67 if(ttmp->ttyp == MAGIC_PORTAL) { 68 int du = distu(ttmp->tx, ttmp->ty); 69 if (du <= 9) 70 pline("%s hot!", Tobjnam(amu, "feel")); 71 else if (du <= 64) 72 pline("%s very warm.", Tobjnam(amu, "feel")); 73 else if (du <= 144) 74 pline("%s warm.", Tobjnam(amu, "feel")); 75 /* else, the amulet feels normal */ 76 break; 77 } 78 } 79 } 80 81 if (!flags.no_of_wizards) 82 return; 83 /* find Wizard, and wake him if necessary */ 84 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 85 if (!DEADMONSTER(mtmp) && mtmp->iswiz && mtmp->msleeping && !rn2(40)) { 86 mtmp->msleeping = 0; 87 if (distu(mtmp->mx,mtmp->my) > 2) 88 You( 89 "get the creepy feeling that somebody noticed your taking the Amulet." 90 ); 91 return; 92 } 93} 94 95#endif /* OVL0 */ 96#ifdef OVLB 97 98int 99mon_has_amulet(mtmp) 100register struct monst *mtmp; 101{ 102 register struct obj *otmp; 103 104 for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 105 if(otmp->otyp == AMULET_OF_YENDOR) return(1); 106 return(0); 107} 108 109int 110mon_has_special(mtmp) 111register struct monst *mtmp; 112{ 113 register struct obj *otmp; 114 115 for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) 116 if(otmp->otyp == AMULET_OF_YENDOR || 117 is_quest_artifact(otmp) || 118 otmp->otyp == BELL_OF_OPENING || 119 otmp->otyp == CANDELABRUM_OF_INVOCATION || 120 otmp->otyp == SPE_BOOK_OF_THE_DEAD) return(1); 121 return(0); 122} 123 124/* 125 * New for 3.1 Strategy / Tactics for the wiz, as well as other 126 * monsters that are "after" something (defined via mflag3). 127 * 128 * The strategy section decides *what* the monster is going 129 * to attempt, the tactics section implements the decision. 130 */ 131#define STRAT(w, x, y, typ) (w | ((long)(x)<<16) | ((long)(y)<<8) | (long)typ) 132 133#define M_Wants(mask) (mtmp->data->mflags3 & (mask)) 134 135STATIC_OVL short 136which_arti(mask) 137 register int mask; 138{ 139 switch(mask) { 140 case M3_WANTSAMUL: return(AMULET_OF_YENDOR); 141 case M3_WANTSBELL: return(BELL_OF_OPENING); 142 case M3_WANTSCAND: return(CANDELABRUM_OF_INVOCATION); 143 case M3_WANTSBOOK: return(SPE_BOOK_OF_THE_DEAD); 144 default: break; /* 0 signifies quest artifact */ 145 } 146 return(0); 147} 148 149/* 150 * If "otyp" is zero, it triggers a check for the quest_artifact, 151 * since bell, book, candle, and amulet are all objects, not really 152 * artifacts right now. [MRS] 153 */ 154STATIC_OVL boolean 155mon_has_arti(mtmp, otyp) 156 register struct monst *mtmp; 157 register short otyp; 158{ 159 register struct obj *otmp; 160 161 for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { 162 if(otyp) { 163 if(otmp->otyp == otyp) 164 return(1); 165 } 166 else if(is_quest_artifact(otmp)) return(1); 167 } 168 return(0); 169 170} 171 172STATIC_OVL struct monst * 173other_mon_has_arti(mtmp, otyp) 174 register struct monst *mtmp; 175 register short otyp; 176{ 177 register struct monst *mtmp2; 178 179 for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) 180 /* no need for !DEADMONSTER check here since they have no inventory */ 181 if(mtmp2 != mtmp) 182 if(mon_has_arti(mtmp2, otyp)) return(mtmp2); 183 184 return((struct monst *)0); 185} 186 187STATIC_OVL struct obj * 188on_ground(otyp) 189 register short otyp; 190{ 191 register struct obj *otmp; 192 193 for (otmp = fobj; otmp; otmp = otmp->nobj) 194 if (otyp) { 195 if (otmp->otyp == otyp) 196 return(otmp); 197 } else if (is_quest_artifact(otmp)) 198 return(otmp); 199 return((struct obj *)0); 200} 201 202STATIC_OVL boolean 203you_have(mask) 204 register int mask; 205{ 206 switch(mask) { 207 case M3_WANTSAMUL: return(boolean)(u.uhave.amulet); 208 case M3_WANTSBELL: return(boolean)(u.uhave.bell); 209 case M3_WANTSCAND: return(boolean)(u.uhave.menorah); 210 case M3_WANTSBOOK: return(boolean)(u.uhave.book); 211 case M3_WANTSARTI: return(boolean)(u.uhave.questart); 212 default: break; 213 } 214 return(0); 215} 216 217STATIC_OVL long 218target_on(mask, mtmp) 219 register int mask; 220 register struct monst *mtmp; 221{ 222 register short otyp; 223 register struct obj *otmp; 224 register struct monst *mtmp2; 225 226 if(!M_Wants(mask)) return(STRAT_NONE); 227 228 otyp = which_arti(mask); 229 if(!mon_has_arti(mtmp, otyp)) { 230 if(you_have(mask)) 231 return(STRAT(STRAT_PLAYER, u.ux, u.uy, mask)); 232 else if((otmp = on_ground(otyp))) 233 return(STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask)); 234 else if((mtmp2 = other_mon_has_arti(mtmp, otyp))) 235 return(STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask)); 236 } 237 return(STRAT_NONE); 238} 239 240STATIC_OVL long 241strategy(mtmp) 242 register struct monst *mtmp; 243{ 244 long strat, dstrat; 245 246 if (!is_covetous(mtmp->data) || 247 /* perhaps a shopkeeper has been polymorphed into a master 248 lich; we don't want it teleporting to the stairs to heal 249 because that will leave its shop untended */ 250 (mtmp->isshk && inhishop(mtmp))) 251 return STRAT_NONE; 252 253 switch((mtmp->mhp*3)/mtmp->mhpmax) { /* 0-3 */ 254 255 default: 256 case 0: /* panic time - mtmp is almost snuffed */ 257 return(STRAT_HEAL); 258 259 case 1: /* the wiz is less cautious */ 260 if(mtmp->data != &mons[PM_WIZARD_OF_YENDOR]) 261 return(STRAT_HEAL); 262 /* else fall through */ 263 264 case 2: dstrat = STRAT_HEAL; 265 break; 266 267 case 3: dstrat = STRAT_NONE; 268 break; 269 } 270 271 if(flags.made_amulet) 272 if((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE) 273 return(strat); 274 275 if(u.uevent.invoked) { /* priorities change once gate opened */ 276 277 if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) 278 return(strat); 279 if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) 280 return(strat); 281 if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) 282 return(strat); 283 if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) 284 return(strat); 285 } else { 286 287 if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) 288 return(strat); 289 if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) 290 return(strat); 291 if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) 292 return(strat); 293 if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) 294 return(strat); 295 } 296 return(dstrat); 297} 298 299int 300tactics(mtmp) 301 register struct monst *mtmp; 302{ 303 long strat = strategy(mtmp); 304 305 mtmp->mstrategy = (mtmp->mstrategy & STRAT_WAITMASK) | strat; 306 307 switch (strat) { 308 case STRAT_HEAL: /* hide and recover */ 309 /* if wounded, hole up on or near the stairs (to block them) */ 310 /* unless, of course, there are no stairs (e.g. endlevel) */ 311 mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ 312 if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) || 313 (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { 314 if (!rn2(3 + mtmp->mhp/10)) (void) rloc(mtmp, FALSE); 315 } else if (xupstair && 316 (mtmp->mx != xupstair || mtmp->my != yupstair)) { 317 (void) mnearto(mtmp, xupstair, yupstair, TRUE); 318 } 319 /* if you're not around, cast healing spells */ 320 if (distu(mtmp->mx,mtmp->my) > (BOLT_LIM * BOLT_LIM)) 321 if(mtmp->mhp <= mtmp->mhpmax - 8) { 322 mtmp->mhp += rnd(8); 323 return(1); 324 } 325 /* fall through :-) */ 326 327 case STRAT_NONE: /* harrass */ 328 if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp); 329 return(0); 330 331 default: /* kill, maim, pillage! */ 332 { 333 long where = (strat & STRAT_STRATMASK); 334 xchar tx = STRAT_GOALX(strat), 335 ty = STRAT_GOALY(strat); 336 int targ = strat & STRAT_GOAL; 337 struct obj *otmp; 338 339 if(!targ) { /* simply wants you to close */ 340 return(0); 341 } 342 if((u.ux == tx && u.uy == ty) || where == STRAT_PLAYER) { 343 /* player is standing on it (or has it) */ 344 mnexto(mtmp); 345 return(0); 346 } 347 if(where == STRAT_GROUND) { 348 if(!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) { 349 /* teleport to it and pick it up */ 350 rloc_to(mtmp, tx, ty); /* clean old pos */ 351 352 if ((otmp = on_ground(which_arti(targ))) != 0) { 353 if (cansee(mtmp->mx, mtmp->my)) 354 pline("%s picks up %s.", 355 Monnam(mtmp), 356 (distu(mtmp->mx, mtmp->my) <= 5) ? 357 doname(otmp) : distant_name(otmp, doname)); 358 obj_extract_self(otmp); 359 (void) mpickobj(mtmp, otmp); 360 return(1); 361 } else return(0); 362 } else { 363 /* a monster is standing on it - cause some trouble */ 364 if (!rn2(5)) mnexto(mtmp); 365 return(0); 366 } 367 } else { /* a monster has it - 'port beside it. */ 368 (void) mnearto(mtmp, tx, ty, FALSE); 369 return(0); 370 } 371 } 372 } 373 /*NOTREACHED*/ 374 return(0); 375} 376 377void 378aggravate() 379{ 380 register struct monst *mtmp; 381 382 for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) 383 if (!DEADMONSTER(mtmp)) { 384 mtmp->msleeping = 0; 385 if(!mtmp->mcanmove && !rn2(5)) { 386 mtmp->mfrozen = 0; 387 mtmp->mcanmove = 1; 388 } 389 } 390} 391 392void 393clonewiz() 394{ 395 register struct monst *mtmp2; 396 397 if ((mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR], 398 u.ux, u.uy, NO_MM_FLAGS)) != 0) { 399 mtmp2->msleeping = mtmp2->mtame = mtmp2->mpeaceful = 0; 400 if (!u.uhave.amulet && rn2(2)) { /* give clone a fake */ 401 (void) add_to_minv(mtmp2, mksobj(FAKE_AMULET_OF_YENDOR, 402 TRUE, FALSE)); 403 } 404 mtmp2->m_ap_type = M_AP_MONSTER; 405 mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))]; 406 newsym(mtmp2->mx,mtmp2->my); 407 } 408} 409 410/* also used by newcham() */ 411int 412pick_nasty() 413{ 414 /* To do? Possibly should filter for appropriate forms when 415 in the elemental planes or surrounded by water or lava. */ 416 return nasties[rn2(SIZE(nasties))]; 417} 418 419/* create some nasty monsters, aligned or neutral with the caster */ 420/* a null caster defaults to a chaotic caster (e.g. the wizard) */ 421int 422nasty(mcast) 423 struct monst *mcast; 424{ 425 register struct monst *mtmp; 426 register int i, j, tmp; 427 int castalign = (mcast ? mcast->data->maligntyp : -1); 428 coord bypos; 429 int count=0; 430 431 if(!rn2(10) && Inhell) { 432 msummon((struct monst *) 0); /* summons like WoY */ 433 count++; 434 } else { 435 tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */ 436 /* if we don't have a casting monster, the nasties appear around you */ 437 bypos.x = u.ux; 438 bypos.y = u.uy; 439 for(i = rnd(tmp); i > 0; --i) 440 for(j=0; j<20; j++) { 441 int makeindex; 442 443 /* Don't create more spellcasters of the monsters' level or 444 * higher--avoids chain summoners filling up the level. 445 */ 446 do { 447 makeindex = pick_nasty(); 448 } while(mcast && attacktype(&mons[makeindex], AT_MAGC) && 449 monstr[makeindex] >= monstr[mcast->mnum]); 450 /* do this after picking the monster to place */ 451 if (mcast && 452 !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex])) 453 continue; 454 if ((mtmp = makemon(&mons[makeindex], 455 bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { 456 mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0; 457 set_malign(mtmp); 458 } else /* GENOD? */ 459 mtmp = makemon((struct permonst *)0, 460 bypos.x, bypos.y, NO_MM_FLAGS); 461 if(mtmp && (mtmp->data->maligntyp == 0 || 462 sgn(mtmp->data->maligntyp) == sgn(castalign)) ) { 463 count++; 464 break; 465 } 466 } 467 } 468 return count; 469} 470 471/* Let's resurrect the wizard, for some unexpected fun. */ 472void 473resurrect() 474{ 475 struct monst *mtmp, **mmtmp; 476 long elapsed; 477 const char *verb; 478 479 if (!flags.no_of_wizards) { 480 /* make a new Wizard */ 481 verb = "kill"; 482 mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT); 483 } else { 484 /* look for a migrating Wizard */ 485 verb = "elude"; 486 mmtmp = &migrating_mons; 487 while ((mtmp = *mmtmp) != 0) { 488 if (mtmp->iswiz && 489 /* if he has the Amulet, he won't bring it to you */ 490 !mon_has_amulet(mtmp) && 491 (elapsed = monstermoves - mtmp->mlstmv) > 0L) { 492 mon_catchup_elapsed_time(mtmp, elapsed); 493 if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1; 494 elapsed /= 50L; 495 if (mtmp->msleeping && rn2((int)elapsed + 1)) 496 mtmp->msleeping = 0; 497 if (mtmp->mfrozen == 1) /* would unfreeze on next move */ 498 mtmp->mfrozen = 0, mtmp->mcanmove = 1; 499 if (mtmp->mcanmove && !mtmp->msleeping) { 500 *mmtmp = mtmp->nmon; 501 mon_arrive(mtmp, TRUE); 502 /* note: there might be a second Wizard; if so, 503 he'll have to wait til the next resurrection */ 504 break; 505 } 506 } 507 mmtmp = &mtmp->nmon; 508 } 509 } 510 511 if (mtmp) { 512 mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0; 513 set_malign(mtmp); 514 pline("A voice booms out..."); 515 verbalize("So thou thought thou couldst %s me, fool.", verb); 516 } 517 518} 519 520/* Here, we make trouble for the poor shmuck who actually */ 521/* managed to do in the Wizard. */ 522void 523intervene() 524{ 525 int which = Is_astralevel(&u.uz) ? rnd(4) : rn2(6); 526 /* cases 0 and 5 don't apply on the Astral level */ 527 switch (which) { 528 case 0: 529 case 1: You_feel("vaguely nervous."); 530 break; 531 case 2: if (!Blind) 532 You("notice a %s glow surrounding you.", 533 hcolor(NH_BLACK)); 534 rndcurse(); 535 break; 536 case 3: aggravate(); 537 break; 538 case 4: (void)nasty((struct monst *)0); 539 break; 540 case 5: resurrect(); 541 break; 542 } 543} 544 545void 546wizdead() 547{ 548 flags.no_of_wizards--; 549 if (!u.uevent.udemigod) { 550 u.uevent.udemigod = TRUE; 551 u.udg_cnt = rn1(250, 50); 552 } 553} 554 555const char * const random_insult[] = { 556 "antic", 557 "blackguard", 558 "caitiff", 559 "chucklehead", 560 "coistrel", 561 "craven", 562 "cretin", 563 "cur", 564 "dastard", 565 "demon fodder", 566 "dimwit", 567 "dolt", 568 "fool", 569 "footpad", 570 "imbecile", 571 "knave", 572 "maledict", 573 "miscreant", 574 "niddering", 575 "poltroon", 576 "rattlepate", 577 "reprobate", 578 "scapegrace", 579 "varlet", 580 "villein", /* (sic.) */ 581 "wittol", 582 "worm", 583 "wretch", 584}; 585 586const char * const random_malediction[] = { 587 "Hell shall soon claim thy remains,", 588 "I chortle at thee, thou pathetic", 589 "Prepare to die, thou", 590 "Resistance is useless,", 591 "Surrender or die, thou", 592 "There shall be no mercy, thou", 593 "Thou shalt repent of thy cunning,", 594 "Thou art as a flea to me,", 595 "Thou art doomed,", 596 "Thy fate is sealed,", 597 "Verily, thou shalt be one dead" 598}; 599 600/* Insult or intimidate the player */ 601void 602cuss(mtmp) 603register struct monst *mtmp; 604{ 605 if (mtmp->iswiz) { 606 if (!rn2(5)) /* typical bad guy action */ 607 pline("%s laughs fiendishly.", Monnam(mtmp)); 608 else 609 if (u.uhave.amulet && !rn2(SIZE(random_insult))) 610 verbalize("Relinquish the amulet, %s!", 611 random_insult[rn2(SIZE(random_insult))]); 612 else if (u.uhp < 5 && !rn2(2)) /* Panic */ 613 verbalize(rn2(2) ? 614 "Even now thy life force ebbs, %s!" : 615 "Savor thy breath, %s, it be thy last!", 616 random_insult[rn2(SIZE(random_insult))]); 617 else if (mtmp->mhp < 5 && !rn2(2)) /* Parthian shot */ 618 verbalize(rn2(2) ? 619 "I shall return." : 620 "I'll be back."); 621 else 622 verbalize("%s %s!", 623 random_malediction[rn2(SIZE(random_malediction))], 624 random_insult[rn2(SIZE(random_insult))]); 625 } else if(is_lminion(mtmp)) { 626 com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) + 627 QT_ANGELIC); 628 } else { 629 if (!rn2(5)) 630 pline("%s casts aspersions on your ancestry.", Monnam(mtmp)); 631 else 632 com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC); 633 } 634} 635 636#endif /* OVLB */ 637 638/*wizard.c*/ 639