OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / mcastu.c
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
33 STATIC_DCL void FDECL(cursetxt,(struct monst *,BOOLEAN_P));
34 STATIC_DCL int FDECL(choose_magic_spell, (int));
35 STATIC_DCL int FDECL(choose_clerical_spell, (int));
36 STATIC_DCL void FDECL(cast_wizard_spell,(struct monst *, int,int));
37 STATIC_DCL void FDECL(cast_cleric_spell,(struct monst *, int,int));
38 STATIC_DCL boolean FDECL(is_undirected_spell,(unsigned int,int));
39 STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,unsigned int,int));
40
41 #ifdef OVL0
42
43 extern const char * const flash_types[];        /* from zap.c */
44
45 /* feedback when frustrated monster couldn't cast a spell */
46 STATIC_OVL
47 void
48 cursetxt(mtmp, undirected)
49 struct monst *mtmp;
50 boolean 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() */
79 STATIC_OVL int
80 choose_magic_spell(spellval)
81 int 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 */
124 STATIC_OVL int
125 choose_clerical_spell(spellnum)
126 int 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  */
161 int
162 castmu(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  */
319 STATIC_OVL
320 void
321 cast_wizard_spell(mtmp, dmg, spellnum)
322 struct monst *mtmp;
323 int dmg;
324 int 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
478 STATIC_OVL
479 void
480 cast_cleric_spell(mtmp, dmg, spellnum)
481 struct monst *mtmp;
482 int dmg;
483 int 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
663 STATIC_DCL
664 boolean
665 is_undirected_spell(adtyp, spellnum)
666 unsigned int adtyp;
667 int 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. */
694 STATIC_DCL
695 boolean
696 spell_would_be_useless(mtmp, adtyp, spellnum)
697 struct monst *mtmp;
698 unsigned int adtyp;
699 int 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
759 int
760 buzzmu(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*/