1    | /*	SCCS Id: @(#)mcastu.c	3.3	97/11/02	*/
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    | STATIC_DCL void FDECL(cursetxt,(struct monst *));
8    | 
9    | #ifdef OVL0
10   | 
11   | extern const char *flash_types[];	/* from zap.c */
12   | 
13   | /* feedback when frustrated monster couldn't cast a spell */
14   | STATIC_OVL
15   | void
16   | cursetxt(mtmp)
17   | struct monst *mtmp;
18   | {
19   | 	if (canseemon(mtmp)) {
20   | 	    const char *point_msg;  /* spellcasting monsters are impolite */
21   | 
22   | 	    if ((Invis && !perceives(mtmp->data) &&
23   | 			(mtmp->mux != u.ux || mtmp->muy != u.uy)) ||
24   | 		    (youmonst.m_ap_type == M_AP_OBJECT &&
25   | 			youmonst.mappearance == STRANGE_OBJECT) ||
26   | 		    u.uundetected)
27   | 		point_msg = "and curses in your general direction";
28   | 	    else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy))
29   | 		point_msg = "and curses at your displaced image";
30   | 	    else
31   | 		point_msg = "at you, then curses";
32   | 
33   | 	    pline("%s points %s.", Monnam(mtmp), point_msg);
34   | 	} else if ((!(moves % 4) || !rn2(4))) {
35   | 	    if (flags.soundok) Norep("You hear a mumbled curse.");
36   | 	}
37   | }
38   | 
39   | #endif /* OVL0 */
40   | #ifdef OVLB
41   | 
42   | int
43   | castmu(mtmp, mattk)	/* monster casts spell at you */
44   | 	register struct monst *mtmp;
45   | 	register struct attack *mattk;
46   | {
47   | 	int	dmg, ml = mtmp->m_lev;
48   | 
49   | 	if(mtmp->mcan || mtmp->mspec_used || !ml) {  /* could not attack */
50   | 	    cursetxt(mtmp);
51   | 	    return(0);
52   | 	} else {
53   | 	    nomul(0);
54   | 	    if(rn2(ml*10) < (mtmp->mconf ? 100 : 20)) {	/* fumbled attack */
55   | 		if (canseemon(mtmp) && flags.soundok)
56   | 		    pline_The("air crackles around %s.", mon_nam(mtmp));
57   | 		return(0);
58   | 	    }
59   | 	}
60   | /*
61   |  *	As these are spells, the damage is related to the level
62   |  *	of the monster casting the spell.
63   |  */
64   | 	if (mattk->damd)
65   | 		dmg = d((int)((ml/3) + mattk->damn), (int)mattk->damd);
66   | 	else dmg = d((int)((ml/3) + 1), 6);
67   | 	if (Half_spell_damage) dmg = (dmg+1) / 2;
68   | 
69   | 	switch(mattk->adtyp)   {
70   | 
71   | 	    case AD_FIRE:
72   | 		pline("You're enveloped in flames.");
73   | 		if(Fire_resistance) {
74   | 			shieldeff(u.ux, u.uy);
75   | 			pline("But you resist the effects.");
76   | 			dmg = 0;
77   | 		}
78   | 		burn_away_slime();
79   | 		break;
80   | 	    case AD_COLD:
81   | 		pline("You're covered in frost.");
82   | 		if(Cold_resistance) {
83   | 			shieldeff(u.ux, u.uy);
84   | 			pline("But you resist the effects.");
85   | 			dmg = 0;
86   | 		}
87   | 		break;
88   | 	    case AD_MAGM:
89   | 		You("are hit by a shower of missiles!");
90   | 		if(Antimagic) {
91   | 			shieldeff(u.ux, u.uy);
92   | 			pline_The("missiles bounce off!");
93   | 			dmg = 0;
94   | 		} else dmg = d((int)mtmp->m_lev/2 + 1,6);
95   | 		break;
96   | 	    case AD_SPEL:	/* random spell */
97   | 
98   | 		mtmp->mspec_used = 10 - mtmp->m_lev;
99   | 		if (mtmp->mspec_used < 2) mtmp->mspec_used = 2;
100  | 		switch(rn2((int)mtmp->m_lev)) {
101  | 		    case 22:
102  | 		    case 21:
103  | 		    case 20:
104  | 			pline("Oh no, %s's using the touch of death!",
105  | 			      humanoid(mtmp->data)
106  | 				  ? (mtmp->female ? "she" : "he")
107  | 				  : "it"
108  | 			     );
109  | 			if (nonliving(youmonst.data) || is_demon(youmonst.data))
110  | 			    You("seem no deader than before.");
111  | 			else if (!Antimagic && rn2(ml) > 12) {
112  | 
113  | 			    if(Hallucination)
114  | 				You("have an out of body experience.");
115  | 			    else  {
116  | 				killer_format = KILLED_BY_AN;
117  | 				killer = "touch of death";
118  | 				done(DIED);
119  | 			    }
120  | 			} else {
121  | 				if(Antimagic) shieldeff(u.ux, u.uy);
122  | 				pline("Lucky for you, it didn't work!");
123  | 			}
124  | 			dmg = 0;
125  | 			break;
126  | 		    case 19:
127  | 		    case 18:
128  | 			if(mtmp->iswiz && flags.no_of_wizards == 1) {
129  | 				pline("Double Trouble...");
130  | 				clonewiz();
131  | 				dmg = 0;
132  | 				break;
133  | 			} /* else fall into the next case */
134  | 		    case 17:
135  | 		    case 16:
136  | 		    case 15:
137  | 			if(mtmp->iswiz)
138  | 			    verbalize("Destroy the thief, my pets!");
139  | 			nasty(mtmp);	/* summon something nasty */
140  | 			/* fall into the next case */
141  | 		    case 14:		/* aggravate all monsters */
142  | 		    case 13:
143  | 			aggravate();
144  | 			dmg = 0;
145  | 			break;
146  | 		    case 12:		/* curse random items */
147  | 		    case 11:
148  | 		    case 10:
149  | 			rndcurse();
150  | 			dmg = 0;
151  | 			break;
152  | 		    case 9:
153  | 		    case 8:		/* destroy armor */
154  | 			if (Antimagic) {
155  | 				shieldeff(u.ux, u.uy);
156  | 				pline("A field of force surrounds you!");
157  | 			} else if(!destroy_arm(some_armor(&youmonst)))
158  | 				Your("skin itches.");
159  | 			dmg = 0;
160  | 			break;
161  | 		    case 7:
162  | 		    case 6:		/* drain strength */
163  | 			if(Antimagic) {
164  | 			    shieldeff(u.ux, u.uy);
165  | 			    You_feel("momentarily weakened.");
166  | 			} else {
167  | 			    You("suddenly feel weaker!");
168  | 			    dmg = ml - 6;
169  | 			    if(Half_spell_damage) dmg = (dmg+1) / 2;
170  | 			    losestr(rnd(dmg));
171  | 			    if(u.uhp < 1)
172  | 				done_in_by(mtmp);
173  | 			}
174  | 			dmg = 0;
175  | 			break;
176  | 		    case 5:		/* make invisible if not */
177  | 		    case 4:
178  | 			if (!mtmp->minvis && !mtmp->invis_blkd) {
179  | 			    if(canseemon(mtmp) && !See_invisible)
180  | 				pline("%s suddenly disappears!", Monnam(mtmp));
181  | 			    mon_set_minvis(mtmp);
182  | 			    dmg = 0;
183  | 			    break;
184  | 			} /* else fall into the next case */
185  | 		    case 3:		/* stun */
186  | 			if (Antimagic || Free_action) {
187  | 			    shieldeff(u.ux, u.uy);
188  | 			    if(!Stunned)
189  | 				You_feel("momentarily disoriented.");
190  | 			    make_stunned(1L, FALSE);
191  | 			} else {
192  | 			    if (Stunned)
193  | 				You("struggle to keep your balance.");
194  | 			    else
195  | 				You("reel...");
196  | 			    dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4);
197  | 			    if(Half_spell_damage) dmg = (dmg+1) / 2;
198  | 			    make_stunned(HStun + dmg, FALSE);
199  | 			}
200  | 			dmg = 0;
201  | 			break;
202  | 		    case 2:		/* haste self */
203  | 			mon_adjust_speed(mtmp, 1);
204  | 			dmg = 0;
205  | 			break;
206  | 		    case 1:		/* cure self */
207  | 			if(mtmp->mhp < mtmp->mhpmax) {
208  | 			    if((mtmp->mhp += rnd(8)) > mtmp->mhpmax)
209  | 				mtmp->mhp = mtmp->mhpmax;
210  | 			    dmg = 0;
211  | 			    break;
212  | 			} /* else fall through to default case */
213  | 		    default:		/* psi bolt */
214  | 			if(Antimagic) {
215  | 			    shieldeff(u.ux, u.uy);
216  | 			    You("get a slight %sache.",body_part(HEAD));
217  | 			    dmg = 1;
218  | 			} else {
219  | 			    if (dmg <= 10)
220  | 				Your("brain is on fire!");
221  | 			    else Your("%s suddenly aches!", body_part(HEAD));
222  | 			}
223  | 			break;
224  | 		}
225  | 		break;
226  | 
227  | 	    case AD_CLRC:	/* clerical spell */
228  | 		mtmp->mspec_used = 10 - mtmp->m_lev;
229  | 		if (mtmp->mspec_used < 2) mtmp->mspec_used = 2;
230  | 		switch(rn2((int)mtmp->m_lev)) {
231  | 		    /* Other ideas: lightning bolts, towers of flame,
232  | 				    gush of water  -3. */
233  | 
234  | 		    default:		/* confuse */
235  | 			if(Antimagic) {
236  | 			    shieldeff(u.ux, u.uy);
237  | 			    You_feel("momentarily dizzy.");
238  | 			} else {
239  | 			    dmg = (int)mtmp->m_lev;
240  | 			    if(Half_spell_damage) dmg = (dmg+1) / 2;
241  | 			    make_confused(HConfusion + dmg, TRUE);
242  | 			}
243  | 			dmg = 0;
244  | 			break;
245  | 		    case 12:		/* curse random items */
246  | 		    case 11:
247  | 		    case 10:
248  | 			rndcurse();
249  | 			dmg = 0;
250  | 			break;
251  | 		    case 9:
252  | 		    case 8:		/* insects */
253  | 			/* Try for insects, and if there are none
254  | 			   left, go for (sticks to) snakes.  -3. */
255  | 			{
256  | 			int i;
257  | 			struct permonst *pm = mkclass(S_ANT,0);
258  | 			struct monst *mtmp2;
259  | 			char let = (pm ? S_ANT : S_SNAKE);
260  | 
261  | 			for (i = 0; i <= (int) mtmp->m_lev; i++)
262  | 			   if ((pm = mkclass(let,0)) &&
263  | 			(mtmp2 = makemon(pm, u.ux, u.uy, NO_MM_FLAGS))) {
264  | 				mtmp2->msleeping = mtmp2->mpeaceful =
265  | 					mtmp2->mtame = 0;
266  | 				set_malign(mtmp2);
267  | 			    }
268  | 			}
269  | 			dmg = 0;
270  | 			break;
271  | 		    case 6:
272  | 		    case 7:		/* blindness */
273  | 			/* note: resists_blnd() doesn't apply here */
274  | 			if (!Blinded) {
275  | 			    pline("Scales cover your %s!", makeplural(body_part(EYE)));
276  | 			    make_blinded(Half_spell_damage ? 100L:200L, FALSE);
277  | 			    dmg = 0;
278  | 			    break;
279  | 			}
280  | 		    case 4:
281  | 		    case 5:		/* wound */
282  | 			if(Antimagic) {
283  | 			    shieldeff(u.ux, u.uy);
284  | 			    Your("skin itches badly for a moment.");
285  | 			    dmg = 0;
286  | 			} else {
287  | 			    pline("Wounds appear on your body!");
288  | 			    dmg = d(2,8) + 1;
289  | 			    if (Half_spell_damage) dmg = (dmg+1) / 2;
290  | 			}
291  | 			break;
292  | 		    case 3:		/* hold */
293  | 			if (Antimagic || Free_action) {
294  | 			    shieldeff(u.ux, u.uy);
295  | 			    if(multi >= 0)
296  | 				You("stiffen briefly.");
297  | 			    nomul(-1);
298  | 			} else {
299  | 			    if (multi >= 0)
300  | 				You("are frozen in place!");
301  | 			    dmg = 4 + (int)mtmp->m_lev;
302  | 			    if (Half_spell_damage) dmg = (dmg+1) / 2;
303  | 			    nomul(-dmg);
304  | 			}
305  | 			dmg = 0;
306  | 			break;
307  | 		    case 2:
308  | 		    case 1:		/* cure self */
309  | 			if(mtmp->mhp < mtmp->mhpmax) {
310  | 			    if((mtmp->mhp += rnd(8)) > mtmp->mhpmax)
311  | 				mtmp->mhp = mtmp->mhpmax;
312  | 			    dmg = 0;
313  | 			    break;
314  | 			} /* else fall through to default case */
315  | 		}
316  | 	}
317  | 	if(dmg) mdamageu(mtmp, dmg);
318  | 	return(1);
319  | }
320  | 
321  | #endif /* OVLB */
322  | #ifdef OVL0
323  | 
324  | /* convert 1..10 to 0..9; add 10 for second group (spell casting) */
325  | #define ad_to_typ(k) (10 + (int)k - 1)
326  | 
327  | int
328  | buzzmu(mtmp, mattk)		/* monster uses spell (ranged) */
329  | 	register struct monst *mtmp;
330  | 	register struct attack  *mattk;
331  | {
332  | 	if(mtmp->mcan || mattk->adtyp > AD_SPC2) {
333  | 	    cursetxt(mtmp);
334  | 	    return(0);
335  | 	}
336  | 	if(lined_up(mtmp) && rn2(3)) {
337  | 	    nomul(0);
338  | 	    if(mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */
339  | 		if(canseemon(mtmp))
340  | 		    pline("%s zaps you with a %s!", Monnam(mtmp),
341  | 			  flash_types[ad_to_typ(mattk->adtyp)]);
342  | 		buzz(-ad_to_typ(mattk->adtyp), (int)mattk->damn,
343  | 		     mtmp->mx, mtmp->my, sgn(tbx), sgn(tby));
344  | 	    } else impossible("Monster spell %d cast", mattk->adtyp-1);
345  | 	}
346  | 	return(1);
347  | }
348  | 
349  | #endif /* OVL0 */
350  | 
351  | /*mcastu.c*/