Move getpos return values to header
[aNetHack.git] / src / mcastu.c
blobe2fdfad6633f54d788804c37e58e9063a1610bdc
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 if (cansee(mtmp->mx, mtmp->my) && !canspotmon(mtmp))
447 map_invisible(mtmp->mx, mtmp->my);
448 dmg = 0;
449 } else
450 impossible("no reason for monster to cast disappear spell?");
451 break;
452 case MGC_STUN_YOU:
453 if (Antimagic || Free_action) {
454 shieldeff(u.ux, u.uy);
455 if (!Stunned)
456 You_feel("momentarily disoriented.");
457 make_stunned(1L, FALSE);
458 } else {
459 You(Stunned ? "struggle to keep your balance." : "reel...");
460 dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
461 if (Half_spell_damage)
462 dmg = (dmg + 1) / 2;
463 make_stunned((HStun & TIMEOUT) + (long) dmg, FALSE);
465 dmg = 0;
466 break;
467 case MGC_HASTE_SELF:
468 mon_adjust_speed(mtmp, 1, (struct obj *) 0);
469 dmg = 0;
470 break;
471 case MGC_CURE_SELF:
472 if (mtmp->mhp < mtmp->mhpmax) {
473 if (canseemon(mtmp))
474 pline("%s looks better.", Monnam(mtmp));
475 /* note: player healing does 6d4; this used to do 1d8 */
476 if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax)
477 mtmp->mhp = mtmp->mhpmax;
478 dmg = 0;
480 break;
481 case MGC_PSI_BOLT:
482 /* prior to 3.4.0 Antimagic was setting the damage to 1--this
483 made the spell virtually harmless to players with magic res. */
484 if (Antimagic) {
485 shieldeff(u.ux, u.uy);
486 dmg = (dmg + 1) / 2;
488 if (dmg <= 5)
489 You("get a slight %sache.", body_part(HEAD));
490 else if (dmg <= 10)
491 Your("brain is on fire!");
492 else if (dmg <= 20)
493 Your("%s suddenly aches painfully!", body_part(HEAD));
494 else
495 Your("%s suddenly aches very painfully!", body_part(HEAD));
496 break;
497 default:
498 impossible("mcastu: invalid magic spell (%d)", spellnum);
499 dmg = 0;
500 break;
503 if (dmg)
504 mdamageu(mtmp, dmg);
507 STATIC_OVL
508 void
509 cast_cleric_spell(mtmp, dmg, spellnum)
510 struct monst *mtmp;
511 int dmg;
512 int spellnum;
514 if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) {
515 impossible("cast directed cleric spell (%d) with dmg=0?", spellnum);
516 return;
519 switch (spellnum) {
520 case CLC_GEYSER:
521 /* this is physical damage (force not heat),
522 * not magical damage or fire damage
524 pline("A sudden geyser slams into you from nowhere!");
525 dmg = d(8, 6);
526 if (Half_physical_damage)
527 dmg = (dmg + 1) / 2;
528 break;
529 case CLC_FIRE_PILLAR:
530 pline("A pillar of fire strikes all around you!");
531 if (Fire_resistance) {
532 shieldeff(u.ux, u.uy);
533 dmg = 0;
534 } else
535 dmg = d(8, 6);
536 if (Half_spell_damage)
537 dmg = (dmg + 1) / 2;
538 burn_away_slime();
539 (void) burnarmor(&youmonst);
540 destroy_item(SCROLL_CLASS, AD_FIRE);
541 destroy_item(POTION_CLASS, AD_FIRE);
542 destroy_item(SPBOOK_CLASS, AD_FIRE);
543 (void) burn_floor_objects(u.ux, u.uy, TRUE, FALSE);
544 break;
545 case CLC_LIGHTNING: {
546 boolean reflects;
548 pline("A bolt of lightning strikes down at you from above!");
549 reflects = ureflects("It bounces off your %s%s.", "");
550 if (reflects || Shock_resistance) {
551 shieldeff(u.ux, u.uy);
552 dmg = 0;
553 if (reflects)
554 break;
555 } else
556 dmg = d(8, 6);
557 if (Half_spell_damage)
558 dmg = (dmg + 1) / 2;
559 destroy_item(WAND_CLASS, AD_ELEC);
560 destroy_item(RING_CLASS, AD_ELEC);
561 (void) flashburn((long) rnd(100));
562 break;
564 case CLC_CURSE_ITEMS:
565 You_feel("as if you need some help.");
566 rndcurse();
567 dmg = 0;
568 break;
569 case CLC_INSECTS: {
570 /* Try for insects, and if there are none
571 left, go for (sticks to) snakes. -3. */
572 struct permonst *pm = mkclass(S_ANT, 0);
573 struct monst *mtmp2 = (struct monst *) 0;
574 char let = (pm ? S_ANT : S_SNAKE);
575 boolean success = FALSE, seecaster;
576 int i, quan, oldseen, newseen;
577 coord bypos;
578 const char *fmt;
580 oldseen = monster_census(TRUE);
581 quan = (mtmp->m_lev < 2) ? 1 : rnd((int) mtmp->m_lev / 2);
582 if (quan < 3)
583 quan = 3;
584 for (i = 0; i <= quan; i++) {
585 if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data))
586 break;
587 if ((pm = mkclass(let, 0)) != 0
588 && (mtmp2 = makemon(pm, bypos.x, bypos.y, MM_ANGRY)) != 0) {
589 success = TRUE;
590 mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0;
591 set_malign(mtmp2);
594 newseen = monster_census(TRUE);
596 /* not canspotmon(), which includes unseen things sensed via warning
598 seecaster = canseemon(mtmp) || tp_sensemon(mtmp) || Detect_monsters;
600 fmt = 0;
601 if (!seecaster) {
602 char *arg; /* [not const: upstart(N==1 ? an() : makeplural())] */
603 const char *what = (let == S_SNAKE) ? "snake" : "insect";
605 if (newseen <= oldseen || Unaware) {
606 /* unseen caster fails or summons unseen critters,
607 or unconscious hero ("You dream that you hear...") */
608 You_hear("someone summoning %s.", makeplural(what));
609 } else {
610 /* unseen caster summoned seen critter(s) */
611 arg = (newseen == oldseen + 1) ? an(what) : makeplural(what);
612 if (!Deaf)
613 You_hear("someone summoning something, and %s %s.", arg,
614 vtense(arg, "appear"));
615 else
616 pline("%s %s.", upstart(arg), vtense(arg, "appear"));
619 /* seen caster, possibly producing unseen--or just one--critters;
620 hero is told what the caster is doing and doesn't necessarily
621 observe complete accuracy of that caster's results (in other
622 words, no need to fuss with visibility or singularization;
623 player is told what's happening even if hero is unconscious) */
624 } else if (!success)
625 fmt = "%s casts at a clump of sticks, but nothing happens.";
626 else if (let == S_SNAKE)
627 fmt = "%s transforms a clump of sticks into snakes!";
628 else if (Invisible && !perceives(mtmp->data)
629 && (mtmp->mux != u.ux || mtmp->muy != u.uy))
630 fmt = "%s summons insects around a spot near you!";
631 else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
632 fmt = "%s summons insects around your displaced image!";
633 else
634 fmt = "%s summons insects!";
635 if (fmt)
636 pline(fmt, Monnam(mtmp));
638 dmg = 0;
639 break;
641 case CLC_BLIND_YOU:
642 /* note: resists_blnd() doesn't apply here */
643 if (!Blinded) {
644 int num_eyes = eyecount(youmonst.data);
645 pline("Scales cover your %s!", (num_eyes == 1)
646 ? body_part(EYE)
647 : makeplural(body_part(EYE)));
648 make_blinded(Half_spell_damage ? 100L : 200L, FALSE);
649 if (!Blind)
650 Your1(vision_clears);
651 dmg = 0;
652 } else
653 impossible("no reason for monster to cast blindness spell?");
654 break;
655 case CLC_PARALYZE:
656 if (Antimagic || Free_action) {
657 shieldeff(u.ux, u.uy);
658 if (multi >= 0)
659 You("stiffen briefly.");
660 nomul(-1);
661 multi_reason = "paralyzed by a monster";
662 } else {
663 if (multi >= 0)
664 You("are frozen in place!");
665 dmg = 4 + (int) mtmp->m_lev;
666 if (Half_spell_damage)
667 dmg = (dmg + 1) / 2;
668 nomul(-dmg);
669 multi_reason = "paralyzed by a monster";
671 nomovemsg = 0;
672 dmg = 0;
673 break;
674 case CLC_CONFUSE_YOU:
675 if (Antimagic) {
676 shieldeff(u.ux, u.uy);
677 You_feel("momentarily dizzy.");
678 } else {
679 boolean oldprop = !!Confusion;
681 dmg = (int) mtmp->m_lev;
682 if (Half_spell_damage)
683 dmg = (dmg + 1) / 2;
684 make_confused(HConfusion + dmg, TRUE);
685 if (Hallucination)
686 You_feel("%s!", oldprop ? "trippier" : "trippy");
687 else
688 You_feel("%sconfused!", oldprop ? "more " : "");
690 dmg = 0;
691 break;
692 case CLC_CURE_SELF:
693 if (mtmp->mhp < mtmp->mhpmax) {
694 if (canseemon(mtmp))
695 pline("%s looks better.", Monnam(mtmp));
696 /* note: player healing does 6d4; this used to do 1d8 */
697 if ((mtmp->mhp += d(3, 6)) > mtmp->mhpmax)
698 mtmp->mhp = mtmp->mhpmax;
699 dmg = 0;
701 break;
702 case CLC_OPEN_WOUNDS:
703 if (Antimagic) {
704 shieldeff(u.ux, u.uy);
705 dmg = (dmg + 1) / 2;
707 if (dmg <= 5)
708 Your("skin itches badly for a moment.");
709 else if (dmg <= 10)
710 pline("Wounds appear on your body!");
711 else if (dmg <= 20)
712 pline("Severe wounds appear on your body!");
713 else
714 Your("body is covered with painful wounds!");
715 break;
716 default:
717 impossible("mcastu: invalid clerical spell (%d)", spellnum);
718 dmg = 0;
719 break;
722 if (dmg)
723 mdamageu(mtmp, dmg);
726 STATIC_DCL
727 boolean
728 is_undirected_spell(adtyp, spellnum)
729 unsigned int adtyp;
730 int spellnum;
732 if (adtyp == AD_SPEL) {
733 switch (spellnum) {
734 case MGC_CLONE_WIZ:
735 case MGC_SUMMON_MONS:
736 case MGC_AGGRAVATION:
737 case MGC_DISAPPEAR:
738 case MGC_HASTE_SELF:
739 case MGC_CURE_SELF:
740 return TRUE;
741 default:
742 break;
744 } else if (adtyp == AD_CLRC) {
745 switch (spellnum) {
746 case CLC_INSECTS:
747 case CLC_CURE_SELF:
748 return TRUE;
749 default:
750 break;
753 return FALSE;
756 /* Some spells are useless under some circumstances. */
757 STATIC_DCL
758 boolean
759 spell_would_be_useless(mtmp, adtyp, spellnum)
760 struct monst *mtmp;
761 unsigned int adtyp;
762 int spellnum;
764 /* Some spells don't require the player to really be there and can be cast
765 * by the monster when you're invisible, yet still shouldn't be cast when
766 * the monster doesn't even think you're there.
767 * This check isn't quite right because it always uses your real position.
768 * We really want something like "if the monster could see mux, muy".
770 boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my);
772 if (adtyp == AD_SPEL) {
773 /* aggravate monsters, etc. won't be cast by peaceful monsters */
774 if (mtmp->mpeaceful
775 && (spellnum == MGC_AGGRAVATION || spellnum == MGC_SUMMON_MONS
776 || spellnum == MGC_CLONE_WIZ))
777 return TRUE;
778 /* haste self when already fast */
779 if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF)
780 return TRUE;
781 /* invisibility when already invisible */
782 if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR)
783 return TRUE;
784 /* peaceful monster won't cast invisibility if you can't see
785 invisible,
786 same as when monsters drink potions of invisibility. This doesn't
787 really make a lot of sense, but lets the player avoid hitting
788 peaceful monsters by mistake */
789 if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR)
790 return TRUE;
791 /* healing when already healed */
792 if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF)
793 return TRUE;
794 /* don't summon monsters if it doesn't think you're around */
795 if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS
796 || (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ)))
797 return TRUE;
798 if ((!mtmp->iswiz || context.no_of_wizards > 1)
799 && spellnum == MGC_CLONE_WIZ)
800 return TRUE;
801 /* aggravation (global wakeup) when everyone is already active */
802 if (spellnum == MGC_AGGRAVATION) {
803 /* if nothing needs to be awakened then this spell is useless
804 but caster might not realize that [chance to pick it then
805 must be very small otherwise caller's many retry attempts
806 will eventually end up picking it too often] */
807 if (!has_aggravatables(mtmp))
808 return rn2(100) ? TRUE : FALSE;
810 } else if (adtyp == AD_CLRC) {
811 /* summon insects/sticks to snakes won't be cast by peaceful monsters
813 if (mtmp->mpeaceful && spellnum == CLC_INSECTS)
814 return TRUE;
815 /* healing when already healed */
816 if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF)
817 return TRUE;
818 /* don't summon insects if it doesn't think you're around */
819 if (!mcouldseeu && spellnum == CLC_INSECTS)
820 return TRUE;
821 /* blindness spell on blinded player */
822 if (Blinded && spellnum == CLC_BLIND_YOU)
823 return TRUE;
825 return FALSE;
828 /* convert 1..10 to 0..9; add 10 for second group (spell casting) */
829 #define ad_to_typ(k) (10 + (int) k - 1)
831 /* monster uses spell (ranged) */
833 buzzmu(mtmp, mattk)
834 register struct monst *mtmp;
835 register struct attack *mattk;
837 /* don't print constant stream of curse messages for 'normal'
838 spellcasting monsters at range */
839 if (mattk->adtyp > AD_SPC2)
840 return (0);
842 if (mtmp->mcan) {
843 cursetxt(mtmp, FALSE);
844 return (0);
846 if (lined_up(mtmp) && rn2(3)) {
847 nomul(0);
848 if (mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */
849 if (canseemon(mtmp))
850 pline("%s zaps you with a %s!", Monnam(mtmp),
851 flash_types[ad_to_typ(mattk->adtyp)]);
852 buzz(-ad_to_typ(mattk->adtyp), (int) mattk->damn, mtmp->mx,
853 mtmp->my, sgn(tbx), sgn(tby));
854 } else
855 impossible("Monster spell %d cast", mattk->adtyp - 1);
857 return (1);
860 /*mcastu.c*/