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