[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     ! 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