option parsing buffer overflow vulnerability
[aNetHack.git] / src / mcastu.c
blob06c084916cddd5e5246f07c57ad02880fa6a11c9
1 /* NetHack 3.6 mcastu.c $NHDT-Date: 1436753517 2015/07/13 02:11:57 $ $NHDT-Branch: master $:$NHDT-Revision: 1.44 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
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
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
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
40 FDECL(spell_would_be_useless, (struct monst *, unsigned int, int));
42 extern const char *const flash_types[]; /* from zap.c */
44 /* feedback when frustrated monster couldn't cast a spell */
45 STATIC_OVL
46 void
47 cursetxt(mtmp, undirected)
48 struct monst *mtmp;
49 boolean undirected;
51 if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
52 const char *point_msg; /* spellcasting monsters are impolite */
54 if (undirected)
55 point_msg = "all around, then curses";
56 else if ((Invis && !perceives(mtmp->data)
57 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
58 || is_obj_mappear(&youmonst, STRANGE_OBJECT)
59 || u.uundetected)
60 point_msg = "and curses in your general direction";
61 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
62 point_msg = "and curses at your displaced image";
63 else
64 point_msg = "at you, then curses";
66 pline("%s points %s.", Monnam(mtmp), point_msg);
67 } else if ((!(moves % 4) || !rn2(4))) {
68 if (!Deaf)
69 Norep("You hear a mumbled curse.");
73 /* convert a level based random selection into a specific mage spell;
74 inappropriate choices will be screened out by spell_would_be_useless() */
75 STATIC_OVL int
76 choose_magic_spell(spellval)
77 int spellval;
79 /* for 3.4.3 and earlier, val greater than 22 selected the default spell
81 while (spellval > 24 && rn2(25))
82 spellval = rn2(spellval);
84 switch (spellval) {
85 case 24:
86 case 23:
87 if (Antimagic || Hallucination)
88 return MGC_PSI_BOLT;
89 /* else FALL THROUGH */
90 case 22:
91 case 21:
92 case 20:
93 return MGC_DEATH_TOUCH;
94 case 19:
95 case 18:
96 return MGC_CLONE_WIZ;
97 case 17:
98 case 16:
99 case 15:
100 return MGC_SUMMON_MONS;
101 case 14:
102 case 13:
103 return MGC_AGGRAVATION;
104 case 12:
105 case 11:
106 case 10:
107 return MGC_CURSE_ITEMS;
108 case 9:
109 case 8:
110 return MGC_DESTRY_ARMR;
111 case 7:
112 case 6:
113 return MGC_WEAKEN_YOU;
114 case 5:
115 case 4:
116 return MGC_DISAPPEAR;
117 case 3:
118 return MGC_STUN_YOU;
119 case 2:
120 return MGC_HASTE_SELF;
121 case 1:
122 return MGC_CURE_SELF;
123 case 0:
124 default:
125 return MGC_PSI_BOLT;
129 /* convert a level based random selection into a specific cleric spell */
130 STATIC_OVL int
131 choose_clerical_spell(spellnum)
132 int spellnum;
134 /* for 3.4.3 and earlier, num greater than 13 selected the default spell
136 while (spellnum > 15 && rn2(16))
137 spellnum = rn2(spellnum);
139 switch (spellnum) {
140 case 15:
141 case 14:
142 if (rn2(3))
143 return CLC_OPEN_WOUNDS;
144 /* else FALL THROUGH */
145 case 13:
146 return CLC_GEYSER;
147 case 12:
148 return CLC_FIRE_PILLAR;
149 case 11:
150 return CLC_LIGHTNING;
151 case 10:
152 case 9:
153 return CLC_CURSE_ITEMS;
154 case 8:
155 return CLC_INSECTS;
156 case 7:
157 case 6:
158 return CLC_BLIND_YOU;
159 case 5:
160 case 4:
161 return CLC_PARALYZE;
162 case 3:
163 case 2:
164 return CLC_CONFUSE_YOU;
165 case 1:
166 return CLC_CURE_SELF;
167 case 0:
168 default:
169 return CLC_OPEN_WOUNDS;
173 /* return values:
174 * 1: successful spell
175 * 0: unsuccessful spell
178 castmu(mtmp, mattk, thinks_it_foundyou, foundyou)
179 register struct monst *mtmp;
180 register struct attack *mattk;
181 boolean thinks_it_foundyou;
182 boolean foundyou;
184 int dmg, ml = mtmp->m_lev;
185 int ret;
186 int spellnum = 0;
188 /* Three cases:
189 * -- monster is attacking you. Search for a useful spell.
190 * -- monster thinks it's attacking you. Search for a useful spell,
191 * without checking for undirected. If the spell found is directed,
192 * it fails with cursetxt() and loss of mspec_used.
193 * -- monster isn't trying to attack. Select a spell once. Don't keep
194 * searching; if that spell is not useful (or if it's directed),
195 * return and do something else.
196 * Since most spells are directed, this means that a monster that isn't
197 * attacking casts spells only a small portion of the time that an
198 * attacking monster does.
200 if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) {
201 int cnt = 40;
203 do {
204 spellnum = rn2(ml);
205 if (mattk->adtyp == AD_SPEL)
206 spellnum = choose_magic_spell(spellnum);
207 else
208 spellnum = choose_clerical_spell(spellnum);
209 /* not trying to attack? don't allow directed spells */
210 if (!thinks_it_foundyou) {
211 if (!is_undirected_spell(mattk->adtyp, spellnum)
212 || spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) {
213 if (foundyou)
214 impossible(
215 "spellcasting monster found you and doesn't know it?");
216 return 0;
218 break;
220 } while (--cnt > 0
221 && spell_would_be_useless(mtmp, mattk->adtyp, spellnum));
222 if (cnt == 0)
223 return 0;
226 /* monster unable to cast spells? */
227 if (mtmp->mcan || mtmp->mspec_used || !ml) {
228 cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum));
229 return (0);
232 if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) {
233 mtmp->mspec_used = 10 - mtmp->m_lev;
234 if (mtmp->mspec_used < 2)
235 mtmp->mspec_used = 2;
238 /* monster can cast spells, but is casting a directed spell at the
239 wrong place? If so, give a message, and return. Do this *after*
240 penalizing mspec_used. */
241 if (!foundyou && thinks_it_foundyou
242 && !is_undirected_spell(mattk->adtyp, spellnum)) {
243 pline("%s casts a spell at %s!",
244 canseemon(mtmp) ? Monnam(mtmp) : "Something",
245 levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water"
246 : "thin air");
247 return (0);
250 nomul(0);
251 if (rn2(ml * 10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */
252 if (canseemon(mtmp) && !Deaf)
253 pline_The("air crackles around %s.", mon_nam(mtmp));
254 return (0);
256 if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) {
257 pline("%s casts a spell%s!",
258 canspotmon(mtmp) ? Monnam(mtmp) : "Something",
259 is_undirected_spell(mattk->adtyp, spellnum)
260 ? ""
261 : (Invisible && !perceives(mtmp->data)
262 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
263 ? " at a spot near you"
264 : (Displaced
265 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
266 ? " at your displaced image"
267 : " at you");
271 * As these are spells, the damage is related to the level
272 * of the monster casting the spell.
274 if (!foundyou) {
275 dmg = 0;
276 if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) {
277 impossible(
278 "%s casting non-hand-to-hand version of hand-to-hand spell %d?",
279 Monnam(mtmp), mattk->adtyp);
280 return (0);
282 } else if (mattk->damd)
283 dmg = d((int) ((ml / 2) + mattk->damn), (int) mattk->damd);
284 else
285 dmg = d((int) ((ml / 2) + 1), 6);
286 if (Half_spell_damage)
287 dmg = (dmg + 1) / 2;
289 ret = 1;
291 switch (mattk->adtyp) {
292 case AD_FIRE:
293 pline("You're enveloped in flames.");
294 if (Fire_resistance) {
295 shieldeff(u.ux, u.uy);
296 pline("But you resist the effects.");
297 dmg = 0;
299 burn_away_slime();
300 break;
301 case AD_COLD:
302 pline("You're covered in frost.");
303 if (Cold_resistance) {
304 shieldeff(u.ux, u.uy);
305 pline("But you resist the effects.");
306 dmg = 0;
308 break;
309 case AD_MAGM:
310 You("are hit by a shower of missiles!");
311 if (Antimagic) {
312 shieldeff(u.ux, u.uy);
313 pline_The("missiles bounce off!");
314 dmg = 0;
315 } else
316 dmg = d((int) mtmp->m_lev / 2 + 1, 6);
317 break;
318 case AD_SPEL: /* wizard spell */
319 case AD_CLRC: /* clerical spell */
321 if (mattk->adtyp == AD_SPEL)
322 cast_wizard_spell(mtmp, dmg, spellnum);
323 else
324 cast_cleric_spell(mtmp, dmg, spellnum);
325 dmg = 0; /* done by the spell casting functions */
326 break;
329 if (dmg)
330 mdamageu(mtmp, dmg);
331 return (ret);
334 /* monster wizard and cleric spellcasting functions */
336 If dmg is zero, then the monster is not casting at you.
337 If the monster is intentionally not casting at you, we have previously
338 called spell_would_be_useless() and spellnum should always be a valid
339 undirected spell.
340 If you modify either of these, be sure to change is_undirected_spell()
341 and spell_would_be_useless().
343 STATIC_OVL
344 void
345 cast_wizard_spell(mtmp, dmg, spellnum)
346 struct monst *mtmp;
347 int dmg;
348 int spellnum;
350 if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) {
351 impossible("cast directed wizard spell (%d) with dmg=0?", spellnum);
352 return;
355 switch (spellnum) {
356 case MGC_DEATH_TOUCH:
357 pline("Oh no, %s's using the touch of death!", mhe(mtmp));
358 if (nonliving(youmonst.data) || is_demon(youmonst.data)) {
359 You("seem no deader than before.");
360 } else if (!Antimagic && rn2(mtmp->m_lev) > 12) {
361 if (Hallucination) {
362 You("have an out of body experience.");
363 } else {
364 killer.format = KILLED_BY_AN;
365 Strcpy(killer.name, "touch of death");
366 done(DIED);
368 } else {
369 if (Antimagic)
370 shieldeff(u.ux, u.uy);
371 pline("Lucky for you, it didn't work!");
373 dmg = 0;
374 break;
375 case MGC_CLONE_WIZ:
376 if (mtmp->iswiz && context.no_of_wizards == 1) {
377 pline("Double Trouble...");
378 clonewiz();
379 dmg = 0;
380 } else
381 impossible("bad wizard cloning?");
382 break;
383 case MGC_SUMMON_MONS: {
384 int count;
386 count = nasty(mtmp); /* summon something nasty */
387 if (mtmp->iswiz)
388 verbalize("Destroy the thief, my pet%s!", plur(count));
389 else {
390 const char *mappear =
391 (count == 1) ? "A monster appears" : "Monsters appear";
393 /* messages not quite right if plural monsters created but
394 only a single monster is seen */
395 if (Invisible && !perceives(mtmp->data)
396 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
397 pline("%s around a spot near you!", mappear);
398 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
399 pline("%s around your displaced image!", mappear);
400 else
401 pline("%s from nowhere!", mappear);
403 dmg = 0;
404 break;
406 case MGC_AGGRAVATION:
407 You_feel("that monsters are aware of your presence.");
408 aggravate();
409 dmg = 0;
410 break;
411 case MGC_CURSE_ITEMS:
412 You_feel("as if you need some help.");
413 rndcurse();
414 dmg = 0;
415 break;
416 case MGC_DESTRY_ARMR:
417 if (Antimagic) {
418 shieldeff(u.ux, u.uy);
419 pline("A field of force surrounds you!");
420 } else if (!destroy_arm(some_armor(&youmonst))) {
421 Your("skin itches.");
423 dmg = 0;
424 break;
425 case MGC_WEAKEN_YOU: /* drain strength */
426 if (Antimagic) {
427 shieldeff(u.ux, u.uy);
428 You_feel("momentarily weakened.");
429 } else {
430 You("suddenly feel weaker!");
431 dmg = mtmp->m_lev - 6;
432 if (Half_spell_damage)
433 dmg = (dmg + 1) / 2;
434 losestr(rnd(dmg));
435 if (u.uhp < 1)
436 done_in_by(mtmp, DIED);
438 dmg = 0;
439 break;
440 case MGC_DISAPPEAR: /* makes self invisible */
441 if (!mtmp->minvis && !mtmp->invis_blkd) {
442 if (canseemon(mtmp))
443 pline("%s suddenly %s!", Monnam(mtmp),
444 !See_invisible ? "disappears" : "becomes transparent");
445 mon_set_minvis(mtmp);
446 dmg = 0;
447 } else
448 impossible("no reason for monster to cast disappear spell?");
449 break;
450 case MGC_STUN_YOU:
451 if (Antimagic || Free_action) {
452 shieldeff(u.ux, u.uy);
453 if (!Stunned)
454 You_feel("momentarily disoriented.");
455 make_stunned(1L, FALSE);
456 } else {
457 You(Stunned ? "struggle to keep your balance." : "reel...");
458 dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
459 if (Half_spell_damage)
460 dmg = (dmg + 1) / 2;
461 make_stunned((HStun & TIMEOUT) + (long) dmg, FALSE);
463 dmg = 0;
464 break;
465 case MGC_HASTE_SELF:
466 mon_adjust_speed(mtmp, 1, (struct obj *) 0);
467 dmg = 0;
468 break;
469 case MGC_CURE_SELF:
470 if (mtmp->mhp < mtmp->mhpmax) {
471 if (canseemon(mtmp))
472 pline("%s looks better.", Monnam(mtmp));
473 /* note: player healing does 6d4; this used to do 1d8 */
474 if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax)
475 mtmp->mhp = mtmp->mhpmax;
476 dmg = 0;
478 break;
479 case MGC_PSI_BOLT:
480 /* prior to 3.4.0 Antimagic was setting the damage to 1--this
481 made the spell virtually harmless to players with magic res. */
482 if (Antimagic) {
483 shieldeff(u.ux, u.uy);
484 dmg = (dmg + 1) / 2;
486 if (dmg <= 5)
487 You("get a slight %sache.", body_part(HEAD));
488 else if (dmg <= 10)
489 Your("brain is on fire!");
490 else if (dmg <= 20)
491 Your("%s suddenly aches painfully!", body_part(HEAD));
492 else
493 Your("%s suddenly aches very painfully!", body_part(HEAD));
494 break;
495 default:
496 impossible("mcastu: invalid magic spell (%d)", spellnum);
497 dmg = 0;
498 break;
501 if (dmg)
502 mdamageu(mtmp, dmg);
505 STATIC_OVL
506 void
507 cast_cleric_spell(mtmp, dmg, spellnum)
508 struct monst *mtmp;
509 int dmg;
510 int spellnum;
512 if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) {
513 impossible("cast directed cleric spell (%d) with dmg=0?", spellnum);
514 return;
517 switch (spellnum) {
518 case CLC_GEYSER:
519 /* this is physical damage (force not heat),
520 * not magical damage or fire damage
522 pline("A sudden geyser slams into you from nowhere!");
523 dmg = d(8, 6);
524 if (Half_physical_damage)
525 dmg = (dmg + 1) / 2;
526 break;
527 case CLC_FIRE_PILLAR:
528 pline("A pillar of fire strikes all around you!");
529 if (Fire_resistance) {
530 shieldeff(u.ux, u.uy);
531 dmg = 0;
532 } else
533 dmg = d(8, 6);
534 if (Half_spell_damage)
535 dmg = (dmg + 1) / 2;
536 burn_away_slime();
537 (void) burnarmor(&youmonst);
538 destroy_item(SCROLL_CLASS, AD_FIRE);
539 destroy_item(POTION_CLASS, AD_FIRE);
540 destroy_item(SPBOOK_CLASS, AD_FIRE);
541 (void) burn_floor_objects(u.ux, u.uy, TRUE, FALSE);
542 break;
543 case CLC_LIGHTNING: {
544 boolean reflects;
546 pline("A bolt of lightning strikes down at you from above!");
547 reflects = ureflects("It bounces off your %s%s.", "");
548 if (reflects || Shock_resistance) {
549 shieldeff(u.ux, u.uy);
550 dmg = 0;
551 if (reflects)
552 break;
553 } else
554 dmg = d(8, 6);
555 if (Half_spell_damage)
556 dmg = (dmg + 1) / 2;
557 destroy_item(WAND_CLASS, AD_ELEC);
558 destroy_item(RING_CLASS, AD_ELEC);
559 (void) flashburn((long) rnd(100));
560 break;
562 case CLC_CURSE_ITEMS:
563 You_feel("as if you need some help.");
564 rndcurse();
565 dmg = 0;
566 break;
567 case CLC_INSECTS: {
568 /* Try for insects, and if there are none
569 left, go for (sticks to) snakes. -3. */
570 struct permonst *pm = mkclass(S_ANT, 0);
571 struct monst *mtmp2 = (struct monst *) 0;
572 char let = (pm ? S_ANT : S_SNAKE);
573 boolean success = FALSE, seecaster;
574 int i, quan, oldseen, newseen;
575 coord bypos;
576 const char *fmt;
578 oldseen = monster_census(TRUE);
579 quan = (mtmp->m_lev < 2) ? 1 : rnd((int) mtmp->m_lev / 2);
580 if (quan < 3)
581 quan = 3;
582 for (i = 0; i <= quan; i++) {
583 if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
584 break;
585 if ((pm = mkclass(let, 0)) != 0
586 && (mtmp2 = makemon(pm, bypos.x, bypos.y, MM_ANGRY)) != 0) {
587 success = TRUE;
588 mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
589 set_malign(mtmp2);
592 newseen = monster_census(TRUE);
594 /* not canspotmon(), which includes unseen things sensed via warning
596 seecaster = canseemon(mtmp) || tp_sensemon(mtmp) || Detect_monsters;
598 fmt = 0;
599 if (!seecaster) {
600 char *arg; /* [not const: upstart(N==1 ? an() : makeplural())] */
601 const char *what = (let == S_SNAKE) ? "snake" : "insect";
603 if (newseen <= oldseen || Unaware) {
604 /* unseen caster fails or summons unseen critters,
605 or unconscious hero ("You dream that you hear...") */
606 You_hear("someone summoning %s.", makeplural(what));
607 } else {
608 /* unseen caster summoned seen critter(s) */
609 arg = (newseen == oldseen + 1) ? an(what) : makeplural(what);
610 if (!Deaf)
611 You_hear("someone summoning something, and %s %s.", arg,
612 vtense(arg, "appear"));
613 else
614 pline("%s %s.", upstart(arg), vtense(arg, "appear"));
617 /* seen caster, possibly producing unseen--or just one--critters;
618 hero is told what the caster is doing and doesn't necessarily
619 observe complete accuracy of that caster's results (in other
620 words, no need to fuss with visibility or singularization;
621 player is told what's happening even if hero is unconscious) */
622 } else if (!success)
623 fmt = "%s casts at a clump of sticks, but nothing happens.";
624 else if (let == S_SNAKE)
625 fmt = "%s transforms a clump of sticks into snakes!";
626 else if (Invisible && !perceives(mtmp->data)
627 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
628 fmt = "%s summons insects around a spot near you!";
629 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
630 fmt = "%s summons insects around your displaced image!";
631 else
632 fmt = "%s summons insects!";
633 if (fmt)
634 pline(fmt, Monnam(mtmp));
636 dmg = 0;
637 break;
639 case CLC_BLIND_YOU:
640 /* note: resists_blnd() doesn't apply here */
641 if (!Blinded) {
642 int num_eyes = eyecount(youmonst.data);
643 pline("Scales cover your %s!", (num_eyes == 1)
644 ? body_part(EYE)
645 : makeplural(body_part(EYE)));
646 make_blinded(Half_spell_damage ? 100L : 200L, FALSE);
647 if (!Blind)
648 Your1(vision_clears);
649 dmg = 0;
650 } else
651 impossible("no reason for monster to cast blindness spell?");
652 break;
653 case CLC_PARALYZE:
654 if (Antimagic || Free_action) {
655 shieldeff(u.ux, u.uy);
656 if (multi >= 0)
657 You("stiffen briefly.");
658 nomul(-1);
659 multi_reason = "paralyzed by a monster";
660 } else {
661 if (multi >= 0)
662 You("are frozen in place!");
663 dmg = 4 + (int) mtmp->m_lev;
664 if (Half_spell_damage)
665 dmg = (dmg + 1) / 2;
666 nomul(-dmg);
667 multi_reason = "paralyzed by a monster";
669 nomovemsg = 0;
670 dmg = 0;
671 break;
672 case CLC_CONFUSE_YOU:
673 if (Antimagic) {
674 shieldeff(u.ux, u.uy);
675 You_feel("momentarily dizzy.");
676 } else {
677 boolean oldprop = !!Confusion;
679 dmg = (int) mtmp->m_lev;
680 if (Half_spell_damage)
681 dmg = (dmg + 1) / 2;
682 make_confused(HConfusion + dmg, TRUE);
683 if (Hallucination)
684 You_feel("%s!", oldprop ? "trippier" : "trippy");
685 else
686 You_feel("%sconfused!", oldprop ? "more " : "");
688 dmg = 0;
689 break;
690 case CLC_CURE_SELF:
691 if (mtmp->mhp < mtmp->mhpmax) {
692 if (canseemon(mtmp))
693 pline("%s looks better.", Monnam(mtmp));
694 /* note: player healing does 6d4; this used to do 1d8 */
695 if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax)
696 mtmp->mhp = mtmp->mhpmax;
697 dmg = 0;
699 break;
700 case CLC_OPEN_WOUNDS:
701 if (Antimagic) {
702 shieldeff(u.ux, u.uy);
703 dmg = (dmg + 1) / 2;
705 if (dmg <= 5)
706 Your("skin itches badly for a moment.");
707 else if (dmg <= 10)
708 pline("Wounds appear on your body!");
709 else if (dmg <= 20)
710 pline("Severe wounds appear on your body!");
711 else
712 Your("body is covered with painful wounds!");
713 break;
714 default:
715 impossible("mcastu: invalid clerical spell (%d)", spellnum);
716 dmg = 0;
717 break;
720 if (dmg)
721 mdamageu(mtmp, dmg);
724 STATIC_DCL
725 boolean
726 is_undirected_spell(adtyp, spellnum)
727 unsigned int adtyp;
728 int spellnum;
730 if (adtyp == AD_SPEL) {
731 switch (spellnum) {
732 case MGC_CLONE_WIZ:
733 case MGC_SUMMON_MONS:
734 case MGC_AGGRAVATION:
735 case MGC_DISAPPEAR:
736 case MGC_HASTE_SELF:
737 case MGC_CURE_SELF:
738 return TRUE;
739 default:
740 break;
742 } else if (adtyp == AD_CLRC) {
743 switch (spellnum) {
744 case CLC_INSECTS:
745 case CLC_CURE_SELF:
746 return TRUE;
747 default:
748 break;
751 return FALSE;
754 /* Some spells are useless under some circumstances. */
755 STATIC_DCL
756 boolean
757 spell_would_be_useless(mtmp, adtyp, spellnum)
758 struct monst *mtmp;
759 unsigned int adtyp;
760 int spellnum;
762 /* Some spells don't require the player to really be there and can be cast
763 * by the monster when you're invisible, yet still shouldn't be cast when
764 * the monster doesn't even think you're there.
765 * This check isn't quite right because it always uses your real position.
766 * We really want something like "if the monster could see mux, muy".
768 boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my);
770 if (adtyp == AD_SPEL) {
771 /* aggravate monsters, etc. won't be cast by peaceful monsters */
772 if (mtmp->mpeaceful
773 && (spellnum == MGC_AGGRAVATION || spellnum == MGC_SUMMON_MONS
774 || spellnum == MGC_CLONE_WIZ))
775 return TRUE;
776 /* haste self when already fast */
777 if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF)
778 return TRUE;
779 /* invisibility when already invisible */
780 if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR)
781 return TRUE;
782 /* peaceful monster won't cast invisibility if you can't see
783 invisible,
784 same as when monsters drink potions of invisibility. This doesn't
785 really make a lot of sense, but lets the player avoid hitting
786 peaceful monsters by mistake */
787 if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR)
788 return TRUE;
789 /* healing when already healed */
790 if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF)
791 return TRUE;
792 /* don't summon monsters if it doesn't think you're around */
793 if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS
794 || (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ)))
795 return TRUE;
796 if ((!mtmp->iswiz || context.no_of_wizards > 1)
797 && spellnum == MGC_CLONE_WIZ)
798 return TRUE;
799 /* aggravation (global wakeup) when everyone is already active */
800 if (spellnum == MGC_AGGRAVATION) {
801 /* if nothing needs to be awakened then this spell is useless
802 but caster might not realize that [chance to pick it then
803 must be very small otherwise caller's many retry attempts
804 will eventually end up picking it too often] */
805 if (!has_aggravatables(mtmp))
806 return rn2(100) ? TRUE : FALSE;
808 } else if (adtyp == AD_CLRC) {
809 /* summon insects/sticks to snakes won't be cast by peaceful monsters
811 if (mtmp->mpeaceful && spellnum == CLC_INSECTS)
812 return TRUE;
813 /* healing when already healed */
814 if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF)
815 return TRUE;
816 /* don't summon insects if it doesn't think you're around */
817 if (!mcouldseeu && spellnum == CLC_INSECTS)
818 return TRUE;
819 /* blindness spell on blinded player */
820 if (Blinded && spellnum == CLC_BLIND_YOU)
821 return TRUE;
823 return FALSE;
826 /* convert 1..10 to 0..9; add 10 for second group (spell casting) */
827 #define ad_to_typ(k) (10 + (int) k - 1)
829 /* monster uses spell (ranged) */
831 buzzmu(mtmp, mattk)
832 register struct monst *mtmp;
833 register struct attack *mattk;
835 /* don't print constant stream of curse messages for 'normal'
836 spellcasting monsters at range */
837 if (mattk->adtyp > AD_SPC2)
838 return (0);
840 if (mtmp->mcan) {
841 cursetxt(mtmp, FALSE);
842 return (0);
844 if (lined_up(mtmp) && rn2(3)) {
845 nomul(0);
846 if (mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */
847 if (canseemon(mtmp))
848 pline("%s zaps you with a %s!", Monnam(mtmp),
849 flash_types[ad_to_typ(mattk->adtyp)]);
850 buzz(-ad_to_typ(mattk->adtyp), (int) mattk->damn, mtmp->mx,
851 mtmp->my, sgn(tbx), sgn(tby));
852 } else
853 impossible("Monster spell %d cast", mattk->adtyp - 1);
855 return (1);
858 /*mcastu.c*/