Annotation of early-roguelike/xrogue/fight.c, Revision 1.1
1.1 ! rubenllo 1: /*
! 2: fight.c - All the fighting gets done here
! 3:
! 4: XRogue: Expeditions into the Dungeons of Doom
! 5: Copyright (C) 1991 Robert Pietkivitch
! 6: All rights reserved.
! 7:
! 8: Based on "Advanced Rogue"
! 9: Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
! 10: All rights reserved.
! 11:
! 12: Based on "Rogue: Exploring the Dungeons of Doom"
! 13: Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
! 14: All rights reserved.
! 15:
! 16: See the file LICENSE.TXT for full copyright and licensing information.
! 17: */
! 18:
! 19: #include <curses.h>
! 20: #include <ctype.h>
! 21: #include <string.h>
! 22: #include <stdlib.h>
! 23: #include "rogue.h"
! 24:
! 25: #define CONF_DAMAGE -1
! 26: #define PARAL_DAMAGE -2
! 27: #define DEST_DAMAGE -3
! 28: #define DRAIN_DAMAGE -4
! 29:
! 30: bool roll_em(struct thing *att_er, struct thing *def_er, struct object *weap,
! 31: bool hurl, struct object *cur_weapon, bool back_stab);
! 32: void hit(struct object *weapon, bool see_att, bool see_def, char *er, char *ee,
! 33: bool back_stab, bool thrown, bool short_msg);
! 34: void miss(struct object *weapon, bool see_att, bool see_def, char *er, char *ee,
! 35: bool thrown, bool short_msg);
! 36: int add_dam(short str);
! 37: int hung_dam(void);
! 38:
! 39: int killed_chance = 0; /* cumulative chance for goodies to loose it */
! 40:
! 41: /*
! 42: * returns true if player has a any chance to hit the monster
! 43: */
! 44:
! 45: bool
! 46: player_can_hit(struct thing *tp, struct object *weap)
! 47: {
! 48: if (off(*tp, CMAGICHIT) && off(*tp, BMAGICHIT) && off(*tp, MAGICHIT))
! 49: return(TRUE);
! 50: if (weap && weap->o_type == RELIC)
! 51: return(TRUE);
! 52: if (on(*tp, CMAGICHIT) && weap && (weap->o_hplus>2 || weap->o_dplus>2))
! 53: return(TRUE);
! 54: if (on(*tp, BMAGICHIT) && weap && (weap->o_hplus>1 || weap->o_dplus>1))
! 55: return(TRUE);
! 56: if (on(*tp, MAGICHIT) && weap && (weap->o_hplus>0 || weap->o_dplus>0))
! 57: return(TRUE);
! 58: if (player.t_ctype == C_MONK) {
! 59: if (on(*tp, CMAGICHIT) && pstats.s_lvl > 15)
! 60: return(TRUE);
! 61: if (on(*tp, BMAGICHIT) && pstats.s_lvl > 10)
! 62: return(TRUE);
! 63: if (on(*tp, MAGICHIT) && pstats.s_lvl > 5)
! 64: return(TRUE);
! 65: }
! 66: return(FALSE);
! 67: }
! 68:
! 69: /*
! 70: * fight:
! 71: * The player attacks the monster.
! 72: */
! 73:
! 74: bool
! 75: fight(coord *mp, struct object *weap, bool thrown)
! 76: {
! 77: register struct thing *tp;
! 78: register struct linked_list *item;
! 79: register bool did_hit = TRUE;
! 80: bool see_def, back_stab = FALSE;
! 81: register char *mname;
! 82:
! 83: /*
! 84: * Find the monster we want to fight
! 85: */
! 86: if ((item = find_mons(mp->y, mp->x)) == NULL) {
! 87: return(FALSE); /* must have killed him already */
! 88: }
! 89: tp = THINGPTR(item);
! 90:
! 91: /*
! 92: * Since we are fighting, things are not quiet so no healing takes
! 93: * place. The -1 also tells us that we are in a fight.
! 94: */
! 95: player.t_quiet = -1;
! 96: tp->t_quiet = -1;
! 97:
! 98: see_def = ((off(*tp, ISINVIS) || on(player, CANSEE)) &&
! 99: (off(*tp, ISSHADOW) || on(player, CANSEE)) &&
! 100: (!thrown || cansee(unc(tp->t_pos))));
! 101:
! 102: mname = see_def ? monster_name(tp) : "something";
! 103:
! 104: /*
! 105: * if its in the wall, we can't hit it
! 106: */
! 107: if (on(*tp, ISINWALL) && off(player, CANINWALL))
! 108: return(FALSE);
! 109:
! 110: if (on(*tp, ISSTONE)) {
! 111: killed(item, FALSE, FALSE, FALSE);
! 112: if (see_def)
! 113: msg("%s shatters into a million pieces!", prname(mname, TRUE));
! 114: count = 0;
! 115: return (TRUE);
! 116: }
! 117: /*
! 118: * Let him know it was really a mimic (if it was one).
! 119: */
! 120: if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) &&
! 121: off(player, ISBLIND))
! 122: {
! 123: if (see_def) {
! 124: msg("Wait! That's a %s!", mname);
! 125: turn_off(*tp, ISDISGUISE);
! 126: }
! 127: did_hit = thrown;
! 128: }
! 129: if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) {
! 130: if (see_def) {
! 131: msg("Wait! There's a %s!", mname);
! 132: turn_off(*tp, CANSURPRISE);
! 133: }
! 134: did_hit = thrown;
! 135: }
! 136:
! 137: /*
! 138: * if he's a thief or assassin and the creature is asleep then he gets
! 139: * a chance for a backstab
! 140: */
! 141: if ((player.t_ctype == C_THIEF || player.t_ctype == C_ASSASSIN) &&
! 142: !thrown &&
! 143: !on(*tp, NOSTAB) &&
! 144: !invisible(tp) &&
! 145: (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_action == A_FREEZE))
! 146: back_stab = TRUE;
! 147:
! 148: /*
! 149: * assassins get an assassination chance, if it fails then its normal
! 150: * damage
! 151: */
! 152: if (back_stab && player.t_ctype == C_ASSASSIN) {
! 153: int chance;
! 154:
! 155: chance = 50 + (pstats.s_lvl - tp->t_stats.s_lvl) * 5;
! 156: if (cur_weapon && (cur_weapon->o_flags & ISPOISON))
! 157: chance += 20;
! 158: if (roll(1,100) > chance || on(*tp, ISUNIQUE))
! 159: back_stab = FALSE;
! 160: }
! 161:
! 162: runto(tp, &hero);
! 163:
! 164: /* Let the monster know that the player has missiles! */
! 165: if (thrown) tp->t_wasshot = TRUE;
! 166:
! 167: if (did_hit)
! 168: {
! 169:
! 170: did_hit = FALSE;
! 171: if (!can_blink(tp) &&
! 172: player_can_hit(tp, weap) &&
! 173: roll_em(&player, tp, weap, thrown, cur_weapon, back_stab))
! 174: {
! 175: did_hit = TRUE;
! 176:
! 177: if (on(*tp, NOMETAL) && weap != NULL &&
! 178: weap->o_type != RELIC && weap->o_flags & ISMETAL) {
! 179: msg("Your %s passes right through %s!",
! 180: weaps[weap->o_which].w_name, prname(mname, FALSE));
! 181: }
! 182: else if (weap != NULL && weap->o_type == MISSILE && on(*tp, CARRYBAMULET)) {
! 183: msg("The magic missile has no effect on %s. ",
! 184: prname(mname, FALSE));
! 185: }
! 186: else {
! 187: hit(thrown ? (struct object *)NULL : weap,
! 188: TRUE, see_def,
! 189: thrown ? weap_name(weap) : NULL,
! 190: mname, back_stab, thrown, terse);
! 191:
! 192: /* See if there are any special effects */
! 193: if (effect(&player, tp, weap, thrown, TRUE, see_def) != 0)
! 194: killed(item, FALSE, FALSE, TRUE);
! 195:
! 196: /*
! 197: * Merchants just disappear if hit
! 198: */
! 199: else if (on(*tp, CANSELL)) {
! 200: if (see_def)
! 201: msg("%s disappears with his wares in a flash! ",
! 202: prname(mname, FALSE));
! 203: killed(item, FALSE, FALSE, FALSE);
! 204: }
! 205:
! 206: else if (tp->t_stats.s_hpt <= 0)
! 207: killed(item, TRUE, TRUE, TRUE);
! 208:
! 209: else {
! 210: /* If the victim was charmed, it now gets a saving throw! */
! 211: if (on(*tp, ISCHARMED) && save(VS_MAGIC, tp, 0)) {
! 212: msg("The eyes of %s turn clear.", prname(mname, FALSE));
! 213: turn_off(*tp, ISCHARMED);
! 214: }
! 215:
! 216: dsrpt_monster(tp, FALSE, see_def); /* Disrupt a spell? */
! 217: }
! 218: }
! 219: }
! 220: else {
! 221: miss(thrown ? (struct object *)NULL : weap,
! 222: TRUE, see_def,
! 223: thrown ? weap_name(weap) : (char *)NULL,
! 224: mname, thrown, terse);
! 225: }
! 226: }
! 227: count = 0;
! 228: return did_hit;
! 229: }
! 230:
! 231: /*
! 232: * attack:
! 233: * The monster attacks the player
! 234: */
! 235:
! 236: bool
! 237: attack(struct thing *mp, struct object *weapon, bool thrown)
! 238: {
! 239: register char *mname;
! 240: register bool see_att, did_hit = FALSE;
! 241: register struct object *wielded; /* The wielded weapon */
! 242: struct linked_list *get_wield; /* Linked list header for wielded */
! 243:
! 244: /*
! 245: * Since this is an attack, stop running and any healing that was
! 246: * going on at the time. The -1 also tells us that we're fighting.
! 247: */
! 248: running = FALSE;
! 249: player.t_quiet = -1;
! 250: mp->t_quiet = -1;
! 251:
! 252: if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
! 253: turn_off(*mp, ISDISGUISE);
! 254:
! 255: see_att = ((off(*mp, ISINVIS) || on(player, CANSEE)) &&
! 256: (off(*mp, ISSHADOW) || on(player, CANSEE)) &&
! 257: (!thrown || cansee(unc(mp->t_pos))));
! 258:
! 259: mname = see_att ? monster_name(mp) : "something";
! 260:
! 261: /*
! 262: * Try to find a weapon to wield. Wield_weap will return a
! 263: * projector if weapon is a projectile (eg. bow for arrow).
! 264: * If weapon is NULL, it will try to find a suitable weapon.
! 265: */
! 266: get_wield = wield_weap(weapon, mp);
! 267: if (get_wield) wielded = OBJPTR(get_wield);
! 268: else wielded = NULL;
! 269:
! 270: /* If we aren't wielding a weapon, wield what we found (could be NULL) */
! 271: if (weapon == NULL) weapon = wielded;
! 272:
! 273: if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) {
! 274: int death_type; /* From one of the effects of getting hit */
! 275:
! 276: did_hit = TRUE;
! 277:
! 278: if (weapon != NULL && weapon->o_type == MISSILE && cur_relic[STONEBONES_AMULET]) {
! 279: hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse);
! 280: msg("Your amulet absorbs the magic missile. ");
! 281: }
! 282: else {
! 283: hit(weapon, see_att, TRUE, mname, (char *)NULL, FALSE, thrown, terse);
! 284: dsrpt_player(); /* see if we disrupted some activity */
! 285: if (pstats.s_hpt <= 0)
! 286: death(mp->t_index); /* Bye bye life ... */
! 287: death_type = effect(mp, &player, weapon, thrown, see_att, TRUE);
! 288: if (death_type != 0) {
! 289: pstats.s_hpt = -1;
! 290: death(death_type);
! 291: }
! 292: }
! 293:
! 294: }
! 295: else {
! 296: /* If the thing was trying to surprise, no good */
! 297: if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
! 298:
! 299: /* If it couldn't surprise, let's tell the player. */
! 300: else miss(weapon, see_att, TRUE, mname, (char *)NULL, thrown, terse);
! 301: }
! 302: if (fight_flush) flushinp();
! 303: count = 0;
! 304: status(FALSE);
! 305: return(did_hit);
! 306: }
! 307:
! 308: /*
! 309: * swing:
! 310: * returns true if the swing hits
! 311: */
! 312:
! 313: bool
! 314: swing(short class, int at_lvl, int op_arm, int wplus)
! 315: {
! 316: register int res = rnd(20)+1;
! 317: register int need;
! 318:
! 319: need = char_class[class].base -
! 320: char_class[class].factor *
! 321: ((min(at_lvl, char_class[class].max_lvl) -
! 322: char_class[class].offset)/char_class[class].range) +
! 323: (10 - op_arm);
! 324: if (need > 20 && need <= 25) need = 20;
! 325:
! 326: return (res+wplus >= need);
! 327: }
! 328:
! 329: /*
! 330: * roll_em:
! 331: * Roll several attacks
! 332: */
! 333:
! 334: bool
! 335: roll_em(struct thing *att_er, struct thing *def_er, struct object *weap,
! 336: bool hurl, struct object *cur_weapon, bool back_stab)
! 337: {
! 338: register struct stats *att, *def;
! 339: register char *cp = NULL;
! 340: register int ndice, nsides, nplus, def_arm;
! 341: char dmgbuf[20];
! 342: bool did_hit = FALSE;
! 343: int prop_hplus, prop_dplus;
! 344: int vampiric_damage;
! 345:
! 346: /* Get statistics */
! 347: att = &att_er->t_stats;
! 348: def = &def_er->t_stats;
! 349:
! 350: prop_hplus = prop_dplus = 0;
! 351: if (weap == NULL) {
! 352: /*
! 353: * monks damage grows with level
! 354: */
! 355: if (att == &pstats && player.t_ctype == C_MONK) {
! 356: sprintf(dmgbuf, "%dd4", att->s_lvl/3+2);
! 357: cp = dmgbuf;
! 358: }
! 359: else
! 360: cp = att->s_dmg;
! 361: }
! 362: else if (weap->o_type == RELIC) {
! 363: switch (weap->o_which) {
! 364: case MUSTY_DAGGER:
! 365: if (player.t_ctype == C_THIEF)
! 366: cp = "4d8+2/4d8+2";
! 367: else
! 368: cp = "4d8/4d8";
! 369: when YEENOGHU_FLAIL:
! 370: cp = "4d8+3/paralyze/confuse";
! 371: when HRUGGEK_MSTAR:
! 372: cp = "4d8+3";
! 373: when AXE_AKLAD:
! 374: if (player.t_ctype == C_FIGHTER) {
! 375: if (hurl)
! 376: cp = "4d8+6/drain";
! 377: else
! 378: cp = "4d8+4/drain";
! 379: }
! 380: else {
! 381: if (hurl)
! 382: cp = "4d8+4/drain";
! 383: else
! 384: cp = "4d8+2/drain";
! 385: }
! 386: when MING_STAFF:
! 387: cp = "4d8+4";
! 388: when ASMO_ROD:
! 389: cp = "4d8/4d8";
! 390: when ORCUS_WAND:
! 391: cp = "4d8/destroy";
! 392: }
! 393: }
! 394: else if (hurl) {
! 395: if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
! 396: cur_weapon->o_which == weap->o_launch)
! 397: {
! 398: cp = weap->o_hurldmg;
! 399: prop_hplus = cur_weapon->o_hplus;
! 400: prop_dplus = cur_weapon->o_dplus;
! 401: }
! 402: else
! 403: cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg);
! 404: }
! 405: else {
! 406: cp = weap->o_damage;
! 407: /*
! 408: * Drain a staff of striking
! 409: */
! 410: if(weap->o_type==STICK && weap->o_which==WS_HIT && weap->o_charges==0)
! 411: {
! 412: strcpy(weap->o_damage,"4d8");
! 413: weap->o_hplus = weap->o_dplus = 0;
! 414: }
! 415: }
! 416: /*
! 417: * If defender is wearing a cloak of displacement -- no damage
! 418: * the first time. (unless its a hurled magic missile or the
! 419: * attacker is very smart and can see thru the illusion)
! 420: */
! 421: if ((weap == NULL || weap->o_type != MISSILE) &&
! 422: def == &pstats &&
! 423: off(*att_er, MISSEDDISP) &&
! 424: att->s_intel < 21 &&
! 425: ((cur_misc[WEAR_CLOAK]!=NULL &&
! 426: cur_misc[WEAR_CLOAK]->o_which==MM_DISP) ||
! 427: cur_relic[EMORI_CLOAK])) {
! 428: turn_on(*att_er, MISSEDDISP);
! 429: if (cansee(att_er->t_pos.y, att_er->t_pos.x) && !invisible(att_er))
! 430: msg("%s looks amazed! ", prname(monster_name(att_er), TRUE));
! 431: return (FALSE);
! 432: }
! 433: if (on(*def_er, CARRYCLOAK) &&
! 434: def != &pstats &&
! 435: (weap == NULL || weap->o_type != MISSILE) &&
! 436: off (*att_er, MISSEDDISP) &&
! 437: pstats.s_intel < 21) {
! 438: turn_on(*att_er, MISSEDDISP);
! 439: msg("You feel amazed! ");
! 440: return(FALSE);
! 441: }
! 442: for (;;)
! 443: {
! 444: int damage;
! 445: int hplus = prop_hplus;
! 446: int dplus = prop_dplus;
! 447:
! 448: if (weap != NULL && weap->o_type == RELIC) {
! 449: switch (weap->o_which) {
! 450: case MUSTY_DAGGER:
! 451: if (att != &pstats || /* Not player or good stats */
! 452: (str_compute() > 15 && dex_compute() > 15)) {
! 453:
! 454: hplus += 6;
! 455: dplus += 6;
! 456:
! 457: /* Give an additional strength and dex bonus */
! 458: if (att == &pstats) {
! 459: hplus += str_plus(str_compute()) +
! 460: dext_plus(dex_compute());
! 461: dplus += dext_plus(dex_compute()) +
! 462: add_dam(str_compute());
! 463: }
! 464: else {
! 465: hplus += str_plus(att->s_str) +
! 466: dext_plus(att->s_dext);
! 467: dplus += dext_plus(att->s_dext) +
! 468: add_dam(att->s_str);
! 469: }
! 470: }
! 471: else {
! 472: hplus -= 3;
! 473: dplus -= 3;
! 474: }
! 475: when YEENOGHU_FLAIL:
! 476: case HRUGGEK_MSTAR:
! 477: hplus += 3;
! 478: dplus += 3;
! 479: when MING_STAFF:
! 480: hplus += 2;
! 481: dplus += 2;
! 482: when AXE_AKLAD:
! 483: hplus += 5;
! 484: dplus += 5;
! 485: }
! 486: }
! 487: else if (weap != NULL) {
! 488: hplus += weap->o_hplus;
! 489: dplus += weap->o_dplus;
! 490: }
! 491:
! 492: /* Is attacker weak? */
! 493: if (on(*att_er, HASSTINK)) hplus -= 2;
! 494:
! 495: if (att == &pstats) /* Is the attacker the player? */
! 496: {
! 497: hplus += hitweight(); /* adjust for encumberence */
! 498: dplus += hung_dam(); /* adjust damage for hungry player */
! 499: dplus += ring_value(R_ADDDAM);
! 500: }
! 501: if (back_stab || (weap && att != &pstats && on(*att_er, CANBSTAB)))
! 502: hplus += 4; /* add in pluses for backstabbing */
! 503:
! 504: /* Get the damage */
! 505: while (isspace(*cp)) cp++;
! 506: if (!isdigit(*cp)) {
! 507: if (strncmp(cp, "confuse", 7) == 0) ndice = CONF_DAMAGE;
! 508: else if (strncmp(cp, "paralyze", 8) == 0) ndice = PARAL_DAMAGE;
! 509: else if (strncmp(cp, "destroy", 6) == 0) ndice = DEST_DAMAGE;
! 510: else if (strncmp(cp, "drain", 5) == 0) ndice = DRAIN_DAMAGE;
! 511: else ndice = 0;
! 512: nsides = 0;
! 513: nplus = 0;
! 514: }
! 515: else {
! 516: char *oldcp;
! 517:
! 518: /* Get the number of damage dice */
! 519: ndice = atoi(cp);
! 520: if ((cp = strchr(cp, 'd')) == NULL)
! 521: break;
! 522:
! 523: /* Skip the 'd' and get the number of sides per die */
! 524: nsides = atoi(++cp);
! 525:
! 526: /* Check for an addition -- save old place in case none is found */
! 527: oldcp = cp;
! 528: if ((cp = strchr(cp, '+')) != NULL) nplus = atoi(++cp);
! 529: else {
! 530: nplus = 0;
! 531: cp = oldcp;
! 532: }
! 533: }
! 534:
! 535: if (def == &pstats) { /* Monster attacks player */
! 536: if (on(*att_er, NOMETAL))
! 537: def_arm = ac_compute(TRUE) - dext_prot(dex_compute());
! 538: else
! 539: def_arm = ac_compute(FALSE) - dext_prot(dex_compute());
! 540: hplus += str_plus(att->s_str)+dext_plus(att->s_dext);
! 541: }
! 542: else if (att == &pstats) { /* Player attacks monster */
! 543: def_arm = def->s_arm - dext_prot(def->s_dext);
! 544: if (player.t_ctype == C_MONK) /* no strength bonus for monk */
! 545: if (weap == NULL)
! 546: hplus += att->s_lvl/5; /* monks hplus varies with level */
! 547: else
! 548: hplus += str_plus(str_compute())+dext_plus(dex_compute());
! 549: }
! 550: else { /* Monster attacks monster */
! 551: def_arm = def->s_arm - dext_prot(def->s_dext);
! 552: hplus += str_plus(att->s_str)+dext_plus(att->s_dext);
! 553: }
! 554:
! 555: if (swing(att_er->t_ctype, att->s_lvl, def_arm, hplus)) {
! 556: register int proll;
! 557:
! 558: /* Take care of special effects */
! 559: switch (ndice) {
! 560: case CONF_DAMAGE:
! 561: if (def == &pstats) { /* Monster attacks player */
! 562: if (!save(VS_MAGIC, &player, 0) && off(player, ISCLEAR)) {
! 563: msg("You feel disoriented.");
! 564: if (find_slot(unconfuse))
! 565: lengthen(unconfuse, HUHDURATION);
! 566: else
! 567: fuse(unconfuse, NULL, HUHDURATION, AFTER);
! 568: turn_on(player, ISHUH);
! 569: }
! 570: else msg("You feel dizzy, but it quickly passes.");
! 571: }
! 572: /* Player or monster hits monster */
! 573: else if (!save(VS_MAGIC, def_er, 0) && off(*def_er, ISCLEAR)) {
! 574: if (att == &pstats) {
! 575: if (rnd(10) > 6)
! 576: msg("The artifact warms you with pleasure! ");
! 577: }
! 578: turn_on(*def_er, ISHUH);
! 579: }
! 580: did_hit = TRUE;
! 581: when PARAL_DAMAGE:
! 582: if (def == &pstats) { /* Monster attacks player */
! 583: if (!save(VS_MAGIC, &player, 0) && off(player, CANINWALL)) {
! 584: msg("You stiffen up.");
! 585: player.t_no_move += movement(&player) * FREEZETIME;
! 586: player.t_action = A_FREEZE;
! 587: }
! 588: }
! 589: else if (!save(VS_MAGIC, def_er, 0)) { /* Player hits monster */
! 590: if (att == &pstats) {
! 591: if (rnd(10) > 6)
! 592: msg("The artifact hums happily! ");
! 593: }
! 594: turn_off(*def_er, ISRUN);
! 595: turn_on(*def_er, ISHELD);
! 596: }
! 597: did_hit = TRUE;
! 598: when DEST_DAMAGE:
! 599: if (def == &pstats) { /* Monster attacks player */
! 600: if (rnd(10) > 5)
! 601: msg("You feel a tug at your life force.");
! 602: if (!save(VS_MAGIC, &player, -4)) {
! 603: msg("The wand devours your soul! --More--");
! 604: wait_for(' ');
! 605: def->s_hpt = -1;
! 606: death(D_RELIC);
! 607: }
! 608: }
! 609: /* Player hits monster */
! 610: else if (!save(VS_MAGIC, def_er, -4)) {
! 611: if (att == &pstats) {
! 612: if (rnd(10) > 4)
! 613: msg("The artifact draws some energy.");
! 614: }
! 615: /* The player loses some major hit pts */
! 616: att->s_hpt -= (att->s_hpt/5)+1;
! 617: if (att->s_hpt <= 0) {
! 618: msg("The wand has devoured your soul! --More--");
! 619: wait_for(' ');
! 620: att->s_hpt = -1;
! 621: death(D_RELIC);
! 622: }
! 623: /* Kill the monster */
! 624: def->s_hpt = 0;
! 625: }
! 626: did_hit = TRUE;
! 627: when DRAIN_DAMAGE:
! 628: if (def == &pstats) { /* Monster attacks player */
! 629: if (!save(VS_MAGIC, &player, -4)) {
! 630: lower_level(att_er->t_index);
! 631: }
! 632: }
! 633: /* Player hits monster */
! 634: else if (!save(VS_MAGIC, def_er, -4)) {
! 635: def->s_hpt -= roll(1, 8);
! 636: def->s_lvl--;
! 637: if (def->s_lvl <= 0)
! 638: def->s_hpt = 0; /* he's dead */
! 639: if (att == &pstats) {
! 640: if (rnd(10) > 7)
! 641: msg("The artifact cackles with laughter! ");
! 642: }
! 643: }
! 644: did_hit = TRUE;
! 645: otherwise:
! 646: /* Heil's ankh always gives maximum damage */
! 647: if (att == &pstats && cur_relic[HEIL_ANKH])
! 648: proll = ndice * nsides;
! 649: else proll = roll(ndice, nsides);
! 650:
! 651: if (ndice + nsides > 0 && proll < 1)
! 652: debug("Damage for %dd%d came out %d.",
! 653: ndice, nsides, proll);
! 654: damage = dplus + proll + nplus;
! 655: if (att == &pstats) {
! 656: /*
! 657: * Monks do not get strength bonus on damage. Instead,
! 658: * if they are wielding a weapon, they get at extra
! 659: * 1/2 point per level of damage.
! 660: */
! 661: if(player.t_ctype == C_MONK) {
! 662: /* Bonus does not apply for hands. */
! 663: if (weap != NULL) damage += att->s_lvl / 2;
! 664: }
! 665: else
! 666: damage += add_dam(str_compute());
! 667: }
! 668: else
! 669: damage += add_dam(att->s_str);
! 670:
! 671: /* Check for half damage monsters */
! 672: if (on(*def_er, HALFDAMAGE)) damage /= 2;
! 673:
! 674: /* add in multipliers for backstabbing */
! 675: if (back_stab ||
! 676: (weap && att != &pstats && on(*att_er, CANBSTAB))) {
! 677: int mult = 2 + (att->s_lvl-1)/4; /* Normal multiplier */
! 678:
! 679: if (mult > 5)
! 680: mult = 5;
! 681: if (weap && weap->o_type == RELIC &&
! 682: weap->o_which == MUSTY_DAGGER)
! 683: mult++;
! 684: damage *= mult;
! 685: }
! 686: if (att == &pstats) {
! 687: if (cur_weapon && (cur_weapon->o_flags & ISPOISON)) {
! 688: cur_weapon->o_flags &= ~ISPOISON;
! 689: if (save(VS_POISON, def_er, -2))
! 690: damage += def->s_hpt/4;
! 691: else
! 692: damage += def->s_hpt/2;
! 693: }
! 694: if (back_stab && player.t_ctype == C_ASSASSIN)
! 695: damage = def->s_hpt + 1;
! 696: }
! 697: /* Check for no-damage and division */
! 698: if (on(*def_er, BLOWDIVIDE)) {
! 699: damage = 0;
! 700: creat_mons(def_er, def_er->t_index, FALSE);
! 701: if (cansee(unc(def_er->t_pos))) light(&hero);
! 702: }
! 703: /* check for immunity to metal -- RELICS are always bad */
! 704: if (on(*def_er, NOMETAL) && weap != NULL &&
! 705: weap->o_type != RELIC && weap->o_flags & ISMETAL) {
! 706: damage = 0;
! 707: }
! 708: if (weap != NULL && weap->o_type == MISSILE) {
! 709: if ((def == &pstats && cur_relic[STONEBONES_AMULET]) ||
! 710: (att == &pstats && on(*def_er, CARRYBAMULET))) {
! 711: damage = 0;
! 712: }
! 713: }
! 714: def->s_hpt -= max(0, damage); /* Do the damage */
! 715: did_hit = TRUE;
! 716: vampiric_damage = damage;
! 717: if (def->s_hpt < 0) /* only want REAL damage inflicted */
! 718: vampiric_damage += def->s_hpt;
! 719: if (vampiric_damage < 0)
! 720: vampiric_damage = 0;
! 721: if (att == &pstats && ISWEARING(R_VAMPREGEN) && !hurl) {
! 722: if ((pstats.s_hpt += vampiric_damage/2) > max_stats.s_hpt)
! 723: pstats.s_hpt = max_stats.s_hpt;
! 724: }
! 725: if (hplus < 0) hplus = 0;
! 726: if (damage < 0) damage = 0;
! 727: debug ("hplus=%d dmg=%d", hplus, damage);
! 728: }
! 729: }
! 730: if ((cp = strchr(cp, '/')) == NULL)
! 731: break;
! 732: cp++;
! 733: }
! 734: return did_hit;
! 735: }
! 736:
! 737: /*
! 738: * prname:
! 739: * The print name of a combatant
! 740: */
! 741:
! 742: char *
! 743: prname(char *who, bool upper)
! 744: {
! 745: static char tbuf[LINELEN];
! 746:
! 747: *tbuf = '\0';
! 748: if (who == 0)
! 749: strcpy(tbuf, "you");
! 750: else if (on(player, ISBLIND) || strcmp(who, "something") == 0)
! 751: strcpy(tbuf, "something");
! 752: else
! 753: {
! 754: /* If we have a name (starts with a capital), don't use a "the" */
! 755: if (islower(*who)) strcpy(tbuf, "the ");
! 756: strcat(tbuf, who);
! 757: }
! 758: if (upper)
! 759: *tbuf = toupper(*tbuf);
! 760: return tbuf;
! 761: }
! 762:
! 763: /*
! 764: * hit:
! 765: * Print a message to indicate a succesful hit
! 766: */
! 767:
! 768: void
! 769: hit(struct object *weapon, bool see_att, bool see_def, char *er, char *ee,
! 770: bool back_stab, bool thrown, bool short_msg)
! 771: {
! 772: register char *s = NULL;
! 773: char att_name[LINELEN], /* Name of attacker */
! 774: def_name[LINELEN]; /* Name of defender */
! 775:
! 776: /* If we can't see either the attacker or defender, don't say anything */
! 777: if (!see_att && !see_def) return;
! 778:
! 779: /* What do we call the attacker? */
! 780: strcpy(att_name, see_att ? prname(er, TRUE) : "Something");
! 781: if (er) { /* A monster is attacking */
! 782:
! 783: /* If the monster is using a weapon and we can see it, report it */
! 784: if (weapon != NULL && (see_att || thrown)) {
! 785: strcat(att_name, "'s ");
! 786: strcat(att_name, weap_name(weapon));
! 787: }
! 788: }
! 789:
! 790: /* What do we call the defender? */
! 791: strcpy(def_name, see_def ? prname(ee, FALSE) : "something");
! 792:
! 793: addmsg(att_name);
! 794: if (short_msg) {
! 795: if (back_stab) {
! 796: if (player.t_ctype == C_ASSASSIN)
! 797: s = (er == 0 ? " assassinate!" : " assassinates!");
! 798: else
! 799: s = (er == 0 ? " backstab!" : " backstabs!");
! 800: }
! 801: else
! 802: s = " hit.";
! 803: }
! 804: else {
! 805: if (back_stab) {
! 806: if (player.t_ctype == C_ASSASSIN)
! 807: s = (er == 0 ? " have assassinated " : " has assassinated ");
! 808: else
! 809: s = (er == 0 ? " have backstabbed " : " has backstabbed ");
! 810: }
! 811: else {
! 812: switch (rnd(thrown ? 2 : 3))
! 813: {
! 814: case 0: s = " hit ";
! 815: when 1: s = " injured ";
! 816: when 2: s = " smacked ";
! 817: }
! 818: }
! 819: }
! 820: if (short_msg) addmsg(s);
! 821: else addmsg("%s%s.", s, def_name);
! 822: endmsg();
! 823: }
! 824:
! 825: /*
! 826: * miss:
! 827: * Print a message to indicate a poor swing
! 828: */
! 829:
! 830: void
! 831: miss(struct object *weapon, bool see_att, bool see_def, char *er, char *ee,
! 832: bool thrown, bool short_msg)
! 833: {
! 834: register char *s = NULL;
! 835: char att_name[LINELEN], /* Name of attacker */
! 836: def_name[LINELEN]; /* Name of defender */
! 837:
! 838: /* If we can't see either the attacker or defender, don't say anything */
! 839: if (!see_att && !see_def) return;
! 840:
! 841: /* What do we call the attacker? */
! 842: strcpy(att_name, see_att ? prname(er, TRUE) : "Something");
! 843: if (er) { /* A monster is attacking */
! 844:
! 845: /* If the monster is using a weapon and we can see it, report it */
! 846: if (weapon != NULL && (see_att || thrown)) {
! 847: strcat(att_name, "'s ");
! 848: strcat(att_name, weap_name(weapon));
! 849: }
! 850: }
! 851:
! 852: /* What do we call the defender? */
! 853: strcpy(def_name, see_def ? prname(ee, FALSE) : "something");
! 854:
! 855: addmsg(att_name);
! 856: switch (short_msg ? 0 : rnd(thrown ? 3 : 2))
! 857: {
! 858: case 0: s = (er == 0 ? " miss" : " misses");
! 859: when 1: s = (er == 0 ? " don't hit" : " doesn't hit");
! 860: when 2: s = (" whizzes by");
! 861: }
! 862: if (short_msg) addmsg("%s.", s);
! 863: else addmsg("%s %s.", s, def_name);
! 864: endmsg();
! 865: }
! 866:
! 867: /*
! 868: * dext_plus:
! 869: * compute to-hit bonus for dexterity
! 870: */
! 871:
! 872: int
! 873: dext_plus(int dexterity)
! 874: {
! 875: return (dexterity > 10 ? (dexterity-13)/3 : (dexterity-10)/3);
! 876: }
! 877:
! 878:
! 879: /*
! 880: * dext_prot:
! 881: * compute armor class bonus for dexterity
! 882: */
! 883:
! 884: int
! 885: dext_prot(int dexterity)
! 886: {
! 887: return ((dexterity-10)/2);
! 888: }
! 889:
! 890: /*
! 891: * str_plus:
! 892: * compute bonus/penalties for strength on the "to hit" roll
! 893: */
! 894:
! 895: int
! 896: str_plus(short str)
! 897: {
! 898: return((str-10)/3);
! 899: }
! 900:
! 901: /*
! 902: * add_dam:
! 903: * compute additional damage done for exceptionally high or low strength
! 904: */
! 905:
! 906: int
! 907: add_dam(short str)
! 908: {
! 909: return((str-9)/2);
! 910: }
! 911:
! 912: /*
! 913: * hung_dam:
! 914: * Calculate damage depending on players hungry state
! 915: */
! 916:
! 917: int
! 918: hung_dam(void)
! 919: {
! 920: reg int howmuch = 0;
! 921:
! 922: switch(hungry_state) {
! 923: case F_SATIATED:
! 924: case F_OKAY:
! 925: case F_HUNGRY: howmuch = 0;
! 926: when F_WEAK: howmuch = -1;
! 927: when F_FAINT: howmuch = -2;
! 928: }
! 929: return howmuch;
! 930: }
! 931:
! 932: /*
! 933: * is_magic:
! 934: * Returns true if an object radiates magic
! 935: */
! 936:
! 937: bool
! 938: is_magic(struct object *obj)
! 939: {
! 940: switch (obj->o_type)
! 941: {
! 942: case ARMOR:
! 943: return obj->o_ac != armors[obj->o_which].a_class;
! 944: when WEAPON:
! 945: return obj->o_hplus != 0 || obj->o_dplus != 0;
! 946: when POTION:
! 947: case SCROLL:
! 948: case STICK:
! 949: case RING:
! 950: case MM:
! 951: case RELIC:
! 952: return TRUE;
! 953: }
! 954: return FALSE;
! 955: }
! 956:
! 957: /*
! 958: * killed:
! 959: * Called to put a monster to death
! 960: */
! 961:
! 962: void
! 963: killed(struct linked_list *item, bool pr, bool points, bool treasure)
! 964: {
! 965: register struct thing *tp, *mp;
! 966: register struct linked_list *pitem, *nexti, *mitem;
! 967: char *monst;
! 968: int adj; /* used for hit point adj. below. */
! 969:
! 970: tp = THINGPTR(item);
! 971:
! 972: if (pr)
! 973: {
! 974: addmsg(terse ? "Defeated " : "You have defeated ");
! 975: if (on(player, ISBLIND))
! 976: msg("it.");
! 977: else
! 978: {
! 979: if (cansee(tp->t_pos.y, tp->t_pos.x) && !invisible(tp))
! 980: monst = monster_name(tp);
! 981: else {
! 982: if (terse) monst = "something";
! 983: else monst = "thing";
! 984: }
! 985: if (!terse)
! 986: addmsg("the ");
! 987: msg("%s.", monst);
! 988: }
! 989: }
! 990:
! 991: /* Take care of any residual effects of the monster */
! 992: check_residue(tp);
! 993:
! 994: /* Make sure that no one is still chasing us */
! 995: for (mitem = mlist; mitem != NULL; mitem = next(mitem)) {
! 996: mp = THINGPTR(mitem);
! 997: if (mp->t_dest == &tp->t_pos) {
! 998: mp->t_dest = &hero;
! 999: mp->t_wasshot = FALSE;
! 1000: turn_off(*mp, ISFLEE); /* Be sure we aren't running away! */
! 1001: }
! 1002: }
! 1003: if (points) { /* you feel uneasy for a moment */
! 1004: if ((off(*tp, ISMEAN) || on(*tp, ISFRIENDLY)) &&
! 1005: (player.t_ctype == C_RANGER || player.t_ctype == C_PALADIN ||
! 1006: player.t_ctype == C_MONK)) {
! 1007: if (tp->t_stats.s_exp > pstats.s_exp)
! 1008: pstats.s_exp = 0;
! 1009: else
! 1010: pstats.s_exp -= tp->t_stats.s_exp;
! 1011: /* Take care of hit points. */
! 1012: if (level <= 12) adj = rnd(2)+1;
! 1013: else if (level <= 25) adj = rnd(3)+2;
! 1014: else if (level <= 50) adj = rnd(4)+3;
! 1015: else if (level <= 80) adj = rnd(5)+4;
! 1016: else adj = rnd(6)+5;
! 1017: /* adjust hit points */
! 1018: max_stats.s_hpt -= adj;
! 1019: pstats.s_hpt -= adj;
! 1020: /* Are hit points now too low? */
! 1021: if (pstats.s_hpt <= 0) {
! 1022: pstats.s_hpt = -1;
! 1023: death(D_STRENGTH);
! 1024: }
! 1025: killed_chance += rnd(3)+1;
! 1026: if (on(*tp, ISUNIQUE)) /* real bad news to kill a diety */
! 1027: killed_chance += 25;
! 1028: if (roll(1,100) < killed_chance) {
! 1029: msg("You had a feeling this was going to happen... ");
! 1030: msg("**POOF** ");
! 1031: changeclass(C_ASSASSIN); /* make him pay */
! 1032: }
! 1033: else {
! 1034: switch (rnd(9)) {
! 1035: case 0:
! 1036: msg("You become solid and stiff for a while. ");
! 1037: player.t_no_move += (5*movement(&player)*FREEZETIME);
! 1038: player.t_action = A_FREEZE;
! 1039: when 1:
! 1040: msg("You collapse, losing it totally. ");
! 1041: player.t_no_move += (2*movement(&player)*FREEZETIME);
! 1042: player.t_action = A_FREEZE;
! 1043: when 2:
! 1044: msg("Your face changes shape! ARGGHH!!!! ");
! 1045: pstats.s_charisma -= rnd(8)+3;
! 1046: if (pstats.s_charisma <= 3) pstats.s_charisma = 3;
! 1047: when 3:
! 1048: case 4:
! 1049: msg("You cry out, I didn't mean to do that! Honest!! ");
! 1050: player.t_no_move += (movement(&player)*FREEZETIME);
! 1051: msg("The Great Old Ones grant you a reprieve. ");
! 1052: otherwise: msg("You feel uneasy for a moment.. ");
! 1053: }
! 1054: }
! 1055: }
! 1056: else {
! 1057: unsigned long test; /* For overflow check */
! 1058: /*
! 1059: * Do an overflow check before increasing experience
! 1060: */
! 1061: test = pstats.s_exp + tp->t_stats.s_exp;
! 1062: if (test > pstats.s_exp)
! 1063: pstats.s_exp = test;
! 1064: }
! 1065:
! 1066: /*
! 1067: * Do adjustments if he went up a level
! 1068: */
! 1069: check_level();
! 1070: }
! 1071:
! 1072: /*
! 1073: * Empty the monsters pack
! 1074: */
! 1075: pitem = tp->t_pack;
! 1076:
! 1077: /*
! 1078: * Get rid of the monster.
! 1079: */
! 1080: mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
! 1081: mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
! 1082: detach(mlist, item);
! 1083: if (on(*tp, AREMANY) && levtype == NORMLEV) /* AREMANYs stick together */
! 1084: wake_room(roomin(&tp->t_pos));
! 1085: /*
! 1086: * empty his pack
! 1087: */
! 1088: while (pitem != NULL)
! 1089: {
! 1090: nexti = next(pitem);
! 1091: (OBJPTR(pitem))->o_pos = tp->t_pos;
! 1092: detach(tp->t_pack, pitem);
! 1093: if (treasure)
! 1094: fall(pitem, FALSE);
! 1095: else
! 1096: o_discard(pitem);
! 1097: pitem = nexti;
! 1098: }
! 1099:
! 1100: turn_on(*tp,ISDEAD);
! 1101: attach(rlist,item);
! 1102: }
! 1103:
! 1104: /*
! 1105: * Returns a pointer to the weapon the monster is wielding corresponding to
! 1106: * the given thrown weapon. If no thrown item is given, try to find any
! 1107: * decent weapon.
! 1108: */
! 1109:
! 1110: struct linked_list *
! 1111: wield_weap(struct object *thrown, struct thing *mp)
! 1112: {
! 1113: int look_for = 0, /* The projectile weapon we are looking for */
! 1114: new_rate, /* The rating of a prospective weapon */
! 1115: cand_rate = -1; /* Rating of current candidate -- higher is better */
! 1116: register struct linked_list *pitem, *candidate = NULL;
! 1117: register struct object *obj;
! 1118:
! 1119: if (thrown != NULL) { /* Using a projectile weapon */
! 1120: switch (thrown->o_which) {
! 1121: case BOLT: look_for = CROSSBOW; /* Find the crossbow */
! 1122: when ARROW: look_for = BOW; /* Find the bow */
! 1123: when ROCK: look_for = SLING; /* find the sling */
! 1124: otherwise: return(NULL);
! 1125: }
! 1126: }
! 1127: else if (off(*mp, ISUNIQUE) && off(*mp, CARRYWEAPON)) return(NULL);
! 1128:
! 1129: for (pitem=mp->t_pack; pitem; pitem=next(pitem)) {
! 1130: obj = OBJPTR(pitem);
! 1131:
! 1132: /*
! 1133: * If we have a thrown weapon, just return the first match
! 1134: * we come to.
! 1135: */
! 1136: if (thrown != NULL && obj->o_type == WEAPON && obj->o_which == look_for)
! 1137: return(pitem);
! 1138:
! 1139: /* If we have a usable RELIC, return it */
! 1140: if (thrown == NULL && obj->o_type == RELIC) {
! 1141: switch (obj->o_which) {
! 1142: case MUSTY_DAGGER:
! 1143: case YEENOGHU_FLAIL:
! 1144: case HRUGGEK_MSTAR:
! 1145: case AXE_AKLAD:
! 1146: case MING_STAFF:
! 1147: case ASMO_ROD:
! 1148: case ORCUS_WAND:
! 1149: return(pitem);
! 1150: }
! 1151: }
! 1152:
! 1153: /* Otherwise if it's a usable weapon, it is a good candidate */
! 1154: else if (thrown == NULL && obj->o_type == WEAPON) {
! 1155: switch (obj->o_which) {
! 1156: case DAGGER:
! 1157: case SPEAR:
! 1158: new_rate = 0;
! 1159: when BATTLEAXE:
! 1160: new_rate = 1;
! 1161: when MACE:
! 1162: new_rate = 2;
! 1163: when SWORD:
! 1164: new_rate = 3;
! 1165: when PIKE:
! 1166: new_rate = 4;
! 1167: when HALBERD:
! 1168: case SPETUM:
! 1169: new_rate = 6;
! 1170: when BARDICHE:
! 1171: new_rate = 7;
! 1172: when TRIDENT:
! 1173: new_rate = 8;
! 1174: when BASWORD:
! 1175: new_rate = 9;
! 1176: when TWOSWORD:
! 1177: new_rate = 10;
! 1178: otherwise:
! 1179: new_rate = -1;
! 1180: }
! 1181:
! 1182: /* Only switch if this is better than the current candidate */
! 1183: if (new_rate > cand_rate) {
! 1184: cand_rate = new_rate;
! 1185: candidate = pitem;
! 1186: }
! 1187: }
! 1188: }
! 1189:
! 1190: return(candidate);
! 1191: }
! 1192:
! 1193: void
! 1194: explode(struct thing *tp)
! 1195: {
! 1196:
! 1197: register int x,y, damage;
! 1198: struct linked_list *item;
! 1199: struct thing *th;
! 1200:
! 1201: /*
! 1202: * check to see if it got the hero
! 1203: */
! 1204: if (off(player, ISINWALL) &&
! 1205: DISTANCE(hero.x, hero.y, tp->t_pos.x, tp->t_pos.y) <= 25) {
! 1206: msg("The explosion hits you! ");
! 1207: damage = roll(6,6);
! 1208: if (save(VS_WAND, &player, 0))
! 1209: damage /= 2;
! 1210: pstats.s_hpt -= damage;
! 1211: }
! 1212:
! 1213: /*
! 1214: * now check for monsters in vicinity
! 1215: */
! 1216: for (x = tp->t_pos.x-5; x<=tp->t_pos.x+5; x++) {
! 1217: if (x < 0 || x > cols - 1)
! 1218: continue;
! 1219: for (y = tp->t_pos.y-5; y<=tp->t_pos.y+5; y++) {
! 1220: if (y < 1 || y > lines - 3)
! 1221: continue;
! 1222: if (isalpha(mvwinch(mw, y, x))) {
! 1223: if ((item = find_mons(y, x)) != NULL) {
! 1224: th = THINGPTR(item);
! 1225: if (th == tp || /* don't count gas spore */
! 1226: on(*th, ISINWALL)) /* Don't count monsters in wall */
! 1227: continue;
! 1228: damage = roll(6, 6);
! 1229: if (save(VS_WAND, th, 0))
! 1230: damage /= 2;
! 1231: runto(th, &hero);
! 1232: if ((th->t_stats.s_hpt -= damage) <= 0) {
! 1233: msg("The explosion kills %s! ",
! 1234: prname(monster_name(th), FALSE));
! 1235: killed(item, FALSE, FALSE, TRUE);
! 1236: }
! 1237: }
! 1238: }
! 1239: }
! 1240: }
! 1241: }
! 1242:
! 1243: /*
! 1244: * skirmish:
! 1245: * Called when one monster attacks another monster.
! 1246: */
! 1247:
! 1248: bool
! 1249: skirmish(struct thing *attacker, coord *mp, struct object *weap, bool thrown)
! 1250: {
! 1251: register struct thing *defender;
! 1252: register struct linked_list *item;
! 1253: register bool did_hit = TRUE, see_att, see_def;
! 1254: char attname[LINELEN+1], defname[LINELEN+1];
! 1255: struct object *wielded; /* The wielded weapon */
! 1256: struct linked_list *get_wield; /* Linked list header for wielded */
! 1257:
! 1258: /*
! 1259: * Find the monster we want to fight
! 1260: */
! 1261: if ((item = find_mons(mp->y, mp->x)) == NULL) {
! 1262: return(FALSE); /* must have killed him already */
! 1263: }
! 1264: defender = THINGPTR(item);
! 1265:
! 1266: /* Can the player see either of the fighters? */
! 1267: see_att = (cansee(unc(attacker->t_pos)) &&
! 1268: (off(*attacker, ISINVIS) || on(player, CANSEE)) &&
! 1269: (off(*attacker, ISSHADOW) || on(player, CANSEE)));
! 1270: see_def = (cansee(unc(defender->t_pos)) &&
! 1271: (off(*defender, ISINVIS) || on(player, CANSEE)) &&
! 1272: (off(*defender, ISSHADOW) || on(player, CANSEE)));
! 1273:
! 1274: /*
! 1275: * Since we are fighting, things are not quiet so no healing takes
! 1276: * place. The -1 also tells us that we are in a fight.
! 1277: */
! 1278: attacker->t_quiet = -1;
! 1279: defender->t_quiet = -1;
! 1280:
! 1281: if (see_att) strcpy(attname, monster_name(attacker));
! 1282: else strcpy(attname, "something");
! 1283:
! 1284: if (see_def) strcpy(defname, monster_name(defender));
! 1285: else strcpy(defname, "something");
! 1286:
! 1287: /*
! 1288: * if its in the wall, we can't hit it
! 1289: */
! 1290: if (on(*defender, ISINWALL) && off(*attacker, CANINWALL))
! 1291: return(FALSE);
! 1292:
! 1293: if (on(*defender, ISSTONE)) {
! 1294: killed(item, FALSE, FALSE, FALSE);
! 1295: if (see_def)
! 1296: msg("%s shatters into a million pieces!", prname(defname, TRUE));
! 1297: return (TRUE);
! 1298: }
! 1299:
! 1300: /*
! 1301: * Let him know it was really a mimic (if it was one).
! 1302: */
! 1303: if (see_def && on(*defender, ISDISGUISE) &&
! 1304: (defender->t_type != defender->t_disguise)) {
! 1305: msg("Wait! There's a %s!", defname);
! 1306: turn_off(*defender, ISDISGUISE);
! 1307: did_hit = thrown;
! 1308: }
! 1309:
! 1310: if (see_def && on(*defender, CANSURPRISE) && !ISWEARING(R_ALERT)) {
! 1311: msg("Wait! There's a %s!", defname);
! 1312: turn_off(*defender, CANSURPRISE);
! 1313: did_hit = thrown;
! 1314: }
! 1315:
! 1316: if (did_hit) {
! 1317:
! 1318: did_hit = FALSE;
! 1319:
! 1320: /*
! 1321: * Try to find a weapon to wield. Wield_weap will return a
! 1322: * projector if weapon is a projectile (eg. bow for arrow).
! 1323: * If weapon is NULL, it will try to find a suitable weapon.
! 1324: */
! 1325: get_wield = wield_weap(weap, attacker);
! 1326: if (get_wield) wielded = OBJPTR(get_wield);
! 1327: else wielded = NULL;
! 1328:
! 1329: #ifdef DOBLINK
! 1330: /*
! 1331: * For now Blink Dogs will not blink away from monsters. We
! 1332: * have to fix can_blink so it isn't dependant on the player
! 1333: * before we can add it.
! 1334: */
! 1335: if (!can_blink(defender) &&
! 1336: #endif
! 1337: if (((weap && weap->o_type == RELIC) ||
! 1338: ((off(*defender, MAGICHIT) ||
! 1339: attacker->t_stats.s_lvl > 4 ||
! 1340: (weap && (weap->o_hplus > 0 || weap->o_dplus > 0))) &&
! 1341: (off(*defender, BMAGICHIT) ||
! 1342: attacker->t_stats.s_lvl > 6 ||
! 1343: (weap && (weap->o_hplus > 1 || weap->o_dplus > 1))) &&
! 1344: (off(*defender, CMAGICHIT) ||
! 1345: attacker->t_stats.s_lvl > 8 ||
! 1346: (weap && (weap->o_hplus > 2 || weap->o_dplus > 2)))))
! 1347: && roll_em(attacker, defender, weap, thrown, wielded, FALSE))
! 1348: {
! 1349: did_hit = TRUE;
! 1350:
! 1351: /* Should we start to chase this creature? */
! 1352: if (attacker->t_index != defender->t_index &&
! 1353: (off(*defender, ISRUN) || rnd(100) < 50)) {
! 1354: /*
! 1355: * If we're intelligent enough to realize that this
! 1356: * is a friendly monster, we will attack the hero instead.
! 1357: */
! 1358: if (on(*attacker, ISFRIENDLY) &&
! 1359: roll(3,6) < defender->t_stats.s_intel) {
! 1360: runto(defender, &hero);
! 1361: debug("%s attacking %s's hero", defname, attname);
! 1362: }
! 1363:
! 1364: /* Otherwise, let's chase the monster */
! 1365: else {
! 1366: runto(defender, &attacker->t_pos);
! 1367: debug("%s now attacking %s", defname, attname);
! 1368: }
! 1369: }
! 1370: else if (off(*defender, ISRUN)) runto(defender, &hero);
! 1371:
! 1372: /* Let the defender know that the attacker has missiles! */
! 1373: if ((defender->t_dest == &attacker->t_pos) && thrown)
! 1374: defender->t_wasshot = TRUE;
! 1375:
! 1376: if (on(*defender, NOMETAL) && weap != NULL &&
! 1377: weap->o_type != RELIC && weap->o_flags & ISMETAL) {
! 1378: if (see_def && see_att)
! 1379: msg("The %s passes right through %s!",
! 1380: weaps[weap->o_which].w_name, prname(defname, FALSE));
! 1381: }
! 1382: else {
! 1383: hit(weap, see_att, see_def,
! 1384: attname, defname, FALSE, thrown, FALSE);
! 1385: }
! 1386:
! 1387: /* See if there are any special effects */
! 1388: if (effect(attacker, defender,
! 1389: weap, thrown, see_att, see_def) != 0) {
! 1390: killed(item, FALSE, FALSE, TRUE);
! 1391: if (see_def) msg("%s dies.", prname(defname, TRUE));
! 1392: else msg("You hear a blood-curdling scream! ");
! 1393: }
! 1394:
! 1395: /*
! 1396: * Merchants just disappear if hit
! 1397: */
! 1398: else if (on(*defender, CANSELL)) {
! 1399: if (see_def)
! 1400: msg("%s disappears with his wares in a flash! ",
! 1401: prname(defname, TRUE));
! 1402: killed(item, FALSE, FALSE, FALSE);
! 1403: }
! 1404:
! 1405: else if (defender->t_stats.s_hpt <= 0) {
! 1406: killed(item, FALSE, FALSE, TRUE);
! 1407: if (see_def) msg("%s dies.", prname(defname, TRUE));
! 1408: else msg("You hear a blood-curdling scream! ");
! 1409: }
! 1410:
! 1411: else {
! 1412: /* Did we disrupt a spell? */
! 1413: /* Don't turn on WASDISRUPTED since player didn't do it */
! 1414: if (defender->t_action == A_SUMMON ||
! 1415: defender->t_action == A_MISSILE) {
! 1416: /* Just make the old fellow start over again */
! 1417: defender->t_action = A_NIL;
! 1418: defender->t_no_move = movement(defender);
! 1419: defender->t_using = NULL;
! 1420:
! 1421: if (see_def)
! 1422: msg("%s was disrupted.", prname(defname, TRUE));
! 1423: }
! 1424:
! 1425: #ifdef FLEEMONST
! 1426: /*
! 1427: * If the monster is fairly intelligent and about to die,
! 1428: * it may turn tail and run.
! 1429: */
! 1430: if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) &&
! 1431: (rnd(21) < tp->t_stats.s_intel)) {
! 1432: turn_on(*tp, ISFLEE);
! 1433:
! 1434: /* If monster was suffocating, stop it */
! 1435: if (on(*tp, DIDSUFFOCATE)) {
! 1436: turn_off(*tp, DIDSUFFOCATE);
! 1437: extinguish(suffocate);
! 1438: }
! 1439:
! 1440: /* If monster held us, stop it */
! 1441: if (on(*tp, DIDHOLD) && (--hold_count == 0))
! 1442: turn_off(player, ISHELD);
! 1443: turn_off(*tp, DIDHOLD);
! 1444:
! 1445: /* It is okay to turn tail */
! 1446: tp->t_oldpos = tp->t_pos;
! 1447: }
! 1448: #endif
! 1449: }
! 1450: }
! 1451: else {
! 1452: /* If the thing was trying to surprise, no good */
! 1453: if (on(*attacker, CANSURPRISE)) {
! 1454: /* If we can't see it, it keeps surprise (from us) */
! 1455: if (see_att) turn_off(*attacker, CANSURPRISE);
! 1456: }
! 1457:
! 1458: miss(weap, see_att, see_def, attname, defname, thrown, FALSE);
! 1459: }
! 1460: }
! 1461: return did_hit;
! 1462: }
! 1463:
CVSweb