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