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