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