1 /* 2 * All the fighting gets done here 3 * 4 * @(#)fight.c 1.43 (AI Design) 1/19/85 5 */ 6 7 #include "rogue.h" 8 #include "curses.h" 9 10 /* 11 * fight: 12 * The player attacks the monster. 13 */ 14 fight(mp, mn, weap, thrown) 15 register coord *mp; 16 char mn; 17 register THING *weap; 18 bool thrown; 19 { 20 register THING *tp; 21 register char *mname; 22 23 /* 24 * Find the monster we want to fight 25 */ 26 if ((tp = moat(mp->y, mp->x)) == 0) 27 return FALSE; 28 /* 29 * Since we are fighting, things are not quiet so no healing takes 30 * place. Cancel any command counts so player can recover. 31 */ 32 count = quiet = 0; 33 start_run(mp); 34 /* 35 * Let him know it was really a mimic (if it was one). 36 */ 37 if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND)) { 38 mn = tp->t_disguise = 'X'; 39 if (thrown) 40 return FALSE; 41 msg("wait! That's a Xeroc!"); 42 } 43 mname = monsters[mn-'A'].m_name; 44 if (on(player, ISBLIND)) 45 mname = it; 46 if (roll_em(&player, tp, weap, thrown)||(weap && weap->o_type == POTION)) { 47 bool did_huh = FALSE; 48 49 if (thrown) 50 thunk(weap, mname, "hits", "hit"); 51 else 52 hit(NULL, mname); 53 if (weap->o_type == POTION) { 54 th_effect(weap, tp); 55 if (!thrown) { 56 if (weap->o_count > 1) 57 weap->o_count--; 58 else { 59 detach(pack, weap); 60 discard(weap); 61 } 62 cur_weapon = NULL; 63 } 64 } 65 if (on(player, CANHUH)) { 66 did_huh = TRUE; 67 tp->t_flags |= ISHUH; 68 player.t_flags &= ~CANHUH; 69 msg("your hands stop glowing red"); 70 } 71 if (tp->t_stats.s_hpt <= 0) 72 killed(tp, TRUE); 73 else if (did_huh && !on(player, ISBLIND)) 74 msg("the %s appears confused", mname); 75 return TRUE; 76 } 77 if (thrown) 78 thunk(weap, mname, "misses", "missed"); 79 else 80 miss(NULL, mname); 81 if (tp->t_type == 'S' && rnd(100) > 25) 82 slime_split(tp); 83 return FALSE; 84 } 85 86 /* 87 * attack: 88 * The monster attacks the player 89 */ 90 attack(mp) 91 THING *mp; 92 { 93 register char *mname; 94 95 /* 96 * Since this is an attack, stop running and any healing that was 97 * going on at the time. 98 */ 99 running = FALSE; 100 count = quiet = 0; 101 if (mp->t_type == 'X' && !on(player, ISBLIND)) 102 mp->t_disguise = 'X'; 103 mname = monsters[mp->t_type-'A'].m_name; 104 if (on(player, ISBLIND)) 105 mname = it; 106 if (roll_em(mp, &player, NULL, FALSE)) { 107 hit(mname, NULL); 108 if (pstats.s_hpt <= 0) 109 death(mp->t_type); /* Bye bye life ... */ 110 if (!on(*mp, ISCANC)) 111 switch (mp->t_type) 112 { 113 when 'A': 114 /* 115 * If a rust monster hits, you lose armor, unless 116 * that armor is leather or there is a magic ring 117 */ 118 if (cur_armor != NULL && cur_armor->o_ac < 9 119 && cur_armor->o_which != LEATHER) 120 if (ISWEARING(R_SUSTARM)) 121 msg("the rust vanishes instantly"); 122 else 123 { 124 msg("your armor weakens, oh my!"); 125 cur_armor->o_ac++; 126 } 127 when 'I': 128 /* 129 * When an Ice Monster hits you, you get unfrozen faster 130 */ 131 if (no_command > 1) 132 no_command--; 133 break; 134 when 'R': 135 /* 136 * Rattlesnakes have poisonous bites 137 */ 138 if (!save(VS_POISON)) 139 if (!ISWEARING(R_SUSTSTR)) 140 { 141 chg_str(-1); 142 msg("you feel a bite in your leg%s", 143 noterse(" and now feel weaker")); 144 } 145 else 146 msg("a bite momentarily weakens you"); 147 when 'W': 148 case 'V': 149 /* 150 * Wraiths might drain energy levels, and Vampires 151 * can steal max_hp 152 */ 153 if (rnd(100) < (mp->t_type == 'W' ? 15 : 30)) 154 { 155 register int fewer; 156 157 if (mp->t_type == 'W') 158 { 159 if (pstats.s_exp == 0) 160 death('W'); /* All levels gone */ 161 if (--pstats.s_lvl == 0) 162 { 163 pstats.s_exp = 0; 164 pstats.s_lvl = 1; 165 } 166 else 167 pstats.s_exp = e_levels[pstats.s_lvl-1]+1; 168 fewer = roll(1, 10); 169 } 170 else 171 fewer = roll(1, 5); 172 pstats.s_hpt -= fewer; 173 max_hp -= fewer; 174 if (pstats.s_hpt < 1) 175 pstats.s_hpt = 1; 176 if (max_hp < 1) 177 death(mp->t_type); 178 msg("you suddenly feel weaker"); 179 } 180 when 'F': 181 /* 182 * Violet fungi stops the poor guy from moving 183 */ 184 player.t_flags |= ISHELD; 185 sprintf(mp->t_stats.s_dmg,"%dd1",++fung_hit); 186 when 'L': 187 { 188 /* 189 * Leperachaun steals some gold 190 */ 191 register long lastpurse; 192 193 lastpurse = purse; 194 purse -= GOLDCALC; 195 if (!save(VS_MAGIC)) 196 purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; 197 if (purse < 0) 198 purse = 0; 199 remove(&mp->t_pos, mp, FALSE); 200 if (purse != lastpurse) 201 msg("your purse feels lighter"); 202 } 203 when 'N': 204 { 205 register THING *obj, *steal; 206 register int nobj; 207 char *she_stole = "she stole %s!"; 208 209 /* 210 * Nymph's steal a magic item, look through the pack 211 * and pick out one we like. 212 */ 213 steal = NULL; 214 for (nobj = 0, obj = pack; obj != NULL; obj = next(obj)) 215 if (obj != cur_armor && obj != cur_weapon 216 && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT] 217 && is_magic(obj) && rnd(++nobj) == 0) 218 steal = obj; 219 if (steal != NULL) 220 { 221 remove(&mp->t_pos, mp, FALSE); 222 inpack--; 223 if (steal->o_count > 1 && steal->o_group == 0) 224 { 225 register int oc; 226 227 oc = steal->o_count--; 228 steal->o_count = 1; 229 msg(she_stole, inv_name(steal, TRUE)); 230 steal->o_count = oc; 231 } 232 else 233 { 234 detach(pack, steal); 235 discard(steal); 236 msg(she_stole, inv_name(steal, TRUE)); 237 } 238 } 239 } 240 otherwise: 241 break; 242 } 243 } 244 else if (mp->t_type != 'I') 245 { 246 if (mp->t_type == 'F') 247 { 248 pstats.s_hpt -= fung_hit; 249 if (pstats.s_hpt <= 0) 250 death(mp->t_type); /* Bye bye life ... */ 251 } 252 miss(mname, NULL); 253 } 254 flush_type(); 255 count = 0; 256 status(); 257 } 258 259 /* 260 * swing: 261 * Returns true if the swing hits 262 */ 263 swing(at_lvl, op_arm, wplus) 264 int at_lvl, op_arm, wplus; 265 { 266 register int res = rnd(20); 267 register int need = (20 - at_lvl) - op_arm; 268 269 return (res + wplus >= need); 270 } 271 272 /* 273 * check_level: 274 * Check to see if the guy has gone up a level. 275 */ 276 check_level() 277 { 278 register int i, add, olevel; 279 280 for (i = 0; e_levels[i] != 0; i++) 281 if (e_levels[i] > pstats.s_exp) 282 break; 283 i++; 284 olevel = pstats.s_lvl; 285 pstats.s_lvl = i; 286 if (i > olevel) 287 { 288 add = roll(i - olevel, 10); 289 max_hp += add; 290 if ((pstats.s_hpt += add) > max_hp) 291 pstats.s_hpt = max_hp; 292 msg("and achieve the rank of \"%s\"", he_man[i-1]); 293 } 294 } 295 296 /* 297 * roll_em: 298 * Roll several attacks 299 */ 300 roll_em(thatt, thdef, weap, hurl) 301 THING *thatt, *thdef, *weap; 302 bool hurl; 303 { 304 register struct stats *att, *def; 305 char *cp; 306 int ndice, nsides, def_arm; 307 register bool did_hit = FALSE; 308 register int hplus; 309 register int dplus; 310 register int damage; 311 char *stpchr(); 312 att = &thatt->t_stats; 313 def = &thdef->t_stats; 314 if (weap == NULL) 315 { 316 cp = att->s_dmg; 317 dplus = 0; 318 hplus = 0; 319 } 320 else 321 { 322 hplus = weap->o_hplus; 323 dplus = weap->o_dplus; 324 /* 325 * Check for vorpally enchanted weapon 326 */ 327 if (thdef->t_type == weap->o_enemy) 328 { 329 hplus += 4; 330 dplus += 4; 331 } 332 if (weap == cur_weapon) 333 { 334 if (ISRING(LEFT, R_ADDDAM)) 335 dplus += cur_ring[LEFT]->o_ac; 336 else if (ISRING(LEFT, R_ADDHIT)) 337 hplus += cur_ring[LEFT]->o_ac; 338 if (ISRING(RIGHT, R_ADDDAM)) 339 dplus += cur_ring[RIGHT]->o_ac; 340 else if (ISRING(RIGHT, R_ADDHIT)) 341 hplus += cur_ring[RIGHT]->o_ac; 342 } 343 cp = weap->o_damage; 344 if (hurl && (weap->o_flags&ISMISL) && cur_weapon != NULL && 345 cur_weapon->o_which == weap->o_launch) 346 { 347 cp = weap->o_hurldmg; 348 hplus += cur_weapon->o_hplus; 349 dplus += cur_weapon->o_dplus; 350 } 351 /* 352 * Drain a staff of striking 353 */ 354 if (weap->o_type == STICK && weap->o_which == WS_HIT 355 && --weap->o_charges < 0) 356 { 357 cp = weap->o_damage = "0d0"; 358 weap->o_hplus = weap->o_dplus = 0; 359 weap->o_charges = 0; 360 } 361 } 362 /* 363 * If the creature being attacked is not running (alseep or held) 364 * then the attacker gets a plus four bonus to hit. 365 */ 366 if (!on(*thdef, ISRUN)) 367 hplus += 4; 368 def_arm = def->s_arm; 369 if (def == &pstats) 370 { 371 if (cur_armor != NULL) 372 def_arm = cur_armor->o_ac; 373 if (ISRING(LEFT, R_PROTECT)) 374 def_arm -= cur_ring[LEFT]->o_ac; 375 if (ISRING(RIGHT, R_PROTECT)) 376 def_arm -= cur_ring[RIGHT]->o_ac; 377 } 378 for (;;) 379 { 380 ndice = atoi(cp); 381 if ((cp = stpchr(cp, 'd')) == NULL) 382 break; 383 nsides = atoi(++cp); 384 if (swing(att->s_lvl, def_arm, hplus + str_plus(att->s_str))) 385 { 386 register int proll; 387 388 proll = roll(ndice, nsides); 389 damage = dplus + proll + add_dam(att->s_str); 390 /* 391 * special goodies for the commercial version of rogue 392 */ 393 if (thdef == &player && max_level == 1) 394 /* 395 * make it easier on level one 396 */ 397 damage = (damage+1) / 2; 398 /* 399 * copy protection goodies 400 */ 401 if (thdef == &player) 402 damage *= hit_mul; 403 def->s_hpt -= max(0, damage); 404 did_hit = TRUE; 405 } 406 if ((cp = stpchr(cp, '/')) == NULL) 407 break; 408 cp++; 409 } 410 return did_hit; 411 } 412 413 /* 414 * prname: 415 * The print name of a combatant 416 */ 417 char * 418 prname(who, upper) 419 register char *who; 420 bool upper; 421 { 422 *tbuf = '\0'; 423 if (who == 0) 424 strcpy(tbuf, you); 425 else if (on(player, ISBLIND)) 426 strcpy(tbuf, it); 427 else 428 { 429 strcpy(tbuf, "the "); 430 strcat(tbuf, who); 431 } 432 if (upper) 433 *tbuf = toupper(*tbuf); 434 return tbuf; 435 } 436 437 /* 438 * hit: 439 * Print a message to indicate a succesful hit 440 */ 441 hit(er, ee) 442 register char *er, *ee; 443 { 444 register char *s; 445 446 addmsg(prname(er, TRUE)); 447 switch ((terse || expert) ? 1 : rnd(4)) 448 { 449 when 0: s = " scored an excellent hit on "; 450 when 1: s = " hit "; 451 when 2: s = (er == 0 ? " have injured " : " has injured "); 452 when 3: s = (er == 0 ? " swing and hit " : " swings and hits "); 453 } 454 msg("%s%s",s,prname(ee, FALSE)); 455 } 456 457 /* 458 * miss: 459 * Print a message to indicate a poor swing 460 */ 461 miss(er, ee) 462 register char *er, *ee; 463 { 464 register char *s; 465 466 467 addmsg(prname(er, TRUE)); 468 switch ((terse || expert) ? 1 : rnd(4)) 469 { 470 when 0: s = (er == 0 ? " swing and miss" : " swings and misses"); 471 when 1: s = (er == 0 ? " miss" : " misses"); 472 when 2: s = (er == 0 ? " barely miss" : " barely misses"); 473 when 3: s = (er == 0 ? " don't hit" : " doesn't hit"); 474 } 475 msg("%s %s",s,prname(ee, FALSE)); 476 } 477 478 /* 479 * save_throw: 480 * See if a creature save against something 481 */ 482 save_throw(which, tp) 483 int which; 484 THING *tp; 485 { 486 register int need; 487 488 need = 14 + which - tp->t_stats.s_lvl / 2; 489 return (roll(1, 20) >= need); 490 } 491 492 /* 493 * save: 494 * See if he saves against various nasty things 495 */ 496 save(which) 497 register int which; 498 { 499 if (which == VS_MAGIC) { 500 if (ISRING(LEFT, R_PROTECT)) 501 which -= cur_ring[LEFT]->o_ac; 502 if (ISRING(RIGHT, R_PROTECT)) 503 which -= cur_ring[RIGHT]->o_ac; 504 } 505 return save_throw(which, &player); 506 } 507 508 /* 509 * str_plus: 510 * Compute bonus/penalties for strength on the "to hit" roll 511 */ 512 str_plus(str) 513 register str_t str; 514 { 515 register int add = 4; 516 517 if (str < 8) 518 return str - 7; 519 if (str < 31) 520 add--; 521 if (str < 21) 522 add--; 523 if (str < 19) 524 add--; 525 if (str < 17) 526 add--; 527 return add; 528 } 529 530 /* 531 * add_dam: 532 * Compute additional damage done for exceptionally high or low strength 533 */ 534 add_dam(str) 535 register str_t str; 536 { 537 int add = 6; 538 539 if (str < 8) 540 return str - 7; 541 if (str < 31) 542 add--; 543 if (str < 22) 544 add--; 545 if (str < 20) 546 add--; 547 if (str < 18) 548 add--; 549 if (str < 17) 550 add--; 551 if (str < 16) 552 add--; 553 return add; 554 } 555 556 /* 557 * raise_level: 558 * The guy just magically went up a level. 559 */ 560 raise_level() 561 { 562 pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L; 563 check_level(); 564 } 565 566 /* 567 * thunk: 568 * A missile hit or missed a monster 569 */ 570 thunk(weap, mname, does, did) 571 register THING *weap; 572 register char *mname, *does, *did; 573 { 574 if (weap->o_type == WEAPON) 575 addmsg("the %s %s ", w_names[weap->o_which], does); 576 else 577 addmsg("you %s ", did); 578 if (on(player, ISBLIND)) 579 msg(it); 580 else 581 msg("the %s", mname); 582 } 583 584 /* 585 * remove: 586 * Remove a monster from the screen 587 */ 588 remove(mp, tp, waskill) 589 register coord *mp; 590 THING *tp; 591 bool waskill; 592 { 593 register THING *obj, *nexti; 594 595 if (tp == NULL) 596 return; 597 598 for (obj = tp->t_pack; obj != NULL; obj = nexti) 599 { 600 nexti = next(obj); 601 bcopy(obj->o_pos,tp->t_pos); 602 detach(tp->t_pack, obj); 603 if (waskill) 604 fall(obj, FALSE); 605 else 606 discard(obj); 607 } 608 if (_level[INDEX(mp->y,mp->x)] == PASSAGE) 609 standout(); 610 if (tp->t_oldch == FLOOR && !cansee(mp->y, mp->x)) 611 mvaddch(mp->y, mp->x, ' '); 612 else if (tp->t_oldch != '@') 613 mvaddch(mp->y, mp->x, tp->t_oldch); 614 standend(); 615 detach(mlist, tp); 616 discard(tp); 617 } 618 619 /* 620 * is_magic: 621 * Returns true if an object radiates magic 622 */ 623 is_magic(obj) 624 register THING *obj; 625 { 626 switch (obj->o_type) 627 { 628 case ARMOR: 629 return obj->o_ac != a_class[obj->o_which]; 630 case WEAPON: 631 return obj->o_hplus != 0 || obj->o_dplus != 0; 632 case POTION: 633 case SCROLL: 634 case STICK: 635 case RING: 636 case AMULET: 637 return TRUE; 638 } 639 return FALSE; 640 } 641 642 /* 643 * killed: 644 * Called to put a monster to death 645 */ 646 killed(tp, pr) 647 THING *tp; 648 bool pr; 649 { 650 pstats.s_exp += tp->t_stats.s_exp; 651 /* 652 * If the monster was a violet fungi, un-hold him 653 */ 654 switch (tp->t_type) 655 { 656 when 'F': 657 player.t_flags &= ~ISHELD; 658 f_restor(); 659 when 'L': 660 { 661 register THING *gold; 662 663 if ((gold = new_item()) == NULL) 664 return; 665 gold->o_type = GOLD; 666 gold->o_goldval = GOLDCALC; 667 if (save(VS_MAGIC)) 668 gold->o_goldval += GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC; 669 attach(tp->t_pack, gold); 670 } 671 } 672 /* 673 * Get rid of the monster. 674 */ 675 remove(&tp->t_pos, tp, TRUE); 676 if (pr) 677 { 678 addmsg("you have defeated "); 679 if (on(player, ISBLIND)) 680 msg(it); 681 else 682 msg("the %s", monsters[tp->t_type-'A'].m_name); 683 } 684 /* 685 * Do adjustments if he went up a level 686 */ 687 check_level(); 688 } 689 ÿ