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

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

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

CVSweb