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

Annotation of early-roguelike/arogue5/fight.c, Revision 1.1

1.1     ! rubenllo    1: /*
        !             2:  * All the fighting gets done here
        !             3:  *
        !             4:  * Advanced Rogue
        !             5:  * Copyright (C) 1984, 1985 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: #include "curses.h"
        !            16: #include <stdlib.h>
        !            17: #include <ctype.h>
        !            18: #include <string.h>
        !            19: #include "rogue.h"
        !            20:
        !            21: bool roll_em(struct thing *att_er, struct thing *def_er, struct object *weap,
        !            22:              bool hurl, struct object *cur_weapon, bool back_stab);
        !            23: void hit(struct object *weapon, struct thing *tp, const char *er,
        !            24:          const char *ee, bool back_stab);
        !            25: void miss(struct object *weapon, struct thing *tp, const char *er,
        !            26:           const char *ee);
        !            27: int dext_plus(int dexterity);
        !            28: int str_plus(short str);
        !            29: int add_dam(short str);
        !            30: int hung_dam(void);
        !            31: void thunk(struct object *weap, struct thing *tp, const char *mname);
        !            32: void m_thunk(struct object *weap, struct thing *tp, const char *mname);
        !            33: void bounce(struct object *weap, struct thing *tp, const char *mname);
        !            34: void m_bounce(struct object *weap, struct thing *tp, const char *mname);
        !            35: struct object *wield_weap(struct object *thrown, struct thing *mp);
        !            36: void explode(struct thing *tp);
        !            37:
        !            38: #define CONF_DAMAGE    -1
        !            39: #define PARAL_DAMAGE   -2
        !            40: #define DEST_DAMAGE    -3
        !            41:
        !            42: static const struct matrix att_mat[5] = {
        !            43: /* Base                Max_lvl,        Factor,         Offset,         Range */
        !            44: {  10,         25,             2,              1,              2 },
        !            45: {  9,          18,             2,              1,              5 },
        !            46: {  10,         19,             2,              1,              3 },
        !            47: {  10,         21,             2,              1,              4 },
        !            48: {   7,         25,             1,              0,              2 }
        !            49: };
        !            50:
        !            51: /*
        !            52:  * fight:
        !            53:  *     The player attacks the monster.
        !            54:  */
        !            55:
        !            56: bool
        !            57: fight(coord *mp, struct object *weap, bool thrown)
        !            58: {
        !            59:     register struct thing *tp;
        !            60:     register struct linked_list *item;
        !            61:     register bool did_hit = TRUE;
        !            62:     bool back_stab = FALSE;
        !            63:
        !            64:     /*
        !            65:      * Find the monster we want to fight
        !            66:      */
        !            67:     if ((item = find_mons(mp->y, mp->x)) == NULL) {
        !            68:        return(FALSE); /* must have killed him already */
        !            69:     }
        !            70:     tp = THINGPTR(item);
        !            71:     /*
        !            72:      * Since we are fighting, things are not quiet so no healing takes
        !            73:      * place.
        !            74:      */
        !            75:     player.t_quiet = 0;
        !            76:     tp->t_quiet = 0;
        !            77:
        !            78:     /*
        !            79:      * if its in the wall, we can't hit it
        !            80:      */
        !            81:     if (on(*tp, ISINWALL) && off(player, CANINWALL))
        !            82:        return(FALSE);
        !            83:
        !            84:     /*
        !            85:      * Let him know it was really a mimic (if it was one).
        !            86:      */
        !            87:     if (on(*tp, ISDISGUISE) && (tp->t_type != tp->t_disguise) &&
        !            88:        off(player, ISBLIND))
        !            89:     {
        !            90:        msg("Wait! That's a %s!", monsters[tp->t_index].m_name);
        !            91:        turn_off(*tp, ISDISGUISE);
        !            92:        did_hit = thrown;
        !            93:     }
        !            94:     if (on(*tp, CANSURPRISE) && off(player, ISBLIND) && !ISWEARING(R_ALERT)) {
        !            95:        msg("Wait! There's a %s!", monsters[tp->t_index].m_name);
        !            96:        turn_off(*tp, CANSURPRISE);
        !            97:        did_hit = thrown;
        !            98:     }
        !            99:     /*
        !           100:      * if he's a thief and the creature is asleep then he gets a chance
        !           101:      * for a backstab
        !           102:      */
        !           103:     if (player.t_ctype == C_THIEF                               &&
        !           104:        (!on(*tp, ISRUN) || on(*tp, ISHELD) || tp->t_no_move > 0)&&
        !           105:        !on(*tp, NOSTAB))
        !           106:        back_stab = TRUE;
        !           107:
        !           108:     runto(tp, &hero);
        !           109:
        !           110:     if (did_hit)
        !           111:     {
        !           112:        register const char *mname;
        !           113:
        !           114:        did_hit = FALSE;
        !           115:        mname = (on(player, ISBLIND)) ? "it" : monsters[tp->t_index].m_name;
        !           116:        if (!can_blink(tp) &&
        !           117:            ( ((weap != NULL) && (weap->o_type == RELIC)) ||
        !           118:             ((off(*tp, MAGICHIT)  || ((weap != NULL) && (weap->o_hplus > 0 || weap->o_dplus > 0)) ) &&
        !           119:              (off(*tp, BMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 1 || weap->o_dplus > 1)) ) &&
        !           120:              (off(*tp, CMAGICHIT) || ((weap != NULL) && (weap->o_hplus > 2 || weap->o_dplus > 2)) ) ) )
        !           121:            && roll_em(&player, tp, weap, thrown, cur_weapon, back_stab))
        !           122:        {
        !           123:            did_hit = TRUE;
        !           124:
        !           125:            if (on(*tp, NOMETAL) && weap != NULL &&
        !           126:                weap->o_type != RELIC && weap->o_flags & ISMETAL) {
        !           127:                sprintf(outstring,"Your %s passes right through the %s!",
        !           128:                    weaps[weap->o_which].w_name, mname);
        !           129:                msg(outstring);
        !           130:            }
        !           131:            else if (thrown) {
        !           132:                tp->t_wasshot = TRUE;
        !           133:                thunk(weap, tp, mname);
        !           134:            }
        !           135:            else
        !           136:                hit(weap, tp, NULL, mname, back_stab);
        !           137:
        !           138:            /* If the player hit a rust monster, he better have a + weapon */
        !           139:            if (on(*tp, CANRUST) && !thrown && (weap != NULL) &&
        !           140:                weap->o_type != RELIC &&
        !           141:                (weap->o_flags & ISMETAL) &&
        !           142:                !(weap->o_flags & ISPROT) &&
        !           143:                (weap->o_hplus < 1) && (weap->o_dplus < 1)) {
        !           144:                if (rnd(100) < 50) weap->o_hplus--;
        !           145:                else weap->o_dplus--;
        !           146:                msg(terse ? "Your %s weakens!"
        !           147:                          : "Your %s appears to be weaker now!",
        !           148:                    weaps[weap->o_which].w_name);
        !           149:            }
        !           150:
        !           151:            /* If the player hit something that shrieks, wake the dungeon */
        !           152:            if (on(*tp, CANSHRIEK)) {
        !           153:                turn_off(*tp, CANSHRIEK);
        !           154:                msg("The %s emits a piercing shriek.", mname);
        !           155:                aggravate();
        !           156:            }
        !           157:
        !           158:            /* If the player hit something that can surprise, it can't now */
        !           159:            if (on(*tp, CANSURPRISE)) turn_off(*tp, CANSURPRISE);
        !           160:
        !           161:
        !           162:            /*
        !           163:             * Can the player confuse?
        !           164:             */
        !           165:            if (on(player, CANHUH) && !thrown) {
        !           166:                msg("Your hands stop glowing red");
        !           167:                msg("The %s appears confused.", mname);
        !           168:                turn_on(*tp, ISHUH);
        !           169:                turn_off(player, CANHUH);
        !           170:            }
        !           171:            /*
        !           172:             * does the creature explode when hit?
        !           173:             */
        !           174:            if (on(*tp, CANEXPLODE))
        !           175:                explode(tp);
        !           176:
        !           177:            /*
        !           178:             * Merchants just disappear if hit
        !           179:             */
        !           180:            if (on(*tp, CANSELL)) {
        !           181:                msg("The %s disappears with his wares in a flash.",mname);
        !           182:                killed(item, FALSE, FALSE);
        !           183:            }
        !           184:
        !           185:            else if (tp->t_stats.s_hpt <= 0)
        !           186:                killed(item, TRUE, TRUE);
        !           187:
        !           188:            /* If the monster is fairly intelligent and about to die, it
        !           189:             * may turn tail and run.
        !           190:             */
        !           191:            else if ((tp->t_stats.s_hpt < max(10, tp->maxstats.s_hpt/10)) &&
        !           192:                     (rnd(25) < tp->t_stats.s_intel)) {
        !           193:                turn_on(*tp, ISFLEE);
        !           194:
        !           195:                /* If monster was suffocating, stop it */
        !           196:                if (on(*tp, DIDSUFFOCATE)) {
        !           197:                    turn_off(*tp, DIDSUFFOCATE);
        !           198:                    extinguish(suffocate);
        !           199:                }
        !           200:
        !           201:                /* If monster held us, stop it */
        !           202:                if (on(*tp, DIDHOLD) && (--hold_count == 0))
        !           203:                        turn_off(player, ISHELD);
        !           204:                turn_off(*tp, DIDHOLD);
        !           205:            }
        !           206:        }
        !           207:        else {
        !           208:            if (thrown)
        !           209:                bounce(weap, tp, mname);
        !           210:            else
        !           211:                miss(weap, tp, NULL, mname);
        !           212:        }
        !           213:     }
        !           214:     count = 0;
        !           215:     return did_hit;
        !           216: }
        !           217:
        !           218: /*
        !           219:  * attack:
        !           220:  *     The monster attacks the player
        !           221:  */
        !           222:
        !           223: bool
        !           224: attack(struct thing *mp, struct object *weapon, bool thrown)
        !           225: {
        !           226:     register const char *mname;
        !           227:     register bool did_hit = FALSE;
        !           228:     register struct object *wielded;   /* The wielded weapon */
        !           229:
        !           230:     /*
        !           231:      * Since this is an attack, stop running and any healing that was
        !           232:      * going on at the time.
        !           233:      */
        !           234:     running = FALSE;
        !           235:     player.t_quiet = 0;
        !           236:     mp->t_quiet = 0;
        !           237:
        !           238:     if (on(*mp, ISDISGUISE) && off(player, ISBLIND))
        !           239:        turn_off(*mp, ISDISGUISE);
        !           240:     mname = on(player, ISBLIND) ? "it" : monsters[mp->t_index].m_name;
        !           241:
        !           242:     /*
        !           243:      * Try to find a weapon to wield.  Wield_weap will return a
        !           244:      * projector if weapon is a projectile (eg. bow for arrow).
        !           245:      * If weapon is NULL, it will try to find a suitable weapon.
        !           246:      */
        !           247:     wielded = wield_weap(weapon, mp);
        !           248:     if (weapon == NULL) weapon = wielded;
        !           249:
        !           250:     if (roll_em(mp, &player, weapon, thrown, wielded, FALSE)) {
        !           251:        did_hit = TRUE;
        !           252:
        !           253:        if (thrown) m_thunk(weapon, mp, mname);
        !           254:        else hit(weapon, mp, mname, NULL, FALSE);
        !           255:
        !           256:        if (pstats.s_hpt <= 0)
        !           257:            death(mp->t_index); /* Bye bye life ... */
        !           258:
        !           259:        /*
        !           260:         * suprising monsters appear after they shoot at you
        !           261:         */
        !           262:        if (thrown) {
        !           263:            if (on(*mp, CANSURPRISE))
        !           264:                turn_off(*mp, CANSURPRISE);
        !           265:        }
        !           266:        if (!thrown) {
        !           267:            /*
        !           268:             * If a vampire hits, it may take half your hit points
        !           269:             */
        !           270:            if (on(*mp, CANSUCK) && !save(VS_MAGIC, &player, 0)) {
        !           271:                if (pstats.s_hpt == 1) death(mp->t_index);
        !           272:                else {
        !           273:                  pstats.s_hpt /= 2;
        !           274:                  msg("You feel your life force being drawn from you.");
        !           275:                }
        !           276:            }
        !           277:
        !           278:            /*
        !           279:             * Stinking monsters make player weaker (to hit)
        !           280:             */
        !           281:            if (on(*mp, CANSTINK)) {
        !           282:                turn_off(*mp, CANSTINK);
        !           283:                if (!save(VS_POISON, &player, 0)) {
        !           284:                    msg("The stench of the %s sickens you.", mname);
        !           285:                    if (on(player, HASSTINK)) lengthen(unstink, STINKTIME);
        !           286:                    else {
        !           287:                        turn_on(player, HASSTINK);
        !           288:                        fuse(unstink, 0, STINKTIME, AFTER);
        !           289:                    }
        !           290:                }
        !           291:            }
        !           292:
        !           293:            /*
        !           294:             * Chilling monster reduces strength each time
        !           295:             */
        !           296:            if (on(*mp, CANCHILL)) {
        !           297:                if (!ISWEARING(R_SUSABILITY) && !save(VS_POISON, &player, 0)) {
        !           298:                    msg("You cringe at the %s's chilling touch.", mname);
        !           299:                    chg_str(-1);
        !           300:                    if (lost_str++ == 0)
        !           301:                        fuse(res_strength, 0, CHILLTIME, AFTER);
        !           302:                    else lengthen(res_strength, CHILLTIME);
        !           303:                }
        !           304:            }
        !           305:
        !           306:            /*
        !           307:             * itching monsters reduce dexterity (temporarily)
        !           308:             */
        !           309:            if (on(*mp, CANITCH) && !save(VS_POISON, &player, 0)) {
        !           310:                msg("The claws of the %s scratch you", mname);
        !           311:                if(ISWEARING(R_SUSABILITY)) {
        !           312:                    msg("The scratch has no effect");
        !           313:                }
        !           314:                else {
        !           315:                    turn_on(player, HASITCH);
        !           316:                    add_dexterity(TRUE);
        !           317:                    lost_dext++;
        !           318:                    fuse(un_itch, 0, roll(HEALTIME,SICKTIME), AFTER);
        !           319:                }
        !           320:            }
        !           321:
        !           322:
        !           323:            /*
        !           324:             * If a hugging monster hits, it may SQUEEEEEEEZE
        !           325:             */
        !           326:            if (on(*mp, CANHUG)) {
        !           327:                if (roll(1,20) >= 18 || roll(1,20) >= 18) {
        !           328:                    msg("The %s squeezes you against itself.", mname);
        !           329:                    if ((pstats.s_hpt -= roll(2,8)) <= 0)
        !           330:                        death(mp->t_index);
        !           331:                }
        !           332:            }
        !           333:
        !           334:            /*
        !           335:             * If a disease-carrying monster hits, there is a chance the
        !           336:             * player will catch the disease
        !           337:             */
        !           338:            if (on(*mp, CANDISEASE) &&
        !           339:                (rnd(pstats.s_const) < mp->t_stats.s_lvl) &&
        !           340:                off(player, HASDISEASE)) {
        !           341:                if (ISWEARING(R_HEALTH)) msg("The wound heals quickly.");
        !           342:                else {
        !           343:                    turn_on(player, HASDISEASE);
        !           344:                    fuse(cure_disease, 0, roll(HEALTIME,SICKTIME), AFTER);
        !           345:                    msg(terse ? "You have been diseased."
        !           346:                        : "You have contracted a disease!");
        !           347:                }
        !           348:            }
        !           349:
        !           350:            /*
        !           351:             * If a rust monster hits, you lose armor
        !           352:             */
        !           353:            if (on(*mp, CANRUST)) {
        !           354:                if (cur_armor != NULL                           &&
        !           355:                    cur_armor->o_which != LEATHER               &&
        !           356:                    cur_armor->o_which != STUDDED_LEATHER       &&
        !           357:                    cur_armor->o_which != PADDED_ARMOR          &&
        !           358:                    !(cur_armor->o_flags & ISPROT)              &&
        !           359:                    cur_armor->o_ac < pstats.s_arm+1            ) {
        !           360:                        msg(terse ? "Your armor weakens"
        !           361:                            : "Your armor appears to be weaker now. Oh my!");
        !           362:                        cur_armor->o_ac++;
        !           363:                }
        !           364:                if (cur_misc[WEAR_BRACERS] != NULL              &&
        !           365:                    cur_misc[WEAR_BRACERS]->o_ac > 0            &&
        !           366:                    !(cur_misc[WEAR_BRACERS]->o_flags & ISPROT)) {
        !           367:                        cur_misc[WEAR_BRACERS]->o_ac--;
        !           368:                        if (cur_misc[WEAR_BRACERS]->o_ac == 0) {
        !           369:                            register struct linked_list *item;
        !           370:
        !           371:                            for (item=pack; item!=NULL; item=next(item)) {
        !           372:                                if (OBJPTR(item) == cur_misc[WEAR_BRACERS]) {
        !           373:                                    detach(pack, item);
        !           374:                                    o_discard(item);
        !           375:                                    break;
        !           376:                                }
        !           377:                            }
        !           378:                            msg ("Your bracers crumble and fall off!");
        !           379:                            cur_misc[WEAR_BRACERS] = NULL;
        !           380:                            inpack--;
        !           381:                        }
        !           382:                        else {
        !           383:                            msg("Your bracers weaken!");
        !           384:                        }
        !           385:                }
        !           386:            }
        !           387:            /*
        !           388:             * If can dissolve and hero has leather type armor
        !           389:             */
        !           390:            if (on(*mp, CANDISSOLVE) && cur_armor != NULL &&
        !           391:                (cur_armor->o_which == LEATHER            ||
        !           392:                 cur_armor->o_which == STUDDED_LEATHER    ||
        !           393:                 cur_armor->o_which == PADDED_ARMOR)      &&
        !           394:                !(cur_armor->o_flags & ISPROT) &&
        !           395:                cur_armor->o_ac < pstats.s_arm+1) {
        !           396:                msg(terse ? "Your armor dissolves"
        !           397:                    : "Your armor appears to dissolve. Oh my!");
        !           398:                cur_armor->o_ac++;
        !           399:            }
        !           400:
        !           401:            /* If a surprising monster hit you, you can see it now */
        !           402:            if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
        !           403:
        !           404:            /*
        !           405:             * If an infesting monster hits you, you get a parasite or rot
        !           406:             */
        !           407:            if (on(*mp, CANINFEST) && rnd(pstats.s_const) < mp->t_stats.s_lvl) {
        !           408:                if (ISWEARING(R_HEALTH)) msg("The wound quickly heals.");
        !           409:                else {
        !           410:                    turn_off(*mp, CANINFEST);
        !           411:                    msg(terse ? "You have been infested."
        !           412:                        : "You have contracted a parasitic infestation!");
        !           413:                    infest_dam++;
        !           414:                    turn_on(player, HASINFEST);
        !           415:                }
        !           416:            }
        !           417:
        !           418:            /*
        !           419:             * Ants have poisonous bites
        !           420:             */
        !           421:            if (on(*mp, CANPOISON) && !save(VS_POISON, &player, 0)) {
        !           422:                if (ISWEARING(R_SUSABILITY))
        !           423:                    msg(terse ? "Sting has no effect"
        !           424:                              : "A sting momentarily weakens you");
        !           425:                else {
        !           426:                    chg_str(-1);
        !           427:                    msg(terse ? "A sting has weakened you" :
        !           428:                    "You feel a sting in your arm and now feel weaker");
        !           429:                }
        !           430:            }
        !           431:            /*
        !           432:             * does it take wisdom away?
        !           433:             */
        !           434:            if (on(*mp, TAKEWISDOM)             &&
        !           435:                !save(VS_MAGIC, &player, 0)     &&
        !           436:                !ISWEARING(R_SUSABILITY)) {
        !           437:                        add_wisdom(TRUE);
        !           438:            }
        !           439:            /*
        !           440:             * does it take intelligence away?
        !           441:             */
        !           442:            if (on(*mp, TAKEINTEL)              &&
        !           443:                !save(VS_MAGIC, &player, 0)     &&
        !           444:                !ISWEARING(R_SUSABILITY)) {
        !           445:                        add_intelligence(TRUE);
        !           446:            }
        !           447:            /*
        !           448:             * Cause fear by touching
        !           449:             */
        !           450:            if (on(*mp, TOUCHFEAR)) {
        !           451:                turn_off(*mp, TOUCHFEAR);
        !           452:                if (!ISWEARING(R_HEROISM)       &&
        !           453:                    !save(VS_WAND, &player, 0)  &&
        !           454:                    !(on(player, ISFLEE) && (player.t_dest == &mp->t_pos))) {
        !           455:                        turn_on(player, ISFLEE);
        !           456:                        player.t_dest = &mp->t_pos;
        !           457:                        msg("The %s's touch terrifies you.", mname);
        !           458:                }
        !           459:            }
        !           460:
        !           461:            /*
        !           462:             * make the hero dance (as in otto's irresistable dance)
        !           463:             */
        !           464:            if (on(*mp, CANDANCE)       &&
        !           465:                !on(player, ISDANCE)    &&
        !           466:                !save(VS_MAGIC, &player, -4)) {
        !           467:                    turn_off(*mp, CANDANCE);
        !           468:                    turn_on(player, ISDANCE);
        !           469:                    msg("You begin to dance uncontrollably!");
        !           470:                    fuse(undance, 0, roll(2,4), AFTER);
        !           471:            }
        !           472:
        !           473:            /*
        !           474:             * Suffocating our hero
        !           475:             */
        !           476:            if (on(*mp, CANSUFFOCATE) && (rnd(100) < 15) &&
        !           477:                (find_slot(suffocate) == FALSE)) {
        !           478:                turn_on(*mp, DIDSUFFOCATE);
        !           479:                msg("The %s is beginning to suffocate you.", mname);
        !           480:                fuse(suffocate, 0, roll(4,2), AFTER);
        !           481:            }
        !           482:
        !           483:            /*
        !           484:             * Turning to stone
        !           485:             */
        !           486:            if (on(*mp, TOUCHSTONE)) {
        !           487:                turn_off(*mp, TOUCHSTONE);
        !           488:                if (on(player, CANINWALL))
        !           489:                        msg("The %s's touch has no effect.", mname);
        !           490:                else {
        !           491:                    if (!save(VS_PETRIFICATION, &player, 0) && rnd(100) < 15) {
        !           492:                        msg("Your body begins to solidify.");
        !           493:                        msg("You are turned to stone !!! --More--");
        !           494:                        wait_for(cw,' ');
        !           495:                        death(D_PETRIFY);
        !           496:                    }
        !           497:                    else {
        !           498:                        msg("The %s's touch stiffens your limbs.", mname);
        !           499:                        no_command += STONETIME;
        !           500:                    }
        !           501:                }
        !           502:            }
        !           503:
        !           504:            /*
        !           505:             * Wraiths might drain energy levels
        !           506:             */
        !           507:            if ((on(*mp, CANDRAIN) || on(*mp, DOUBLEDRAIN)) && rnd(100) < 15) {
        !           508:                lower_level(mp->t_index);
        !           509:                if (on(*mp, DOUBLEDRAIN)) lower_level(mp->t_index);
        !           510:                turn_on(*mp, DIDDRAIN);
        !           511:            }
        !           512:
        !           513:            /*
        !           514:             * Violet fungi stops the poor guy from moving
        !           515:             */
        !           516:            if (on(*mp, CANHOLD) && off(*mp, DIDHOLD)) {
        !           517:                turn_on(player, ISHELD);
        !           518:                turn_on(*mp, DIDHOLD);
        !           519:                hold_count++;
        !           520:            }
        !           521:
        !           522:            /*
        !           523:             * Sucker will suck blood and run
        !           524:             */
        !           525:            if (on(*mp, CANDRAW)) {
        !           526:                turn_off(*mp, CANDRAW);
        !           527:                turn_on(*mp, ISFLEE);
        !           528:                msg("The %s sates itself with your blood.", mname);
        !           529:                if ((pstats.s_hpt -= 12) <= 0) death(mp->t_index);
        !           530:            }
        !           531:
        !           532:            /*
        !           533:             * Bad smell will force a reduction in strength
        !           534:             */
        !           535:            if (on(*mp, CANSMELL)) {
        !           536:                turn_off(*mp, CANSMELL);
        !           537:                if (save(VS_MAGIC, &player, 0) || ISWEARING(R_SUSABILITY))
        !           538:                    msg("You smell an unpleasant odor.");
        !           539:                else {
        !           540:                    int odor_str = -(rnd(6)+1);
        !           541:
        !           542:                    msg("You are overcome by a foul odor.");
        !           543:                    if (lost_str == 0) {
        !           544:                        chg_str(odor_str);
        !           545:                        fuse(res_strength, 0, SMELLTIME, AFTER);
        !           546:                        lost_str -= odor_str;
        !           547:                    }
        !           548:                    else lengthen(res_strength, SMELLTIME);
        !           549:                }
        !           550:            }
        !           551:
        !           552:            /*
        !           553:             * Paralyzation
        !           554:             */
        !           555:            if (on(*mp, CANPARALYZE)) {
        !           556:                turn_off(*mp, CANPARALYZE);
        !           557:                if (!save(VS_PARALYZATION, &player, 0)) {
        !           558:                    if (on(player, CANINWALL))
        !           559:                        msg("The %s's touch has no effect.", mname);
        !           560:                    else {
        !           561:                        msg("The %s's touch paralyzes you.", mname);
        !           562:                        no_command += FREEZETIME;
        !           563:                    }
        !           564:                }
        !           565:            }
        !           566:
        !           567:            /*
        !           568:             * Painful wounds make you faint
        !           569:             */
        !           570:             if (on(*mp, CANPAIN)) {
        !           571:                turn_off(*mp, CANPAIN);
        !           572:                if (!ISWEARING(R_ALERT) && !save(VS_POISON, &player, 0)) {
        !           573:                        msg("You faint from the painful wound");
        !           574:                        no_command += PAINTIME;
        !           575:                }
        !           576:            }
        !           577:
        !           578:            /*
        !           579:             * The monsters touch slows the hero down
        !           580:             */
        !           581:             if (on(*mp, CANSLOW)) {
        !           582:                turn_off(*mp, CANSLOW);
        !           583:                if (!save(VS_PARALYZATION, &player, 0))
        !           584:                        add_slow();
        !           585:            }
        !           586:
        !           587:            /*
        !           588:             * Rotting
        !           589:             */
        !           590:            if (on(*mp, CANROT)) {
        !           591:                if (!ISWEARING(R_HEALTH) &&
        !           592:                    !save(VS_POISON, &player, 0)     &&
        !           593:                    off(player, DOROT)) {
        !           594:                    turn_on(player, DOROT);
        !           595:                    msg("You feel your skin starting to rot away!");
        !           596:                }
        !           597:            }
        !           598:
        !           599:            if (on(*mp, STEALGOLD)) {
        !           600:                /*
        !           601:                 * steal some gold
        !           602:                 */
        !           603:                register long lastpurse;
        !           604:                register struct linked_list *item;
        !           605:                register struct object *obj;
        !           606:
        !           607:                lastpurse = purse;
        !           608:                purse -= GOLDCALC + GOLDCALC;
        !           609:                if (!save(VS_MAGIC, &player, mp->t_stats.s_lvl/10)) {
        !           610:                    if (on(*mp, ISUNIQUE))
        !           611:                        purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
        !           612:                    purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
        !           613:                }
        !           614:                if (purse < 0)
        !           615:                    purse = 0;
        !           616:                if (purse != lastpurse) {
        !           617:                    msg("Your purse feels lighter");
        !           618:
        !           619:                    /* Give the gold to the thief */
        !           620:                    for (item=mp->t_pack; item != NULL; item=next(item)) {
        !           621:                        obj = OBJPTR(item);
        !           622:                        if (obj->o_type == GOLD) {
        !           623:                            obj->o_count += lastpurse - purse;
        !           624:                            break;
        !           625:                        }
        !           626:                    }
        !           627:
        !           628:                    /* Did we do it? */
        !           629:                    if (item == NULL) { /* Then make some */
        !           630:                        item = new_item(sizeof *obj);
        !           631:                        obj = OBJPTR(item);
        !           632:                        obj->o_type = GOLD;
        !           633:                        obj->o_count = lastpurse - purse;
        !           634:                        obj->o_hplus = obj->o_dplus = 0;
        !           635:                        strcpy(obj->o_damage,"0d0");
        !           636:                         strcpy(obj->o_hurldmg,"0d0");
        !           637:                        obj->o_ac = 11;
        !           638:                        obj->contents = NULL;
        !           639:                        obj->o_group = 0;
        !           640:                        obj->o_flags = 0;
        !           641:                        obj->o_mark[0] = '\0';
        !           642:                        obj->o_pos = mp->t_pos;
        !           643:
        !           644:                        attach(mp->t_pack, item);
        !           645:                    }
        !           646:                }
        !           647:
        !           648:                turn_on(*mp, ISFLEE);
        !           649:                turn_on(*mp, ISINVIS);
        !           650:            }
        !           651:
        !           652:            if (on(*mp, STEALMAGIC)) {
        !           653:                register struct linked_list *list, *steal;
        !           654:                register struct object *obj;
        !           655:                register int nobj;
        !           656:
        !           657:                /*
        !           658:                 * steal a magic item, look through the pack
        !           659:                 * and pick out one we like.
        !           660:                 */
        !           661:                steal = NULL;
        !           662:                for (nobj = 0, list = pack; list != NULL; list = next(list))
        !           663:                {
        !           664:                    obj = OBJPTR(list);
        !           665:                    if (!is_current(obj) &&
        !           666:                        is_magic(obj)    &&
        !           667:                        rnd(++nobj) == 0)
        !           668:                            steal = list;
        !           669:                }
        !           670:                if (steal != NULL)
        !           671:                {
        !           672:                    register struct object *obj;
        !           673:                    struct linked_list *item;
        !           674:
        !           675:                    obj = OBJPTR(steal);
        !           676:                    if (on(*mp, ISUNIQUE))
        !           677:                        monsters[mp->t_index].m_normal = TRUE;
        !           678:                    item = find_mons(mp->t_pos.y, mp->t_pos.x);
        !           679:                    killed(item, FALSE, FALSE);
        !           680:                    if (obj->o_count > 1 && obj->o_group == 0) {
        !           681:                        register int oc;
        !           682:
        !           683:                        oc = --(obj->o_count);
        !           684:                        obj->o_count = 1;
        !           685:                        sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE));
        !           686:                        msg(outstring);
        !           687:                        obj->o_count = oc;
        !           688:                    }
        !           689:                    else {
        !           690:                        sprintf(outstring,"The %s stole %s!", mname, inv_name(obj, TRUE));
        !           691:                        msg(outstring);
        !           692:                        detach(pack, steal);
        !           693:
        !           694:                        /* If this is a relic, clear its holding field */
        !           695:                        if (obj->o_type == RELIC)
        !           696:                            cur_relic[obj->o_which] = 0;
        !           697:
        !           698:                        o_discard(steal);
        !           699:                        inpack--;
        !           700:                    }
        !           701:                    updpack(FALSE);
        !           702:                }
        !           703:            }
        !           704:        }
        !           705:     }
        !           706:     else {
        !           707:        /* If the thing was trying to surprise, no good */
        !           708:        if (on(*mp, CANSURPRISE)) turn_off(*mp, CANSURPRISE);
        !           709:
        !           710:        else if (thrown) m_bounce(weapon, mp, mname);
        !           711:        else miss(weapon, mp, mname, NULL);
        !           712:     }
        !           713:     if (fight_flush)
        !           714:        md_flushinp();
        !           715:     count = 0;
        !           716:     status(FALSE);
        !           717:     return(did_hit);
        !           718: }
        !           719:
        !           720: /*
        !           721:  * swing:
        !           722:  *     returns true if the swing hits
        !           723:  */
        !           724:
        !           725: bool
        !           726: swing(short class, int at_lvl, int op_arm, int wplus)
        !           727: {
        !           728:     register int res = rnd(20)+1;
        !           729:     register int need;
        !           730:
        !           731:     need = att_mat[class].base -
        !           732:           att_mat[class].factor *
        !           733:           ((min(at_lvl, att_mat[class].max_lvl) -
        !           734:            att_mat[class].offset)/att_mat[class].range) +
        !           735:           (10 - op_arm);
        !           736:     if (need > 20 && need <= 25) need = 20;
        !           737:
        !           738:     return (res+wplus >= need);
        !           739: }
        !           740:
        !           741: /*
        !           742:  * roll_em:
        !           743:  *     Roll several attacks
        !           744:  */
        !           745:
        !           746: bool
        !           747: roll_em(struct thing *att_er, struct thing *def_er, struct object *weap,
        !           748:         bool hurl, struct object *cur_weapon, bool back_stab)
        !           749: {
        !           750:     register struct stats *att, *def;
        !           751:     register char *cp = NULL;
        !           752:     register int ndice, nsides, nplus, def_arm;
        !           753:     bool did_hit = FALSE;
        !           754:     int prop_hplus, prop_dplus;
        !           755:     int vampiric_damage;
        !           756:
        !           757:     /* Get statistics */
        !           758:     att = &att_er->t_stats;
        !           759:     def = &def_er->t_stats;
        !           760:
        !           761:     prop_hplus = prop_dplus = 0;
        !           762:     if (weap == NULL)
        !           763:        cp = att->s_dmg;
        !           764:     else if (hurl) {
        !           765:        if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
        !           766:          cur_weapon->o_which == weap->o_launch)
        !           767:        {
        !           768:            cp = weap->o_hurldmg;
        !           769:            prop_hplus = cur_weapon->o_hplus;
        !           770:            prop_dplus = cur_weapon->o_dplus;
        !           771:        }
        !           772:        else
        !           773:            cp = (weap->o_flags&ISMISL ? weap->o_damage : weap->o_hurldmg);
        !           774:     }
        !           775:     else {
        !           776:        if (weap->o_type == RELIC) {
        !           777:            switch (weap->o_which) {
        !           778:                case MUSTY_DAGGER:      cp = "1d4+1/1d4+1";
        !           779:                when YEENOGHU_FLAIL:    cp = "3d6/paralyze/confuse";
        !           780:                when HRUGGEK_MSTAR:     cp = "3d10";
        !           781:                when MING_STAFF:        cp = "1d8";
        !           782:                when ASMO_ROD:          cp = "2d8+1";
        !           783:                when ORCUS_WAND:        cp = "destroy";
        !           784:            }
        !           785:        }
        !           786:        else cp = weap->o_damage;
        !           787:        /*
        !           788:         * Drain a staff of striking
        !           789:         */
        !           790:        if (weap->o_type == STICK && weap->o_which == WS_HIT
        !           791:            && weap->o_charges == 0)
        !           792:                {
        !           793:                    strcpy(weap->o_damage,"0d0");
        !           794:                    weap->o_hplus = weap->o_dplus = 0;
        !           795:                }
        !           796:     }
        !           797:     for (;;)
        !           798:     {
        !           799:        int damage;
        !           800:        int hplus = prop_hplus;
        !           801:        int dplus = prop_dplus;
        !           802:
        !           803:        if (weap != NULL && weap->o_type == RELIC) {
        !           804:            switch (weap->o_which) {
        !           805:                case MUSTY_DAGGER:
        !           806:                    if (att != &pstats || /* Not player or good stats */
        !           807:                        (str_compute() > 15 && dex_compute() > 15)) {
        !           808:
        !           809:                        hplus += 6;
        !           810:                        dplus += 6;
        !           811:
        !           812:                        /* Give an additional strength and dex bonus */
        !           813:                        if (att == &pstats) {
        !           814:                            hplus += str_plus(str_compute()) +
        !           815:                                     dext_plus(dex_compute());
        !           816:                            dplus += dext_plus(dex_compute()) +
        !           817:                                     add_dam(str_compute());
        !           818:                        }
        !           819:                        else {
        !           820:                            hplus += str_plus(att->s_str) +
        !           821:                                     dext_plus(att->s_dext);
        !           822:                            dplus += dext_plus(att->s_dext) +
        !           823:                                     add_dam(att->s_str);
        !           824:                        }
        !           825:                    }
        !           826:                    else {
        !           827:                        hplus -= 3;
        !           828:                        dplus -= 3;
        !           829:                    }
        !           830:                when YEENOGHU_FLAIL:
        !           831:                case HRUGGEK_MSTAR:
        !           832:                    hplus += 3;
        !           833:                    dplus += 3;
        !           834:                when MING_STAFF:
        !           835:                    hplus += 2;
        !           836:                    dplus += 2;
        !           837:            }
        !           838:        }
        !           839:        else if (weap != NULL) {
        !           840:            hplus += weap->o_hplus;
        !           841:            dplus += weap->o_dplus;
        !           842:        }
        !           843:
        !           844:        /* Is attacker weak? */
        !           845:        if (on(*att_er, HASSTINK)) hplus -= 2;
        !           846:
        !           847:        if (att == &pstats)     /* Is the attacker the player? */
        !           848:        {
        !           849:            hplus += hitweight();       /* adjust for encumberence */
        !           850:            dplus += hung_dam();        /* adjust damage for hungry player */
        !           851:            dplus += ring_value(R_ADDDAM);
        !           852:        }
        !           853:        if (back_stab || (weap && att != &pstats && on(*att_er, CANBSTAB)))
        !           854:            hplus += 4; /* add in pluses for backstabbing */
        !           855:
        !           856:        /* Get the damage */
        !           857:        while (isspace(*cp)) cp++;
        !           858:        if (!isdigit(*cp)) {
        !           859:            if (strncmp(cp, "confuse", 7) == 0) ndice = CONF_DAMAGE;
        !           860:            else if (strncmp(cp, "paralyze", 8) == 0) ndice = PARAL_DAMAGE;
        !           861:            else if (strncmp(cp, "destroy", 7) == 0) ndice = DEST_DAMAGE;
        !           862:            else ndice = 0;
        !           863:            nsides = 0;
        !           864:            nplus = 0;
        !           865:        }
        !           866:        else {
        !           867:            char *oldcp;
        !           868:
        !           869:            /* Get the number of damage dice */
        !           870:            ndice = atoi(cp);
        !           871:            if ((cp = strchr(cp, 'd')) == NULL)
        !           872:                break;
        !           873:
        !           874:            /* Skip the 'd' and get the number of sides per die */
        !           875:            nsides = atoi(++cp);
        !           876:
        !           877:            /* Check for an addition -- save old place in case none is found */
        !           878:            oldcp = cp;
        !           879:            if ((cp = strchr(cp, '+')) != NULL) nplus = atoi(++cp);
        !           880:            else {
        !           881:                nplus = 0;
        !           882:                cp = oldcp;
        !           883:            }
        !           884:        }
        !           885:
        !           886:        if (def == &pstats) { /* Monster attacks player */
        !           887:            def_arm = ac_compute() - dext_prot(dex_compute());
        !           888:            hplus += str_plus(att->s_str)+dext_plus(att->s_dext);
        !           889:        }
        !           890:        else {  /* Player attacks monster */
        !           891:            def_arm = def->s_arm - dext_prot(def->s_dext);
        !           892:            hplus += str_plus(str_compute())+dext_plus(dex_compute());
        !           893:        }
        !           894:
        !           895:        if (swing(att_er->t_ctype, att->s_lvl, def_arm, hplus)) {
        !           896:            register int proll;
        !           897:
        !           898:            /* Take care of special effects */
        !           899:            switch (ndice) {
        !           900:              case CONF_DAMAGE:
        !           901:                if (def == &pstats) { /* Monster attacks player */
        !           902:                    if (!save(VS_MAGIC, &player, 0) && off(player, ISCLEAR)) {
        !           903:                        msg("You feel disoriented.");
        !           904:                        if (find_slot(unconfuse))
        !           905:                            lengthen(unconfuse, rnd(8)+HUHDURATION);
        !           906:                        else
        !           907:                            fuse(unconfuse, 0, rnd(8)+HUHDURATION, AFTER);
        !           908:                        turn_on(player, ISHUH);
        !           909:                    }
        !           910:                    else msg("You feel dizzy, but it quickly passes.");
        !           911:                }
        !           912:                /* Player hits monster */
        !           913:                else if (!save(VS_MAGIC, def_er, 0) && off(*def_er, ISCLEAR)) {
        !           914:                    msg("The artifact warms with pleasure.");
        !           915:                    turn_on(*def_er, ISHUH);
        !           916:                }
        !           917:                did_hit = TRUE;
        !           918:              when PARAL_DAMAGE:
        !           919:                if (def == &pstats) { /* Monster attacks player */
        !           920:                    if (!save(VS_MAGIC, &player, 0) && off(player, CANINWALL)) {
        !           921:                        msg("You stiffen up.");
        !           922:                        no_command += FREEZETIME;
        !           923:                    }
        !           924:                }
        !           925:                else if (!save(VS_MAGIC, def_er, 0)) { /* Player hits monster */
        !           926:                    msg("The artifact hums happily.");
        !           927:                    turn_off(*def_er, ISRUN);
        !           928:                    turn_on(*def_er, ISHELD);
        !           929:                }
        !           930:                did_hit = TRUE;
        !           931:              when DEST_DAMAGE:
        !           932:                if (def == &pstats) { /* Monster attacks player */
        !           933:                    msg("You feel a tug at your life force.");
        !           934:                    if (!save(VS_MAGIC, &player, -4)) {
        !           935:                        msg("The wand devours your soul.");
        !           936:                        def->s_hpt = 0;
        !           937:                    }
        !           938:                }
        !           939:                /* Player hits monster */
        !           940:                else if (!save(VS_MAGIC, def_er, -4)) {
        !           941:                    msg("The artifact draws energy.");
        !           942:
        !           943:                    /* Give the player half the monster's hits */
        !           944:                    att->s_hpt += def->s_hpt/2;
        !           945:                    if (att->s_hpt > att_er->maxstats.s_hpt)
        !           946:                        att->s_hpt = att_er->maxstats.s_hpt;
        !           947:
        !           948:                    /* Kill the monster */
        !           949:                    def->s_hpt = 0;
        !           950:                }
        !           951:                did_hit = TRUE;
        !           952:              otherwise:
        !           953:                /* Heil's ankh always gives maximum damage */
        !           954:                if (att == &pstats && cur_relic[HEIL_ANKH])
        !           955:                    proll = ndice * nsides;
        !           956:                else proll = roll(ndice, nsides);
        !           957:
        !           958:                if (ndice + nsides > 0 && proll < 1)
        !           959:                    debug("Damage for %dd%d came out %d.",
        !           960:                                ndice, nsides, proll);
        !           961:                damage = dplus + proll + nplus;
        !           962:                if (def == &pstats)
        !           963:                    damage += add_dam(att->s_str);
        !           964:                else
        !           965:                    damage += add_dam(str_compute());
        !           966:
        !           967:                /* Check for half damage monsters */
        !           968:                if (on(*def_er, HALFDAMAGE)) damage /= 2;
        !           969:
        !           970:                /* add in multipliers for backstabbing */
        !           971:                if (back_stab ||
        !           972:                    (weap && att != &pstats && on(*att_er, CANBSTAB))) {
        !           973:                    int mult = 2 + (att->s_lvl-1)/4; /* Normal multiplier */
        !           974:
        !           975:                    if (mult > 5 && att != &pstats)
        !           976:                        mult = 5;/*be nice with maximum of 5x for monsters*/
        !           977:                    if (weap->o_type == RELIC && weap->o_which == MUSTY_DAGGER)
        !           978:                        mult++;
        !           979:                    damage *= mult;
        !           980:                }
        !           981:
        !           982:                /* Check for no-damage and division */
        !           983:                if (on(*def_er, BLOWDIVIDE)) {
        !           984:                    damage = 0;
        !           985:                    creat_mons(def_er, def_er->t_index, FALSE);
        !           986:                    light(&hero);
        !           987:                }
        !           988:                /* check for immunity to metal -- RELICS are always bad */
        !           989:                if (on(*def_er, NOMETAL) && weap != NULL &&
        !           990:                    weap->o_type != RELIC && weap->o_flags & ISMETAL) {
        !           991:                    damage = 0;
        !           992:                }
        !           993:
        !           994:                /*
        !           995:                 * If defender is wearing a cloak of displacement -- no damage
        !           996:                 * the first time. (unless its a hurled magic missile)
        !           997:                 */
        !           998:                if ( ((weap == NULL) || weap->o_type != MISSILE) &&
        !           999:                    def == &pstats                               &&
        !          1000:                    cur_misc[WEAR_CLOAK] != NULL                 &&
        !          1001:                    cur_misc[WEAR_CLOAK]->o_which == MM_DISP &&
        !          1002:                    off(*att_er, MISSEDDISP)) {
        !          1003:                    damage = 0;
        !          1004:                    did_hit = FALSE;
        !          1005:                    turn_on(*att_er, MISSEDDISP);
        !          1006:                    if (cansee(att_er->t_pos.y, att_er->t_pos.x) &&
        !          1007:                        !invisible(att_er))
        !          1008:                        msg("The %s looks amazed",
        !          1009:                                monsters[att_er->t_index].m_name);
        !          1010:                }
        !          1011:                else {
        !          1012:                    def->s_hpt -= max(0, damage);       /* Do the damage */
        !          1013:                    did_hit = TRUE;
        !          1014:                }
        !          1015:
        !          1016:                vampiric_damage = damage;
        !          1017:                if (def->s_hpt < 0)     /* only want REAL damage inflicted */
        !          1018:                    vampiric_damage += def->s_hpt;
        !          1019:                 if (vampiric_damage < 0)
        !          1020:                     vampiric_damage = 0;
        !          1021:                if (att == &pstats && ISWEARING(R_VAMPREGEN) && !hurl) {
        !          1022:                    if ((pstats.s_hpt += vampiric_damage/2) > max_stats.s_hpt)
        !          1023:                        pstats.s_hpt = max_stats.s_hpt;
        !          1024:                }
        !          1025:                debug ("hplus=%d dmg=%d", hplus, damage);
        !          1026:            }
        !          1027:        }
        !          1028:        if ((cp = strchr(cp, '/')) == NULL)
        !          1029:            break;
        !          1030:        cp++;
        !          1031:     }
        !          1032:     return did_hit;
        !          1033: }
        !          1034:
        !          1035: /*
        !          1036:  * prname:
        !          1037:  *     The print name of a combatant
        !          1038:  */
        !          1039:
        !          1040: char *
        !          1041: prname(const char *who, bool upper)
        !          1042: {
        !          1043:     static char tbuf[LINELEN];
        !          1044:
        !          1045:     *tbuf = '\0';
        !          1046:     if (who == 0)
        !          1047:        strcpy(tbuf, "you");
        !          1048:     else if (on(player, ISBLIND))
        !          1049:        strcpy(tbuf, "it");
        !          1050:     else
        !          1051:     {
        !          1052:        strcpy(tbuf, "the ");
        !          1053:        strcat(tbuf, who);
        !          1054:     }
        !          1055:     if (upper)
        !          1056:        *tbuf = toupper(*tbuf);
        !          1057:     return tbuf;
        !          1058: }
        !          1059:
        !          1060: /*
        !          1061:  * hit:
        !          1062:  *     Print a message to indicate a succesful hit
        !          1063:  */
        !          1064:
        !          1065: void
        !          1066: hit(struct object *weapon, struct thing *tp, const char *er, const char *ee,
        !          1067:     bool back_stab)
        !          1068: {
        !          1069:     register char *s = NULL;
        !          1070:     char
        !          1071:                  att_name[80], /* Name of attacker */
        !          1072:                  def_name[80];/* Name of defender */
        !          1073:     bool see_monst = !invisible(tp);   /* Can the player see the monster? */
        !          1074:
        !          1075:     /* What do we call the attacker? */
        !          1076:     if (er == NULL) {  /* Player is attacking */
        !          1077:        strcpy(att_name, prname(er, TRUE));
        !          1078:        strcpy(def_name, see_monst ? prname(ee, FALSE) : "something");
        !          1079:     }
        !          1080:     else {
        !          1081:        strcpy(att_name, see_monst ? prname(er, TRUE) : "Something");
        !          1082:
        !          1083:        /* If the monster is using a weapon and we can see it, report it */
        !          1084:        if (weapon != NULL && see_monst) {
        !          1085:            strcat(att_name, "'s ");
        !          1086:            strcat(att_name, weap_name(weapon));
        !          1087:        }
        !          1088:
        !          1089:        strcpy(def_name, prname(ee, FALSE));
        !          1090:     }
        !          1091:
        !          1092:     addmsg(att_name);
        !          1093:     if (terse) {
        !          1094:        if (back_stab)
        !          1095:            s = " backstab!";
        !          1096:        else
        !          1097:            s = " hit.";
        !          1098:     }
        !          1099:     else {
        !          1100:        if (back_stab)
        !          1101:            s = (er == 0 ? " have backstabbed " : " has backstabbed ");
        !          1102:        else {
        !          1103:            switch (rnd(4))
        !          1104:            {
        !          1105:                case 0: s = " scored an excellent hit on ";
        !          1106:                when 1: s = " hit ";
        !          1107:                when 2: s = (er == 0 ? " have injured " : " has injured ");
        !          1108:                when 3: s = (er == 0 ? " swing and hit " : " swings and hits ");
        !          1109:            }
        !          1110:        }
        !          1111:     }
        !          1112:     addmsg(s);
        !          1113:     if (!terse)
        !          1114:        addmsg(def_name);
        !          1115:     endmsg();
        !          1116: }
        !          1117:
        !          1118: /*
        !          1119:  * miss:
        !          1120:  *     Print a message to indicate a poor swing
        !          1121:  */
        !          1122:
        !          1123: void
        !          1124: miss(struct object *weapon, struct thing *tp, const char *er, const char *ee)
        !          1125: {
        !          1126:     register char *s = NULL;
        !          1127:     char
        !          1128:                  att_name[80], /* Name of attacker */
        !          1129:                  def_name[80];/* Name of defender */
        !          1130:     bool see_monst = !invisible(tp);   /* Can the player see the monster? */
        !          1131:
        !          1132:     /* What do we call the attacker? */
        !          1133:     if (er == NULL) {  /* Player is attacking */
        !          1134:        strcpy(att_name, prname(er, TRUE));
        !          1135:        strcpy(def_name, see_monst ? prname(ee, FALSE) : "something");
        !          1136:     }
        !          1137:     else {
        !          1138:        strcpy(att_name, see_monst ? prname(er, TRUE) : "Something");
        !          1139:
        !          1140:        /* If the monster is using a weapon and we can see it, report it */
        !          1141:        if (weapon != NULL && see_monst) {
        !          1142:            strcat(att_name, "'s ");
        !          1143:            strcat(att_name, weap_name(weapon));
        !          1144:        }
        !          1145:
        !          1146:        strcpy(def_name, prname(ee, FALSE));
        !          1147:     }
        !          1148:
        !          1149:     addmsg(att_name);
        !          1150:     switch (terse ? 0 : rnd(4))
        !          1151:     {
        !          1152:        case 0: s = (er == 0 ? " miss" : " misses");
        !          1153:        when 1: s = (er == 0 ? " swing and miss" : " swings and misses");
        !          1154:        when 2: s = (er == 0 ? " barely miss" : " barely misses");
        !          1155:        when 3: s = (er == 0 ? " don't hit" : " doesn't hit");
        !          1156:     }
        !          1157:     addmsg(s);
        !          1158:     if (!terse)
        !          1159:        addmsg(" %s", def_name);
        !          1160:     endmsg();
        !          1161: }
        !          1162:
        !          1163: /*
        !          1164:  * dext_plus:
        !          1165:  *     compute to-hit bonus for dexterity
        !          1166:  */
        !          1167:
        !          1168: int
        !          1169: dext_plus(int dexterity)
        !          1170: {
        !          1171:        return (dexterity > 10 ? (dexterity-13)/3 : (dexterity-10)/3);
        !          1172: }
        !          1173:
        !          1174:
        !          1175: /*
        !          1176:  * dext_prot:
        !          1177:  *     compute armor class bonus for dexterity
        !          1178:  */
        !          1179:
        !          1180: int
        !          1181: dext_prot(int dexterity)
        !          1182: {
        !          1183:     return ((dexterity-10)/2);
        !          1184: }
        !          1185: /*
        !          1186:  * str_plus:
        !          1187:  *     compute bonus/penalties for strength on the "to hit" roll
        !          1188:  */
        !          1189:
        !          1190: int
        !          1191: str_plus(short str)
        !          1192: {
        !          1193:     return((str-10)/3);
        !          1194: }
        !          1195:
        !          1196: /*
        !          1197:  * add_dam:
        !          1198:  *     compute additional damage done for exceptionally high or low strength
        !          1199:  */
        !          1200:
        !          1201: int
        !          1202: add_dam(short str)
        !          1203: {
        !          1204:     return((str-9)/2);
        !          1205: }
        !          1206:
        !          1207: /*
        !          1208:  * hung_dam:
        !          1209:  *     Calculate damage depending on players hungry state
        !          1210:  */
        !          1211: int
        !          1212: hung_dam(void)
        !          1213: {
        !          1214:        reg int howmuch = 0;
        !          1215:
        !          1216:        switch(hungry_state) {
        !          1217:                case F_OKAY:
        !          1218:                case F_HUNGRY:  howmuch = 0;
        !          1219:                when F_WEAK:    howmuch = -1;
        !          1220:                when F_FAINT:   howmuch = -2;
        !          1221:        }
        !          1222:        return howmuch;
        !          1223: }
        !          1224:
        !          1225: /*
        !          1226:  * thunk:
        !          1227:  *     A missile hits a monster
        !          1228:  */
        !          1229:
        !          1230: void
        !          1231: thunk(struct object *weap, struct thing *tp, const char *mname)
        !          1232: {
        !          1233:     /* tp: Defender */
        !          1234:     char *def_name;    /* Name of defender */
        !          1235:
        !          1236:     /* What do we call the defender? */
        !          1237:     if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
        !          1238:        def_name = "something";
        !          1239:     else def_name = prname(mname, FALSE);
        !          1240:
        !          1241:     if (weap->o_type == WEAPON){
        !          1242:        sprintf(outstring,"The %s hits %s", weaps[weap->o_which].w_name, def_name);
        !          1243:        msg(outstring);
        !          1244:     }
        !          1245:     else if (weap->o_type == MISSILE){
        !          1246:        sprintf(outstring,"The %s hits %s",ws_magic[weap->o_which].mi_name, def_name);
        !          1247:        msg(outstring);
        !          1248:     }
        !          1249:     else
        !          1250:        msg("You hit %s.", def_name);
        !          1251: }
        !          1252:
        !          1253: /*
        !          1254:  * mthunk:
        !          1255:  *      A missile from a monster hits the player
        !          1256:  */
        !          1257:
        !          1258: void
        !          1259: m_thunk(struct object *weap, struct thing *tp, const char *mname)
        !          1260: {
        !          1261:     char *att_name;    /* Name of attacker */
        !          1262:
        !          1263:     /* What do we call the attacker? */
        !          1264:     if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
        !          1265:        att_name = "Something";
        !          1266:     else att_name = prname(mname, TRUE);
        !          1267:
        !          1268:     if (weap->o_type == WEAPON){
        !          1269:        sprintf(outstring,"%s's %s hits you.", att_name, weaps[weap->o_which].w_name);
        !          1270:        msg(outstring);
        !          1271:     }
        !          1272:     else if (weap->o_type == MISSILE){
        !          1273:        sprintf(outstring,"%s's %s hits you.", att_name, ws_magic[weap->o_which].mi_name);
        !          1274:        msg(outstring);
        !          1275:     }
        !          1276:     else
        !          1277:        msg("%s hits you.", att_name);
        !          1278: }
        !          1279:
        !          1280: /*
        !          1281:  * bounce:
        !          1282:  *     A missile misses a monster
        !          1283:  */
        !          1284:
        !          1285: void
        !          1286: bounce(struct object *weap, struct thing *tp, const char *mname)
        !          1287: {
        !          1288:     /* tp: Defender */
        !          1289:     char *def_name;    /* Name of defender */
        !          1290:
        !          1291:     /* What do we call the defender? */
        !          1292:     if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
        !          1293:        def_name = "something";
        !          1294:     else def_name = prname(mname, FALSE);
        !          1295:
        !          1296:     if (weap->o_type == WEAPON){
        !          1297:        sprintf(outstring,"The %s misses %s",weaps[weap->o_which].w_name, def_name);
        !          1298:        msg(outstring);
        !          1299:     }
        !          1300:     else if (weap->o_type == MISSILE){
        !          1301:        sprintf(outstring,"The %s misses %s",ws_magic[weap->o_which].mi_name, def_name);
        !          1302:        msg(outstring);
        !          1303:     }
        !          1304:     else
        !          1305:        msg("You missed %s.", def_name);
        !          1306: }
        !          1307:
        !          1308: /*
        !          1309:  * m_bounce:
        !          1310:          A missle from a monster misses the player
        !          1311:  */
        !          1312:
        !          1313: void
        !          1314: m_bounce(struct object *weap, struct thing *tp, const char *mname)
        !          1315: {
        !          1316:     char *att_name;    /* Name of attacker */
        !          1317:
        !          1318:     /* What do we call the attacker? */
        !          1319:     if (!cansee(tp->t_pos.y, tp->t_pos.x) || invisible(tp))
        !          1320:        att_name = "Something";
        !          1321:     else att_name = prname(mname, TRUE);
        !          1322:
        !          1323:     if (weap->o_type == WEAPON){
        !          1324:        sprintf(outstring,"%s's %s misses you.", att_name, weaps[weap->o_which].w_name);
        !          1325:        msg(outstring);
        !          1326:     }
        !          1327:     else if (weap->o_type == MISSILE){
        !          1328:        sprintf(outstring,"%s's %s misses you.", att_name, ws_magic[weap->o_which].mi_name);
        !          1329:        msg(outstring);
        !          1330:     }
        !          1331:     else
        !          1332:        msg("%s misses you.", att_name);
        !          1333: }
        !          1334:
        !          1335:
        !          1336: /*
        !          1337:  * is_magic:
        !          1338:  *     Returns true if an object radiates magic
        !          1339:  */
        !          1340:
        !          1341: bool
        !          1342: is_magic(struct object *obj)
        !          1343: {
        !          1344:     switch (obj->o_type)
        !          1345:     {
        !          1346:        case ARMOR:
        !          1347:            return obj->o_ac != armors[obj->o_which].a_class;
        !          1348:        when WEAPON:
        !          1349:            return obj->o_hplus != 0 || obj->o_dplus != 0;
        !          1350:        when POTION:
        !          1351:        case SCROLL:
        !          1352:        case STICK:
        !          1353:        case RING:
        !          1354:        case MM:
        !          1355:        case RELIC:
        !          1356:            return TRUE;
        !          1357:     }
        !          1358:     return FALSE;
        !          1359: }
        !          1360:
        !          1361: /*
        !          1362:  * killed:
        !          1363:  *     Called to put a monster to death
        !          1364:  */
        !          1365:
        !          1366: void
        !          1367: killed(struct linked_list *item, bool pr, bool points)
        !          1368: {
        !          1369:     register struct thing *tp;
        !          1370:     register struct linked_list *pitem, *nexti;
        !          1371:     const char *monst;
        !          1372:
        !          1373:     tp = THINGPTR(item);
        !          1374:
        !          1375:     if (pr)
        !          1376:     {
        !          1377:        addmsg(terse ? "Defeated " : "You have defeated ");
        !          1378:        if (on(player, ISBLIND))
        !          1379:            msg("it.");
        !          1380:        else
        !          1381:        {
        !          1382:            if (cansee(tp->t_pos.y, tp->t_pos.x) && !invisible(tp))
        !          1383:                monst = monsters[tp->t_index].m_name;
        !          1384:            else {
        !          1385:                if (terse) monst = "something";
        !          1386:                else monst = "thing";
        !          1387:            }
        !          1388:            if (!terse)
        !          1389:                addmsg("the ");
        !          1390:            msg("%s.", monst);
        !          1391:        }
        !          1392:     }
        !          1393:
        !          1394:     /* Take care of any residual effects of the monster */
        !          1395:     check_residue(tp);
        !          1396:
        !          1397:     if (points) {
        !          1398:        unsigned long test;     /* For overflow check */
        !          1399:
        !          1400:        test = pstats.s_exp + tp->t_stats.s_exp;
        !          1401:
        !          1402:        /* Do an overflow check before increasing experience */
        !          1403:        if (test > pstats.s_exp) pstats.s_exp = test;
        !          1404:
        !          1405:        /*
        !          1406:         * Do adjustments if he went up a level
        !          1407:         */
        !          1408:        check_level(TRUE);
        !          1409:     }
        !          1410:
        !          1411:     /*
        !          1412:      * Empty the monsters pack
        !          1413:      */
        !          1414:     pitem = tp->t_pack;
        !          1415:
        !          1416:     /*
        !          1417:      * Get rid of the monster.
        !          1418:      */
        !          1419:     mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' ');
        !          1420:     mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
        !          1421:     detach(mlist, item);
        !          1422:     /*
        !          1423:      * empty his pack
        !          1424:      */
        !          1425:     while (pitem != NULL)
        !          1426:     {
        !          1427:        nexti = next(tp->t_pack);
        !          1428:        (OBJPTR(pitem))->o_pos = tp->t_pos;
        !          1429:        detach(tp->t_pack, pitem);
        !          1430:        if (points)
        !          1431:            fall(pitem, FALSE);
        !          1432:        else
        !          1433:            o_discard(pitem);
        !          1434:        pitem = nexti;
        !          1435:     }
        !          1436:     turn_on(*tp, ISDEAD);
        !          1437:     attach(monst_dead, item);
        !          1438: }
        !          1439:
        !          1440:
        !          1441: /*
        !          1442:  * Returns a pointer to the weapon the monster is wielding corresponding to
        !          1443:  * the given thrown weapon.  If no thrown item is given, try to find any
        !          1444:  * decent weapon.
        !          1445:  */
        !          1446:
        !          1447: struct object *
        !          1448: wield_weap(struct object *thrown, struct thing *mp)
        !          1449: {
        !          1450:     int look_for = 0,  /* The projectile weapon we are looking for */
        !          1451:        new_rate,       /* The rating of a prospective weapon */
        !          1452:         cand_rate = -1; /* Rating of current candidate -- higher is better */
        !          1453:     register struct linked_list *pitem;
        !          1454:     register struct object *obj, *candidate = NULL;
        !          1455:
        !          1456:     if (thrown != NULL) {      /* Using a projectile weapon */
        !          1457:       switch (thrown->o_which) {
        !          1458:        case BOLT:      look_for = CROSSBOW;    /* Find the crossbow */
        !          1459:        when ARROW:     look_for = BOW;         /* Find the bow */
        !          1460:        when ROCK:      look_for = SLING;       /* find the sling */
        !          1461:        otherwise:      return(NULL);
        !          1462:       }
        !          1463:     }
        !          1464:     else if (off(*mp, ISUNIQUE) && off(*mp, CARRYWEAPON)) return(NULL);
        !          1465:
        !          1466:     for (pitem=mp->t_pack; pitem; pitem=next(pitem)) {
        !          1467:        obj = OBJPTR(pitem);
        !          1468:
        !          1469:        /*
        !          1470:         * If we have a thrown weapon, just return the first match
        !          1471:         * we come to.
        !          1472:         */
        !          1473:        if (thrown != NULL && obj->o_type == WEAPON && obj->o_which == look_for)
        !          1474:            return(obj);
        !          1475:
        !          1476:        /* If we have a usable RELIC, return it */
        !          1477:        if (thrown == NULL && obj->o_type == RELIC) {
        !          1478:            switch (obj->o_which) {
        !          1479:                case MUSTY_DAGGER:
        !          1480:                case YEENOGHU_FLAIL:
        !          1481:                case HRUGGEK_MSTAR:
        !          1482:                case MING_STAFF:
        !          1483:                case ASMO_ROD:
        !          1484:                case ORCUS_WAND:
        !          1485:                    return(obj);
        !          1486:            }
        !          1487:        }
        !          1488:
        !          1489:        /* Otherwise if it's a usable weapon, it is a good candidate */
        !          1490:        else if (thrown == NULL && obj->o_type == WEAPON) {
        !          1491:            switch (obj->o_which) {
        !          1492:                case DAGGER:
        !          1493:                    new_rate = 0;
        !          1494:                when BATTLEAXE:
        !          1495:                    new_rate = 1;
        !          1496:                when MACE:
        !          1497:                    new_rate = 2;
        !          1498:                when SWORD:
        !          1499:                    new_rate = 3;
        !          1500:                when PIKE:
        !          1501:                    new_rate = 4;
        !          1502:                when HALBERD:
        !          1503:                case SPETUM:
        !          1504:                    new_rate = 6;
        !          1505:                when BARDICHE:
        !          1506:                    new_rate = 7;
        !          1507:                when TRIDENT:
        !          1508:                    new_rate = 8;
        !          1509:                when BASWORD:
        !          1510:                    new_rate = 9;
        !          1511:                when TWOSWORD:
        !          1512:                    new_rate = 10;
        !          1513:                otherwise:
        !          1514:                    new_rate = -1;
        !          1515:            }
        !          1516:
        !          1517:            /* Only switch if this is better than the current candidate */
        !          1518:            if (new_rate > cand_rate) {
        !          1519:                cand_rate = new_rate;
        !          1520:                candidate = obj;
        !          1521:            }
        !          1522:        }
        !          1523:     }
        !          1524:
        !          1525:     return(candidate);
        !          1526: }
        !          1527:
        !          1528: void
        !          1529: explode(struct thing *tp)
        !          1530: {
        !          1531:
        !          1532:     register int x,y, damage;
        !          1533:     struct linked_list *item;
        !          1534:     struct thing *th;
        !          1535:
        !          1536:     msg("the %s explodes!", monsters[tp->t_index].m_name);
        !          1537:     /*
        !          1538:      * check to see if it got the hero
        !          1539:      */
        !          1540:      if (DISTANCE(hero.x, hero.y, tp->t_pos.x, tp->t_pos.y) <= 25) {
        !          1541:        msg("the explosion hits you");
        !          1542:        damage = roll(6,6);
        !          1543:        if (save(VS_WAND, &player, 0))
        !          1544:            damage /= 2;
        !          1545:        if ((pstats.s_hpt -= damage) <= 0)
        !          1546:            death(tp->t_index);
        !          1547:     }
        !          1548:
        !          1549:     /*
        !          1550:      * now check for monsters in vicinity
        !          1551:      */
        !          1552:      for (x = tp->t_pos.x-5; x<=tp->t_pos.x+5; x++) {
        !          1553:         if (x < 0 || x > COLS - 1)
        !          1554:             continue;
        !          1555:         for (y = tp->t_pos.y-5; y<=tp->t_pos.y+5; y++) {
        !          1556:            if (y < 1 || y > LINES - 3)
        !          1557:                continue;
        !          1558:            if (isalpha(mvwinch(mw, y, x))) {
        !          1559:                if ((item = find_mons(y, x)) != NULL) {
        !          1560:                    th = THINGPTR(item);
        !          1561:                    if (th == tp) /* don't count gas spore */
        !          1562:                        continue;
        !          1563:                    damage = roll(6, 6);
        !          1564:                    if (save(VS_WAND, th, 0))
        !          1565:                        damage /= 2;
        !          1566:                    if ((tp->t_stats.s_hpt -= damage) <= 0) {
        !          1567:                        msg("the explosion kills the %s",
        !          1568:                                monsters[th->t_index].m_name);
        !          1569:                        killed(item, FALSE, FALSE);
        !          1570:                    }
        !          1571:                }
        !          1572:            }
        !          1573:        }
        !          1574:     }
        !          1575: }

CVSweb