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

Annotation of early-roguelike/rogue5/fight.c, Revision 1.2

1.1       rubenllo    1: /*
                      2:  * All the fighting gets done here
                      3:  *
                      4:  * @(#)fight.c 4.67 (Berkeley) 09/06/83
                      5:  *
                      6:  * Rogue: Exploring the Dungeons of Doom
                      7:  * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
                      8:  * All rights reserved.
                      9:  *
                     10:  * See the file LICENSE.TXT for full copyright and licensing information.
                     11:  */
                     12:
                     13: #include <stdlib.h>
                     14: #include <curses.h>
                     15: #include <string.h>
                     16: #include <ctype.h>
                     17: #include "rogue.h"
                     18:
                     19: #define        EQSTR(a, b)     (strcmp(a, b) == 0)
                     20:
                     21: static const char *h_names[] = {               /* strings for hitting */
                     22:        " scored an excellent hit on ",
                     23:        " hit ",
                     24:        " have injured ",
                     25:        " swing and hit ",
                     26:        " scored an excellent hit on ",
                     27:        " hit ",
                     28:        " has injured ",
                     29:        " swings and hits "
                     30: };
                     31:
                     32: static const char *m_names[] = {               /* strings for missing */
                     33:        " miss",
                     34:        " swing and miss",
                     35:        " barely miss",
                     36:        " don't hit",
                     37:        " misses",
                     38:        " swings and misses",
                     39:        " barely misses",
                     40:        " doesn't hit",
                     41: };
                     42:
                     43: /*
                     44:  * adjustments to hit probabilities due to strength
                     45:  */
                     46: static int str_plus[] = {
                     47:     -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
                     48:     1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
                     49: };
                     50:
                     51: /*
                     52:  * adjustments to damage done due to strength
                     53:  */
                     54: static int add_dam[] = {
                     55:     -7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
                     56:     3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6
                     57: };
                     58:
                     59: /*
                     60:  * fight:
                     61:  *     The player attacks the monster.
                     62:  */
                     63: int
                     64: fight(const coord *mp, const THING *weap, int thrown)
                     65: {
                     66:     THING *tp;
                     67:     int did_hit = TRUE;
                     68:     const char *mname;
                     69:        int ch;
                     70:
                     71:     /*
                     72:      * Find the monster we want to fight
                     73:      */
                     74:     if ((tp = moat(mp->y, mp->x)) == NULL)
                     75:        {
                     76: #ifdef MASTER
                     77:                debug("Fight what @ %d,%d", mp->y, mp->x);
                     78: #endif
                     79:                return FALSE;
                     80:        }
                     81:     /*
                     82:      * Since we are fighting, things are not quiet so no healing takes
                     83:      * place.
                     84:      */
                     85:     count = 0;
                     86:     quiet = 0;
                     87:     /*
                     88:      * Let him know it was really a xeroc (if it was one).
                     89:      */
                     90:     ch = '\0';
                     91:     if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND))
                     92:     {
                     93:        tp->t_disguise = 'X';
                     94:        if (on(player, ISHALU)) {
                     95:            ch = rnd(26) + 'A';
                     96:            mvaddch(tp->t_pos.y, tp->t_pos.x, ch);
                     97:        }
                     98:        msg(choose_str("heavy!  That's a nasty critter!",
                     99:                       "wait!  That's a xeroc!"));
                    100:        if (!thrown)
                    101:            return FALSE;
                    102:     }
                    103:     mname = set_mname(tp);
                    104:     did_hit = FALSE;
                    105:     has_hit = (terse && !to_death);
                    106:     if (roll_em(&player, tp, weap, thrown))
                    107:     {
                    108:        did_hit = FALSE;
                    109:        if (thrown)
                    110:            thunk(weap, mname, terse);
                    111:        else
                    112:            hit(NULL, mname, terse);
                    113:        if (on(player, CANHUH))
                    114:        {
                    115:            did_hit = TRUE;
                    116:            tp->t_flags |= ISHUH;
                    117:            player.t_flags &= ~CANHUH;
                    118:            endmsg();
                    119:            has_hit = FALSE;
                    120:            msg("your hands stop glowing %s", pick_color("red"));
                    121:        }
                    122:        if (tp->t_stats.s_hpt <= 0)
                    123:            killed(tp, TRUE);
                    124:        else if (did_hit && !on(player, ISBLIND))
                    125:            msg("%s appears confused", mname);
                    126:        did_hit = TRUE;
                    127:     }
                    128:     else
                    129:        if (thrown)
                    130:            bounce(weap, mname, terse);
                    131:        else
                    132:            miss(NULL, mname, terse);
