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