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