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

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

1.1       rubenllo    1: /*
                      2:  * chase.c  -  Code for one object to chase another
                      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: /*
                     16:  * Code for one object to chase another
                     17:  *
                     18:  */
                     19:
                     20: #include <ctype.h>
                     21: #include <limits.h>
                     22: #include <stdlib.h>
                     23: #include "curses.h"
                     24: #include "rogue.h"
                     25: #define        MAXINT  INT_MAX
                     26: #define        MININT  INT_MIN
                     27:
                     28: bool straight_shot(int ery, int erx, int eey, int eex, coord *shooting);
                     29:
                     30: /*
                     31:  * Canblink checks if the monster can teleport (blink).  If so, it will
                     32:  * try to blink the monster next to the player.
                     33:  */
                     34:
                     35: bool
                     36: can_blink(struct thing *tp)
                     37: {
                     38:     register int y, x, index=9;
                     39:     coord tryp;        /* To hold the coordinates for use in diag_ok */
                     40:     bool spots[9], found_one=FALSE;
                     41:
                     42:     /*
                     43:      * First, can the monster even blink?  And if so, there is only a 50%
                     44:      * chance that it will do so.  And it won't blink if it is running or
                     45:      * held.
                     46:      */
                     47:     if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
                     48:        on(*tp, ISFLEE) ||
                     49:        tp->t_action == A_FREEZE ||
                     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 prey (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:     /*
                    136:      * They must be in the same room or very close (at door)
                    137:      */
                    138:     if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
                    139:        return(NULL);
                    140:
                    141:     /* Do we have a straight shot? */
                    142:     if (!straight_shot(er->y, er->x, ee->y, ee->x, &shoot_dir)) return(NULL);
                    143:     else return(&shoot_dir);
                    144: }
                    145: 
                    146: /*
                    147:  * chase:
                    148:  *     Find the spot for the chaser(er) to move closer to the
                    149:  *     chasee(ee).  Rer is the room of the chaser, and ree is the
                    150:  *     room of the creature being chased (chasee).  Flee is true if
                    151:  *     destination (ee) is player and monster is running away
                    152:  *     or the player is in a wall and the monster can't get to it
                    153:  */
                    154:
                    155: void
                    156: chase(struct thing *tp, coord *ee, struct room *rer, struct room *ree,
                    157:       bool flee)
                    158: {
                    159:     int dist, thisdist, monst_dist = MAXINT;
                    160:     register coord *er = &tp->t_pos;
                    161:     struct thing *prey;                        /* What we are chasing */
                    162:     coord ch_ret;                      /* Where chasing takes you */
                    163:     char ch, mch;
                    164:     bool next_player = FALSE;
                    165:
                    166:     /*
                    167:      * set the distance from the chas(er) to the chas(ee) here and then
                    168:      * we won't have to reset it unless the chas(er) moves (instead of shoots)
                    169:      */
                    170:     dist = DISTANCE(er->y, er->x, ee->y, ee->x);
                    171:
                    172:     /*
                    173:      * See if our destination is a monster or player.  If so, make "prey" point
                    174:      * to it.
                    175:      */
                    176:     if (ce(hero, *ee)) prey = &player; /* Is it the player? */
                    177:     else if (tp->t_dest && ce(*(tp->t_dest), *ee)) {   /* Is it a monster? */
                    178:        struct linked_list *item;
                    179:
                    180:        /* What is the monster we're chasing? */
                    181:        item = find_mons(ee->y, ee->x);
                    182:        if (item != NULL) prey = THINGPTR(item);
                    183:        else prey = NULL;
                    184:     }
                    185:     else prey = NULL;
                    186:
                    187:     /* We will use at least one movement period */
                    188:     tp->t_no_move = movement(tp);
                    189:     if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */
                    190:        tp->t_no_move /= 2;
                    191:
                    192:     /*
                    193:      * If the thing is confused or it can't see the player,
                    194:      * let it move randomly.
                    195:      */
                    196:     if ((on(*tp, ISHUH) && rnd(10) < 8) ||
                    197:        (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */
                    198:        /*
                    199:         * get a valid random move
                    200:         */
                    201:        tp->t_newpos = *rndmove(tp);
                    202:        dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x);
                    203:     }
                    204:
                    205:     /*
                    206:      * Otherwise, find the empty spot next to the chaser that is
                    207:      * closest to the chasee.
                    208:      */
                    209:     else {
                    210:        register int ey, ex, x, y;
                    211:        int dist_to_old = MININT; /* Dist from goal to old position */
                    212:
                    213:        /*
                    214:         * This will eventually hold where we move to get closer
                    215:         * If we can't find an empty spot, we stay where we are.
                    216:         */
                    217:        dist = flee ? 0 : MAXINT;
                    218:        ch_ret = *er;
                    219:
                    220:        /* Are we at our goal already? */
                    221:        if (!flee && ce(ch_ret, *ee)) {
                    222:            turn_off(*tp, ISRUN);       /* So stop running! */
                    223:            return;
                    224:        }
                    225:
                    226:        ey = er->y + 1;
                    227:        ex = er->x + 1;
                    228:
                    229:        /* Check all possible moves */
                    230:        for (x = er->x - 1; x <= ex; x++) {
                    231:            if (x < 0 || x >= cols) /* Don't try off the board */
                    232:                continue;
                    233:            for (y = er->y - 1; y <= ey; y++) {
                    234:                coord tryp;
                    235:
                    236:                if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */
                    237:                    continue;
                    238:
                    239:                /* Don't try the player if not going after the player */
                    240:                if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) &&
                    241:                    x == hero.x && y == hero.y) {
                    242:                    next_player = TRUE;
                    243:                    continue;
                    244:                }
                    245:
                    246:                tryp.x = x;
                    247:                tryp.y = y;
                    248:
                    249:                /* Is there a monster on this spot closer to our goal?
                    250:                 * Don't look in our spot or where we were.
                    251:                 */
                    252:                if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
                    253:                    isalpha(mch = CCHAR( mvwinch(mw, y, x) ) )) {
                    254:                    int test_dist;
                    255:
                    256:                    test_dist = DISTANCE(y, x, ee->y, ee->x);
                    257:                    if (test_dist <= 25 &&   /* Let's be fairly close */
                    258:                        test_dist < monst_dist) {
                    259:                        /* Could we really move there? */
                    260:                        mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
                    261:                        if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
                    262:                        mvwaddch(mw, y, x, mch); /* Restore monster */
                    263:                    }
                    264:                }
                    265:
                    266:                /* Can we move onto the spot? */
                    267:                if (!diag_ok(er, &tryp, tp)) continue;
                    268:
                    269:                ch = CCHAR( mvwinch(cw, y, x) );        /* Screen character */
                    270:
                    271:                /*
                    272:                 * Stepping on player is NOT okay if we are fleeing.
                    273:                 * If we are friendly to the player and there is a monster
                    274:                 * in the way that is not of our race, it is okay to move
                    275:                 * there.
                    276:                 */
                    277:                if (step_ok(y, x, FIGHTOK, tp) &&
                    278:                    (off(*tp, ISFLEE) || ch != PLAYER))
                    279:                {
                    280:                    /*
                    281:                     * If it is a trap, an intelligent monster may not
                    282:                     * step on it (unless our hero is on top!)
                    283:                     */
                    284:                    if ((isatrap(ch))                   &&
                    285:                        (rnd(10) < tp->t_stats.s_intel) &&
                    286:                        (!on(*tp, ISFLY))               &&
                    287:                        (y != hero.y || x != hero.x))
                    288:                            continue;
                    289:
                    290:                    /*
                    291:                     * OK -- this place counts
                    292:                     */
                    293:                    thisdist = DISTANCE(y, x, ee->y, ee->x);
                    294:
                    295:                    /* Adjust distance if we are being shot at */
                    296:                    if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
                    297:                        prey != NULL) {
                    298:                        /* Move out of line of sight */
                    299:                        if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) {
                    300:                            if (flee) thisdist -= SHOTPENALTY;
                    301:                            else thisdist += SHOTPENALTY;
                    302:                        }
                    303:
                    304:                        /* But do we want to leave the room? */
                    305:                        else if (rer && rer == ree && ch == DOOR)
                    306:                            thisdist += DOORPENALTY;
                    307:                    }
                    308:
                    309:                    /* Don't move to the last position if we can help it
                    310:                     * (unless out prey just moved there)
                    311:                     */
                    312:                    if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
                    313:                        dist_to_old = thisdist;
                    314:
                    315:                    else if ((flee && (thisdist > dist)) ||
                    316:                        (!flee && (thisdist < dist)))
                    317:                    {
                    318:                        ch_ret = tryp;
                    319:                        dist = thisdist;
                    320:                    }
                    321:                }
                    322:            }
                    323:        }
                    324:
                    325:        /* If we aren't trying to get the player, but he is in our way,
                    326:         * hit him (unless we have been turned or are friendly).  next_player
                    327:         * being TRUE -> we are next to the player but don't want to hit him.
                    328:         *
                    329:         * If we are friendly to the player, following him, and standing next
                    330:         * to him, we will try to help him out in battle.
                    331:         */
                    332:        if (next_player && off(*tp, WASTURNED)) {
                    333:            if (off(*tp, ISFRIENDLY) &&
                    334:                ((flee && ce(ch_ret, *er)) ||
                    335:                 (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
                    336:                step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
                    337:                /* Okay to hit player */
                    338:                debug("Switching to hero.");
                    339:                tp->t_newpos = hero;
                    340:                tp->t_action = A_MOVE;
                    341:                return;
                    342:            }
                    343:            else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) {
                    344:                /*
                    345:                 * Look all around the player.  If there is a fightable
                    346:                 * creature next to both of us, hit it.  Otherwise, if
                    347:                 * there is a fightable creature next to the player, try
                    348:                 * to move next to it.
                    349:                 */
                    350:                dist = MAXINT;
                    351:                for (x = hero.x - 1; x <= hero.x + 1; x++) {
                    352:                    if (x < 0 || x >= cols) /* Don't try off the board */
                    353:                        continue;
                    354:                    for (y = hero.y - 1; y <= hero.y + 1; y++) {
                    355:                        if ((y < 1) || (y >= lines - 2)) /* Stay on the board */
                    356:                            continue;
                    357:
                    358:                        /* Is there a fightable monster here? */
                    359:                        if (isalpha(mvwinch(mw, y, x)) &&
                    360:                            step_ok(y, x, FIGHTOK, tp) &&
                    361:                            off(*tp, ISSTONE)) {
                    362:                            thisdist = DISTANCE(er->y, er->x, y, x);
                    363:                            if (thisdist < dist) {
                    364:                                dist = thisdist;
                    365:                                ch_ret.y = y;
                    366:                                ch_ret.x = x;
                    367:                            }
                    368:                        }
                    369:                    }
                    370:                }
                    371:
                    372:                /* Are we next to a bad guy? */
                    373:                if (dist <= 2) {        /* Get him! */
                    374:                    tp->t_newpos = ch_ret;
                    375:                    tp->t_action = A_MOVE;
                    376:                }
                    377:
                    378:                /* Try to move to the bad guy */
                    379:                else if (dist < MAXINT)
                    380:                    chase(tp, &ch_ret,
                    381:                          roomin(&tp->t_pos), roomin(&ch_ret), FALSE);
                    382:
                    383:                else tp->t_action = A_NIL;
                    384:
                    385:                return;
                    386:            }
                    387:        }
                    388:
                    389:
                    390:        /*
                    391:         * If we have decided that we can move onto a monster (we are
                    392:         * friendly to the player, go to it.
                    393:         */
                    394:        if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) {
                    395:            debug("Attack monster");
                    396:            tp->t_newpos = ch_ret;
                    397:            tp->t_action = A_MOVE;
                    398:            return;
                    399:        }
                    400:
                    401:        /* If we can't get closer to the player (if that's our goal)
                    402:         * because other monsters are in the way, just stay put
                    403:         */
                    404:        if (!flee && ce(hero, *ee) && monst_dist < MAXINT &&
                    405:            DISTANCE(er->y, er->x, hero.y, hero.x) < dist) {
                    406:                tp->t_action = A_NIL; /* do nothing for awhile */
                    407:                return;
                    408:        }
                    409:
                    410:        /* Do we want to go back to the last position? */
                    411:        else if (dist_to_old != MININT &&      /* It is possible to move back */
                    412:            ((flee && dist == 0) ||     /* No other possible moves */
                    413:             (!flee && dist == MAXINT))) {
                    414:            /* Do we move back or just stay put (default)? */
                    415:            dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
                    416:            if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
                    417:        }
                    418:
                    419:        /* Record the new destination */
                    420:        tp->t_newpos = ch_ret;
                    421:     }
                    422:
                    423:     /*
                    424:      * Do we want to fight or move?  If our selected destination (ch_ret)
                    425:      * is our hero, then we want to fight.  Otherwise, we want to move.
                    426:      */
                    427:     if (ce(tp->t_newpos, hero)) {
                    428:        /* Fight! (or sell) */
                    429:        if (on(*tp, CANSELL)) {
                    430:            tp->t_action = A_SELL;
                    431:            tp->t_no_move += movement(tp); /* takes a little time to sell */
                    432:        }
                    433:        else {
                    434:            tp->t_action = A_ATTACK;
                    435:
                    436:            /*
                    437:             * Try to find a weapon to wield.  Wield_weap will return a
                    438:             * projector if weapon is a projectile (eg. bow for arrow).
                    439:             * If weapon is NULL (the case here), it will try to find
                    440:             * a suitable weapon.
                    441:             *
                    442:             *          Add in rest of time. Fight is
                    443:             *          movement() + weap_move() + FIGHTBASE
                    444:             */
                    445:            tp->t_using = wield_weap(NULL, tp);
                    446:            if (tp->t_using == NULL)
                    447:                tp->t_no_move += weap_move(tp, NULL);
                    448:            else
                    449:                tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using));
                    450:
                    451:            if (on(*tp, ISHASTE))
                    452:                    tp->t_no_move += FIGHTBASE/2;
                    453:            else if (on(*tp, ISSLOW))
                    454:                    tp->t_no_move += FIGHTBASE*2;
                    455:            else
                    456:                    tp->t_no_move += FIGHTBASE;
                    457:        }
                    458:     }
                    459:     else {
                    460:        /* Move */
                    461:        tp->t_action = A_MOVE;
                    462:
                    463:        /*
                    464:         * Check if the creature is not next to the player.  If it
                    465:         * is not and has held or suffocated the player, then stop it!
                    466:         * Note that this code should more appropriately appear in
                    467:         * the area that actually moves the monster, but for now it
                    468:         * is okay here because the player can't move while held or
                    469:         * suffocating.
                    470:         */
                    471:        if (dist > 2) {
                    472:            if (on(*tp, DIDHOLD)) {
                    473:                 turn_off(*tp, DIDHOLD);
                    474:                 turn_on(*tp, CANHOLD);
                    475:                 if (--hold_count == 0)
                    476:                     turn_off(player, ISHELD);
                    477:            }
                    478:
                    479:            /* If monster was suffocating, stop it */
                    480:            if (on(*tp, DIDSUFFOCATE)) {
                    481:                turn_off(*tp, DIDSUFFOCATE);
                    482:                turn_on(*tp, CANSUFFOCATE);
                    483:                extinguish(suffocate);
                    484:                msg("You can breathe again.....Whew!");
                    485:            }
                    486:        }
                    487:     }
                    488: }
                    489: 
                    490: /*
                    491:  * do_chase:
                    492:  *     Make one thing chase another.
                    493:  */
                    494:
                    495: void
                    496: do_chase(struct thing *th)
                    497: {
                    498:     register struct room *orig_rer,    /* Original room of chaser */
                    499:                         *new_room;     /* new room of monster */
                    500:     char floor, rch, sch;
                    501:     coord old_pos,                     /* Old position of monster */
                    502:          ch_ret;                       /* Where we want to go */
                    503:
                    504:     if (on(*th, NOMOVE)) return;
                    505:
                    506:     ch_ret = th->t_newpos;     /* Record our desired new position */
                    507:
                    508:     /*
                    509:      * Make sure we have an open spot (no other monster's gotten in our way,
                    510:      * someone didn't just drop a scare monster there, our prey didn't just
                    511:      * get there, etc.)
                    512:      */
                    513:     if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) {
                    514:        /*
                    515:         * Most monsters get upset now.  Guardians are all friends,
                    516:         * and we don't want to see 50 messages in a row!
                    517:         */
                    518:        if (th->t_stats.s_intel > 4     &&
                    519:            off(*th, ISUNDEAD)          &&
                    520:            off(*th, ISGUARDIAN)        &&
                    521:            off(*th, AREMANY)           &&
                    522:            off(*th, ISHUH)             &&
                    523:            off(player, ISBLIND)        &&
                    524:            cansee(unc(th->t_pos))      &&
                    525:            !invisible(th))
                    526:            msg("%s motions angrily.", prname(monster_name(th), TRUE));
                    527:        return;
                    528:     }
                    529:     else if (ce(th->t_newpos, hero) || /* Player just got in our way */
                    530:             isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) {
                    531:        bool fightplayer = ce(th->t_newpos, hero);
                    532:
                    533:        /* If we were turned or are friendly, we just have to sit here! */
                    534:        if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return;
                    535:
                    536:        /* Do we want to sell something? */
                    537:        if (fightplayer && on(*th, CANSELL)) {
                    538:            th->t_action = A_SELL;
                    539:            th->t_no_move += movement(th); /* takes a little time to sell */
                    540:            return;
                    541:        }
                    542:
                    543:        /* Let's hit him */
                    544:        th->t_action = A_ATTACK;
                    545:
                    546:        /*
                    547:         * Try to find a weapon to wield.  Wield_weap will return a
                    548:         * projector if weapon is a projectile (eg. bow for arrow).
                    549:         * If weapon is NULL (the case here), it will try to find
                    550:         * a suitable weapon.
                    551:         */
                    552:        th->t_using = wield_weap(NULL, th);
                    553:        /*
                    554:         * add in rest of time
                    555:         */
                    556:        if (th->t_using == NULL)
                    557:            th->t_no_move += weap_move(th, NULL);
                    558:        else
                    559:            th->t_no_move += weap_move(th, OBJPTR(th->t_using));
                    560:        if (on(*th, ISHASTE))
                    561:                th->t_no_move += FIGHTBASE/2;
                    562:        else if (on(*th, ISSLOW))
                    563:                th->t_no_move += FIGHTBASE*2;
                    564:        else
                    565:                th->t_no_move += FIGHTBASE;
                    566:        return;
                    567:     }
                    568:
                    569:     /*
                    570:      * Blank out the old position and record the new position --
                    571:      * the blanking must be done first in case the positions are the same.
                    572:      */
                    573:     mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
                    574:     mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
                    575:
                    576:     /* Get new and old rooms of monster */
                    577:     new_room = roomin(&ch_ret);
                    578:     orig_rer = roomin(&th->t_pos);
                    579:
                    580:     /* Store the critter's old position and update the current one */
                    581:     old_pos = th->t_pos;
                    582:     th->t_pos = ch_ret;
                    583:     floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
                    584:
                    585:     /* If we have a scavenger, it can pick something up */
                    586:     if (off(*th, ISGUARDIAN)) {
                    587:        register struct linked_list *n_item, *o_item;
                    588:        register int item_count = 0;
                    589:        bool want_something = FALSE;
                    590:
                    591:        while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
                    592:            register struct object *n_obj, *o_obj;
                    593:            bool wants_it;
                    594:
                    595:            /* Does this monster want anything? */
                    596:            if (want_something == FALSE) {
                    597:                if (on(*th, ISSCAVENGE)  || on(*th, CARRYFOOD)   ||
                    598:                    on(*th, CARRYGOLD)   || on(*th, CARRYSCROLL) ||
                    599:                    on(*th, CARRYPOTION) || on(*th, CARRYRING)   ||
                    600:                    on(*th, CARRYSTICK)  || on(*th, CARRYMISC)   ||
                    601:                    on(*th, CARRYWEAPON) || on(*th, CARRYARMOR)  ||
                    602:                    on(*th, CARRYDAGGER))  {
                    603:                        want_something = TRUE;
                    604:
                    605:                        /*
                    606:                         * Blank the area.  We have to do it only before the
                    607:                         * first item in case an item gets dropped in same
                    608:                         * place.  We don't want to blank it out after it get
                    609:                         * dropped.
                    610:                         */
                    611:                        mvaddch(ch_ret.y, ch_ret.x, floor);
                    612:
                    613:                        /* Were we specifically after something here? */
                    614:                        if (ce(*th->t_dest, ch_ret)) {
                    615:                            /* If we're mean, we go after the hero */
                    616:                            if (on(*th, ISMEAN)) runto(th, &hero);
                    617:
                    618:                            /* Otherwise just go back to sleep */
                    619:                            else {
                    620:                                turn_off(*th, ISRUN);
                    621:                                th->t_dest = NULL;
                    622:                            }
                    623:                        }
                    624:                }
                    625:                else break;
                    626:            }
                    627:
                    628:            item_count++;       /* Count the number of items */
                    629:
                    630:            /*
                    631:             * see if he's got one of this group already
                    632:             */
                    633:            o_item = NULL;
                    634:            n_obj = OBJPTR(n_item);
                    635:            detach(lvl_obj, n_item);
                    636:
                    637:            /* See if he wants it */
                    638:            if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE &&
                    639:                th->t_stats.s_intel < 16)
                    640:                wants_it = FALSE; /* Most monsters don't want a scare monster */
                    641:            else if (on(*th, ISSCAVENGE)) wants_it = TRUE;
                    642:            else {
                    643:                wants_it = FALSE;       /* Default case */
                    644:                switch (n_obj->o_type) {
                    645:                    case FOOD:  if(on(*th, CARRYFOOD))   wants_it = TRUE;
                    646:                    when GOLD:  if(on(*th, CARRYGOLD))   wants_it = TRUE;
                    647:                    when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE;
                    648:                    when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE;
                    649:                    when RING:  if(on(*th, CARRYRING))   wants_it = TRUE;
                    650:                    when STICK: if(on(*th, CARRYSTICK))  wants_it = TRUE;
                    651:                    when MM:    if(on(*th, CARRYMISC))   wants_it = TRUE;
                    652:                    when ARMOR: if(on(*th, CARRYARMOR))  wants_it = TRUE;
                    653:                    when WEAPON:if(on(*th, CARRYWEAPON) ||
                    654:                                  (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER))
                    655:                                        wants_it = TRUE;
                    656:                }
                    657:            }
                    658:            /*
                    659:             * The quartermaster doesn't sell cursed stuff so he won't
                    660:             * pick it up
                    661:             */
                    662:            if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED))
                    663:                wants_it = FALSE;
                    664:
                    665:            /* If he doesn't want it, throw it away */
                    666:            if (wants_it == FALSE) {
                    667:                fall(n_item, FALSE);
                    668:                continue;
                    669:            }
                    670:
                    671:            /* Otherwise, let's pick it up */
                    672:            if (n_obj->o_group) {
                    673:                for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
                    674:                    o_obj = OBJPTR(o_item);
                    675:                    if (o_obj->o_group == n_obj->o_group) {
                    676:                        o_obj->o_count += n_obj->o_count;
                    677:                        o_discard(n_item);
                    678:                        break;
                    679:                    }
                    680:                }
                    681:            }
                    682:            if (o_item == NULL) {       /* didn't find it */
                    683:                attach(th->t_pack, n_item);
                    684:            }
                    685:        }
                    686:
                    687:        /* If there was anything here, we may have to update the screen */
                    688:        if (item_count) {
                    689:            if (cansee(ch_ret.y, ch_ret.x))
                    690:                mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x));
                    691:            updpack(TRUE, th); /* Update the monster's encumberance, too */
                    692:        }
                    693:     }
                    694:
                    695:
                    696:     rch = CCHAR( mvwinch(stdscr, old_pos.y, old_pos.x) );
                    697:     if (th->t_oldch == floor && rch != floor && !isatrap(rch))
                    698:        mvwaddch(cw, old_pos.y, old_pos.x, rch);
                    699:     else
                    700:        mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch);
                    701:     sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* What player sees */
                    702:     rch = CCHAR( mvwinch(stdscr, ch_ret.y, ch_ret.x) ); /* What's really there */
                    703:
                    704:     /* If we have a tunneling monster, it may be making a tunnel */
                    705:     if (on(*th, CANTUNNEL)     &&
                    706:        (rch == SECRETDOOR || rch == WALL || rch == '|' || rch == '-')) {
                    707:        char nch;       /* The new look to the tunnel */
                    708:
                    709:        if (rch == WALL) nch = PASSAGE;
                    710:        else if (levtype == MAZELEV) nch = FLOOR;
                    711:        else nch = DOOR;
                    712:        addch(nch);
                    713:
                    714:        if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
                    715:
                    716:        /* Does this make a new exit? */
                    717:        if (rch == '|' || rch == '-') {
                    718:            struct linked_list *newroom;
                    719:            coord *exit;
                    720:
                    721:            newroom = new_item(sizeof(coord));
                    722:            exit = DOORPTR(newroom);
                    723:            *exit = ch_ret;
                    724:            attach(new_room->r_exit, newroom);
                    725:        }
                    726:     }
                    727:
                    728:     /* Mark if the monster is inside a wall */
                    729:     if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
                    730:     else turn_off(*th, ISINWALL);
                    731:
                    732:     /* If the monster can illuminate rooms, check for a change */
                    733:     if (on(*th, HASFIRE)) {
                    734:        register struct linked_list *fire_item;
                    735:
                    736:        /* Is monster entering a room? */
                    737:        if (orig_rer != new_room && new_room != NULL) {
                    738:            fire_item = creat_item();   /* Get an item-only structure */
                    739:            ldata(fire_item) = (char *) th;
                    740:
                    741:            attach(new_room->r_fires, fire_item);
                    742:            new_room->r_flags |= HASFIRE;
                    743:
                    744:            if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
                    745:                light(&hero);
                    746:        }
                    747:
                    748:        /* Is monster leaving a room? */
                    749:        if (orig_rer != new_room && orig_rer != NULL) {
                    750:            /* Find the bugger in the list and delete him */
                    751:            for (fire_item = orig_rer->r_fires; fire_item != NULL;
                    752:                 fire_item = next(fire_item)) {
                    753:                if (THINGPTR(fire_item) == th)  {       /* Found him! */
                    754:                    detach(orig_rer->r_fires, fire_item);
                    755:                    destroy_item(fire_item);
                    756:                    if (orig_rer->r_fires == NULL) {
                    757:                        orig_rer->r_flags &= ~HASFIRE;
                    758:                        if (cansee(old_pos.y, old_pos.x))
                    759:                            light(&old_pos);
                    760:                    }
                    761:                    break;
                    762:                }
                    763:            }
                    764:        }
                    765:     }
                    766:
                    767:     /* If monster is entering player's room and player can see it,
                    768:      * stop the player's running.
                    769:      */
                    770:     if (new_room != orig_rer && new_room != NULL  &&
                    771:        new_room == roomin(th->t_dest) && cansee(unc(ch_ret))    &&
                    772:        (off(*th, ISINVIS)     || on(player, CANSEE)) &&
                    773:        (off(*th, ISSHADOW)    || on(player, CANSEE)) &&
                    774:        (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) {
                    775:                running = FALSE;
                    776:                if (fight_flush) md_flushinp();
                    777:     }
                    778:
                    779:     th->t_oldch = sch;
                    780:
                    781:     /* Let's display those creatures that we can see. */
                    782:     if (cansee(unc(ch_ret)) &&
                    783:        off(*th, ISINWALL) &&
                    784:        !invisible(th))
                    785:         mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
                    786:
                    787:     /* Record monster's last position (if new one is different) */
                    788:     if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos;
                    789:
                    790:     /* If the monster is on a trap, trap it */
                    791:     sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) );
                    792:     if (isatrap(sch)) {
                    793:        if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
                    794:        be_trapped(th, &ch_ret);
                    795:     }
                    796: }
                    797:
                    798: 
                    799: /*
                    800:  * Get_hurl returns the weapon that the monster will "throw" if he has one
                    801:  */
                    802:
                    803: struct linked_list *
                    804: get_hurl(struct thing *tp)
                    805: {
                    806:     struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL,
                    807:        *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL;
                    808:     register struct linked_list *pitem;
                    809:     register struct object *obj;
                    810:     bool bow=FALSE, crossbow=FALSE, sling=FALSE;
                    811:
                    812:     for (pitem=tp->t_pack; pitem; pitem=next(pitem)) {
                    813:        obj = OBJPTR(pitem);
                    814:        if (obj->o_type == WEAPON)
                    815:            switch (obj->o_which) {
                    816:                case BOW:       bow = TRUE;
                    817:                when CROSSBOW:  crossbow = TRUE;
                    818:                when SLING:     sling = TRUE;
                    819:                when ROCK:      rock = pitem;
                    820:                when ARROW:     arrow = pitem;
                    821:                when BOLT:      bolt = pitem;
                    822:                when SPEAR:     spear = pitem;
                    823:                when DAGGER:
                    824:                    /* Don't throw the dagger if it's our last one */
                    825:                    if (obj->o_count > 1) dagger = pitem;
                    826:                when DART:      dart = pitem;
                    827:            }
                    828:        else if (obj->o_type == RELIC &&
                    829:                 obj->o_which == AXE_AKLAD)
                    830:                    aklad = pitem;
                    831:     }
                    832:
                    833:     /* Do we have that all-powerful Aklad Axe? */
                    834:     if (aklad) return(aklad);
                    835:
                    836:     /* Use crossbow bolt if possible */
                    837:     if (crossbow && bolt) return(bolt);
                    838:     if (bow && arrow) return(arrow);
                    839:     if (spear) return(spear);
                    840:     if (dagger) return(dagger);
                    841:     if (sling && rock) return(rock);
                    842:     if (dart) return(dart);
                    843:     return(NULL);
                    844: }
                    845: 
                    846: /*
                    847:  * runto:
                    848:  *     Set a monster running after something
                    849:  */
                    850:
                    851: void
                    852: runto(struct thing *runner, coord *spot)
                    853: {
                    854:     if (on(*runner, ISSTONE))
                    855:        return;
                    856:
                    857:     /* If we are chasing a new creature, forget about thrown weapons */
                    858:     if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE;
                    859:
                    860:     /*
                    861:      * Start the beastie running
                    862:      */
                    863:     runner->t_dest = spot;
                    864:     turn_on(*runner, ISRUN);
                    865:     turn_off(*runner, ISDISGUISE);
                    866: }
                    867:
                    868:
                    869: 
                    870: /*
                    871:  * straight_shot:
                    872:  *     See if there is a straight line of sight between the two
                    873:  *     given coordinates.  If shooting is not NULL, it is a pointer
                    874:  *     to a structure which should be filled with the direction
                    875:  *     to shoot (if there is a line of sight).  If shooting, monsters
                    876:  *     get in the way.  Otherwise, they do not.
                    877:  */
                    878:
                    879: bool
                    880: straight_shot(int ery, int erx, int eey, int eex, coord *shooting)
                    881: {
                    882:     register int dy, dx;       /* Deltas */
                    883:     char ch;
                    884:
                    885:     /* Does the monster have a straight shot at prey */
                    886:     if ((ery != eey) && (erx != eex) &&
                    887:        (abs(ery - eey) != abs(erx - eex))) return(FALSE);
                    888:
                    889:     /* Get the direction to shoot */
                    890:     if (eey > ery) dy = 1;
                    891:     else if (eey == ery) dy = 0;
                    892:     else dy = -1;
                    893:
                    894:     if (eex > erx) dx = 1;
                    895:     else if (eex == erx) dx = 0;
                    896:     else dx = -1;
                    897:
                    898:     /* Make sure we have free area all the way to the player */
                    899:     ery += dy;
                    900:     erx += dx;
                    901:     while ((ery != eey) || (erx != eex)) {
                    902:        switch (ch = CCHAR( winat(ery, erx) )) {
                    903:            case '|':
                    904:            case '-':
                    905:            case WALL:
                    906:            case DOOR:
                    907:            case SECRETDOOR:
                    908:            case FOREST:
                    909:                return(FALSE);
                    910:            default:
                    911:                if (shooting && isalpha(ch)) return(FALSE);
                    912:        }
                    913:        ery += dy;
                    914:        erx += dx;
                    915:     }
                    916:
                    917:     if (shooting) {    /* If we are shooting -- put in the directions */
                    918:        shooting->y = dy;
                    919:        shooting->x = dx;
                    920:     }
                    921:     return(TRUE);
                    922: }

CVSweb