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

Annotation of early-roguelike/arogue7/util.c, Revision 1.1.1.1

1.1       rubenllo    1: /*
                      2:  * util.c  -  all sorts of miscellaneous routines
                      3:  *
                      4:  * Advanced Rogue
                      5:  * Copyright (C) 1984, 1985, 1986 Michael Morgan, Ken Dalka and AT&T
                      6:  * All rights reserved.
                      7:  *
                      8:  * Based on "Rogue: Exploring the Dungeons of Doom"
                      9:  * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
                     10:  * All rights reserved.
                     11:  *
                     12:  * See the file LICENSE.TXT for full copyright and licensing information.
                     13:  */
                     14:
                     15: #include "curses.h"
                     16: #include "rogue.h"
                     17: #include <ctype.h>
                     18: #include <string.h>
                     19: #ifdef PC7300
                     20: #include <track.h>
                     21: #include <kcodes.h>
                     22: #include <sys/window.h>
                     23: extern struct uwdata wdata;
                     24: #endif
                     25:
                     26: /*
                     27:  * all sorts of miscellaneous routines
                     28:  *
                     29:  */
                     30:
                     31:
                     32:
                     33:
                     34: /*
                     35:  * this routine computes the players current AC without dex bonus's
                     36:  */
                     37: int
                     38: ac_compute(bool ignoremetal)
                     39: {
                     40:     register int ac;
                     41:
                     42:     ac = pstats.s_arm; /* base armor of "skin" */
                     43:     if (cur_armor) {
                     44:        if (!ignoremetal ||
                     45:             (cur_armor->o_which != LEATHER             &&
                     46:              cur_armor->o_which != STUDDED_LEATHER     &&
                     47:              cur_armor->o_which != PADDED_ARMOR))
                     48:                ac -= (10 - cur_armor->o_ac);
                     49:     }
                     50:     if (player.t_ctype == C_MONK)
                     51:        ac -= pstats.s_lvl * 2 / 3;
                     52:     ac -= ring_value(R_PROTECT);
                     53:     if (cur_misc[WEAR_BRACERS] != NULL)
                     54:        ac -= cur_misc[WEAR_BRACERS]->o_ac;
                     55:     if (cur_misc[WEAR_CLOAK] != NULL)
                     56:        ac -= cur_misc[WEAR_CLOAK]->o_ac;
                     57:
                     58:     /* If player has the cloak, must be wearing it */
                     59:     if (cur_relic[EMORI_CLOAK]) ac -= 5;
                     60:
                     61:     if (ac > 10)
                     62:        ac = 10;
                     63:     return(ac);
                     64: }
                     65: 
                     66: /*
                     67:  * aggravate:
                     68:  *     aggravate all the monsters on this level
                     69:  */
                     70:
                     71: void
                     72: aggravate(bool do_uniques, bool do_good)
                     73: {
                     74:     register struct linked_list *mi;
                     75:     register struct thing *thingptr;
                     76:
                     77:     for (mi = mlist; mi != NULL; mi = next(mi)) {
                     78:        thingptr = THINGPTR(mi);
                     79:        if (do_good == FALSE && off(*thingptr, ISMEAN)) continue;
                     80:        if (do_uniques || off(*thingptr, ISUNIQUE)) runto(thingptr, &hero);
                     81:     }
                     82: }
                     83: 
                     84: /*
                     85:  * cansee:
                     86:  *     returns true if the hero can see a certain coordinate.
                     87:  */
                     88:
                     89: bool
                     90: cansee(int y, int x)
                     91: {
                     92:     register struct room *rer;
                     93:     register int radius;
                     94:     coord tp;
                     95:
                     96:     if (on(player, ISBLIND))
                     97:        return FALSE;
                     98:
                     99:     tp.y = y;
                    100:     tp.x = x;
                    101:     rer = roomin(&tp);
                    102:
                    103:     /* How far can we see? */
                    104:     if (levtype == OUTSIDE) {
                    105:        if (daytime) radius = 36;
                    106:        else if (lit_room(rer)) radius = 9;
                    107:        else radius = 3;
                    108:     }
                    109:     else radius = 3;
                    110:
                    111:     /*
                    112:      * We can only see if the hero in the same room as
                    113:      * the coordinate and the room is lit or if it is close.
                    114:      */
                    115:     return ((rer != NULL &&
                    116:             levtype != OUTSIDE &&
                    117:             (levtype != MAZELEV ||     /* Maze level needs direct line */
                    118:              maze_view(tp.y, tp.x)) &&
                    119:             rer == roomin(&hero) &&
                    120:             lit_room(rer)) ||
                    121:            DISTANCE(y, x, hero.y, hero.x) < radius);
                    122: }
                    123: 
                    124: /*
                    125:  * check_level:
                    126:  *     Check to see if the guy has gone up a level.
                    127:  *
                    128:  *     Return points needed to obtain next level.
                    129:  *
                    130:  * These are certain beginning experience levels for all players.
                    131:  * All further experience levels are computed by muliplying by 2
                    132:  * up through MAXDOUBLE. Then the cap is added in to compute
                    133:  * further levels
                    134:  */
                    135: long
                    136: check_level(void)
                    137: {
                    138:     register int i, j, add = 0;
                    139:     register unsigned long exp;
                    140:     long retval;       /* Return value */
                    141:     int nsides;
                    142:
                    143:     pstats.s_lvl -= pstats.s_lvladj; /* correct for level adjustment */
                    144:     /* See if we are past the doubling stage */
                    145:     exp = char_class[player.t_ctype].cap;
                    146:     if (pstats.s_exp >= exp) {
                    147:        i = pstats.s_exp/exp;   /* First get amount above doubling area */
                    148:        retval = exp + i * exp; /* Compute next higher boundary */
                    149:        i += MAXDOUBLE; /* Add in the previous doubled levels */
                    150:     }
                    151:     else {
                    152:        i = 0;
                    153:        exp = char_class[player.t_ctype].start_exp;
                    154:        while (exp <= pstats.s_exp) {
                    155:            i++;
                    156:            exp <<= 1;
                    157:        }
                    158:        retval = exp;
                    159:     }
                    160:     if (++i > pstats.s_lvl) {
                    161:        nsides = char_class[player.t_ctype].hit_pts;
                    162:        for (j=0; j<(i-pstats.s_lvl); j++) /* Take care of multi-level jumps */
                    163:            add += max(1, roll(1,nsides) + const_bonus());
                    164:        max_stats.s_hpt += add;
                    165:        if ((pstats.s_hpt += add) > max_stats.s_hpt)
                    166:            pstats.s_hpt = max_stats.s_hpt;
                    167:        msg("Welcome, %s, to level %d",
                    168:            cnames[player.t_ctype][min(i-1, NUM_CNAMES-1)], i);
                    169:     }
                    170:     pstats.s_lvl = i;
                    171:     pstats.s_lvl += pstats.s_lvladj; /* correct for level adjustment */
                    172:     return(retval);
                    173: }
                    174: 
                    175: /*
                    176:  * Used to modify the players strength
                    177:  * it keeps track of the highest it has been, just in case
                    178:  */
                    179:
                    180: void
                    181: chg_str(int amt)
                    182: {
                    183:     register int ring_str;             /* ring strengths */
                    184:     register struct stats *ptr;                /* for speed */
                    185:
                    186:     ptr = &pstats;
                    187:     ring_str = ring_value(R_ADDSTR);
                    188:     ptr->s_str -= ring_str;
                    189:     ptr->s_str += amt;
                    190:     if (ptr->s_str > 25)
                    191:        ptr->s_str = 25;
                    192:     if (ptr->s_str > max_stats.s_str)
                    193:        max_stats.s_str = ptr->s_str;
                    194:     ptr->s_str += ring_str;
                    195:     if (ptr->s_str <= 0)
                    196:        death(D_STRENGTH);
                    197:     updpack(TRUE, &player);
                    198: }
                    199: 
                    200: /*
                    201:  * let's confuse the player
                    202:  */
                    203: void
                    204: confus_player(void)
                    205: {
                    206:     if (off(player, ISCLEAR))
                    207:     {
                    208:        msg("Wait, what's going on here. Huh? What? Who?");
                    209:        if (find_slot(unconfuse))
                    210:            lengthen(unconfuse, HUHDURATION);
                    211:        else
                    212:            fuse(unconfuse, NULL, HUHDURATION, AFTER);
                    213:        turn_on(player, ISHUH);
                    214:     }
                    215:     else msg("You feel dizzy for a moment, but it quickly passes.");
                    216: }
                    217: 
                    218: /*
                    219:  * this routine computes the players current dexterity
                    220:  */
                    221: int
                    222: dex_compute(void)
                    223: {
                    224:     if (cur_misc[WEAR_GAUNTLET] != NULL                &&
                    225:        cur_misc[WEAR_GAUNTLET]->o_which == MM_G_DEXTERITY) {
                    226:        if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
                    227:            return (3);
                    228:        else
                    229:            return (18);
                    230:     }
                    231:     else
                    232:            return (pstats.s_dext);
                    233: }
                    234: 
                    235: /*
                    236:  * diag_ok:
                    237:  *     Check to see if the move is legal if it is diagonal
                    238:  */
                    239:
                    240: bool
                    241: diag_ok(coord *sp, coord *ep, struct thing *flgptr)
                    242: {
                    243:     register int numpaths = 0;
                    244:
                    245:     /* Horizontal and vertical moves are always ok */
                    246:     if (ep->x == sp->x || ep->y == sp->y)
                    247:        return TRUE;
                    248:
                    249:     /* Diagonal moves are not allowed if there is a horizontal or
                    250:      * vertical path to the destination
                    251:      */
                    252:     if (step_ok(ep->y, sp->x, MONSTOK, flgptr)) numpaths++;
                    253:     if (step_ok(sp->y, ep->x, MONSTOK, flgptr)) numpaths++;
                    254:     return(numpaths != 1);
                    255: }
                    256: 
                    257: /*
                    258:  * pick a random position around the give (y, x) coordinates
                    259:  */
                    260: coord *
                    261: fallpos(coord *pos, bool be_clear, int range)
                    262: {
                    263:        register int tried, i, j;
                    264:        register char ch;
                    265:        static coord ret;
                    266:        static short masks[] = {
                    267:                0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x100 };
                    268:
                    269: /*
                    270:  * Pick a spot at random centered on the position given by 'pos' and
                    271:  * up to 'range' squares away from 'pos'
                    272:  *
                    273:  * If 'be_clear' is TRUE, the spot must be either FLOOR or PASSAGE
                    274:  * inorder to be considered valid
                    275:  *
                    276:  *
                    277:  * Generate a number from 0 to 8, representing the position to pick.
                    278:  * Note that this DOES include the positon 'pos' itself
                    279:  *
                    280:  * If this position is not valid, mark it as 'tried', and pick another.
                    281:  * Whenever a position is picked that has been tried before,
                    282:  * sequentially find the next untried position. This eliminates costly
                    283:  * random number generation
                    284:  */
                    285:
                    286:        tried = 0;
                    287:        while( tried != 0x1ff ) {
                    288:                i = rnd(9);
                    289:                while( tried & masks[i] )
                    290:                        i = (i + 1) % 9;
                    291:
                    292:                tried |= masks[i];
                    293:
                    294:                for( j = 1; j <= range; j++ ) {
                    295:                        ret.x = pos->x + j*grid[i].x;
                    296:                        ret.y = pos->y + j*grid[i].y;
                    297:
                    298:                        if (ret.x == hero.x && ret.y == hero.y)
                    299:                                continue; /* skip the hero */
                    300:
                    301:                        if (ret.x < 0 || ret.x > cols - 1 ||
                    302:                            ret.y < 1 || ret.y > lines - 3)
                    303:                                continue; /* off the screen? */
                    304:
                    305:                        ch = CCHAR( winat(ret.y, ret.x) );
                    306:
                    307:                        /*
                    308:                         * Check to make certain the spot is valid
                    309:                         */
                    310:                        switch( ch ) {
                    311:                        case FLOOR:
                    312:                        case PASSAGE:
                    313:                                return( &ret );
                    314:                        case GOLD:
                    315:                        case SCROLL:
                    316:                        case POTION:
                    317:                        case STICK:
                    318:                        case RING:
                    319:                        case WEAPON:
                    320:                        case ARMOR:
                    321:                        case MM:
                    322:                        case FOOD:
                    323:                                if(!be_clear && levtype != POSTLEV)
                    324:                                        return( &ret );
                    325:                        default:
                    326:                                break;
                    327:                        }
                    328:                }
                    329:        }
                    330:        return( NULL );
                    331: }
                    332:
                    333: 
                    334: /*
                    335:  * findmindex:
                    336:  *     Find the index into the monster table of a monster given its name.
                    337:  */
                    338:
                    339: int
                    340: findmindex(char *name)
                    341: {
                    342:     int which;
                    343:
                    344:     for (which=1; which<NUMMONST; which++) {
                    345:         if (strcmp(name, monsters[which].m_name) == 0)
                    346:             break;
                    347:     }
                    348:     if (which >= NUMMONST) {
                    349:         debug("couldn't find monster index");
                    350:         which = 1;
                    351:     }
                    352:     return(which);
                    353: }
                    354: 
                    355: /*
                    356:  * find_mons:
                    357:  *     Find the monster from his coordinates
                    358:  */
                    359:
                    360: struct linked_list *
                    361: find_mons(int y, int x)
                    362: {
                    363:     register struct linked_list *item;
                    364:     register struct thing *th;
                    365:
                    366:     for (item = mlist; item != NULL; item = next(item))
                    367:     {
                    368:        th = THINGPTR(item);
                    369:        if (th->t_pos.y == y && th->t_pos.x == x)
                    370:            return item;
                    371:     }
                    372:     return NULL;
                    373: }
                    374: 
                    375: /*
                    376:  * find_obj:
                    377:  *     find the unclaimed object at y, x
                    378:  */
                    379:
                    380: struct linked_list *
                    381: find_obj(int y, int x)
                    382: {
                    383:     register struct linked_list *obj;
                    384:     register struct object *op;
                    385:
                    386:     for (obj = lvl_obj; obj != NULL; obj = next(obj))
                    387:     {
                    388:        op = OBJPTR(obj);
                    389:        if (op->o_pos.y == y && op->o_pos.x == x)
                    390:                return obj;
                    391:     }
                    392:     return NULL;
                    393: }
                    394: 
                    395: /*
                    396:  * get coordinates from the player using the cursor keys (or mouse)
                    397:  */
                    398: coord
                    399: get_coordinates(void)
                    400: {
                    401:     register int which;
                    402:     coord c;
                    403: #ifdef PC7300
                    404:     struct umdata startmouse, listenmouse;     /* Mouse parameters */
                    405:     int xmouse,        /* x-position of mouse */
                    406:        ymouse, /* y-position of mouse */
                    407:        bmouse, /* button value of mouse */
                    408:        rmouse; /* reason for mouse change */
                    409: #endif
                    410:
                    411:     c = hero;
                    412:     wmove(cw, hero.y, hero.x);
                    413:     draw(cw);
                    414: #ifdef PC7300
                    415:     keypad(0, 1);      /* Turn on escape sequences */
                    416:     ioctl(0, WIOCGETMOUSE, &startmouse); /* Get current mouse parameters */
                    417:     listenmouse = startmouse;  /* Make a copy */
                    418:     listenmouse.um_flags |= MSDOWN;    /* Enable detection of button down */
                    419:     ioctl(0, WIOCSETMOUSE, &listenmouse);      /* Make the change */
                    420: #endif
                    421:     for (;;) {
                    422: #ifdef PC7300
                    423:        which = wgetc(0);
                    424: #else
                    425:        which = (getchar() & 0177);
                    426: #endif
                    427:        switch(which) {
                    428: #ifdef PC7300
                    429:            case Home:
                    430:                c.x = 0; c.y = 1;
                    431:            when Beg:
                    432:                c.x = 0;
                    433:            when End:
                    434:                c.x = cols - 1;
                    435:            when Mouse:
                    436:            case ESCAPE:
                    437:            case Cancl:
                    438:            case s_Cancl:
                    439:                if (which == Mouse) {
                    440:                    if (wreadmouse(0,&xmouse,&ymouse,&bmouse,&rmouse) != 0 ||
                    441:                        (rmouse & MSDOWN) == 0)
                    442:                        break;
                    443:                    c.y = ymouse / wdata.uw_vs;
                    444:                    c.x = xmouse / wdata.uw_hs;
                    445:                    c.y = max(c.y, 1);
                    446:                    c.y = min(c.y, lines - 3);
                    447:                    c.x = max(c.x, 0);
                    448:                    c.x = min(c.x, cols - 1);
                    449:                }
                    450:                else c = hero;
                    451:                wmove(cw, c.y, c.x);
                    452:                draw(cw);
                    453:            case '\n':
                    454:            case '\c':
                    455:                keypad(0, 0);   /* Turn off escape interpretation */
                    456:                ioctl(0, WIOCSETMOUSE, &startmouse); /* No mouse tracking */
                    457:                return(c);
                    458:            when 'h':
                    459:            case 'H':
                    460:            case Back:
                    461:            case s_Back:
                    462:                c.x--;
                    463:            when 'j':
                    464:            case 'J':
                    465:            case Down:
                    466:            case RollDn:
                    467:                c.y++;
                    468:            when 'k':
                    469:            case 'K':
                    470:            case Up:
                    471:            case RollUp:
                    472:                c.y--;
                    473:            when 'l':
                    474:            case 'L':
                    475:            case Forward:
                    476:            case s_Forward:
                    477:                c.x++;
                    478:            when 'y':
                    479:            case 'Y':
                    480:            case Prev:
                    481:                c.x--; c.y--;
                    482:            when 'u':
                    483:            case 'U':
                    484:            case Next:
                    485:                c.x++; c.y--;
                    486:            when 'b':
                    487:            case 'B':
                    488:            case s_Prev:
                    489:                c.x--; c.y++;
                    490:            when 'n':
                    491:            case 'N':
                    492:            case s_Next:
                    493:                c.x++; c.y++;
                    494:            when '*':
                    495:                msg("Select location via mouse, or");
                    496:                msg("Use cursor keys,h,j,k,l,y,u,b,or n, then hit return.");
                    497: #else
                    498:            case ESCAPE:
                    499:                c = hero;
                    500:                wmove(cw, c.y, c.x);
                    501:                draw(cw);
                    502:            case '\n':
                    503:            case '\r':
                    504:                return(c);
                    505:            when 'h':
                    506:            case 'H':
                    507:                c.x--;
                    508:            when 'j':
                    509:            case 'J':
                    510:                c.y++;
                    511:            when 'k':
                    512:            case 'K':
                    513:                c.y--;
                    514:            when 'l':
                    515:            case 'L':
                    516:                c.x++;
                    517:            when 'y':
                    518:            case 'Y':
                    519:                c.x--; c.y--;
                    520:            when 'u':
                    521:            case 'U':
                    522:                c.x++; c.y--;
                    523:            when 'b':
                    524:            case 'B':
                    525:                c.x--; c.y++;
                    526:            when 'n':
                    527:            case 'N':
                    528:                c.x++; c.y++;
                    529:            when '*':
                    530:                msg("Use h,j,k,l,y,u,b,n to position cursor, then hit return.");
                    531: #endif
                    532:        }
                    533:        c.y = max(c.y, 1);
                    534:        c.y = min(c.y, lines - 3);
                    535:        c.x = max(c.x, 0);
                    536:        c.x = min(c.x, cols - 1);
                    537:        wmove(cw, c.y, c.x);
                    538:        draw(cw);
                    539:     }
                    540: }
                    541: 
                    542: /*
                    543:  * set up the direction co_ordinate for use in various "prefix" commands
                    544:  */
                    545: bool
                    546: get_dir(coord *direction)
                    547: {
                    548:     register char *prompt;
                    549:     register bool gotit;
                    550:     int x,y;
                    551:
                    552:     prompt = terse ? "Direction?" :  "Which direction? ";
                    553:     msg(prompt);
                    554:     do
                    555:     {
                    556:        gotit = TRUE;
                    557:        switch (md_readchar(msgw))
                    558:        {
                    559:            case 'h': case'H': direction->y =  0; direction->x = -1;
                    560:            when 'j': case'J': direction->y =  1; direction->x =  0;
                    561:            when 'k': case'K': direction->y = -1; direction->x =  0;
                    562:            when 'l': case'L': direction->y =  0; direction->x =  1;
                    563:            when 'y': case'Y': direction->y = -1; direction->x = -1;
                    564:            when 'u': case'U': direction->y = -1; direction->x =  1;
                    565:            when 'b': case'B': direction->y =  1; direction->x = -1;
                    566:            when 'n': case'N': direction->y =  1; direction->x =  1;
                    567:            case 0:
                    568:            when 3: quit(0);
                    569:                    return(FALSE);
                    570:            when ESCAPE: return (FALSE);
                    571:            otherwise:
                    572:                mpos = 0;
                    573:                msg(prompt);
                    574:                gotit = FALSE;
                    575:        }
                    576:     } until (gotit);
                    577:     if ((on(player, ISHUH) || on(player, ISDANCE)) && rnd(100) > 20) {
                    578:        do
                    579:        {
                    580:            *direction = grid[rnd(9)];
                    581:        } while (direction->y == 0 && direction->x == 0);
                    582:     }
                    583:     else if (on(player, ISFLEE)) {
                    584:            y = hero.y;
                    585:            x = hero.x;
                    586:            while (shoot_ok(winat(y, x))) {
                    587:                y += direction->y;
                    588:                x += direction->x;
                    589:            }
                    590:            if (isalpha(mvwinch(mw, y, x))) {
                    591:                if (y == player.t_dest->y && x == player.t_dest->x) {
                    592:                    mpos = 0;
                    593:                    msg("You are too frightened to!");
                    594:                    return(FALSE);
                    595:            }
                    596:        }
                    597:     }
                    598:     mpos = 0;
                    599:     return TRUE;
                    600: }
                    601: 
                    602: /*
                    603:  * see if the object is one of the currently used items
                    604:  */
                    605: bool
                    606: is_current(struct object *obj)
                    607: {
                    608:     if (obj == NULL)
                    609:        return FALSE;
                    610:     if (obj == cur_armor               || obj == cur_weapon            ||
                    611:        obj == cur_ring[LEFT_1]         || obj == cur_ring[LEFT_2]      ||
                    612:        obj == cur_ring[LEFT_3]         || obj == cur_ring[LEFT_4]      ||
                    613:        obj == cur_ring[RIGHT_1]        || obj == cur_ring[RIGHT_2]     ||
                    614:        obj == cur_ring[RIGHT_3]        || obj == cur_ring[RIGHT_4]     ||
                    615:        obj == cur_misc[WEAR_BOOTS]     || obj == cur_misc[WEAR_JEWEL]  ||
                    616:        obj == cur_misc[WEAR_BRACERS]   || obj == cur_misc[WEAR_CLOAK]  ||
                    617:        obj == cur_misc[WEAR_GAUNTLET]  || obj == cur_misc[WEAR_NECKLACE]) {
                    618:
                    619:        return TRUE;
                    620:     }
                    621:
                    622:     /* Is it a "current" relic? */
                    623:     if (obj->o_type == RELIC) {
                    624:        switch (obj->o_which) {
                    625:            case MUSTY_DAGGER:
                    626:            case EMORI_CLOAK:
                    627:            case HEIL_ANKH:
                    628:            case YENDOR_AMULET:
                    629:            case STONEBONES_AMULET:
                    630:            case HRUGGEK_MSTAR:
                    631:            case AXE_AKLAD:
                    632:            case YEENOGHU_FLAIL:
                    633:            case SURTUR_RING:
                    634:                if (cur_relic[obj->o_which]) return TRUE;
                    635:        }
                    636:     }
                    637:
                    638:     return FALSE;
                    639: }
                    640:
                    641: 
                    642: /*
                    643:  * Look:
                    644:  *     A quick glance all around the player
                    645:  * wakeup: Should we wake up monsters
                    646:  * runend: At end of a run -- for mazes
                    647:  */
                    648:
                    649: void
                    650: look(bool wakeup, bool runend)
                    651: {
                    652:     register int x, y, radius;
                    653:     register char ch, och;
                    654:     register int oldx, oldy;
                    655:     register bool inpass, horiz, vert, do_light = FALSE, do_blank = FALSE;
                    656:     register int passcount = 0, curfloorcount = 0, nextfloorcount = 0;
                    657:     register struct room *rp;
                    658:     register int ey, ex;
                    659:
                    660:     inpass = ((rp = roomin(&hero)) == NULL); /* Are we in a passage? */
                    661:
                    662:     /* Are we moving vertically or horizontally? */
                    663:     if (runch == 'h' || runch == 'l') horiz = TRUE;
                    664:     else horiz = FALSE;
                    665:     if (runch == 'j' || runch == 'k') vert = TRUE;
                    666:     else vert = FALSE;
                    667:
                    668:     /* How far around himself can the player see? */
                    669:     if (levtype == OUTSIDE) {
                    670:        if (daytime) radius = 6;
                    671:        else if (lit_room(rp)) radius = 3;
                    672:        else radius = 1;
                    673:     }
                    674:     else radius = 1;
                    675:
                    676:     getyx(cw, oldy, oldx);     /* Save current position */
                    677:
                    678:     /* Blank out the floor around our last position and check for
                    679:      * moving out of a corridor in a maze.
                    680:      */
                    681:     if (levtype == OUTSIDE) do_blank = !daytime;
                    682:     else if (oldrp != NULL && !lit_room(oldrp) && off(player, ISBLIND))
                    683:            do_blank = TRUE;
                    684:
                    685:     /* Now move around the old position and blank things out */
                    686:     ey = player.t_oldpos.y + radius;
                    687:     ex = player.t_oldpos.x + radius;
                    688:     for (x = player.t_oldpos.x - radius; x <= ex; x++)
                    689:       if (x >= 0 && x < cols)
                    690:        for (y = player.t_oldpos.y - radius; y <= ey; y++) {
                    691:            struct linked_list *it;
                    692:            coord here;         /* Current <x,y> coordinate */
                    693:            char savech;        /* Saves character in monster window */
                    694:            bool in_room;       /* Are we in a room? */
                    695:
                    696:            if (y < 1 || y > lines - 3) continue;
                    697:
                    698:            /* See what's there -- ignore monsters, just see what they're on */
                    699:            savech = CCHAR( mvwinch(mw, y, x) );
                    700:            waddch(mw, ' ');
                    701:            ch = show(y, x);
                    702:            mvwaddch(mw, y, x, savech); /* Restore monster */
                    703:
                    704:            /*
                    705:             * If we have a monster that we can't see anymore, make sure
                    706:             * that we can note that fact.
                    707:             */
                    708:            if (isalpha(savech) &&
                    709:                (y < hero.y - radius || y > hero.y + radius ||
                    710:                 x < hero.x - radius || x > hero.x + radius)) {
                    711:                /* Find the monster */
                    712:                it = find_mons(y, x);
                    713:            }
                    714:            else it = NULL;
                    715:
                    716:            /* Are we in a room? */
                    717:            here.y = y;
                    718:            here.x = x;
                    719:            in_room = (roomin(&here) != NULL);
                    720:
                    721:            if ((do_blank || !in_room) && (y != hero.y || x != hero.x))
                    722:                switch (ch) {
                    723:                    case DOOR:
                    724:                    case SECRETDOOR:
                    725:                    case PASSAGE:
                    726:                    case STAIRS:
                    727:                    case TRAPDOOR:
                    728:                    case TELTRAP:
                    729:                    case BEARTRAP:
                    730:                    case SLEEPTRAP:
                    731:                    case ARROWTRAP:
                    732:                    case DARTTRAP:
                    733:                    case MAZETRAP:
                    734:                    case POOL:
                    735:                    case POST:
                    736:                    case '|':
                    737:                    case '-':
                    738:                    case WALL:
                    739:                        /* If there was a monster showing, make it disappear */
                    740:                        if (isalpha(savech)) {
                    741:                            mvwaddch(cw, y, x, ch);
                    742:
                    743:                            /*
                    744:                             * If we found it (we should!), set it to
                    745:                             * the right character!
                    746:                             */
                    747:                            if (it) (THINGPTR(it))->t_oldch = ch;
                    748:                        }
                    749:                        break;
                    750:                    when FLOOR:
                    751:                    case FOREST:
                    752:                    default:
                    753:                        mvwaddch(cw, y, x, in_room ? ' ' : PASSAGE);
                    754:
                    755:                        /* If we found a monster, set it to darkness! */
                    756:                        if (it) (THINGPTR(it))->t_oldch = CCHAR( mvwinch(cw, y, x) );
                    757:                }
                    758:
                    759:            /* Moving out of a corridor? */
                    760:            if (levtype == MAZELEV && !ce(hero, player.t_oldpos) &&
                    761:                !running && !isrock(ch) &&  /* Not running and not a wall */
                    762:                ((vert && x != player.t_oldpos.x && y==player.t_oldpos.y) ||
                    763:                 (horiz && y != player.t_oldpos.y && x==player.t_oldpos.x)))
                    764:                    do_light = off(player, ISBLIND);
                    765:        }
                    766:
                    767:     /* Take care of unlighting a corridor */
                    768:     if (do_light && lit_room(rp)) light(&player.t_oldpos);
                    769:
                    770:     /* Are we coming or going between a wall and a corridor in a maze? */
                    771:     och = show(player.t_oldpos.y, player.t_oldpos.x);
                    772:     ch = show(hero.y, hero.x);
                    773:     if (levtype == MAZELEV &&
                    774:        ((isrock(och) && !isrock(ch)) || (isrock(ch) && !isrock(och)))) {
                    775:        do_light = off(player, ISBLIND); /* Light it up if not blind */
                    776:
                    777:        /* Unlight what we just saw */
                    778:        if (do_light && lit_room(&rooms[0])) light(&player.t_oldpos);
                    779:     }
                    780:
                    781:     /* Look around the player */
                    782:     ey = hero.y + radius;
                    783:     ex = hero.x + radius;
                    784:     for (x = hero.x - radius; x <= ex; x++)
                    785:        if (x >= 0 && x < cols) for (y = hero.y - radius; y <= ey; y++) {
                    786:            if (y < 1 || y >= lines - 2)
                    787:                continue;
                    788:            if (isalpha(mvwinch(mw, y, x)))
                    789:            {
                    790:                register struct linked_list *it;
                    791:                register struct thing *tp;
                    792:
                    793:                if (wakeup)
                    794:                    it = wake_monster(y, x);
                    795:                else
                    796:                    it = find_mons(y, x);
                    797:
                    798:                if (it) {
                    799:                    tp = THINGPTR(it);
                    800:                    tp->t_oldch = CCHAR( mvinch(y, x) );
                    801:                    if (isatrap(tp->t_oldch)) {
                    802:                        register struct trap *trp = trap_at(y, x);
                    803:
                    804:                        tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch
                    805:                                                                : trp->tr_show;
                    806:                    }
                    807:                    if (tp->t_oldch == FLOOR && !lit_room(rp) &&
                    808:                        off(player, ISBLIND))
                    809:                            tp->t_oldch = ' ';
                    810:                }
                    811:            }
                    812:
                    813:            /*
                    814:             * Secret doors show as walls
                    815:             */
                    816:            if ((ch = show(y, x)) == SECRETDOOR)
                    817:                ch = secretdoor(y, x);
                    818:            /*
                    819:             * Don't show room walls if he is in a passage and
                    820:             * check for maze turns
                    821:             */
                    822:            if (off(player, ISBLIND))
                    823:            {
                    824:                if (y == hero.y && x == hero.x
                    825:                    || (inpass && (ch == '-' || ch == '|')))
                    826:                        continue;
                    827:
                    828:                /* Did we come to a crossroads in a maze? */
                    829:                if (levtype == MAZELEV &&
                    830:                    (runend || !ce(hero, player.t_oldpos)) &&
                    831:                    !isrock(ch) &&      /* Not a wall */
                    832:                    ((vert && x != hero.x && y == hero.y) ||
                    833:                     (horiz && y != hero.y && x == hero.x)))
                    834:                        /* Just came to a turn */
                    835:                        do_light = off(player, ISBLIND);
                    836:            }
                    837:            else if (y != hero.y || x != hero.x)
                    838:                continue;
                    839:
                    840:            wmove(cw, y, x);
                    841:            waddch(cw, ch);
                    842:            if (door_stop && !firstmove && running)
                    843:            {
                    844:                switch (runch)
                    845:                {
                    846:                    case 'h':
                    847:                        if (x == hero.x + 1)
                    848:                            continue;
                    849:                    when 'j':
                    850:                        if (y == hero.y - 1)
                    851:                            continue;
                    852:                    when 'k':
                    853:                        if (y == hero.y + 1)
                    854:                            continue;
                    855:                    when 'l':
                    856:                        if (x == hero.x - 1)
                    857:                            continue;
                    858:                    when 'y':
                    859:                        if ((x + y) - (hero.x + hero.y) >= 1)
                    860:                            continue;
                    861:                    when 'u':
                    862:                        if ((y - x) - (hero.y - hero.x) >= 1)
                    863:                            continue;
                    864:                    when 'n':
                    865:                        if ((x + y) - (hero.x + hero.y) <= -1)
                    866:                            continue;
                    867:                    when 'b':
                    868:                        if ((y - x) - (hero.y - hero.x) <= -1)
                    869:                            continue;
                    870:                }
                    871:                switch (ch)
                    872:                {
                    873:                    case DOOR:
                    874:                        if (x == hero.x || y == hero.y)
                    875:                            running = FALSE;
                    876:                        break;
                    877:                    case PASSAGE:
                    878:                        if (x == hero.x || y == hero.y)
                    879:                            passcount++;
                    880:                        break;
                    881:                    case FLOOR:
                    882:                        /* Stop by new passages in a maze (floor next to us) */
                    883:                        if ((levtype == MAZELEV) &&
                    884:                            !(hero.y == y && hero.x == x)) {
                    885:                            if (vert) { /* Moving vertically */
                    886:                                /* We have a passage on our row */
                    887:                                if (y == hero.y) curfloorcount++;
                    888:
                    889:                                /* Some passage on the next row */
                    890:                                else if (y != player.t_oldpos.y)
                    891:                                    nextfloorcount++;
                    892:                            }
                    893:                            else {      /* Moving horizontally */
                    894:                                /* We have a passage on our column */
                    895:                                if (x == hero.x) curfloorcount++;
                    896:
                    897:                                /* Some passage in the next column */
                    898:                                else if (x != player.t_oldpos.x)
                    899:                                    nextfloorcount++;
                    900:                            }
                    901:                        }
                    902:                    case '|':
                    903:                    case '-':
                    904:                    case ' ':
                    905:                        break;
                    906:                    default:
                    907:                        running = FALSE;
                    908:                        break;
                    909:                }
                    910:            }
                    911:        }
                    912:
                    913:     /* Have we passed a side passage, with multiple choices? */
                    914:     if (curfloorcount > 0 && nextfloorcount > 0) running = FALSE;
                    915:
                    916:     else if (door_stop && !firstmove && passcount > 1)
                    917:        running = FALSE;
                    918:
                    919:     /* Do we have to light up the area (just stepped into a new corridor)? */
                    920:     if (do_light && !running && lit_room(rp)) light(&hero);
                    921:
                    922:     mvwaddch(cw, hero.y, hero.x, PLAYER);
                    923:     wmove(cw, oldy, oldx);
                    924:     if (!ce(player.t_oldpos, hero)) {
                    925:        player.t_oldpos = hero; /* Don't change if we didn't move */
                    926:        oldrp = rp;
                    927:     }
                    928: }
                    929: 
                    930: /*
                    931:  * Lower a level of experience
                    932:  */
                    933:
                    934: void
                    935: lower_level(short who)
                    936: {
                    937:     int fewer, nsides;
                    938:     unsigned int exp;
                    939:
                    940:     msg("You suddenly feel less skillful.");
                    941:     if (--pstats.s_lvl == 0)
                    942:        death(who);             /* All levels gone */
                    943:     if (pstats.s_lvladj > 0) { /* lose artificial levels first */
                    944:        pstats.s_lvladj--;
                    945:        return;
                    946:     }
                    947:     exp = char_class[player.t_ctype].cap;
                    948:     if (pstats.s_exp >= exp*2)
                    949:        pstats.s_exp -= exp;
                    950:     else
                    951:        pstats.s_exp /= 2;
                    952:
                    953:     nsides = char_class[player.t_ctype].hit_pts;
                    954:     fewer = max(1, roll(1,nsides) + const_bonus());
                    955:     pstats.s_hpt -= fewer;
                    956:     max_stats.s_hpt -= fewer;
                    957:     if (pstats.s_hpt < 1)
                    958:        pstats.s_hpt = 1;
                    959:     if (max_stats.s_hpt < 1)
                    960:        death(who);
                    961: }
                    962: 
                    963: /*
                    964:  * print out the name of a monster
                    965:  */
                    966: char *
                    967: monster_name(struct thing *tp)
                    968: {
                    969:     prbuf[0] = '\0';
                    970:     if (on(*tp, ISFLEE) || on(*tp, WASTURNED))
                    971:        strcat(prbuf, "terrified ");
                    972:     if (on(*tp, ISHUH))
                    973:        strcat(prbuf, "confused ");
                    974:     if (on(*tp, ISCHARMED))
                    975:        strcat(prbuf, "charmed ");
                    976:     else if (on(*tp, ISFLY))
                    977:        strcat(prbuf, "flying ");
                    978:
                    979:     /* If it is sleeping or stoned, write over any of the above attributes */
                    980:     if (off(*tp, ISRUN))
                    981:        strcpy(prbuf, "sleeping ");
                    982:     if (on(*tp, ISSTONE))
                    983:        strcpy(prbuf, "petrified ");
                    984:
                    985:     if (tp->t_name) strcat(prbuf, tp->t_name);
                    986:     else strcat(prbuf, monsters[tp->t_index].m_name);
                    987:
                    988:     return(prbuf);
                    989: }
                    990: 
                    991: /*
                    992:  * move_hero:
                    993:  *     Try to move the hero somplace besides next to where he is.  We ask him
                    994:  *     where.  There can be restrictions based on why he is moving.
                    995:  */
                    996:
                    997: bool
                    998: move_hero(int why)
                    999: {
                   1000:     char *action = "";
                   1001:     char which;
                   1002:     coord c;
                   1003:
                   1004:     switch (why) {
                   1005:        case H_TELEPORT:
                   1006:            action = "teleport";
                   1007:     }
                   1008:
                   1009:     msg("Where do you wish to %s to? (* for help) ", action);
                   1010:     c = get_coordinates();
                   1011:     mpos = 0;
                   1012:     which = CCHAR( winat(c.y, c.x) );
                   1013:     switch (which) {
                   1014:        default:
                   1015:            if (!isrock(which) || off(player, CANINWALL)) break;
                   1016:
                   1017:        case FLOOR:
                   1018:        case PASSAGE:
                   1019:        case DOOR:
                   1020:        case STAIRS:
                   1021:        case POST:
                   1022:        case GOLD:
                   1023:        case POTION:
                   1024:        case SCROLL:
                   1025:        case FOOD:
                   1026:        case WEAPON:
                   1027:        case ARMOR:
                   1028:        case RING:
                   1029:        case MM:
                   1030:        case RELIC:
                   1031:        case STICK:
                   1032:            hero = c;
                   1033:            return(TRUE);
                   1034:     }
                   1035:     return(FALSE);
                   1036: }
                   1037: 
                   1038: /*
                   1039:  * raise_level:
                   1040:  *     The guy just magically went up a level.
                   1041:  */
                   1042:
                   1043: void
                   1044: raise_level(void)
                   1045: {
                   1046:     unsigned long test;        /* Next level -- be sure it is not an overflow */
                   1047:
                   1048:     test = check_level();      /* Get next boundary */
                   1049:
                   1050:     /* Be sure it is higher than what we have no -- else overflow */
                   1051:     if (test > pstats.s_exp) pstats.s_exp = test;
                   1052:     check_level();
                   1053: }
                   1054: 
                   1055: /*
                   1056:  * saving throw matrix for character saving throws
                   1057:  * this table is indexed by char type and saving throw type
                   1058:  */
                   1059: static int st_matrix[NUM_CHARTYPES][5] = {
                   1060: /* Poison,     Petrify,        wand,           Breath,         Magic */
                   1061: { 14,          15,             16,             16,             17 },
                   1062: { 14,          15,             16,             16,             17 },
                   1063: { 14,          15,             16,             16,             17 },
                   1064: { 14,          13,             11,             15,             12 },
                   1065: { 10,          13,             14,             16,             15 },
                   1066: { 13,          12,             14,             16,             15 },
                   1067: { 13,          12,             14,             16,             15 },
                   1068: { 10,          13,             14,             16,             15 },
                   1069: { 13,          12,             14,             16,             15 },
                   1070: { 14,          15,             16,             16,             17 }
                   1071: };
                   1072:
                   1073: /*
                   1074:  * save:
                   1075:  *     See if a creature saves against something
                   1076:  * which: which type of save
                   1077:  * who: who is saving
                   1078:  * adj: saving throw adjustment
                   1079:  */
                   1080: bool
                   1081: save(int which, struct thing *who, int adj)
                   1082: {
                   1083:     register int need, level, protect;
                   1084:
                   1085:     protect = 0;
                   1086:     level = who->t_stats.s_lvl;
                   1087:     need = st_matrix[who->t_ctype][which];
                   1088:     switch (who->t_ctype) {
                   1089:     case C_FIGHTER:
                   1090:     case C_RANGER:
                   1091:     case C_PALADIN:
                   1092:     case C_MONSTER:
                   1093:        need -= (level-1) / 2;
                   1094:     when C_MAGICIAN:
                   1095:        need -= 2 * (level-1) / 5;
                   1096:     when C_CLERIC:
                   1097:     case C_DRUID:
                   1098:        need -= (level-1) / 3;
                   1099:     when C_THIEF:
                   1100:     case C_ASSASIN:
                   1101:     case C_MONK:
                   1102:        need -= 2 * (level-1) / 4;
                   1103:     }
                   1104:     /*
                   1105:      * add in pluses against poison for execeptional constitution
                   1106:      */
                   1107:     if (which == VS_POISON && who->t_stats.s_const > 18)
                   1108:        need -= (who->t_stats.s_const - 17) / 2;
                   1109:     if (who == &player) {
                   1110:        /*
                   1111:         * does the player have a ring of protection on?
                   1112:         */
                   1113:        protect +=  ring_value(R_PROTECT);
                   1114:        /*
                   1115:         * does the player have a cloak of protection on?
                   1116:         */
                   1117:         if (cur_misc[WEAR_CLOAK])
                   1118:            protect += cur_misc[WEAR_CLOAK]->o_ac;
                   1119:
                   1120:         protect = min(protect, 4);/* no more than a +4 bonus */
                   1121:         need -= protect;
                   1122:     }
                   1123:     need -= adj;
                   1124:     /*
                   1125:      * always miss or save on a 1 (except for UNIQUEs
                   1126:      */
                   1127:     if (who == &player || off(*who, ISUNIQUE))
                   1128:        need = max(need, 2);
                   1129:     need = min(20, need); /* always make our save on a 20 */
                   1130:     debug("need a %d to save", need);
                   1131:     return (roll(1, 20) >= need);
                   1132: }
                   1133:
                   1134: 
                   1135: /*
                   1136:  * secret_door:
                   1137:  *     Figure out what a secret door looks like.
                   1138:  */
                   1139:
                   1140: char
                   1141: secretdoor(int y, int x)
                   1142: {
                   1143:     register int i;
                   1144:     register struct room *rp;
                   1145:     register coord *cpp;
                   1146:     static coord cp;
                   1147:
                   1148:     cp.y = y;
                   1149:     cp.x = x;
                   1150:     cpp = &cp;
                   1151:     for (rp = rooms, i = 0; i < MAXROOMS; rp++, i++)
                   1152:        if (inroom(rp, cpp))
                   1153:            if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1)
                   1154:                return('-');
                   1155:            else
                   1156:                return('|');
                   1157:
                   1158:     return('p');
                   1159: }
                   1160: 
                   1161: /*
                   1162:  * this routine computes the players current strength
                   1163:  */
                   1164: int
                   1165: str_compute(void)
                   1166: {
                   1167:     if (cur_misc[WEAR_GAUNTLET] != NULL                &&
                   1168:        cur_misc[WEAR_GAUNTLET]->o_which == MM_G_OGRE) {
                   1169:        if (cur_misc[WEAR_GAUNTLET]->o_flags & ISCURSED)
                   1170:            return (3);
                   1171:        else
                   1172:            return (18);
                   1173:     }
                   1174:     else
                   1175:            return (pstats.s_str);
                   1176: }
                   1177: 
                   1178: /*
                   1179:  * copy string using unctrl for things
                   1180:  */
                   1181: void
                   1182: strucpy(char *s1, char *s2, int len)
                   1183: {
                   1184:     const char *sp;
                   1185:
                   1186:     while (len--)
                   1187:     {
                   1188:        strcpy(s1, (sp = unctrl(*s2++)));
                   1189:        s1 += strlen(sp);
                   1190:     }
                   1191:     *s1 = '\0';
                   1192: }
                   1193: 
                   1194: /*
                   1195:  * tr_name:
                   1196:  *     print the name of a trap
                   1197:  */
                   1198:
                   1199: char *
                   1200: tr_name(char ch)
                   1201: {
                   1202:     register char *s = "";
                   1203:
                   1204:     switch (ch)
                   1205:     {
                   1206:        case TRAPDOOR:
                   1207:            s = terse ? "A trapdoor." : "You found a trapdoor.";
                   1208:        when BEARTRAP:
                   1209:            s = terse ? "A beartrap." : "You found a beartrap.";
                   1210:        when SLEEPTRAP:
                   1211:            s = terse ? "A sleeping gas trap.":"You found a sleeping gas trap.";
                   1212:        when ARROWTRAP:
                   1213:            s = terse ? "An arrow trap." : "You found an arrow trap.";
                   1214:        when TELTRAP:
                   1215:            s = terse ? "A teleport trap." : "You found a teleport trap.";
                   1216:        when DARTTRAP:
                   1217:            s = terse ? "A dart trap." : "You found a poison dart trap.";
                   1218:        when POOL:
                   1219:            s = terse ? "A shimmering pool." : "You found a shimmering pool";
                   1220:        when MAZETRAP:
                   1221:            s = terse ? "A maze entrance." : "You found a maze entrance";
                   1222:     }
                   1223:     return s;
                   1224: }
                   1225: 
                   1226: /*
                   1227:  * for printfs: if string starts with a vowel, return "n" for an "an"
                   1228:  */
                   1229: char *
                   1230: vowelstr(char *str)
                   1231: {
                   1232:     switch (*str)
                   1233:     {
                   1234:        case 'a':
                   1235:        case 'e':
                   1236:        case 'i':
                   1237:        case 'o':
                   1238:        case 'u':
                   1239:            return "n";
                   1240:        default:
                   1241:            return "";
                   1242:     }
                   1243: }
                   1244: 
                   1245: /*
                   1246:  * wake up a room full (hopefully) of creatures
                   1247:  */
                   1248: void
                   1249: wake_room(struct room *rp)
                   1250: {
                   1251:        register struct linked_list *item;
                   1252:        register struct thing *tp;
                   1253:
                   1254:        for (item=mlist; item!=NULL; item=next(item)) {
                   1255:            tp = THINGPTR(item);
                   1256:            if (off(*tp,ISRUN) && on(*tp,ISMEAN) && roomin(&tp->t_pos) == rp)
                   1257:                runto(tp, &hero);
                   1258:        }
                   1259: }
                   1260:
                   1261: 
                   1262: /*
                   1263:  * waste_time:
                   1264:  *     Do nothing but let other things happen
                   1265:  */
                   1266:
                   1267: void
                   1268: waste_time(void)
                   1269: {
                   1270:     if (inwhgt)                        /* if from wghtchk then done */
                   1271:        return;
                   1272:     do_daemons(BEFORE);
                   1273:     do_fuses(BEFORE);
                   1274:     do_daemons(AFTER);
                   1275:     do_fuses(AFTER);
                   1276: }

CVSweb