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