1/* SCCS Id: @(#)mcastu.c 3.4 2003/01/08 */ 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/* monster mage spells */ 8#define MGC_PSI_BOLT 0 9#define MGC_CURE_SELF 1 10#define MGC_HASTE_SELF 2 11#define MGC_STUN_YOU 3 12#define MGC_DISAPPEAR 4 13#define MGC_WEAKEN_YOU 5 14#define MGC_DESTRY_ARMR 6 15#define MGC_CURSE_ITEMS 7 16#define MGC_AGGRAVATION 8 17#define MGC_SUMMON_MONS 9 18#define MGC_CLONE_WIZ 10 19#define MGC_DEATH_TOUCH 11 20 21/* monster cleric spells */ 22#define CLC_OPEN_WOUNDS 0 23#define CLC_CURE_SELF 1 24#define CLC_CONFUSE_YOU 2 25#define CLC_PARALYZE 3 26#define CLC_BLIND_YOU 4 27#define CLC_INSECTS 5 28#define CLC_CURSE_ITEMS 6 29#define CLC_LIGHTNING 7 30#define CLC_FIRE_PILLAR 8 31#define CLC_GEYSER 9 32 33STATIC_DCL void FDECL(cursetxt,(struct monst *,BOOLEAN_P)); 34STATIC_DCL int FDECL(choose_magic_spell, (int)); 35STATIC_DCL int FDECL(choose_clerical_spell, (int)); 36STATIC_DCL void FDECL(cast_wizard_spell,(struct monst *, int,int)); 37STATIC_DCL void FDECL(cast_cleric_spell,(struct monst *, int,int)); 38STATIC_DCL boolean FDECL(is_undirected_spell,(unsigned int,int)); 39STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,unsigned int,int)); 40 41#ifdef OVL0 42 43extern const char * const flash_types[]; /* from zap.c */ 44 45/* feedback when frustrated monster couldn't cast a spell */ 46STATIC_OVL 47void 48cursetxt(mtmp, undirected) 49struct monst *mtmp; 50boolean undirected; 51{ 52 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { 53 const char *point_msg; /* spellcasting monsters are impolite */ 54 55 if (undirected) 56 point_msg = "all around, then curses"; 57 else if ((Invis && !perceives(mtmp->data) && 58 (mtmp->mux != u.ux || mtmp->muy != u.uy)) || 59 (youmonst.m_ap_type == M_AP_OBJECT && 60 youmonst.mappearance == STRANGE_OBJECT) || 61 u.uundetected) 62 point_msg = "and curses in your general direction"; 63 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) 64 point_msg = "and curses at your displaced image"; 65 else 66 point_msg = "at you, then curses"; 67 68 pline("%s points %s.", Monnam(mtmp), point_msg); 69 } else if ((!(moves % 4) || !rn2(4))) { 70 if (flags.soundok) Norep("You hear a mumbled curse."); 71 } 72} 73 74#endif /* OVL0 */ 75#ifdef OVLB 76 77/* convert a level based random selection into a specific mage spell; 78 inappropriate choices will be screened out by spell_would_be_useless() */ 79STATIC_OVL int 80choose_magic_spell(spellval) 81int spellval; 82{ 83 switch (spellval) { 84 case 22: 85 case 21: 86 case 20: 87 return MGC_DEATH_TOUCH; 88 case 19: 89 case 18: 90 return MGC_CLONE_WIZ; 91 case 17: 92 case 16: 93 case 15: 94 return MGC_SUMMON_MONS; 95 case 14: 96 case 13: 97 return MGC_AGGRAVATION; 98 case 12: 99 case 11: 100 case 10: 101 return MGC_CURSE_ITEMS; 102 case 9: 103 case 8: 104 return MGC_DESTRY_ARMR; 105 case 7: 106 case 6: 107 return MGC_WEAKEN_YOU; 108 case 5: 109 case 4: 110 return MGC_DISAPPEAR; 111 case 3: 112 return MGC_STUN_YOU; 113 case 2: 114 return MGC_HASTE_SELF; 115 case 1: 116 return MGC_CURE_SELF; 117 case 0: 118 default: 119 return MGC_PSI_BOLT; 120 } 121} 122 123/* convert a level based random selection into a specific cleric spell */ 124STATIC_OVL int 125choose_clerical_spell(spellnum) 126int spellnum; 127{ 128 switch (spellnum) { 129 case 13: 130 return CLC_GEYSER; 131 case 12: 132 return CLC_FIRE_PILLAR; 133 case 11: 134 return CLC_LIGHTNING; 135 case 10: 136 case 9: 137 return CLC_CURSE_ITEMS; 138 case 8: 139 return CLC_INSECTS; 140 case 7: 141 case 6: 142 return CLC_BLIND_YOU; 143 case 5: 144 case 4: 145 return CLC_PARALYZE; 146 case 3: 147 case 2: 148 return CLC_CONFUSE_YOU; 149 case 1: 150 return CLC_CURE_SELF; 151 case 0: 152 default: 153 return CLC_OPEN_WOUNDS; 154 } 155} 156 157/* return values: 158 * 1: successful spell 159 * 0: unsuccessful spell 160 */ 161int 162castmu(mtmp, mattk, thinks_it_foundyou, foundyou) 163 register struct monst *mtmp; 164 register struct attack *mattk; 165 boolean thinks_it_foundyou; 166 boolean foundyou; 167{ 168 int dmg, ml = mtmp->m_lev; 169 int ret; 170 int spellnum = 0; 171 172 /* Three cases: 173 * -- monster is attacking you. Search for a useful spell. 174 * -- monster thinks it's attacking you. Search for a useful spell, 175 * without checking for undirected. If the spell found is directed, 176 * it fails with cursetxt() and loss of mspec_used. 177 * -- monster isn't trying to attack. Select a spell once. Don't keep 178 * searching; if that spell is not useful (or if it's directed), 179 * return and do something else. 180 * Since most spells are directed, this means that a monster that isn't 181 * attacking casts spells only a small portion of the time that an 182 * attacking monster does. 183 */ 184 if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { 185 int cnt = 40; 186 187 do { 188 spellnum = rn2(ml); 189 if (mattk->adtyp == AD_SPEL) 190 spellnum = choose_magic_spell(spellnum); 191 else 192 spellnum = choose_clerical_spell(spellnum); 193 /* not trying to attack? don't allow directed spells */ 194 if (!thinks_it_foundyou) { 195 if (!is_undirected_spell(mattk->adtyp, spellnum) || 196 spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) { 197 if (foundyou) 198 impossible("spellcasting monster found you and doesn't know it?"); 199 return 0; 200 } 201 break; 202 } 203 } while(--cnt > 0 && 204 spell_would_be_useless(mtmp, mattk->adtyp, spellnum)); 205 if (cnt == 0) return 0; 206 } 207 208 /* monster unable to cast spells? */ 209 if(mtmp->mcan || mtmp->mspec_used || !ml) { 210 cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum)); 211 return(0); 212 } 213 214 if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { 215 mtmp->mspec_used = 10 - mtmp->m_lev; 216 if (mtmp->mspec_used < 2) mtmp->mspec_used = 2; 217 } 218 219 /* monster can cast spells, but is casting a directed spell at the 220 wrong place? If so, give a message, and return. Do this *after* 221 penalizing mspec_used. */ 222 if (!foundyou && thinks_it_foundyou && 223 !is_undirected_spell(mattk->adtyp, spellnum)) { 224 pline("%s casts a spell at %s!", 225 canseemon(mtmp) ? Monnam(mtmp) : "Something", 226 levl[mtmp->mux][mtmp->muy].typ == WATER 227 ? "empty water" : "thin air"); 228 return(0); 229 } 230 231 nomul(0); 232 if(rn2(ml*10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */ 233 if (canseemon(mtmp) && flags.soundok) 234 pline_The("air crackles around %s.", mon_nam(mtmp)); 235 return(0); 236 } 237 if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) { 238 pline("%s casts a spell%s!", 239 canspotmon(mtmp) ? Monnam(mtmp) : "Something", 240 is_undirected_spell(mattk->adtyp, spellnum) ? "" : 241 (Invisible && !perceives(mtmp->data) && 242 (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? 243 " at a spot near you" : 244 (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? 245 " at your displaced image" : 246 " at you"); 247 } 248 249/* 250 * As these are spells, the damage is related to the level 251 * of the monster casting the spell. 252 */ 253 if (!foundyou) { 254 dmg = 0; 255 if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) { 256 impossible( 257 "%s casting non-hand-to-hand version of hand-to-hand spell %d?", 258 Monnam(mtmp), mattk->adtyp); 259 return(0); 260 } 261 } else if (mattk->damd) 262 dmg = d((int)((ml/2) + mattk->damn), (int)mattk->damd); 263 else dmg = d((int)((ml/2) + 1), 6); 264 if (Half_spell_damage) dmg = (dmg+1) / 2; 265 266 ret = 1; 267 268 switch (mattk->adtyp) { 269 270 case AD_FIRE: 271 pline("You're enveloped in flames."); 272 if(Fire_resistance) { 273 shieldeff(u.ux, u.uy); 274 pline("But you resist the effects."); 275 dmg = 0; 276 } 277 burn_away_slime(); 278 break; 279 case AD_COLD: 280 pline("You're covered in frost."); 281 if(Cold_resistance) { 282 shieldeff(u.ux, u.uy); 283 pline("But you resist the effects."); 284 dmg = 0; 285 } 286 break; 287 case AD_MAGM: 288 You("are hit by a shower of missiles!"); 289 if(Antimagic) { 290 shieldeff(u.ux, u.uy); 291 pline_The("missiles bounce off!"); 292 dmg = 0; 293 } else dmg = d((int)mtmp->m_lev/2 + 1,6); 294 break; 295 case AD_SPEL: /* wizard spell */ 296 case AD_CLRC: /* clerical spell */ 297 { 298 if (mattk->adtyp == AD_SPEL) 299 cast_wizard_spell(mtmp, dmg, spellnum); 300 else 301 cast_cleric_spell(mtmp, dmg, spellnum); 302 dmg = 0; /* done by the spell casting functions */ 303 break; 304 } 305 } 306 if(dmg) mdamageu(mtmp, dmg); 307 return(ret); 308} 309 310/* monster wizard and cleric spellcasting functions */ 311/* 312 If dmg is zero, then the monster is not casting at you. 313 If the monster is intentionally not casting at you, we have previously 314 called spell_would_be_useless() and spellnum should always be a valid 315 undirected spell. 316 If you modify either of these, be sure to change is_undirected_spell() 317 and spell_would_be_useless(). 318 */ 319STATIC_OVL 320void 321cast_wizard_spell(mtmp, dmg, spellnum) 322struct monst *mtmp; 323int dmg; 324int spellnum; 325{ 326 if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { 327 impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); 328 return; 329 } 330 331 switch (spellnum) { 332 case MGC_DEATH_TOUCH: 333 pline("Oh no, %s's using the touch of death!", mhe(mtmp)); 334 if (nonliving(youmonst.data) || is_demon(youmonst.data)) { 335 You("seem no deader than before."); 336 } else if (!Antimagic && rn2(mtmp->m_lev) > 12) { 337 if (Hallucination) { 338 You("have an out of body experience."); 339 } else { 340 killer_format = KILLED_BY_AN; 341 killer = "touch of death"; 342 done(DIED); 343 } 344 } else { 345 if (Antimagic) shieldeff(u.ux, u.uy); 346 pline("Lucky for you, it didn't work!"); 347 } 348 dmg = 0; 349 break; 350 case MGC_CLONE_WIZ: 351 if (mtmp->iswiz && flags.no_of_wizards == 1) { 352 pline("Double Trouble..."); 353 clonewiz(); 354 dmg = 0; 355 } else 356 impossible("bad wizard cloning?"); 357 break; 358 case MGC_SUMMON_MONS: 359 { 360 int count; 361 362 count = nasty(mtmp); /* summon something nasty */ 363 if (mtmp->iswiz) 364 verbalize("Destroy the thief, my pet%s!", plur(count)); 365 else { 366 const char *mappear = 367 (count == 1) ? "A monster appears" : "Monsters appear"; 368 369 /* messages not quite right if plural monsters created but 370 only a single monster is seen */ 371 if (Invisible && !perceives(mtmp->data) && 372 (mtmp->mux != u.ux || mtmp->muy != u.uy)) 373 pline("%s around a spot near you!", mappear); 374 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) 375 pline("%s around your displaced image!", mappear); 376 else 377 pline("%s from nowhere!", mappear); 378 } 379 dmg = 0; 380 break; 381 } 382 case MGC_AGGRAVATION: 383 You_feel("that monsters are aware of your presence."); 384 aggravate(); 385 dmg = 0; 386 break; 387 case MGC_CURSE_ITEMS: 388 You_feel("as if you need some help."); 389 rndcurse(); 390 dmg = 0; 391 break; 392 case MGC_DESTRY_ARMR: 393 if (Antimagic) { 394 shieldeff(u.ux, u.uy); 395 pline("A field of force surrounds you!"); 396 } else if (!destroy_arm(some_armor(&youmonst))) { 397 Your("skin itches."); 398 } 399 dmg = 0; 400 break; 401 case MGC_WEAKEN_YOU: /* drain strength */ 402 if (Antimagic) { 403 shieldeff(u.ux, u.uy); 404 You_feel("momentarily weakened."); 405 } else { 406 You("suddenly feel weaker!"); 407 dmg = mtmp->m_lev - 6; 408 if (Half_spell_damage) dmg = (dmg + 1) / 2; 409 losestr(rnd(dmg)); 410 if (u.uhp < 1) 411 done_in_by(mtmp); 412 } 413 dmg = 0; 414 break; 415 case MGC_DISAPPEAR: /* makes self invisible */ 416 if (!mtmp->minvis && !mtmp->invis_blkd) { 417 if (canseemon(mtmp)) 418 pline("%s suddenly %s!", Monnam(mtmp), 419 !See_invisible ? "disappears" : "becomes transparent"); 420 mon_set_minvis(mtmp); 421 dmg = 0; 422 } else 423 impossible("no reason for monster to cast disappear spell?"); 424 break; 425 case MGC_STUN_YOU: 426 if (Antimagic || Free_action) { 427 shieldeff(u.ux, u.uy); 428 if (!Stunned) 429 You_feel("momentarily disoriented."); 430 make_stunned(1L, FALSE); 431 } else { 432 You(Stunned ? "struggle to keep your balance." : "reel..."); 433 dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4); 434 if (Half_spell_damage) dmg = (dmg + 1) / 2; 435 make_stunned(HStun + dmg, FALSE); 436 } 437 dmg = 0; 438 break; 439 case MGC_HASTE_SELF: 440 mon_adjust_speed(mtmp, 1, (struct obj *)0); 441 dmg = 0; 442 break; 443 case MGC_CURE_SELF: 444 if (mtmp->mhp < mtmp->mhpmax) { 445 if (canseemon(mtmp)) 446 pline("%s looks better.", Monnam(mtmp)); 447 /* note: player healing does 6d4; this used to do 1d8 */ 448 if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax) 449 mtmp->mhp = mtmp->mhpmax; 450 dmg = 0; 451 } 452 break; 453 case MGC_PSI_BOLT: 454 /* prior to 3.4.0 Antimagic was setting the damage to 1--this 455 made the spell virtually harmless to players with magic res. */ 456 if (Antimagic) { 457 shieldeff(u.ux, u.uy); 458 dmg = (dmg + 1) / 2; 459 } 460 if (dmg <= 5) 461 You("get a slight %sache.", body_part(HEAD)); 462 else if (dmg <= 10) 463 Your("brain is on fire!"); 464 else if (dmg <= 20) 465 Your("%s suddenly aches painfully!", body_part(HEAD)); 466 else 467 Your("%s suddenly aches very painfully!", body_part(HEAD)); 468 break; 469 default: 470 impossible("mcastu: invalid magic spell (%d)", spellnum); 471 dmg = 0; 472 break; 473 } 474 475 if (dmg) mdamageu(mtmp, dmg); 476} 477 478STATIC_OVL 479void 480cast_cleric_spell(mtmp, dmg, spellnum) 481struct monst *mtmp; 482int dmg; 483int spellnum; 484{ 485 if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) { 486 impossible("cast directed cleric spell (%d) with dmg=0?", spellnum); 487 return; 488 } 489 490 switch (spellnum) { 491 case CLC_GEYSER: 492 /* this is physical damage, not magical damage */ 493 pline("A sudden geyser slams into you from nowhere!"); 494 dmg = d(8, 6); 495 if (Half_physical_damage) dmg = (dmg + 1) / 2; 496 break; 497 case CLC_FIRE_PILLAR: 498 pline("A pillar of fire strikes all around you!"); 499 if (Fire_resistance) { 500 shieldeff(u.ux, u.uy); 501 dmg = 0; 502 } else 503 dmg = d(8, 6); 504 if (Half_spell_damage) dmg = (dmg + 1) / 2; 505 burn_away_slime(); 506 (void) burnarmor(&youmonst); 507 destroy_item(SCROLL_CLASS, AD_FIRE); 508 destroy_item(POTION_CLASS, AD_FIRE); 509 destroy_item(SPBOOK_CLASS, AD_FIRE); 510 (void) burn_floor_paper(u.ux, u.uy, TRUE, FALSE); 511 break; 512 case CLC_LIGHTNING: 513 { 514 boolean reflects; 515 516 pline("A bolt of lightning strikes down at you from above!"); 517 reflects = ureflects("It bounces off your %s%s.", ""); 518 if (reflects || Shock_resistance) { 519 shieldeff(u.ux, u.uy); 520 dmg = 0; 521 if (reflects) 522 break; 523 } else 524 dmg = d(8, 6); 525 if (Half_spell_damage) dmg = (dmg + 1) / 2; 526 destroy_item(WAND_CLASS, AD_ELEC); 527 destroy_item(RING_CLASS, AD_ELEC); 528 break; 529 } 530 case CLC_CURSE_ITEMS: 531 You_feel("as if you need some help."); 532 rndcurse(); 533 dmg = 0; 534 break; 535 case CLC_INSECTS: 536 { 537 /* Try for insects, and if there are none 538 left, go for (sticks to) snakes. -3. */ 539 struct permonst *pm = mkclass(S_ANT,0); 540 struct monst *mtmp2 = (struct monst *)0; 541 char let = (pm ? S_ANT : S_SNAKE); 542 boolean success; 543 int i; 544 coord bypos; 545 int quan; 546 547 quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2); 548 if (quan < 3) quan = 3; 549 success = pm ? TRUE : FALSE; 550 for (i = 0; i <= quan; i++) { 551 if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data)) 552 break; 553 if ((pm = mkclass(let,0)) != 0 && 554 (mtmp2 = makemon(pm, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { 555 success = TRUE; 556 mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0; 557 set_malign(mtmp2); 558 } 559 } 560 /* Not quite right: 561 * -- message doesn't always make sense for unseen caster (particularly 562 * the first message) 563 * -- message assumes plural monsters summoned (non-plural should be 564 * very rare, unlike in nasty()) 565 * -- message assumes plural monsters seen 566 */ 567 if (!success) 568 pline("%s casts at a clump of sticks, but nothing happens.", 569 Monnam(mtmp)); 570 else if (let == S_SNAKE) 571 pline("%s transforms a clump of sticks into snakes!", 572 Monnam(mtmp)); 573 else if (Invisible && !perceives(mtmp->data) && 574 (mtmp->mux != u.ux || mtmp->muy != u.uy)) 575 pline("%s summons insects around a spot near you!", 576 Monnam(mtmp)); 577 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) 578 pline("%s summons insects around your displaced image!", 579 Monnam(mtmp)); 580 else 581 pline("%s summons insects!", Monnam(mtmp)); 582 dmg = 0; 583 break; 584 } 585 case CLC_BLIND_YOU: 586 /* note: resists_blnd() doesn't apply here */ 587 if (!Blinded) { 588 int num_eyes = eyecount(youmonst.data); 589 pline("Scales cover your %s!", 590 (num_eyes == 1) ? 591 body_part(EYE) : makeplural(body_part(EYE))); 592 make_blinded(Half_spell_damage ? 100L : 200L, FALSE); 593 if (!Blind) Your(vision_clears); 594 dmg = 0; 595 } else 596 impossible("no reason for monster to cast blindness spell?"); 597 break; 598 case CLC_PARALYZE: 599 if (Antimagic || Free_action) { 600 shieldeff(u.ux, u.uy); 601 if (multi >= 0) 602 You("stiffen briefly."); 603 nomul(-1); 604 } else { 605 if (multi >= 0) 606 You("are frozen in place!"); 607 dmg = 4 + (int)mtmp->m_lev; 608 if (Half_spell_damage) dmg = (dmg + 1) / 2; 609 nomul(-dmg); 610 } 611 dmg = 0; 612 break; 613 case CLC_CONFUSE_YOU: 614 if (Antimagic) { 615 shieldeff(u.ux, u.uy); 616 You_feel("momentarily dizzy."); 617 } else { 618 boolean oldprop = !!Confusion; 619 620 dmg = (int)mtmp->m_lev; 621 if (Half_spell_damage) dmg = (dmg + 1) / 2; 622 make_confused(HConfusion + dmg, TRUE); 623 if (Hallucination) 624 You_feel("%s!", oldprop ? "trippier" : "trippy"); 625 else 626 You_feel("%sconfused!", oldprop ? "more " : ""); 627 } 628 dmg = 0; 629 break; 630 case CLC_CURE_SELF: 631 if (mtmp->mhp < mtmp->mhpmax) { 632 if (canseemon(mtmp)) 633 pline("%s looks better.", Monnam(mtmp)); 634 /* note: player healing does 6d4; this used to do 1d8 */ 635 if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax) 636 mtmp->mhp = mtmp->mhpmax; 637 dmg = 0; 638 } 639 break; 640 case CLC_OPEN_WOUNDS: 641 if (Antimagic) { 642 shieldeff(u.ux, u.uy); 643 dmg = (dmg + 1) / 2; 644 } 645 if (dmg <= 5) 646 Your("skin itches badly for a moment."); 647 else if (dmg <= 10) 648 pline("Wounds appear on your body!"); 649 else if (dmg <= 20) 650 pline("Severe wounds appear on your body!"); 651 else 652 Your("body is covered with painful wounds!"); 653 break; 654 default: 655 impossible("mcastu: invalid clerical spell (%d)", spellnum); 656 dmg = 0; 657 break; 658 } 659 660 if (dmg) mdamageu(mtmp, dmg); 661} 662 663STATIC_DCL 664boolean 665is_undirected_spell(adtyp, spellnum) 666unsigned int adtyp; 667int spellnum; 668{ 669 if (adtyp == AD_SPEL) { 670 switch (spellnum) { 671 case MGC_CLONE_WIZ: 672 case MGC_SUMMON_MONS: 673 case MGC_AGGRAVATION: 674 case MGC_DISAPPEAR: 675 case MGC_HASTE_SELF: 676 case MGC_CURE_SELF: 677 return TRUE; 678 default: 679 break; 680 } 681 } else if (adtyp == AD_CLRC) { 682 switch (spellnum) { 683 case CLC_INSECTS: 684 case CLC_CURE_SELF: 685 return TRUE; 686 default: 687 break; 688 } 689 } 690 return FALSE; 691} 692 693/* Some spells are useless under some circumstances. */ 694STATIC_DCL 695boolean 696spell_would_be_useless(mtmp, adtyp, spellnum) 697struct monst *mtmp; 698unsigned int adtyp; 699int spellnum; 700{ 701 /* Some spells don't require the player to really be there and can be cast 702 * by the monster when you're invisible, yet still shouldn't be cast when 703 * the monster doesn't even think you're there. 704 * This check isn't quite right because it always uses your real position. 705 * We really want something like "if the monster could see mux, muy". 706 */ 707 boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my); 708 709 if (adtyp == AD_SPEL) { 710 /* aggravate monsters, etc. won't be cast by peaceful monsters */ 711 if (mtmp->mpeaceful && (spellnum == MGC_AGGRAVATION || 712 spellnum == MGC_SUMMON_MONS || spellnum == MGC_CLONE_WIZ)) 713 return TRUE; 714 /* haste self when already fast */ 715 if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF) 716 return TRUE; 717 /* invisibility when already invisible */ 718 if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR) 719 return TRUE; 720 /* peaceful monster won't cast invisibility if you can't see invisible, 721 same as when monsters drink potions of invisibility. This doesn't 722 really make a lot of sense, but lets the player avoid hitting 723 peaceful monsters by mistake */ 724 if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR) 725 return TRUE; 726 /* healing when already healed */ 727 if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF) 728 return TRUE; 729 /* don't summon monsters if it doesn't think you're around */ 730 if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS || 731 (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ))) 732 return TRUE; 733 if ((!mtmp->iswiz || flags.no_of_wizards > 1) 734 && spellnum == MGC_CLONE_WIZ) 735 return TRUE; 736 } else if (adtyp == AD_CLRC) { 737 /* summon insects/sticks to snakes won't be cast by peaceful monsters */ 738 if (mtmp->mpeaceful && spellnum == CLC_INSECTS) 739 return TRUE; 740 /* healing when already healed */ 741 if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF) 742 return TRUE; 743 /* don't summon insects if it doesn't think you're around */ 744 if (!mcouldseeu && spellnum == CLC_INSECTS) 745 return TRUE; 746 /* blindness spell on blinded player */ 747 if (Blinded && spellnum == CLC_BLIND_YOU) 748 return TRUE; 749 } 750 return FALSE; 751} 752 753#endif /* OVLB */ 754#ifdef OVL0 755 756/* convert 1..10 to 0..9; add 10 for second group (spell casting) */ 757#define ad_to_typ(k) (10 + (int)k - 1) 758 759int 760buzzmu(mtmp, mattk) /* monster uses spell (ranged) */ 761 register struct monst *mtmp; 762 register struct attack *mattk; 763{ 764 /* don't print constant stream of curse messages for 'normal' 765 spellcasting monsters at range */ 766 if (mattk->adtyp > AD_SPC2) 767 return(0); 768 769 if (mtmp->mcan) { 770 cursetxt(mtmp, FALSE); 771 return(0); 772 } 773 if(lined_up(mtmp) && rn2(3)) { 774 nomul(0); 775 if(mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */ 776 if(canseemon(mtmp)) 777 pline("%s zaps you with a %s!", Monnam(mtmp), 778 flash_types[ad_to_typ(mattk->adtyp)]); 779 buzz(-ad_to_typ(mattk->adtyp), (int)mattk->damn, 780 mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); 781 } else impossible("Monster spell %d cast", mattk->adtyp-1); 782 } 783 return(1); 784} 785 786#endif /* OVL0 */ 787 788/*mcastu.c*/ 789