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