| 1 | /* |
| 2 | * zap.c |
| 3 | * |
| 4 | * This source herein may be modified and/or distributed by anybody who |
| 5 | * so desires, with the following restrictions: |
| 6 | * 1.) No portion of this notice shall be removed. |
| 7 | * 2.) Credit shall not be taken for the creation of this source. |
| 8 | * 3.) This code is not to be traded, sold, or used for personal |
| 9 | * gain or profit. |
| 10 | * |
| 11 | */ |
| 12 | |
| 13 | #ifndef lint |
| 14 | static char sccsid[] = "@(#)zap.c 5.1 (Berkeley) %G%"; |
| 15 | #endif /* not lint */ |
| 16 | |
| 17 | #include "rogue.h" |
| 18 | |
| 19 | boolean wizard = 0; |
| 20 | |
| 21 | extern boolean being_held, score_only, detect_monster; |
| 22 | extern short cur_room; |
| 23 | |
| 24 | zapp() |
| 25 | { |
| 26 | short wch; |
| 27 | boolean first_miss = 1; |
| 28 | object *wand; |
| 29 | short dir, d, row, col; |
| 30 | object *monster; |
| 31 | |
| 32 | while (!is_direction(dir = rgetchar(), &d)) { |
| 33 | sound_bell(); |
| 34 | if (first_miss) { |
| 35 | message("direction? ", 0); |
| 36 | first_miss = 0; |
| 37 | } |
| 38 | } |
| 39 | check_message(); |
| 40 | if (dir == CANCEL) { |
| 41 | return; |
| 42 | } |
| 43 | if ((wch = pack_letter("zap with what?", WAND)) == CANCEL) { |
| 44 | return; |
| 45 | } |
| 46 | check_message(); |
| 47 | |
| 48 | if (!(wand = get_letter_object(wch))) { |
| 49 | message("no such item.", 0); |
| 50 | return; |
| 51 | } |
| 52 | if (wand->what_is != WAND) { |
| 53 | message("you can't zap with that", 0); |
| 54 | return; |
| 55 | } |
| 56 | if (wand->class <= 0) { |
| 57 | message("nothing happens", 0); |
| 58 | } else { |
| 59 | wand->class--; |
| 60 | row = rogue.row; col = rogue.col; |
| 61 | if ((wand->which_kind == COLD) || (wand->which_kind == FIRE)) { |
| 62 | bounce((short) wand->which_kind, d, row, col, 0); |
| 63 | } else { |
| 64 | monster = get_zapped_monster(d, &row, &col); |
| 65 | if (wand->which_kind == DRAIN_LIFE) { |
| 66 | wdrain_life(monster); |
| 67 | } else if (monster) { |
| 68 | wake_up(monster); |
| 69 | s_con_mon(monster); |
| 70 | zap_monster(monster, wand->which_kind); |
| 71 | relight(); |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | (void) reg_move(); |
| 76 | } |
| 77 | |
| 78 | object * |
| 79 | get_zapped_monster(dir, row, col) |
| 80 | short dir; |
| 81 | short *row, *col; |
| 82 | { |
| 83 | short orow, ocol; |
| 84 | |
| 85 | for (;;) { |
| 86 | orow = *row; ocol = *col; |
| 87 | get_dir_rc(dir, row, col, 0); |
| 88 | if (((*row == orow) && (*col == ocol)) || |
| 89 | (dungeon[*row][*col] & (HORWALL | VERTWALL)) || |
| 90 | (dungeon[*row][*col] == NOTHING)) { |
| 91 | return(0); |
| 92 | } |
| 93 | if (dungeon[*row][*col] & MONSTER) { |
| 94 | if (!imitating(*row, *col)) { |
| 95 | return(object_at(&level_monsters, *row, *col)); |
| 96 | } |
| 97 | } |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | zap_monster(monster, kind) |
| 102 | object *monster; |
| 103 | unsigned short kind; |
| 104 | { |
| 105 | short row, col; |
| 106 | object *nm; |
| 107 | short tc; |
| 108 | |
| 109 | row = monster->row; |
| 110 | col = monster->col; |
| 111 | |
| 112 | switch(kind) { |
| 113 | case SLOW_MONSTER: |
| 114 | if (monster->m_flags & HASTED) { |
| 115 | monster->m_flags &= (~HASTED); |
| 116 | } else { |
| 117 | monster->slowed_toggle = 0; |
| 118 | monster->m_flags |= SLOWED; |
| 119 | } |
| 120 | break; |
| 121 | case HASTE_MONSTER: |
| 122 | if (monster->m_flags & SLOWED) { |
| 123 | monster->m_flags &= (~SLOWED); |
| 124 | } else { |
| 125 | monster->m_flags |= HASTED; |
| 126 | } |
| 127 | break; |
| 128 | case TELE_AWAY: |
| 129 | tele_away(monster); |
| 130 | break; |
| 131 | case INVISIBILITY: |
| 132 | monster->m_flags |= INVISIBLE; |
| 133 | break; |
| 134 | case POLYMORPH: |
| 135 | if (monster->m_flags & HOLDS) { |
| 136 | being_held = 0; |
| 137 | } |
| 138 | nm = monster->next_monster; |
| 139 | tc = monster->trail_char; |
| 140 | (void) gr_monster(monster, get_rand(0, MONSTERS-1)); |
| 141 | monster->row = row; |
| 142 | monster->col = col; |
| 143 | monster->next_monster = nm; |
| 144 | monster->trail_char = tc; |
| 145 | if (!(monster->m_flags & IMITATES)) { |
| 146 | wake_up(monster); |
| 147 | } |
| 148 | break; |
| 149 | case MAGIC_MISSILE: |
| 150 | rogue_hit(monster, 1); |
| 151 | break; |
| 152 | case CANCELLATION: |
| 153 | if (monster->m_flags & HOLDS) { |
| 154 | being_held = 0; |
| 155 | } |
| 156 | if (monster->m_flags & STEALS_ITEM) { |
| 157 | monster->drop_percent = 0; |
| 158 | } |
| 159 | monster->m_flags &= (~(FLIES | FLITS | SPECIAL_HIT | INVISIBLE | |
| 160 | FLAMES | IMITATES | CONFUSES | SEEKS_GOLD | HOLDS)); |
| 161 | break; |
| 162 | case DO_NOTHING: |
| 163 | message("nothing happens", 0); |
| 164 | break; |
| 165 | } |
| 166 | } |
| 167 | |
| 168 | tele_away(monster) |
| 169 | object *monster; |
| 170 | { |
| 171 | short row, col; |
| 172 | |
| 173 | if (monster->m_flags & HOLDS) { |
| 174 | being_held = 0; |
| 175 | } |
| 176 | gr_row_col(&row, &col, (FLOOR | TUNNEL | STAIRS | OBJECT)); |
| 177 | mvaddch(monster->row, monster->col, monster->trail_char); |
| 178 | dungeon[monster->row][monster->col] &= ~MONSTER; |
| 179 | monster->row = row; monster->col = col; |
| 180 | dungeon[row][col] |= MONSTER; |
| 181 | monster->trail_char = mvinch(row, col); |
| 182 | if (detect_monster || rogue_can_see(row, col)) { |
| 183 | mvaddch(row, col, gmc(monster)); |
| 184 | } |
| 185 | } |
| 186 | |
| 187 | wizardize() |
| 188 | { |
| 189 | char buf[100]; |
| 190 | |
| 191 | if (wizard) { |
| 192 | wizard = 0; |
| 193 | message("not wizard anymore", 0); |
| 194 | } else { |
| 195 | if (get_input_line("wizard's password:", "", buf, "", 0, 0)) { |
| 196 | (void) xxx(1); |
| 197 | xxxx(buf, strlen(buf)); |
| 198 | if (!strncmp(buf, "\247\104\126\272\115\243\027", 7)) { |
| 199 | wizard = 1; |
| 200 | score_only = 1; |
| 201 | message("Welcome, mighty wizard!", 0); |
| 202 | } else { |
| 203 | message("sorry", 0); |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | wdrain_life(monster) |
| 210 | object *monster; |
| 211 | { |
| 212 | short hp; |
| 213 | object *lmon, *nm; |
| 214 | |
| 215 | hp = rogue.hp_current / 3; |
| 216 | rogue.hp_current = (rogue.hp_current + 1) / 2; |
| 217 | |
| 218 | if (cur_room >= 0) { |
| 219 | lmon = level_monsters.next_monster; |
| 220 | while (lmon) { |
| 221 | nm = lmon->next_monster; |
| 222 | if (get_room_number(lmon->row, lmon->col) == cur_room) { |
| 223 | wake_up(lmon); |
| 224 | (void) mon_damage(lmon, hp); |
| 225 | } |
| 226 | lmon = nm; |
| 227 | } |
| 228 | } else { |
| 229 | if (monster) { |
| 230 | wake_up(monster); |
| 231 | (void) mon_damage(monster, hp); |
| 232 | } |
| 233 | } |
| 234 | print_stats(STAT_HP); |
| 235 | relight(); |
| 236 | } |
| 237 | |
| 238 | bounce(ball, dir, row, col, r) |
| 239 | short ball, dir, row, col, r; |
| 240 | { |
| 241 | short orow, ocol; |
| 242 | char buf[DCOLS], *s; |
| 243 | short i, ch, new_dir = -1, damage; |
| 244 | static short btime; |
| 245 | |
| 246 | if (++r == 1) { |
| 247 | btime = get_rand(3, 6); |
| 248 | } else if (r > btime) { |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | if (ball == FIRE) { |
| 253 | s = "fire"; |
| 254 | } else { |
| 255 | s = "ice"; |
| 256 | } |
| 257 | if (r > 1) { |
| 258 | sprintf(buf, "the %s bounces", s); |
| 259 | message(buf, 0); |
| 260 | } |
| 261 | orow = row; |
| 262 | ocol = col; |
| 263 | do { |
| 264 | ch = mvinch(orow, ocol); |
| 265 | standout(); |
| 266 | mvaddch(orow, ocol, ch); |
| 267 | get_dir_rc(dir, &orow, &ocol, 1); |
| 268 | } while (!( (ocol <= 0) || |
| 269 | (ocol >= DCOLS-1) || |
| 270 | (dungeon[orow][ocol] == NOTHING) || |
| 271 | (dungeon[orow][ocol] & MONSTER) || |
| 272 | (dungeon[orow][ocol] & (HORWALL | VERTWALL)) || |
| 273 | ((orow == rogue.row) && (ocol == rogue.col)))); |
| 274 | standend(); |
| 275 | refresh(); |
| 276 | do { |
| 277 | orow = row; |
| 278 | ocol = col; |
| 279 | ch = mvinch(row, col); |
| 280 | mvaddch(row, col, ch); |
| 281 | get_dir_rc(dir, &row, &col, 1); |
| 282 | } while (!( (col <= 0) || |
| 283 | (col >= DCOLS-1) || |
| 284 | (dungeon[row][col] == NOTHING) || |
| 285 | (dungeon[row][col] & MONSTER) || |
| 286 | (dungeon[row][col] & (HORWALL | VERTWALL)) || |
| 287 | ((row == rogue.row) && (col == rogue.col)))); |
| 288 | |
| 289 | if (dungeon[row][col] & MONSTER) { |
| 290 | object *monster; |
| 291 | |
| 292 | monster = object_at(&level_monsters, row, col); |
| 293 | |
| 294 | wake_up(monster); |
| 295 | if (rand_percent(33)) { |
| 296 | sprintf(buf, "the %s misses the %s", s, mon_name(monster)); |
| 297 | message(buf, 0); |
| 298 | goto ND; |
| 299 | } |
| 300 | if (ball == FIRE) { |
| 301 | if (!(monster->m_flags & RUSTS)) { |
| 302 | if (monster->m_flags & FREEZES) { |
| 303 | damage = monster->hp_to_kill; |
| 304 | } else if (monster->m_flags & FLAMES) { |
| 305 | damage = (monster->hp_to_kill / 10) + 1; |
| 306 | } else { |
| 307 | damage = get_rand((rogue.hp_current / 3), rogue.hp_max); |
| 308 | } |
| 309 | } else { |
| 310 | damage = (monster->hp_to_kill / 2) + 1; |
| 311 | } |
| 312 | sprintf(buf, "the %s hits the %s", s, mon_name(monster)); |
| 313 | message(buf, 0); |
| 314 | (void) mon_damage(monster, damage); |
| 315 | } else { |
| 316 | damage = -1; |
| 317 | if (!(monster->m_flags & FREEZES)) { |
| 318 | if (rand_percent(33)) { |
| 319 | message("the monster is frozen", 0); |
| 320 | monster->m_flags |= (ASLEEP | NAPPING); |
| 321 | monster->nap_length = get_rand(3, 6); |
| 322 | } else { |
| 323 | damage = rogue.hp_current / 4; |
| 324 | } |
| 325 | } else { |
| 326 | damage = -2; |
| 327 | } |
| 328 | if (damage != -1) { |
| 329 | sprintf(buf, "the %s hits the %s", s, mon_name(monster)); |
| 330 | message(buf, 0); |
| 331 | (void) mon_damage(monster, damage); |
| 332 | } |
| 333 | } |
| 334 | } else if ((row == rogue.row) && (col == rogue.col)) { |
| 335 | if (rand_percent(10 + (3 * get_armor_class(rogue.armor)))) { |
| 336 | sprintf(buf, "the %s misses", s); |
| 337 | message(buf, 0); |
| 338 | goto ND; |
| 339 | } else { |
| 340 | damage = get_rand(3, (3 * rogue.exp)); |
| 341 | if (ball == FIRE) { |
| 342 | damage = (damage * 3) / 2; |
| 343 | damage -= get_armor_class(rogue.armor); |
| 344 | } |
| 345 | sprintf(buf, "the %s hits", s); |
| 346 | rogue_damage(damage, (object *) 0, |
| 347 | ((ball == FIRE) ? KFIRE : HYPOTHERMIA)); |
| 348 | message(buf, 0); |
| 349 | } |
| 350 | } else { |
| 351 | short nrow, ncol; |
| 352 | |
| 353 | ND: for (i = 0; i < 10; i++) { |
| 354 | dir = get_rand(0, DIRS-1); |
| 355 | nrow = orow; |
| 356 | ncol = ocol; |
| 357 | get_dir_rc(dir, &nrow, &ncol, 1); |
| 358 | if (((ncol >= 0) && (ncol <= DCOLS-1)) && |
| 359 | (dungeon[nrow][ncol] != NOTHING) && |
| 360 | (!(dungeon[nrow][ncol] & (VERTWALL | HORWALL)))) { |
| 361 | new_dir = dir; |
| 362 | break; |
| 363 | } |
| 364 | } |
| 365 | if (new_dir != -1) { |
| 366 | bounce(ball, new_dir, orow, ocol, r); |
| 367 | } |
| 368 | } |
| 369 | } |