[BACK]Return to fight.c CVS log [TXT][DIR] Up to [contributed] / early-roguelike / xrogue

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