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