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