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

Annotation of early-roguelike/arogue5/chase.c, Revision 1.1.1.1

1.1       rubenllo    1: /*
                      2:  * Code for one object to chase another
                      3:  *
                      4:  * Advanced Rogue
                      5:  * Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
                      6:  * All rights reserved.
                      7:  *
                      8:  * Based on "Rogue: Exploring the Dungeons of Doom"
                      9:  * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
                     10:  * All rights reserved.
                     11:  *
                     12:  * See the file LICENSE.TXT for full copyright and licensing information.
                     13:  */
                     14:
                     15: #include <stdlib.h>
                     16: #include <ctype.h>
                     17: #include <limits.h>
                     18: #include "curses.h"
                     19: #include "rogue.h"
                     20: #define        MAXINT  INT_MAX
                     21: #define        MININT  INT_MIN
                     22:
                     23: coord ch_ret;                          /* Where chasing takes you */
                     24:
                     25: struct linked_list *get_hurl(struct thing *tp);
                     26: bool straight_shot(int ery, int erx, int eey, int eex, coord *shooting);
                     27:
                     28:
                     29: /*
                     30:  * Canblink checks if the monster can teleport (blink).  If so, it will
                     31:  * try to blink the monster next to the player.
                     32:  */
                     33:
                     34: bool
                     35: can_blink(struct thing *tp)
                     36: {
                     37:     register int y, x, index=9;
                     38:     coord tryp;        /* To hold the coordinates for use in diag_ok */
                     39:     bool spots[9], found_one=FALSE;
                     40:
                     41:     /*
                     42:      * First, can the monster even blink?  And if so, there is only a 50%
                     43:      * chance that it will do so.  And it won't blink if it is running or
                     44:      * held.
                     45:      */
                     46:     if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
                     47:        on(*tp, ISFLEE) ||
                     48:        (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) ||
                     49:        tp->t_no_move ||
                     50:        (rnd(12) < 6)) return(FALSE);
                     51:
                     52:
                     53:     /* Initialize the spots as illegal */
                     54:     do {
                     55:        spots[--index] = FALSE;
                     56:     } while (index > 0);
                     57:
                     58:     /* Find a suitable spot next to the player */
                     59:     for (y=hero.y-1; y<hero.y+2; y++)
                     60:        for (x=hero.x-1; x<hero.x+2; x++, index++) {
                     61:            /* Make sure x coordinate is in range and that we are
                     62:             * not at the player's position
                     63:             */
                     64:            if (x<0 || x >= COLS || index == 4) continue;
                     65:
                     66:            /* Is it OK to move there? */
                     67:            if (step_ok(y, x, NOMONST, tp) &&
                     68:                (!isatrap(mvwinch(cw, y, x)) ||
                     69:                  rnd(10) >= tp->t_stats.s_intel ||
                     70:                  on(*tp, ISFLY))) {
                     71:                /* OK, we can go here.  But don't go there if
                     72:                 * monster can't get at player from there
                     73:                 */
                     74:                tryp.y = y;
                     75:                tryp.x = x;
                     76:                if (diag_ok(&tryp, &hero, tp)) {
                     77:                    spots[index] = TRUE;
                     78:                    found_one = TRUE;
                     79:                }
                     80:            }
                     81:        }
                     82:
                     83:     /* If we found one, go to it */
                     84:     if (found_one) {
                     85:        char rch;       /* What's really where the creatures moves to */
                     86:
                     87:        /* Find a legal spot */
                     88:        while (spots[index=rnd(9)] == FALSE) continue;
                     89:
                     90:        /* Get the coordinates */
                     91:        y = hero.y + (index/3) - 1;
                     92:        x = hero.x + (index % 3) - 1;
                     93:
                     94:        /* Move the monster from the old space */
                     95:        mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
                     96:
                     97:        /* Move it to the new space */
                     98:        tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
                     99:
                    100:        /* Display the creature if our hero can see it */
                    101:        if (cansee(y, x) &&
                    102:            off(*tp, ISINWALL) &&
                    103:            !invisible(tp))
                    104:            mvwaddch(cw, y, x, tp->t_type);
                    105:
                    106:        /* Fix the monster window */
                    107:        mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
                    108:        mvwaddch(mw, y, x, tp->t_type);
                    109:
                    110:        /* Record the new position */
                    111:        tp->t_pos.y = y;
                    112:        tp->t_pos.x = x;
                    113:
                    114:        /* If the monster is on a trap, trap it */
                    115:        rch = CCHAR( mvinch(y, x) );
                    116:        if (isatrap(rch)) {
                    117:            if (cansee(y, x)) tp->t_oldch = rch;
                    118:            be_trapped(tp, &(tp->t_pos));
                    119:        }
                    120:     }
                    121:
                    122:     return(found_one);
                    123: }
                    124: 
                    125: /*
                    126:  * Can_shoot determines if the monster (er) has a direct line of shot
                    127:  * at the player (ee).  If so, it returns the direction in which to shoot.
                    128:  */
                    129:
                    130: coord *
                    131: can_shoot(coord *er, coord *ee)
                    132: {
                    133:     static coord shoot_dir;
                    134:
                    135:     /* Make sure we are chasing the player */
                    136:     if (!ce((*ee), hero)) return(NULL);
                    137:
                    138:     /*
                    139:      * They must be in the same room or very close (at door)
                    140:      */
                    141:     if (roomin(er) != roomin(&hero) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
                    142:        return(NULL);
                    143:
                    144:     /* Do we have a straight shot? */
                    145:     if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
                    146:     else return(&shoot_dir);
                    147: }
                    148: 
                    149: /*
                    150:  * chase:
                    151:  *     Find the spot for the chaser(er) to move closer to the
                    152:  *     chasee(ee).  Returns TRUE if we want to keep on chasing later
                    153:  *     FALSE if we reach the goal.
                    154:  */
                    155:
                    156: /* flee: True if destination (ee) is player and monster is running
                    157:  * away or the player is in a wall and the monster can't get to it
                    158:  */
                    159: bool
                    160: chase(struct thing *tp, coord *ee, bool flee, bool *mdead)
                    161: {
                    162:     int damage, dist, thisdist, monst_dist = MAXINT;
                    163:     struct linked_list *weapon;
                    164:     register coord *er = &tp->t_pos;
                    165:     coord *shoot_dir;
                    166:     char ch, mch;
                    167:     bool next_player = FALSE;
                    168:
                    169:     if (mdead != NULL)
                    170:        *mdead = 0;
                    171:
                    172:     /*
                    173:      * set the distance from the chas(er) to the chas(ee) here and then
                    174:      * we won't have to reset it unless the chas(er) moves (instead of shoots)
                    175:      */
                    176:     dist = DISTANCE(er->y, er->x, ee->y, ee->x);
                    177:
                    178:     /*
                    179:      * If the thing is confused or it can't see the player,
                    180:      * let it move randomly.
                    181:      */
                    182:     if ((on(*tp, ISHUH) && rnd(10) < 8) ||
                    183:        (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */
                    184:        /*
                    185:         * get a valid random move
                    186:         */
                    187:        ch_ret = *rndmove(tp);
                    188:        dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
                    189:        /*
                    190:         * check to see if random move takes creature away from player
                    191:         * if it does then turn off ISHELD
                    192:         */
                    193:        if (dist > 2) {
                    194:            if (on(*tp, DIDHOLD)) {
                    195:                 turn_off(*tp, DIDHOLD);
                    196:                 turn_on(*tp, CANHOLD);
                    197:                 if (--hold_count == 0)
                    198:                     turn_off(player, ISHELD);
                    199:            }
                    200:
                    201:            /* If monster was suffocating, stop it */
                    202:            if (on(*tp, DIDSUFFOCATE)) {
                    203:                turn_off(*tp, DIDSUFFOCATE);
                    204:                turn_on(*tp, CANSUFFOCATE);
                    205:                extinguish(suffocate);
                    206:            }
                    207:        }
                    208:     }
                    209:
                    210:     /* If we can breathe, we may do so */
                    211:     else if (on(*tp, CANBREATHE)               &&
                    212:             (dist < BOLT_LENGTH*BOLT_LENGTH)   &&
                    213:             (shoot_dir = can_shoot(er, ee))    &&
                    214:             !on(player, ISINWALL)              &&
                    215:             (rnd(100) < 75)) {
                    216:                register char *breath = NULL;
                    217:
                    218:                damage = tp->t_stats.s_hpt;
                    219:                /* Will it breathe at random */
                    220:                if (on(*tp, CANBRANDOM)) {
                    221:                    /* Turn off random breath */
                    222:                    turn_off(*tp, CANBRANDOM);
                    223:
                    224:                    /* Select type of breath */
                    225:                    switch (rnd(10)) {
                    226:                    case 0: breath = "acid";
                    227:                            turn_on(*tp, NOACID);
                    228:                    when 1: breath = "flame";
                    229:                            turn_on(*tp, NOFIRE);
                    230:                    when 2: breath = "lightning bolt";
                    231:                            turn_on(*tp, NOBOLT);
                    232:                    when 3: breath = "chlorine gas";
                    233:                            turn_on(*tp, NOGAS);
                    234:                    when 4: breath = "ice";
                    235:                            turn_on(*tp, NOCOLD);
                    236:                    when 5: breath = "nerve gas";
                    237:                            turn_on(*tp, NOPARALYZE);
                    238:                    when 6: breath = "sleeping gas";
                    239:                            turn_on(*tp, NOSLEEP);
                    240:                    when 7: breath = "slow gas";
                    241:                            turn_on(*tp, NOSLOW);
                    242:                    when 8: breath = "confusion gas";
                    243:                            turn_on(*tp, ISCLEAR);
                    244:                    when 9: breath = "fear gas";
                    245:                            turn_on(*tp, NOFEAR);
                    246:                    }
                    247:                }
                    248:
                    249:                /* Or can it breathe acid? */
                    250:                else if (on(*tp, CANBACID)) {
                    251:                    turn_off(*tp, CANBACID);
                    252:                    breath = "acid";
                    253:                }
                    254:
                    255:                /* Or can it breathe fire */
                    256:                else if (on(*tp, CANBFIRE)) {
                    257:                    turn_off(*tp, CANBFIRE);
                    258:                    breath = "flame";
                    259:                }
                    260:
                    261:                /* Or can it breathe electricity? */
                    262:                else if (on(*tp, CANBBOLT)) {
                    263:                    turn_off(*tp, CANBBOLT);
                    264:                    breath = "lightning bolt";
                    265:                }
                    266:
                    267:                /* Or can it breathe gas? */
                    268:                else if (on(*tp, CANBGAS)) {
                    269:                    turn_off(*tp, CANBGAS);
                    270:                    breath = "chlorine gas";
                    271:                }
                    272:
                    273:                /* Or can it breathe ice? */
                    274:                else if (on(*tp, CANBICE)) {
                    275:                    turn_off(*tp, CANBICE);
                    276:                    breath = "ice";
                    277:                }
                    278:
                    279:                else if (on(*tp, CANBPGAS)) {
                    280:                    turn_off(*tp, CANBPGAS);
                    281:                    breath = "nerve gas";
                    282:                }
                    283:
                    284:                /* can it breathe sleeping gas */
                    285:                else if (on(*tp, CANBSGAS)) {
                    286:                    turn_off(*tp, CANBSGAS);
                    287:                    breath = "sleeping gas";
                    288:                }
                    289:
                    290:                /* can it breathe slow gas */
                    291:                else if (on(*tp, CANBSLGAS)) {
                    292:                    turn_off(*tp, CANBSLGAS);
                    293:                    breath = "slow gas";
                    294:                }
                    295:                /* can it breathe confusion gas */
                    296:                else if (on(*tp, CANBCGAS)) {
                    297:                    turn_off(*tp, CANBCGAS);
                    298:                    breath = "confusion gas";
                    299:                }
                    300:                /* can it breathe fear gas */
                    301:                else {
                    302:                    turn_off(*tp, CANBFGAS);
                    303:                    breath = "fear gas";
                    304:                }
                    305:
                    306:                /* Now breathe -- sets "monst_dead" if it kills someone */
                    307:                *mdead = shoot_bolt(    tp, *er, *shoot_dir, FALSE,
                    308:                                tp->t_index, breath, damage);
                    309:
                    310:                ch_ret = *er;
                    311:                running = FALSE;
                    312:                if (*mdead) return(TRUE);
                    313:     }
                    314:
                    315:     /* We may shoot missiles if we can */
                    316:     else if (on(*tp, CANMISSILE)               &&
                    317:            (shoot_dir = can_shoot(er, ee))     &&
                    318:            !on(player, ISINWALL)               &&
                    319:            (rnd(100) < 75)) {
                    320:            static struct object missile =
                    321:            {
                    322:                MISSILE, {0, 0}, "", 0, "", "0d4 " , NULL, 0, WS_MISSILE, 100, 1
                    323:            };
                    324:
                    325:            sprintf(missile.o_hurldmg, "%dd4", tp->t_stats.s_lvl);
                    326:            do_motion(&missile, shoot_dir->y, shoot_dir->x, tp);
                    327:            hit_monster(unc(missile.o_pos), &missile, tp);
                    328:            turn_off(*tp, CANMISSILE);
                    329:            ch_ret = *er;
                    330:            running = FALSE;
                    331:     }
                    332:
                    333:     /* We may use a sonic blast if we can */
                    334:     else if (on(*tp, CANSONIC)                 &&
                    335:            (dist < BOLT_LENGTH*2)              &&
                    336:            (shoot_dir = can_shoot(er, ee))     &&
                    337:            !on(player, ISINWALL)               &&
                    338:            (rnd(100) < 50)) {
                    339:            static struct object blast =
                    340:            {
                    341:                MISSILE, {0, 0}, "", 0, "", "150" , NULL, 0, 0, 0, 0
                    342:            };
                    343:
                    344:            turn_off(*tp, CANSONIC);
                    345:            do_motion(&blast, shoot_dir->y, shoot_dir->x, tp);
                    346:            damage = 150;
                    347:            if (save(VS_BREATH, &player, -3))
                    348:                damage /= 2;
                    349:            msg ("The %s's sonic blast hits you", monsters[tp->t_index].m_name);
                    350:            if ((pstats.s_hpt -= damage) <= 0)
                    351:                death(tp->t_index);
                    352:            ch_ret = *er;
                    353:            running = FALSE;
                    354:     }
                    355:     /*
                    356:      * If we have a special magic item, we might use it.  We will restrict
                    357:      * this options to uniques with relics for now.
                    358:      */
                    359:     else if (on(*tp, ISUNIQUE) && m_use_item(tp, er, ee)) {
                    360:            ch_ret = *er;
                    361:            running = FALSE;
                    362:     }
                    363:     /*
                    364:      * If we can shoot or throw something, we might do so.
                    365:      * If next to player, then 80% prob will fight.
                    366:      */
                    367:     else if(on(*tp, CANSHOOT)                  &&
                    368:            (shoot_dir = can_shoot(er, ee))     &&
                    369:            !on(player, ISINWALL)               &&
                    370:            (dist > 3 || (rnd(100) > 80))       &&
                    371:            (weapon = get_hurl(tp))) {
                    372:                missile(shoot_dir->y, shoot_dir->x, weapon, tp);
                    373:                ch_ret = *er;
                    374:        }
                    375:
                    376:     /*
                    377:      * Otherwise, find the empty spot next to the chaser that is
                    378:      * closest to the chasee.
                    379:      */
                    380:     else {
                    381:        register int ey, ex, x, y;
                    382:        register struct room *rer, *ree;
                    383:        int dist_to_old = MININT; /* Dist from goal to old position */
                    384:
                    385:        /* Get rooms */
                    386:        rer = roomin(er);       /* Room the chasER (monster) is in */
                    387:        ree = roomin(ee);       /* Room the chasEE is in */
                    388:
                    389:        /*
                    390:         * This will eventually hold where we move to get closer
                    391:         * If we can't find an empty spot, we stay where we are.
                    392:         */
                    393:        dist = flee ? 0 : MAXINT;
                    394:        ch_ret = *er;
                    395:
                    396:        /* Are we at our goal already? */
                    397:        if (!flee && ce(ch_ret, *ee)) return(FALSE);
                    398:
                    399:        ey = er->y + 1;
                    400:        ex = er->x + 1;
                    401:
                    402:        /* Check all possible moves */
                    403:        for (x = er->x - 1; x <= ex; x++) {
                    404:            if (x < 0 || x >= COLS) /* Don't try off the board */
                    405:                continue;
                    406:            for (y = er->y - 1; y <= ey; y++) {
                    407:                coord tryp;
                    408:
                    409:                if ((y < 1) || (y >= LINES - 2)) /* Don't try off the board */
                    410:                    continue;
                    411:
                    412:                /* Don't try the player if not going after the player */
                    413:                if ((flee || !ce(hero, *ee)) && x == hero.x && y == hero.y) {
                    414:                    next_player = TRUE;
                    415:                    continue;
                    416:                }
                    417:
                    418:                tryp.x = x;
                    419:                tryp.y = y;
                    420:
                    421:                /* Is there a monster on this spot closer to our goal?
                    422:                 * Don't look in our spot or where we were.
                    423:                 */
                    424:                if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
                    425:                    isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
                    426:                    int test_dist;
                    427:
                    428:                    test_dist = DISTANCE(y, x, ee->y, ee->x);
                    429:                    if (test_dist <= 25 &&   /* Let's be fairly close */
                    430:                        test_dist < monst_dist) {
                    431:                        /* Could we really move there? */
                    432:                        mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
                    433:                        if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
                    434:                        mvwaddch(mw, y, x, mch); /* Restore monster */
                    435:                    }
                    436:                }
                    437:
                    438:                /* Can we move onto the spot? */
                    439:                if (!diag_ok(er, &tryp, tp)) continue;
                    440:
                    441:                ch = CCHAR( mvwinch(cw, y, x) );        /* Screen character */
                    442:
                    443:                /* Stepping on player is NOT okay if we are fleeing */
                    444:                if (step_ok(y, x, NOMONST, tp) &&
                    445:                    (off(*tp, ISFLEE) || ch != PLAYER))
                    446:                {
                    447:                    /*
                    448:                     * If it is a trap, an intelligent monster may not
                    449:                     * step on it (unless our hero is on top!)
                    450:                     */
                    451:                    if ((isatrap(ch))                   &&
                    452:                        (rnd(10) < tp->t_stats.s_intel) &&
                    453:                        (!on(*tp, ISFLY))               &&
                    454:                        (y != hero.y || x != hero.x))
                    455:                            continue;
                    456:
                    457:                    /*
                    458:                     * OK -- this place counts
                    459:                     */
                    460:                    thisdist = DISTANCE(y, x, ee->y, ee->x);
                    461:
                    462:                    /* Adjust distance if we are being shot at */
                    463:                    if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
                    464:                        ce(hero, *ee)) {
                    465:                        /* Move out of line of sight */
                    466:                        if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
                    467:                            if (flee) thisdist -= SHOTPENALTY;
                    468:                            else thisdist += SHOTPENALTY;
                    469:                        }
                    470:
                    471:                        /* But do we want to leave the room? */
                    472:                        else if (rer && rer == ree && ch == DOOR)
                    473:                            thisdist += DOORPENALTY;
                    474:                    }
                    475:
                    476:                    /* Don't move to the last position if we can help it
                    477:                     * (unless out prey just moved there)
                    478:                     */
                    479:                    if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
                    480:                        dist_to_old = thisdist;
                    481:
                    482:                    else if ((flee && (thisdist > dist)) ||
                    483:                        (!flee && (thisdist < dist)))
                    484:                    {
                    485:                        ch_ret = tryp;
                    486:                        dist = thisdist;
                    487:                    }
                    488:                }
                    489:            }
                    490:        }
                    491:
                    492:        /* If we aren't trying to get the player, but he is in our way,
                    493:         * hit him (unless we have been turned)
                    494:         */
                    495:        if (next_player && off(*tp, WASTURNED) &&
                    496:            ((flee && ce(ch_ret, *er)) ||
                    497:             (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
                    498:            step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
                    499:            /* Okay to hit player */
                    500:            ch_ret = hero;
                    501:            return(FALSE);
                    502:        }
                    503:
                    504:
                    505:        /* If we can't get closer to the player (if that's our goal)
                    506:         * because other monsters are in the way, just stay put
                    507:         */
                    508:        if (!flee && ce(hero, *ee) && monst_dist < MAXINT &&
                    509:            DISTANCE(er->y, er->x, hero.y, hero.x) < dist)
                    510:                ch_ret = *er;
                    511:
                    512:        /* Do we want to go back to the last position? */
                    513:        else if (dist_to_old != MININT &&      /* It is possible to move back */
                    514:            ((flee && dist == 0) ||     /* No other possible moves */
                    515:             (!flee && dist == MAXINT))) {
                    516:            /* Do we move back or just stay put (default)? */
                    517:            dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
                    518:            if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
                    519:        }
                    520:     }
                    521:
                    522:     /* May actually hit here from a confused move */
                    523:     return(!ce(ch_ret, hero));
                    524: }
                    525: 
                    526: /*
                    527:  * do_chase:
                    528:  *     Make one thing chase another.
                    529:  */
                    530: /* flee: True if running away or player is inaccessible in wall */
                    531:
                    532: void
                    533: do_chase(struct thing *th, bool flee)
                    534: {
                    535:     register struct room *rer, *ree,   /* room of chaser, room of chasee */
                    536:                         *orig_rer,     /* Original room of chaser */
                    537:                         *new_room;     /* new room of monster */
                    538:     int dist = MININT;
                    539:     int mindist = MAXINT, maxdist = MININT;
                    540:     bool stoprun = FALSE,              /* TRUE means we are there */
                    541:         rundoor;                       /* TRUE means run to a door */
                    542:     bool mdead = 0;
                    543:     char rch, sch;
                    544:     coord *last_door=0,                        /* Door we just came from */
                    545:           this;                        /* Temporary destination for chaser */
                    546:
                    547:     /* Make sure the monster can move */
                    548:     if (th->t_no_move != 0) {
                    549:        th->t_no_move--;
                    550:        return;
                    551:     }
                    552:
                    553:     rer = roomin(&th->t_pos);  /* Find room of chaser */
                    554:     ree = roomin(th->t_dest);  /* Find room of chasee */
                    555:     orig_rer = rer;    /* Original room of chaser (including doors) */
                    556:
                    557:     /*
                    558:      * We don't count monsters on doors as inside rooms for this routine
                    559:      */
                    560:     if ((sch = CCHAR( mvwinch(stdscr, th->t_pos.y, th->t_pos.x) )) == DOOR ||
                    561:        sch == PASSAGE) {
                    562:        rer = NULL;
                    563:     }
                    564:     this = *th->t_dest;
                    565:
                    566:     /*
                    567:      * If we are not in a corridor and not a Xorn, then if we are running
                    568:      * after the player, we run to a door if he is not in the same room.
                    569:      * If we are fleeing, we run to a door if he IS in the same room.
                    570:      * Note:  We don't bother with doors in mazes.
                    571:      */
                    572:     if (levtype != MAZELEV && rer != NULL && off(*th, CANINWALL)) {
                    573:        if (flee) rundoor = (rer == ree);
                    574:        else rundoor = (rer != ree);
                    575:     }
                    576:     else rundoor = FALSE;
                    577:
                    578:     if (rundoor) {
                    579:        register struct linked_list *exitptr;   /* For looping through exits */
                    580:        coord *exit;                            /* A particular door */
                    581:        int exity, exitx;                       /* Door's coordinates */
                    582:        char dch='\0';                          /* Door character */
                    583:
                    584:        if (th->t_doorgoal)
                    585:            dch = CCHAR( mvwinch(stdscr, th->t_doorgoal->y, th->t_doorgoal->x) );
                    586:
                    587:        /* Do we have a valid goal? */
                    588:        if ((dch == PASSAGE || dch == DOOR) &&  /* A real door */
                    589:            (!flee || !ce(*th->t_doorgoal, hero))) { /* Player should not
                    590:                                                      * be at door if we are
                    591:                                                      * running away
                    592:                                                      */
                    593:            this = *th->t_doorgoal;
                    594:            dist = 0;   /* Indicate that we have our door */
                    595:        }
                    596:
                    597:        /* Go through all the doors */
                    598:        else for (exitptr = rer->r_exit; exitptr; exitptr = next(exitptr)) {
                    599:            exit = DOORPTR(exitptr);
                    600:            exity = exit->y;
                    601:            exitx = exit->x;
                    602:
                    603:            /* Make sure it is a real door */
                    604:            dch = CCHAR( mvwinch(stdscr, exity, exitx) );
                    605:            if (dch == PASSAGE || dch == DOOR) {
                    606:                /* Don't count a door if we are fleeing from the player and
                    607:                 * he is standing on it
                    608:                 */
                    609:                if (flee && ce(*exit, hero)) continue;
                    610:
                    611:                /* Were we just on this door? */
                    612:                if (ce(*exit, th->t_oldpos)) last_door = exit;
                    613:
                    614:                else {
                    615:                    dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx);
                    616:
                    617:                    /* If fleeing, we want to maximize distance from door to
                    618:                     * what we flee, and minimize distance from door to us.
                    619:                     */
                    620:                    if (flee)
                    621:                       dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx);
                    622:
                    623:                    /* Maximize distance if fleeing, otherwise minimize it */
                    624:                    if ((flee && (dist > maxdist)) ||
                    625:                        (!flee && (dist < mindist))) {
                    626:                        th->t_doorgoal = exit;  /* Use this door */
                    627:                        this = *exit;
                    628:                        mindist = maxdist = dist;
                    629:                    }
                    630:                }
                    631:            }
                    632:        }
                    633:
                    634:        /* Could we not find a door? */
                    635:        if (dist == MININT) {
                    636:            /* If we were on a door, go ahead and use it */
                    637:            if (last_door) {
                    638:                th->t_doorgoal = last_door;
                    639:                this = th->t_oldpos;
                    640:                dist = 0;       /* Indicate that we found a door */
                    641:            }
                    642:            else th->t_doorgoal = NULL; /* No more door goal */
                    643:        }
                    644:
                    645:        /* Indicate that we do not want to flee from the door */
                    646:        if (dist != MININT) flee = FALSE;
                    647:     }
                    648:     else th->t_doorgoal = 0;   /* Not going to any door */
                    649:
                    650:     /*
                    651:      * this now contains what we want to run to this time
                    652:      * so we run to it.  If we hit it we either want to fight it
                    653:      * or stop running
                    654:      */
                    655:     if (!chase(th, &this, flee, &mdead)) {
                    656:        if (ce(ch_ret, hero)) {
                    657:            /* merchants try to sell something --> others attack */
                    658:            if (on(*th, CANSELL)) sell(th);
                    659:            else attack(th, NULL, FALSE);
                    660:            return;
                    661:        }
                    662:        else if (on(*th, NOMOVE))
                    663:            stoprun = TRUE;
                    664:     }
                    665:
                    666:     if (mdead) return; /* Did monster kill someone? */
                    667:
                    668:     if (on(*th, NOMOVE)) return;
                    669:
                    670:     /* If we have a scavenger, it can pick something up */
                    671:     if (on(*th, ISSCAVENGE)) {
                    672:        register struct linked_list *n_item, *o_item;
                    673:
                    674:        while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
                    675:            char floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
                    676:            register struct object *n_obj, *o_obj;
                    677:
                    678:            /*
                    679:             * see if he's got one of this group already
                    680:             */
                    681:            o_item = NULL;
                    682:            n_obj = OBJPTR(n_item);
                    683:            detach(lvl_obj, n_item);
                    684:            if (n_obj->o_group) {
                    685:                for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
                    686:                    o_obj = OBJPTR(o_item);
                    687:                    if (o_obj->o_group == n_obj->o_group) {
                    688:                        o_obj->o_count += n_obj->o_count;
                    689:                        o_discard(n_item);
                    690:                        break;
                    691:                    }
                    692:                }
                    693:            }
                    694:            if (o_item == NULL) {       /* didn't find it */
                    695:                attach(th->t_pack, n_item);
                    696:            }
                    697:            if (cansee(ch_ret.y, ch_ret.x))
                    698:                mvwaddch(cw, ch_ret.y, ch_ret.x, floor);
                    699:            mvaddch(ch_ret.y, ch_ret.x, floor);
                    700:        }
                    701:     }
                    702:
                    703:     mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
                    704:     sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */
                    705:     rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */
                    706:
                    707:     /* Get new room of monster */
                    708:     new_room=roomin(&ch_ret);
                    709:
                    710:     /* If we have a tunneling monster, it may be making a tunnel */
                    711:     if (on(*th, CANTUNNEL)     &&
                    712:        (rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) {
                    713:        char nch;       /* The new look to the tunnel */
                    714:
                    715:        if (rch == WALL) nch = PASSAGE;
                    716:        else if (levtype == MAZELEV) nch = FLOOR;
                    717:        else nch = DOOR;
                    718:        addch(nch);
                    719:
                    720:        if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
                    721:
                    722:        /* Does this make a new exit? */
                    723:        if (rch == '|' || rch == '-') {
                    724:            struct linked_list *newroom;
                    725:            coord *exit;
                    726:
                    727:            newroom = new_item(sizeof(coord));
                    728:            exit = DOORPTR(newroom);
                    729:            *exit = ch_ret;
                    730:            attach(new_room->r_exit, newroom);
                    731:        }
                    732:     }
                    733:
                    734:     /* Mark if the monster is inside a wall */
                    735:     if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
                    736:     else turn_off(*th, ISINWALL);
                    737:
                    738:     /* If the monster can illuminate rooms, check for a change */
                    739:     if (on(*th, HASFIRE)) {
                    740:        register struct linked_list *fire_item;
                    741:
                    742:        /* Is monster entering a room? */
                    743:        if (orig_rer != new_room && new_room != NULL) {
                    744:            fire_item = creat_item();   /* Get an item-only structure */
                    745:            ldata(fire_item) = (char *) th;
                    746:
                    747:            attach(new_room->r_fires, fire_item);
                    748:            new_room->r_flags |= HASFIRE;
                    749:
                    750:            if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
                    751:                light(&hero);
                    752:        }
                    753:
                    754:        /* Is monster leaving a room? */
                    755:        if (orig_rer != new_room && orig_rer != NULL) {
                    756:            /* Find the bugger in the list and delete him */
                    757:            for (fire_item = orig_rer->r_fires; fire_item != NULL;
                    758:                 fire_item = next(fire_item)) {
                    759:                if (THINGPTR(fire_item) == th)  {       /* Found him! */
                    760:                    detach(orig_rer->r_fires, fire_item);
                    761:                    destroy_item(fire_item);
                    762:                    if (orig_rer->r_fires == NULL) {
                    763:                        orig_rer->r_flags &= ~HASFIRE;
                    764:                        if (cansee(th->t_pos.y, th->t_pos.x))
                    765:                            light(&th->t_pos);
                    766:                    }
                    767:                    break;
                    768:                }
                    769:            }
                    770:        }
                    771:     }
                    772:
                    773:     /* If monster is entering player's room and player can see it,
                    774:      * stop the player's running.
                    775:      */
                    776:     if (new_room != orig_rer && new_room != NULL  &&
                    777:        new_room == ree && cansee(unc(ch_ret))    &&
                    778:        (off(*th, ISINVIS)     || on(player, CANSEE)) &&
                    779:        (off(*th, ISSHADOW)    || on(player, CANSEE)) &&
                    780:        (off(*th, CANSURPRISE) || ISWEARING(R_ALERT)))
                    781:                running = FALSE;
                    782:
                    783: /*
                    784:     if (rer != NULL && !lit_room(orig_rer) && sch == FLOOR &&
                    785:        DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3 &&
                    786:        off(player, ISBLIND))
                    787:            th->t_oldch = ' ';
                    788:     else
                    789:  */
                    790:        th->t_oldch = sch;
                    791:
                    792:     /* Let's display those creatures that we can see. */
                    793:     if (cansee(unc(ch_ret)) &&
                    794:        off(*th, ISINWALL) &&
                    795:        !invisible(th))
                    796:         mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
                    797:
                    798:     /*
                    799:      * Blank out the old position and record the new position --
                    800:      * the blanking must be done first in case the positions are the same.
                    801:      */
                    802:     mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
                    803:     mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
                    804:
                    805:     /* Record monster's last position (if new one is different) */
                    806:     if (!ce(ch_ret, th->t_pos)) th->t_oldpos = th->t_pos;
                    807:     th->t_pos = ch_ret;                /* Mark the monster's new position */
                    808:
                    809:     /* If the monster is on a trap, trap it */
                    810:     sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) );
                    811:     if (isatrap(sch)) {
                    812:        if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
                    813:        be_trapped(th, &ch_ret);
                    814:     }
                    815:
                    816:
                    817:     /*
                    818:      * And stop running if need be
                    819:      */
                    820:     if (stoprun && ce(th->t_pos, *(th->t_dest)))
                    821:        turn_off(*th, ISRUN);
                    822: }
                    823:
                    824: 
                    825: /*
                    826:  * Get_hurl returns the weapon that the monster will "throw" if he has one
                    827:  */
                    828:
                    829: struct linked_list *
                    830: get_hurl(struct thing *tp)
                    831: {
                    832:     struct linked_list *arrow, *bolt, *rock;
                    833:     register struct linked_list *pitem;
                    834:     bool bow=FALSE, crossbow=FALSE, sling=FALSE;
                    835:
                    836:     arrow = bolt = rock = NULL;        /* Don't point to anything to begin with */
                    837:     for (pitem=tp->t_pack; pitem; pitem=next(pitem))
                    838:        if ((OBJPTR(pitem))->o_type == WEAPON)
                    839:            switch ((OBJPTR(pitem))->o_which) {
                    840:                case BOW:       bow = TRUE;
                    841:                when CROSSBOW:  crossbow = TRUE;
                    842:                when SLING:     sling = TRUE;
                    843:                when ROCK:      rock = pitem;
                    844:                when ARROW:     arrow = pitem;
                    845:                when BOLT:      bolt = pitem;
                    846:            }
                    847:
                    848:     /* Use crossbow bolt if possible */
                    849:     if (crossbow && bolt) return(bolt);
                    850:     if (bow && arrow) return(arrow);
                    851:     if (sling && rock) return(rock);
                    852:     return(NULL);
                    853: }
                    854: 
                    855: /*
                    856:  * runners:
                    857:  *     Make all the running monsters move.
                    858:  */
                    859:
                    860: void
                    861: runners(void)
                    862: {
                    863:     register struct linked_list *item;
                    864:     register struct thing *tp = NULL;
                    865:
                    866:     /*
                    867:      * loop thru the list of running (wandering) monsters and see what
                    868:      * each one will do this time.
                    869:      *
                    870:      * Note: the special case that one of this buggers kills another.
                    871:      *      if this happens than we have to see if the monster killed
                    872:      *      himself or someone else. In case its himself we have to get next
                    873:      *      one immediately. If it wasn't we have to get next one at very
                    874:      *      end in case he killed the next one.
                    875:      */
                    876:
                    877:     for (item = mlist; item != NULL; item = next(item)) {
                    878:        tp = THINGPTR(item);
                    879:        turn_on(*tp, ISREADY);
                    880:     }
                    881:
                    882:     for (;;) {
                    883:        for (item = mlist; item != NULL; item = next(item)) {
                    884:            tp = THINGPTR(item);
                    885:
                    886:            if (on(*tp, ISREADY))
                    887:                break;
                    888:        }
                    889:
                    890:        if (item == NULL)
                    891:            break;
                    892:
                    893:        turn_off(*tp, ISREADY);
                    894:
                    895:        if (on(*tp, ISHELD) && rnd(tp->t_stats.s_lvl) > 11) {
                    896:            turn_off(*tp, ISHELD);
                    897:            turn_on(*tp, ISRUN);
                    898:            turn_off(*tp, ISDISGUISE);
                    899:            tp->t_dest = &hero;
                    900:            if (tp->t_stats.s_hpt < tp->maxstats.s_hpt)
                    901:                turn_on(*tp, ISFLEE);
                    902:            if (cansee(tp->t_pos.y, tp->t_pos.x))
                    903:                msg("The %s breaks free from the hold spell",
                    904:                        monsters[tp->t_index].m_name);
                    905:        }
                    906:        if (off(*tp, ISHELD) && on(*tp, ISRUN)) {
                    907:            register bool flee;
                    908:
                    909:            /* Should monster run away? */
                    910:            flee = on(*tp, ISFLEE) ||
                    911:                ((tp->t_dest == &hero) && on(player, ISINWALL) &&
                    912:                 off(*tp, CANINWALL));
                    913:
                    914:            if (off(*tp, ISSLOW) || tp->t_turn) {
                    915:                doctor(tp);
                    916:                do_chase(tp, flee);
                    917:            }
                    918:            if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE) && on(*tp, ISHASTE)) {
                    919:                doctor(tp);
                    920:                do_chase(tp, flee);
                    921:            }
                    922:            if (off(*tp, ISDEAD) && off(*tp, ISELSEWHERE)) {
                    923:                tp->t_turn ^= TRUE;
                    924:                tp->t_wasshot = FALSE;  /* Not shot anymore */
                    925:            }
                    926:        }
                    927:     }
                    928: }
                    929: 
                    930: /*
                    931:  * runto:
                    932:  *     Set a monster running after something
                    933:  */
                    934:
                    935: void
                    936: runto(struct thing *runner, coord *spot)
                    937: {
                    938:     /*
                    939:      * Start the beastie running
                    940:      */
                    941:     runner->t_dest = spot;
                    942:     turn_on(*runner, ISRUN);
                    943:     turn_off(*runner, ISDISGUISE);
                    944: }
                    945:
                    946:
                    947: 
                    948: /*
                    949:  * straight_shot:
                    950:  *     See if there is a straight line of sight between the two
                    951:  *     given coordinates.  If shooting is not NULL, it is a pointer
                    952:  *     to a structure which should be filled with the direction
                    953:  *     to shoot (if there is a line of sight).  If shooting, monsters
                    954:  *     get in the way.  Otherwise, they do not.
                    955:  */
                    956:
                    957: bool
                    958: straight_shot(int ery, int erx, int eey, int eex, coord *shooting)
                    959: {
                    960:     register int dy, dx;       /* Deltas */
                    961:     char ch;
                    962:
                    963:     /* Does the monster have a straight shot at player */
                    964:     if ((ery != eey) && (erx != eex) &&
                    965:        (abs(ery - eey) != abs(erx - eex))) return(FALSE);
                    966:
                    967:     /* Get the direction to shoot */
                    968:     if (eey > ery) dy = 1;
                    969:     else if (eey == ery) dy = 0;
                    970:     else dy = -1;
                    971:
                    972:     if (eex > erx) dx = 1;
                    973:     else if (eex == erx) dx = 0;
                    974:     else dx = -1;
                    975:
                    976:     /* Make sure we have free area all the way to the player */
                    977:     ery += dy;
                    978:     erx += dx;
                    979:     while ((ery != eey) || (erx != eex)) {
                    980:        switch (ch = CCHAR( winat(ery, erx) )) {
                    981:            case '|':
                    982:            case '-':
                    983:            case WALL:
                    984:            case DOOR:
                    985:            case SECRETDOOR:
                    986:            case FOREST:
                    987:                return(FALSE);
                    988:            default:
                    989:                if (shooting && isalpha(ch)) return(FALSE);
                    990:        }
                    991:        ery += dy;
                    992:        erx += dx;
                    993:     }
                    994:
                    995:     if (shooting) {    /* If we are shooting -- put in the directions */
                    996:        shooting->y = dy;
                    997:        shooting->x = dx;
                    998:     }
                    999:     return(TRUE);
                   1000: }
                   1001:
                   1002:

CVSweb