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

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