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, 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 /*static char sccsid[] = "from: @(#)spec_hit.c 5.3 (Berkeley) 6/1/90";*/ 39 static char rcsid[] = "$Id: spec_hit.c,v 1.2 1993/08/01 18:52:12 mycroft Exp $"; 40 #endif /* not lint */ 41 42 /* 43 * special_hit.c 44 * 45 * This source herein may be modified and/or distributed by anybody who 46 * so desires, with the following restrictions: 47 * 1.) No portion of this notice shall be removed. 48 * 2.) Credit shall not be taken for the creation of this source. 49 * 3.) This code is not to be traded, sold, or used for personal 50 * gain or profit. 51 * 52 */ 53 54 #include "rogue.h" 55 56 short less_hp = 0; 57 boolean being_held; 58 59 extern short cur_level, max_level, blind, levitate, ring_exp; 60 extern long level_points[]; 61 extern boolean detect_monster, mon_disappeared; 62 extern boolean sustain_strength, maintain_armor; 63 extern char *you_can_move_again; 64 65 special_hit(monster) 66 object *monster; 67 { 68 if ((monster->m_flags & CONFUSED) && rand_percent(66)) { 69 return; 70 } 71 if (monster->m_flags & RUSTS) { 72 rust(monster); 73 } 74 if ((monster->m_flags & HOLDS) && !levitate) { 75 being_held = 1; 76 } 77 if (monster->m_flags & FREEZES) { 78 freeze(monster); 79 } 80 if (monster->m_flags & STINGS) { 81 sting(monster); 82 } 83 if (monster->m_flags & DRAINS_LIFE) { 84 drain_life(); 85 } 86 if (monster->m_flags & DROPS_LEVEL) { 87 drop_level(); 88 } 89 if (monster->m_flags & STEALS_GOLD) { 90 steal_gold(monster); 91 } else if (monster->m_flags & STEALS_ITEM) { 92 steal_item(monster); 93 } 94 } 95 96 rust(monster) 97 object *monster; 98 { 99 if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) || 100 (rogue.armor->which_kind == LEATHER)) { 101 return; 102 } 103 if ((rogue.armor->is_protected) || maintain_armor) { 104 if (monster && (!(monster->m_flags & RUST_VANISHED))) { 105 message("the rust vanishes instantly", 0); 106 monster->m_flags |= RUST_VANISHED; 107 } 108 } else { 109 rogue.armor->d_enchant--; 110 message("your armor weakens", 0); 111 print_stats(STAT_ARMOR); 112 } 113 } 114 115 freeze(monster) 116 object *monster; 117 { 118 short freeze_percent = 99; 119 short i, n; 120 121 if (rand_percent(12)) { 122 return; 123 } 124 freeze_percent -= (rogue.str_current+(rogue.str_current / 2)); 125 freeze_percent -= ((rogue.exp + ring_exp) * 4); 126 freeze_percent -= (get_armor_class(rogue.armor) * 5); 127 freeze_percent -= (rogue.hp_max / 3); 128 129 if (freeze_percent > 10) { 130 monster->m_flags |= FREEZING_ROGUE; 131 message("you are frozen", 1); 132 133 n = get_rand(4, 8); 134 for (i = 0; i < n; i++) { 135 mv_mons(); 136 } 137 if (rand_percent(freeze_percent)) { 138 for (i = 0; i < 50; i++) { 139 mv_mons(); 140 } 141 killed_by((object *)0, HYPOTHERMIA); 142 } 143 message(you_can_move_again, 1); 144 monster->m_flags &= (~FREEZING_ROGUE); 145 } 146 } 147 148 steal_gold(monster) 149 object *monster; 150 { 151 int amount; 152 153 if ((rogue.gold <= 0) || rand_percent(10)) { 154 return; 155 } 156 157 amount = get_rand((cur_level * 10), (cur_level * 30)); 158 159 if (amount > rogue.gold) { 160 amount = rogue.gold; 161 } 162 rogue.gold -= amount; 163 message("your purse feels lighter", 0); 164 print_stats(STAT_GOLD); 165 disappear(monster); 166 } 167 168 steal_item(monster) 169 object *monster; 170 { 171 object *obj; 172 short i, n, t; 173 char desc[80]; 174 boolean has_something = 0; 175 176 if (rand_percent(15)) { 177 return; 178 } 179 obj = rogue.pack.next_object; 180 181 if (!obj) { 182 goto DSPR; 183 } 184 while (obj) { 185 if (!(obj->in_use_flags & BEING_USED)) { 186 has_something = 1; 187 break; 188 } 189 obj = obj->next_object; 190 } 191 if (!has_something) { 192 goto DSPR; 193 } 194 n = get_rand(0, MAX_PACK_COUNT); 195 obj = rogue.pack.next_object; 196 197 for (i = 0; i <= n; i++) { 198 obj = obj->next_object; 199 while ((!obj) || (obj->in_use_flags & BEING_USED)) { 200 if (!obj) { 201 obj = rogue.pack.next_object; 202 } else { 203 obj = obj->next_object; 204 } 205 } 206 } 207 (void) strcpy(desc, "she stole "); 208 if (obj->what_is != WEAPON) { 209 t = obj->quantity; 210 obj->quantity = 1; 211 } 212 get_desc(obj, desc+10); 213 message(desc, 0); 214 215 obj->quantity = ((obj->what_is != WEAPON) ? t : 1); 216 217 vanish(obj, 0, &rogue.pack); 218 DSPR: 219 disappear(monster); 220 } 221 222 disappear(monster) 223 object *monster; 224 { 225 short row, col; 226 227 row = monster->row; 228 col = monster->col; 229 230 dungeon[row][col] &= ~MONSTER; 231 if (rogue_can_see(row, col)) { 232 mvaddch(row, col, get_dungeon_char(row, col)); 233 } 234 take_from_pack(monster, &level_monsters); 235 free_object(monster); 236 mon_disappeared = 1; 237 } 238 239 cough_up(monster) 240 object *monster; 241 { 242 object *obj; 243 short row, col, i, n; 244 245 if (cur_level < max_level) { 246 return; 247 } 248 249 if (monster->m_flags & STEALS_GOLD) { 250 obj = alloc_object(); 251 obj->what_is = GOLD; 252 obj->quantity = get_rand((cur_level * 15), (cur_level * 30)); 253 } else { 254 if (!rand_percent((int) monster->drop_percent)) { 255 return; 256 } 257 obj = gr_object(); 258 } 259 row = monster->row; 260 col = monster->col; 261 262 for (n = 0; n <= 5; n++) { 263 for (i = -n; i <= n; i++) { 264 if (try_to_cough(row+n, col+i, obj)) { 265 return; 266 } 267 if (try_to_cough(row-n, col+i, obj)) { 268 return; 269 } 270 } 271 for (i = -n; i <= n; i++) { 272 if (try_to_cough(row+i, col-n, obj)) { 273 return; 274 } 275 if (try_to_cough(row+i, col+n, obj)) { 276 return; 277 } 278 } 279 } 280 free_object(obj); 281 } 282 283 try_to_cough(row, col, obj) 284 short row, col; 285 object *obj; 286 { 287 if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) { 288 return(0); 289 } 290 if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) && 291 (dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) { 292 place_at(obj, row, col); 293 if (((row != rogue.row) || (col != rogue.col)) && 294 (!(dungeon[row][col] & MONSTER))) { 295 mvaddch(row, col, get_dungeon_char(row, col)); 296 } 297 return(1); 298 } 299 return(0); 300 } 301 302 seek_gold(monster) 303 object *monster; 304 { 305 short i, j, rn, s; 306 307 if ((rn = get_room_number(monster->row, monster->col)) < 0) { 308 return(0); 309 } 310 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) { 311 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) { 312 if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) { 313 monster->m_flags |= CAN_FLIT; 314 s = mon_can_go(monster, i, j); 315 monster->m_flags &= (~CAN_FLIT); 316 if (s) { 317 move_mon_to(monster, i, j); 318 monster->m_flags |= ASLEEP; 319 monster->m_flags &= (~(WAKENS | SEEKS_GOLD)); 320 return(1); 321 } 322 monster->m_flags &= (~SEEKS_GOLD); 323 monster->m_flags |= CAN_FLIT; 324 mv_1_monster(monster, i, j); 325 monster->m_flags &= (~CAN_FLIT); 326 monster->m_flags |= SEEKS_GOLD; 327 return(1); 328 } 329 } 330 } 331 return(0); 332 } 333 334 gold_at(row, col) 335 short row, col; 336 { 337 if (dungeon[row][col] & OBJECT) { 338 object *obj; 339 340 if ((obj = object_at(&level_objects, row, col)) && 341 (obj->what_is == GOLD)) { 342 return(1); 343 } 344 } 345 return(0); 346 } 347 348 check_gold_seeker(monster) 349 object *monster; 350 { 351 monster->m_flags &= (~SEEKS_GOLD); 352 } 353 354 check_imitator(monster) 355 object *monster; 356 { 357 char msg[80]; 358 359 if (monster->m_flags & IMITATES) { 360 wake_up(monster); 361 if (!blind) { 362 mvaddch(monster->row, monster->col, 363 get_dungeon_char(monster->row, monster->col)); 364 check_message(); 365 sprintf(msg, "wait, that's a %s!", mon_name(monster)); 366 message(msg, 1); 367 } 368 return(1); 369 } 370 return(0); 371 } 372 373 imitating(row, col) 374 register short row, col; 375 { 376 if (dungeon[row][col] & MONSTER) { 377 object *object_at(), *monster; 378 379 if (monster = object_at(&level_monsters, row, col)) { 380 if (monster->m_flags & IMITATES) { 381 return(1); 382 } 383 } 384 } 385 return(0); 386 } 387 388 sting(monster) 389 object *monster; 390 { 391 short sting_chance = 35; 392 char msg[80]; 393 394 if ((rogue.str_current <= 3) || sustain_strength) { 395 return; 396 } 397 sting_chance += (6 * (6 - get_armor_class(rogue.armor))); 398 399 if ((rogue.exp + ring_exp) > 8) { 400 sting_chance -= (6 * ((rogue.exp + ring_exp) - 8)); 401 } 402 if (rand_percent(sting_chance)) { 403 sprintf(msg, "the %s's bite has weakened you", 404 mon_name(monster)); 405 message(msg, 0); 406 rogue.str_current--; 407 print_stats(STAT_STRENGTH); 408 } 409 } 410 411 drop_level() 412 { 413 int hp; 414 415 if (rand_percent(80) || (rogue.exp <= 5)) { 416 return; 417 } 418 rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29); 419 rogue.exp -= 2; 420 hp = hp_raise(); 421 if ((rogue.hp_current -= hp) <= 0) { 422 rogue.hp_current = 1; 423 } 424 if ((rogue.hp_max -= hp) <= 0) { 425 rogue.hp_max = 1; 426 } 427 add_exp(1, 0); 428 } 429 430 drain_life() 431 { 432 short n; 433 434 if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) { 435 return; 436 } 437 n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */ 438 439 if ((n != 2) || (!sustain_strength)) { 440 message("you feel weaker", 0); 441 } 442 if (n != 2) { 443 rogue.hp_max--; 444 rogue.hp_current--; 445 less_hp++; 446 } 447 if (n != 1) { 448 if ((rogue.str_current > 3) && (!sustain_strength)) { 449 rogue.str_current--; 450 if (coin_toss()) { 451 rogue.str_max--; 452 } 453 } 454 } 455 print_stats((STAT_STRENGTH | STAT_HP)); 456 } 457 458 m_confuse(monster) 459 object *monster; 460 { 461 char msg[80]; 462 463 if (!rogue_can_see(monster->row, monster->col)) { 464 return(0); 465 } 466 if (rand_percent(45)) { 467 monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */ 468 return(0); 469 } 470 if (rand_percent(55)) { 471 monster->m_flags &= (~CONFUSES); 472 sprintf(msg, "the gaze of the %s has confused you", mon_name(monster)); 473 message(msg, 1); 474 cnfs(); 475 return(1); 476 } 477 return(0); 478 } 479 480 flame_broil(monster) 481 object *monster; 482 { 483 short row, col, dir; 484 485 if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) { 486 return(0); 487 } 488 row = rogue.row - monster->row; 489 col = rogue.col - monster->col; 490 if (row < 0) { 491 row = -row; 492 } 493 if (col < 0) { 494 col = -col; 495 } 496 if (((row != 0) && (col != 0) && (row != col)) || 497 ((row > 7) || (col > 7))) { 498 return(0); 499 } 500 dir = get_dir(monster->row, monster->col, row, col); 501 bounce(FIRE, dir, monster->row, monster->col, 0); 502 503 return(1); 504 } 505 506 get_dir(srow, scol, drow, dcol) 507 short srow, scol, drow, dcol; 508 { 509 if (srow == drow) { 510 if (scol < dcol) { 511 return(RIGHT); 512 } else { 513 return(LEFT); 514 } 515 } 516 if (scol == dcol) { 517 if (srow < drow) { 518 return(DOWN); 519 } else { 520 return(UPWARD); 521 } 522 } 523 if ((srow > drow) && (scol > dcol)) { 524 return(UPLEFT); 525 } 526 if ((srow < drow) && (scol < dcol)) { 527 return(DOWNRIGHT); 528 } 529 if ((srow < drow) && (scol > dcol)) { 530 return(DOWNLEFT); 531 } 532 /*if ((srow > drow) && (scol < dcol)) {*/ 533 return(UPRIGHT); 534 /*}*/ 535 } 536