1.2     ! rubenllo  133:
        !           134:        if ((tp = moat(mp->y, mp->x)) != NULL) //BUGFIX!
        !           135:                runto(mp);
1.1       rubenllo  136:     return did_hit;
                    137: }
                    138:
                    139: /*
                    140:  * attack:
                    141:  *     The monster attacks the player
                    142:  */
                    143: int
                    144: attack(THING *mp)
                    145: {
                    146:     const char *mname;
                    147:     int oldhp;
                    148:
                    149:     /*
                    150:      * Since this is an attack, stop running and any healing that was
                    151:      * going on at the time.
                    152:      */
                    153:     running = FALSE;
                    154:     count = 0;
                    155:     quiet = 0;
                    156:     if (to_death && !on(*mp, ISTARGET))
                    157:     {
                    158:        to_death = FALSE;
                    159:        kamikaze = FALSE;
                    160:     }
                    161:     if (mp->t_type == 'F')
                    162:        vf_hit = atoi(mp->t_stats.s_dmg);
                    163:     if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(player, ISBLIND))
                    164:     {
                    165:        mp->t_disguise = 'X';
                    166:        if (on(player, ISHALU))
                    167:            mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A');
                    168:     }
                    169:     mname = set_mname(mp);
                    170:     oldhp = pstats.s_hpt;
                    171:     if (roll_em(mp, &player, NULL, FALSE))
                    172:     {
                    173:        if (mp->t_type != 'I')
                    174:        {
                    175:            if (has_hit)
                    176:                addmsg(".  ");
                    177:            hit(mname, NULL, FALSE);
                    178:        }
                    179:        else
                    180:            if (has_hit)
                    181:                endmsg();
                    182:        has_hit = FALSE;
                    183:        if (pstats.s_hpt <= 0)
                    184:            death(mp->t_type);  /* Bye bye life ... */
                    185:        else if (!kamikaze)
                    186:        {
                    187:            oldhp -= pstats.s_hpt;
                    188:            if (oldhp > max_hit)
                    189:                max_hit = oldhp;
                    190:            if (pstats.s_hpt <= max_hit)
                    191:                to_death = FALSE;
                    192:        }
                    193:        if (!on(*mp, ISCANC))
                    194:            switch (mp->t_type)
                    195:            {
                    196:                case 'A':
                    197:                    /*
                    198:                     * If an aquator hits, you can lose armor class.
                    199:                     */
                    200:                    rust_armor(cur_armor);
                    201:                when 'I':
                    202:                    /*
                    203:                     * The ice monster freezes you
                    204:                     */
                    205:                    player.t_flags &= ~ISRUN;
                    206:                    if (!no_command)
                    207:                    {
                    208:                        addmsg("you are frozen");
                    209:                        if (!terse)
                    210:                            addmsg(" by the %s", mname);
                    211:                        endmsg();
                    212:                    }
                    213:                    no_command += rnd(2) + 2;
                    214:                    if (no_command > BORE_LEVEL)
                    215:                        death('h');
                    216:                when 'R':
                    217:                    /*
                    218:                     * Rattlesnakes have poisonous bites
                    219:                     */
                    220:                    if (!save(VS_POISON))
                    221:                    {
                    222:                        if (!ISWEARING(R_SUSTSTR))
                    223:                        {
                    224:                            chg_str(-1);
                    225:                            if (!terse)
                    226:                                msg("you feel a bite in your leg and now feel weaker");
                    227:                            else
                    228:                                msg("a bite has weakened you");
                    229:                        }
                    230:                        else if (!to_death)
                    231:                        {
                    232:                            if (!terse)
                    233:                                msg("a bite momentarily weakens you");
                    234:                            else
                    235:                                msg("bite has no effect");
                    236:                        }
                    237:                    }
                    238:                when 'W':
                    239:                case 'V':
                    240:                    /*
                    241:                     * Wraiths might drain energy levels, and Vampires
                    242:                     * can steal max_hp
                    243:                     */
                    244:                    if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
                    245:                    {
                    246:                        int fewer;
                    247:
                    248:                        if (mp->t_type == 'W')
                    249:                        {
                    250:                            if (pstats.s_exp == 0)
                    251:                                death('W');             /* All levels gone */
                    252:                            if (--pstats.s_lvl == 0)
                    253:                            {
                    254:                                pstats.s_exp = 0;
                    255:                                pstats.s_lvl = 1;
                    256:                            }
                    257:                            else
                    258:                                pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
                    259:                            fewer = roll(1, 10);
                    260:                        }
                    261:                        else
                    262:                            fewer = roll(1, 3);
                    263:                        pstats.s_hpt -= fewer;
                    264:                        max_hp -= fewer;
                    265:                        if (pstats.s_hpt <= 0)
                    266:                            pstats.s_hpt = 1;
                    267:                        if (max_hp <= 0)
                    268:                            death(mp->t_type);
                    269:                        msg("you suddenly feel weaker");
                    270:                    }
                    271:                when 'F':
                    272:                    /*
                    273:                     * Venus Flytrap stops the poor guy from moving
                    274:                     */
                    275:                    player.t_flags |= ISHELD;
                    276:                    sprintf(mp->t_stats.s_dmg,"%dx1", ++vf_hit);
                    277:                    if (--pstats.s_hpt <= 0)
                    278:                        death('F');
                    279:                when 'L':
                    280:                {
                    281:                    /*
                    282:                     * Leperachaun steals some gold
                    283:                     */
                    284:                    int lastpurse;
                    285:
                    286:                    lastpurse = purse;
                    287:                    purse -= GOLDCALC;
                    288:                    if (!save(VS_MAGIC))
                    289:                        purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
                    290:                    if (purse < 0)
                    291:                        purse = 0;
                    292:                    remove_mon(&mp->t_pos, mp, FALSE);
                    293:                     mp=NULL;
                    294:                    if (purse != lastpurse)
                    295:                        msg("your purse feels lighter");
                    296:                }
                    297:                when 'N':
                    298:                {
                    299:                    THING *obj, *steal;
                    300:                    int nobj;
                    301:
                    302:                    /*
                    303:                     * Nymph's steal a magic item, look through the pack
                    304:                     * and pick out one we like.
                    305:                     */
                    306:                    steal = NULL;
                    307:                    for (nobj = 0, obj = pack; obj != NULL; obj = next(obj))
                    308:                        if (obj != cur_armor && obj != cur_weapon
                    309:                            && obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]
                    310:                            && is_magic(obj) && rnd(++nobj) == 0)
                    311:                                steal = obj;
                    312:                    if (steal != NULL)
                    313:                    {
                    314:                        remove_mon(&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
                    315:                         mp=NULL;
                    316:                        steal = leave_pack(steal, TRUE, FALSE);
                    317:                        msg("she stole %s!", inv_name(steal, TRUE));
                    318:                        discard(steal);
                    319:                    }
                    320:                }
                    321:                otherwise:
                    322:                    break;
                    323:            }
                    324:     }
                    325:     else if (mp->t_type != 'I')
                    326:     {
                    327:        if (has_hit)
                    328:        {
                    329:            addmsg(".  ");
                    330:            has_hit = FALSE;
                    331:        }
                    332:        if (mp->t_type == 'F')
                    333:        {
                    334:            pstats.s_hpt -= vf_hit;
                    335:            if (pstats.s_hpt <= 0)
                    336:                death(mp->t_type);      /* Bye bye life ... */
                    337:        }
                    338:        miss(mname, NULL, FALSE);
                    339:     }
                    340:     if (fight_flush && !to_death)
                    341:        flush_type();
                    342:     count = 0;
                    343:     status();
                    344:     if (mp == NULL)
                    345:         return(-1);
                    346:     else
                    347:         return(0);
                    348: }
                    349:
                    350: /*
                    351:  * set_mname:
                    352:  *     return the monster name for the given monster
                    353:  */
                    354: const char *
                    355: set_mname(const THING *tp)
                    356: {
                    357:     int ch;
                    358:     const char *mname;
                    359:     static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' };
                    360:
                    361:     if (!see_monst(tp) && !on(player, SEEMONST))
                    362:        return (terse ? "it" : "something");
                    363:     else if (on(player, ISHALU))
                    364:     {
                    365:        move(tp->t_pos.y, tp->t_pos.x);
                    366:        ch = toascii(CCHAR(inch()));
                    367:        if (!isupper(ch))
                    368:            ch = rnd(26);
                    369:        else
                    370:            ch -= 'A';
                    371:        mname = monsters[ch].m_name;
                    372:     }
                    373:     else
                    374:        mname = monsters[tp->t_type - 'A'].m_name;
                    375:     strcpy(&tbuf[4], mname);
                    376:     return tbuf;
                    377: }
                    378:
                    379: /*
                    380:  * swing:
                    381:  *     Returns true if the swing hits
                    382:  */
                    383: int
                    384: swing(int at_lvl, int op_arm, int wplus)
                    385: {
                    386:     int res = rnd(20);
                    387:     int need = (20 - at_lvl) - op_arm;
                    388:
                    389:     return (res + wplus >= need);
                    390: }
                    391:
                    392: /*
                    393:  * roll_em:
                    394:  *     Roll several attacks
                    395:  */
                    396: int
                    397: roll_em(const THING *thatt, THING *thdef, const THING *weap, int hurl)
                    398: {
                    399:     const struct stats *att;
                    400:     struct stats *def;
                    401:     const char *cp;
                    402:     int ndice, nsides, def_arm;
                    403:     int did_hit = FALSE;
                    404:     int hplus;
                    405:     int dplus;
                    406:     int damage;
                    407:
                    408:     att = &thatt->t_stats;
                    409:     def = &thdef->t_stats;
                    410:     if (weap == NULL)
                    411:     {
                    412:        cp = att->s_dmg;
                    413:        dplus = 0;
                    414:        hplus = 0;
                    415:     }
                    416:     else
                    417:     {
                    418:        hplus = (weap == NULL ? 0 : weap->o_hplus);
                    419:        dplus = (weap == NULL ? 0 : weap->o_dplus);
                    420:        if (weap == cur_weapon)
                    421:        {
                    422:            if (ISRING(LEFT, R_ADDDAM))
                    423:                dplus += cur_ring[LEFT]->o_arm;
                    424:            else if (ISRING(LEFT, R_ADDHIT))
                    425:                hplus += cur_ring[LEFT]->o_arm;
                    426:            if (ISRING(RIGHT, R_ADDDAM))
                    427:                dplus += cur_ring[RIGHT]->o_arm;
                    428:            else if (ISRING(RIGHT, R_ADDHIT))
                    429:                hplus += cur_ring[RIGHT]->o_arm;
                    430:        }
                    431:        cp = weap->o_damage;
                    432:        if (hurl)
                    433:        {
                    434:            if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
                    435:              cur_weapon->o_which == weap->o_launch)
                    436:            {
                    437:                cp = weap->o_hurldmg;
                    438:                hplus += cur_weapon->o_hplus;
                    439:                dplus += cur_weapon->o_dplus;
                    440:            }
                    441:            else if (weap->o_launch < 0)
                    442:                cp = weap->o_hurldmg;
                    443:        }
                    444:     }
                    445:     /*
                    446:      * If the creature being attacked is not running (alseep or held)
                    447:      * then the attacker gets a plus four bonus to hit.
                    448:      */
                    449:     if (!on(*thdef, ISRUN))
                    450:        hplus += 4;
                    451:     def_arm = def->s_arm;
                    452:     if (def == &pstats)
                    453:     {
                    454:        if (cur_armor != NULL)
                    455:            def_arm = cur_armor->o_arm;
                    456:        if (ISRING(LEFT, R_PROTECT))
                    457:            def_arm -= cur_ring[LEFT]->o_arm;
                    458:        if (ISRING(RIGHT, R_PROTECT))
                    459:            def_arm -= cur_ring[RIGHT]->o_arm;
                    460:     }
                    461:     while(cp != NULL && *cp != '\0')
                    462:     {
                    463:        ndice = atoi(cp);
                    464:        if ((cp = strchr(cp, 'x')) == NULL)
                    465:            break;
                    466:        nsides = atoi(++cp);
                    467:        if (swing(att->s_lvl, def_arm, hplus + str_plus[att->s_str]))
                    468:        {
                    469:            int proll;
                    470:
                    471:            proll = roll(ndice, nsides);
                    472: #ifdef MASTER
                    473:            if (ndice + nsides > 0 && proll <= 0)
                    474:                debug("Damage for %dx%d came out %d, dplus = %d, add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, add_dam[att->s_str], def_arm);
                    475: #endif
                    476:            damage = dplus + proll + add_dam[att->s_str];
                    477:            def->s_hpt -= max(0, damage);
                    478:            did_hit = TRUE;
                    479:        }
                    480:        if ((cp = strchr(cp, '/')) == NULL)
                    481:            break;
                    482:        cp++;
                    483:     }
                    484:     return did_hit;
                    485: }
                    486:
                    487: /*
                    488:  * prname:
                    489:  *     The print name of a combatant
                    490:  */
                    491: char *
                    492: prname(const char *mname, int upper)
                    493: {
                    494:     static char tbuf[MAXSTR];
                    495:
                    496:     *tbuf = '\0';
                    497:     if (mname == 0)
                    498:        strcpy(tbuf, "you");
                    499:     else
                    500:        strcpy(tbuf, mname);
                    501:     if (upper)
                    502:        *tbuf = (char) toupper(*tbuf);
                    503:     return tbuf;
                    504: }
                    505:
                    506: /*
                    507:  * thunk:
                    508:  *     A missile hits a monster
                    509:  */
                    510: void
                    511: thunk(const THING *weap, const char *mname, int noend)
                    512: {
                    513:     if (to_death)
                    514:        return;
                    515:     if (weap->o_type == WEAPON)
                    516:        addmsg("the %s hits ", weap_info[weap->o_which].oi_name);
                    517:     else
                    518:        addmsg("you hit ");
                    519:     addmsg("%s", mname);
                    520:     if (!noend)
                    521:        endmsg();
                    522: }
                    523:
                    524: /*
                    525:  * hit:
                    526:  *     Print a message to indicate a succesful hit
                    527:  */
                    528:
                    529: void
                    530: hit(const char *er, const char *ee, int noend)
                    531: {
                    532:     int i;
                    533:     const char *s;
                    534:
                    535:     if (to_death)
                    536:        return;
                    537:     addmsg(prname(er, TRUE));
                    538:     if (terse)
                    539:        s = " hit";
                    540:     else
                    541:     {
                    542:        i = rnd(4);
                    543:        if (er != NULL)
                    544:            i += 4;
                    545:        s = h_names[i];
                    546:     }
                    547:     addmsg(s);
                    548:     if (!terse)
                    549:        addmsg(prname(ee, FALSE));
                    550:     if (!noend)
                    551:        endmsg();
                    552: }
                    553:
                    554: /*
                    555:  * miss:
                    556:  *     Print a message to indicate a poor swing
                    557:  */
                    558: void
                    559: miss(const char *er, const char *ee, int noend)
                    560: {
                    561:     int i;
                    562:
                    563:     if (to_death)
                    564:        return;
                    565:     addmsg(prname(er, TRUE));
                    566:     if (terse)
                    567:        i = 0;
                    568:     else
                    569:        i = rnd(4);
                    570:     if (er != NULL)
                    571:        i += 4;
                    572:     addmsg(m_names[i]);
                    573:     if (!terse)
                    574:        addmsg(" %s", prname(ee, FALSE));
                    575:     if (!noend)
                    576:        endmsg();
                    577: }
                    578:
                    579: /*
                    580:  * bounce:
                    581:  *     A missile misses a monster
                    582:  */
                    583: void
                    584: bounce(const THING *weap, const char *mname, int noend)
                    585: {
                    586:     if (to_death)
                    587:        return;
                    588:     if (weap->o_type == WEAPON)
                    589:        addmsg("the %s misses ", weap_info[weap->o_which].oi_name);
                    590:     else
                    591:        addmsg("you missed ");
                    592:     addmsg(mname);
                    593:     if (!noend)
                    594:        endmsg();
                    595: }
                    596:
                    597: /*
                    598:  * remove_mon:
                    599:  *     Remove a monster from the screen
                    600:  */
                    601: void
                    602: remove_mon(const coord *mp, THING *tp, int waskill)
                    603: {
                    604:     THING *obj, *nexti;
                    605:
                    606:     for (obj = tp->t_pack; obj != NULL; obj = nexti)
                    607:     {
                    608:        nexti = next(obj);
                    609:        obj->o_pos = tp->t_pos;
                    610:        detach(tp->t_pack, obj);
                    611:        if (waskill)
                    612:            fall(obj, FALSE);
                    613:        else
                    614:            discard(obj);
                    615:     }
                    616:     moat(mp->y, mp->x) = NULL;
                    617:     mvaddch(mp->y, mp->x, tp->t_oldch);
                    618:     detach(mlist, tp);
                    619:     if (on(*tp, ISTARGET))
                    620:     {
                    621:        kamikaze = FALSE;
                    622:        to_death = FALSE;
                    623:        if (fight_flush)
                    624:            flush_type();
                    625:     }
                    626:     discard(tp);
                    627: }
                    628:
                    629: /*
                    630:  * killed:
                    631:  *     Called to put a monster to death
                    632:  */
                    633: void
                    634: killed(THING *tp, int pr)
                    635: {
                    636:     const char *mname;
                    637:
                    638:     pstats.s_exp += tp->t_stats.s_exp;
                    639:
                    640:     /*
                    641:      * If the monster was a venus flytrap, un-hold him
                    642:      */
                    643:     switch (tp->t_type)
                    644:     {
                    645:        case 'F':
                    646:            player.t_flags &= ~ISHELD;
                    647:            vf_hit = 0;
                    648:        when 'L':
                    649:        {
                    650:            THING *gold;
                    651:
                    652:            if (fallpos(&tp->t_pos, &tp->t_room->r_gold) && level >= max_level)
                    653:            {
                    654:                gold = new_item();
                    655:                gold->o_type = GOLD;
                    656:                gold->o_goldval = GOLDCALC;
                    657:                if (save(VS_MAGIC))
                    658:                    gold->o_goldval += GOLDCALC + GOLDCALC
                    659:                                     + GOLDCALC + GOLDCALC;
                    660:                attach(tp->t_pack, gold);
                    661:            }
                    662:        }
                    663:     }
                    664:     /*
                    665:      * Get rid of the monster.
                    666:      */
                    667:     mname = set_mname(tp);
                    668:     remove_mon(&tp->t_pos, tp, TRUE);
                    669:     if (pr)
                    670:     {
                    671:        if (has_hit)
                    672:        {
                    673:            addmsg(".  Defeated ");
                    674:            has_hit = FALSE;
                    675:        }
                    676:        else
                    677:        {
                    678:            if (!terse)
                    679:                addmsg("you have ");
                    680:            addmsg("defeated ");
                    681:        }
                    682:        msg(mname);
                    683:     }
                    684:     /*
                    685:      * Do adjustments if he went up a level
                    686:      */
                    687:     check_level();
                    688:     if (fight_flush)
                    689:        flush_type();
                    690: }

CVSweb