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