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