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*/