1 /* $NetBSD: spec_hit.c,v 1.4 1997/10/12 11:46:04 lukem 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[] = "@(#)spec_hit.c 8.1 (Berkeley) 5/31/93"; 43 #else 44 __RCSID("$NetBSD: spec_hit.c,v 1.4 1997/10/12 11:46:04 lukem Exp $"); 45 #endif 46 #endif /* not lint */ 47 48 /* 49 * special_hit.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 short less_hp = 0; 63 boolean being_held; 64 65 void 66 special_hit(monster) 67 object *monster; 68 { 69 if ((monster->m_flags & CONFUSED) && rand_percent(66)) { 70 return; 71 } 72 if (monster->m_flags & RUSTS) { 73 rust(monster); 74 } 75 if ((monster->m_flags & HOLDS) && !levitate) { 76 being_held = 1; 77 } 78 if (monster->m_flags & FREEZES) { 79 freeze(monster); 80 } 81 if (monster->m_flags & STINGS) { 82 sting(monster); 83 } 84 if (monster->m_flags & DRAINS_LIFE) { 85 drain_life(); 86 } 87 if (monster->m_flags & DROPS_LEVEL) { 88 drop_level(); 89 } 90 if (monster->m_flags & STEALS_GOLD) { 91 steal_gold(monster); 92 } else if (monster->m_flags & STEALS_ITEM) { 93 steal_item(monster); 94 } 95 } 96 97 void 98 rust(monster) 99 object *monster; 100 { 101 if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) || 102 (rogue.armor->which_kind == LEATHER)) { 103 return; 104 } 105 if ((rogue.armor->is_protected) || maintain_armor) { 106 if (monster && (!(monster->m_flags & RUST_VANISHED))) { 107 message("the rust vanishes instantly", 0); 108 monster->m_flags |= RUST_VANISHED; 109 } 110 } else { 111 rogue.armor->d_enchant--; 112 message("your armor weakens", 0); 113 print_stats(STAT_ARMOR); 114 } 115 } 116 117 void 118 freeze(monster) 119 object *monster; 120 { 121 short freeze_percent = 99; 122 short i, n; 123 124 if (rand_percent(12)) { 125 return; 126 } 127 freeze_percent -= (rogue.str_current+(rogue.str_current / 2)); 128 freeze_percent -= ((rogue.exp + ring_exp) * 4); 129 freeze_percent -= (get_armor_class(rogue.armor) * 5); 130 freeze_percent -= (rogue.hp_max / 3); 131 132 if (freeze_percent > 10) { 133 monster->m_flags |= FREEZING_ROGUE; 134 message("you are frozen", 1); 135 136 n = get_rand(4, 8); 137 for (i = 0; i < n; i++) { 138 mv_mons(); 139 } 140 if (rand_percent(freeze_percent)) { 141 for (i = 0; i < 50; i++) { 142 mv_mons(); 143 } 144 killed_by((object *)0, HYPOTHERMIA); 145 } 146 message(you_can_move_again, 1); 147 monster->m_flags &= (~FREEZING_ROGUE); 148 } 149 } 150 151 void 152 steal_gold(monster) 153 object *monster; 154 { 155 int amount; 156 157 if ((rogue.gold <= 0) || rand_percent(10)) { 158 return; 159 } 160 161 amount = get_rand((cur_level * 10), (cur_level * 30)); 162 163 if (amount > rogue.gold) { 164 amount = rogue.gold; 165 } 166 rogue.gold -= amount; 167 message("your purse feels lighter", 0); 168 print_stats(STAT_GOLD); 169 disappear(monster); 170 } 171 172 void 173 steal_item(monster) 174 object *monster; 175 { 176 object *obj; 177 short i, n, t = 0; 178 char desc[80]; 179 boolean has_something = 0; 180 181 if (rand_percent(15)) { 182 return; 183 } 184 obj = rogue.pack.next_object; 185 186 if (!obj) { 187 goto DSPR; 188 } 189 while (obj) { 190 if (!(obj->in_use_flags & BEING_USED)) { 191 has_something = 1; 192 break; 193 } 194 obj = obj->next_object; 195 } 196 if (!has_something) { 197 goto DSPR; 198 } 199 n = get_rand(0, MAX_PACK_COUNT); 200 obj = rogue.pack.next_object; 201 202 for (i = 0; i <= n; i++) { 203 obj = obj->next_object; 204 while ((!obj) || (obj->in_use_flags & BEING_USED)) { 205 if (!obj) { 206 obj = rogue.pack.next_object; 207 } else { 208 obj = obj->next_object; 209 } 210 } 211 } 212 (void) strcpy(desc, "she stole "); 213 if (obj->what_is != WEAPON) { 214 t = obj->quantity; 215 obj->quantity = 1; 216 } 217 get_desc(obj, desc+10); 218 message(desc, 0); 219 220 obj->quantity = ((obj->what_is != WEAPON) ? t : 1); 221 222 vanish(obj, 0, &rogue.pack); 223 DSPR: 224 disappear(monster); 225 } 226 227 void 228 disappear(monster) 229 object *monster; 230 { 231 short row, col; 232 233 row = monster->row; 234 col = monster->col; 235 236 dungeon[row][col] &= ~MONSTER; 237 if (rogue_can_see(row, col)) { 238 mvaddch(row, col, get_dungeon_char(row, col)); 239 } 240 take_from_pack(monster, &level_monsters); 241 free_object(monster); 242 mon_disappeared = 1; 243 } 244 245 void 246 cough_up(monster) 247 object *monster; 248 { 249 object *obj; 250 short row, col, i, n; 251 252 if (cur_level < max_level) { 253 return; 254 } 255 256 if (monster->m_flags & STEALS_GOLD) { 257 obj = alloc_object(); 258 obj->what_is = GOLD; 259 obj->quantity = get_rand((cur_level * 15), (cur_level * 30)); 260 } else { 261 if (!rand_percent((int) monster->drop_percent)) { 262 return; 263 } 264 obj = gr_object(); 265 } 266 row = monster->row; 267 col = monster->col; 268 269 for (n = 0; n <= 5; n++) { 270 for (i = -n; i <= n; i++) { 271 if (try_to_cough(row+n, col+i, obj)) { 272 return; 273 } 274 if (try_to_cough(row-n, col+i, obj)) { 275 return; 276 } 277 } 278 for (i = -n; i <= n; i++) { 279 if (try_to_cough(row+i, col-n, obj)) { 280 return; 281 } 282 if (try_to_cough(row+i, col+n, obj)) { 283 return; 284 } 285 } 286 } 287 free_object(obj); 288 } 289 290 boolean 291 try_to_cough(row, col, obj) 292 short row, col; 293 object *obj; 294 { 295 if ((row < MIN_ROW) || 296 (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) { 297 return(0); 298 } 299 if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) && 300 (dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) { 301 place_at(obj, row, col); 302 if (((row != rogue.row) || (col != rogue.col)) && 303 (!(dungeon[row][col] & MONSTER))) { 304 mvaddch(row, col, get_dungeon_char(row, col)); 305 } 306 return(1); 307 } 308 return(0); 309 } 310 311 boolean 312 seek_gold(monster) 313 object *monster; 314 { 315 short i, j, rn, s; 316 317 if ((rn = get_room_number(monster->row, monster->col)) < 0) { 318 return(0); 319 } 320 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) { 321 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) { 322 if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) { 323 monster->m_flags |= CAN_FLIT; 324 s = mon_can_go(monster, i, j); 325 monster->m_flags &= (~CAN_FLIT); 326 if (s) { 327 move_mon_to(monster, i, j); 328 monster->m_flags |= ASLEEP; 329 monster->m_flags &= (~(WAKENS | SEEKS_GOLD)); 330 return(1); 331 } 332 monster->m_flags &= (~SEEKS_GOLD); 333 monster->m_flags |= CAN_FLIT; 334 mv_1_monster(monster, i, j); 335 monster->m_flags &= (~CAN_FLIT); 336 monster->m_flags |= SEEKS_GOLD; 337 return(1); 338 } 339 } 340 } 341 return(0); 342 } 343 344 boolean 345 gold_at(row, col) 346 short row, col; 347 { 348 if (dungeon[row][col] & OBJECT) { 349 object *obj; 350 351 if ((obj = object_at(&level_objects, row, col)) && 352 (obj->what_is == GOLD)) { 353 return(1); 354 } 355 } 356 return(0); 357 } 358 359 void 360 check_gold_seeker(monster) 361 object *monster; 362 { 363 monster->m_flags &= (~SEEKS_GOLD); 364 } 365 366 boolean 367 check_imitator(monster) 368 object *monster; 369 { 370 char msg[80]; 371 372 if (monster->m_flags & IMITATES) { 373 wake_up(monster); 374 if (!blind) { 375 mvaddch(monster->row, monster->col, 376 get_dungeon_char(monster->row, monster->col)); 377 check_message(); 378 sprintf(msg, "wait, that's a %s!", mon_name(monster)); 379 message(msg, 1); 380 } 381 return(1); 382 } 383 return(0); 384 } 385 386 boolean 387 imitating(row, col) 388 short row, col; 389 { 390 if (dungeon[row][col] & MONSTER) { 391 object *monster; 392 393 if ((monster = object_at(&level_monsters, row, col)) != NULL) { 394 if (monster->m_flags & IMITATES) { 395 return(1); 396 } 397 } 398 } 399 return(0); 400 } 401 402 void 403 sting(monster) 404 object *monster; 405 { 406 short sting_chance = 35; 407 char msg[80]; 408 409 if ((rogue.str_current <= 3) || sustain_strength) { 410 return; 411 } 412 sting_chance += (6 * (6 - get_armor_class(rogue.armor))); 413 414 if ((rogue.exp + ring_exp) > 8) { 415 sting_chance -= (6 * ((rogue.exp + ring_exp) - 8)); 416 } 417 if (rand_percent(sting_chance)) { 418 sprintf(msg, "the %s's bite has weakened you", 419 mon_name(monster)); 420 message(msg, 0); 421 rogue.str_current--; 422 print_stats(STAT_STRENGTH); 423 } 424 } 425 426 void 427 drop_level() 428 { 429 int hp; 430 431 if (rand_percent(80) || (rogue.exp <= 5)) { 432 return; 433 } 434 rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29); 435 rogue.exp -= 2; 436 hp = hp_raise(); 437 if ((rogue.hp_current -= hp) <= 0) { 438 rogue.hp_current = 1; 439 } 440 if ((rogue.hp_max -= hp) <= 0) { 441 rogue.hp_max = 1; 442 } 443 add_exp(1, 0); 444 } 445 446 void 447 drain_life() 448 { 449 short n; 450 451 if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) { 452 return; 453 } 454 n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */ 455 456 if ((n != 2) || (!sustain_strength)) { 457 message("you feel weaker", 0); 458 } 459 if (n != 2) { 460 rogue.hp_max--; 461 rogue.hp_current--; 462 less_hp++; 463 } 464 if (n != 1) { 465 if ((rogue.str_current > 3) && (!sustain_strength)) { 466 rogue.str_current--; 467 if (coin_toss()) { 468 rogue.str_max--; 469 } 470 } 471 } 472 print_stats((STAT_STRENGTH | STAT_HP)); 473 } 474 475 boolean 476 m_confuse(monster) 477 object *monster; 478 { 479 char msg[80]; 480 481 if (!rogue_can_see(monster->row, monster->col)) { 482 return(0); 483 } 484 if (rand_percent(45)) { 485 monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */ 486 return(0); 487 } 488 if (rand_percent(55)) { 489 monster->m_flags &= (~CONFUSES); 490 sprintf(msg, "the gaze of the %s has confused you", mon_name(monster)); 491 message(msg, 1); 492 cnfs(); 493 return(1); 494 } 495 return(0); 496 } 497 498 boolean 499 flame_broil(monster) 500 object *monster; 501 { 502 short row, col, dir; 503 504 if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) { 505 return(0); 506 } 507 row = rogue.row - monster->row; 508 col = rogue.col - monster->col; 509 if (row < 0) { 510 row = -row; 511 } 512 if (col < 0) { 513 col = -col; 514 } 515 if (((row != 0) && (col != 0) && (row != col)) || 516 ((row > 7) || (col > 7))) { 517 return(0); 518 } 519 dir = get_dir(monster->row, monster->col, row, col); 520 bounce(FIRE, dir, monster->row, monster->col, 0); 521 522 return(1); 523 } 524 525 int 526 get_dir(srow, scol, drow, dcol) 527 short srow, scol, drow, dcol; 528 { 529 if (srow == drow) { 530 if (scol < dcol) { 531 return(RIGHT); 532 } else { 533 return(LEFT); 534 } 535 } 536 if (scol == dcol) { 537 if (srow < drow) { 538 return(DOWN); 539 } else { 540 return(UPWARD); 541 } 542 } 543 if ((srow > drow) && (scol > dcol)) { 544 return(UPLEFT); 545 } 546 if ((srow < drow) && (scol < dcol)) { 547 return(DOWNRIGHT); 548 } 549 if ((srow < drow) && (scol > dcol)) { 550 return(DOWNLEFT); 551 } 552 /*if ((srow > drow) && (scol < dcol)) {*/ 553 return(UPRIGHT); 554 /*}*/ 555 } 556