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