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

Annotation of early-roguelike/rogue5/chase.c, Revision 1.1

1.1     ! rubenllo    1: /*
        !             2:  * Code for one creature to chase another
        !             3:  *
        !             4:  * @(#)chase.c 4.57 (Berkeley) 02/05/99
        !             5:  *
        !             6:  * Rogue: Exploring the Dungeons of Doom
        !             7:  * Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * See the file LICENSE.TXT for full copyright and licensing information.
        !            11:  */
        !            12:
        !            13: #include <stdlib.h>
        !            14: #include <curses.h>
        !            15: #include "rogue.h"
        !            16:
        !            17: #define DRAGONSHOT  5  /* one chance in DRAGONSHOT that a dragon will flame */
        !            18:
        !            19: static coord ch_ret;                           /* Where chasing takes you */
        !            20:
        !            21: /*
        !            22:  * runners:
        !            23:  *     Make all the running monsters move.
        !            24:  */
        !            25: void
        !            26: runners(void)
        !            27: {
        !            28:     THING *tp;
        !            29:     THING *next;
        !            30:     int wastarget;
        !            31:     coord orig_pos;
        !            32:
        !            33:     for (tp = mlist; tp != NULL; tp = next)
        !            34:     {
        !            35:         /* remember this in case the monster's "next" is changed */
        !            36:         next = next(tp);
        !            37:        if (!on(*tp, ISHELD) && on(*tp, ISRUN))
        !            38:        {
        !            39:            orig_pos = tp->t_pos;
        !            40:            wastarget = on(*tp, ISTARGET);
        !            41:            if (move_monst(tp) == -1)
        !            42:                 continue;
        !            43:            if (on(*tp, ISFLY) && dist_cp(&hero, &tp->t_pos) >= 3)
        !            44:                move_monst(tp);
        !            45:            if (wastarget && !ce(orig_pos, tp->t_pos))
        !            46:            {
        !            47:                tp->t_flags &= ~ISTARGET;
        !            48:                to_death = FALSE;
        !            49:            }
        !            50:        }
        !            51:     }
        !            52:     if (has_hit)
        !            53:     {
        !            54:        endmsg();
        !            55:        has_hit = FALSE;
        !            56:     }
        !            57: }
        !            58:
        !            59: /*
        !            60:  * move_monst:
        !            61:  *     Execute a single turn of running for a monster
        !            62:  */
        !            63: int
        !            64: move_monst(THING *tp)
        !            65: {
        !            66:     if (!on(*tp, ISSLOW) || tp->t_turn)
        !            67:        if (do_chase(tp) == -1)
        !            68:             return(-1);
        !            69:     if (on(*tp, ISHASTE))
        !            70:        if (do_chase(tp) == -1)
        !            71:             return(-1);
        !            72:     tp->t_turn ^= TRUE;
        !            73:     return(0);
        !            74: }
        !            75:
        !            76: /*
        !            77:  * relocate:
        !            78:  *     Make the monster's new location be the specified one, updating
        !            79:  *     all the relevant state.
        !            80:  */
        !            81: void
        !            82: relocate(THING *th, const coord *new_loc)
        !            83: {
        !            84:     struct room *oroom;
        !            85:
        !            86:     if (!ce(*new_loc, th->t_pos))
        !            87:     {
        !            88:        mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
        !            89:        th->t_room = roomin(new_loc);
        !            90:        set_oldch(th, new_loc);
        !            91:        oroom = th->t_room;
        !            92:        moat(th->t_pos.y, th->t_pos.x) = NULL;
        !            93:
        !            94:        if (oroom != th->t_room)
        !            95:            th->t_dest = find_dest(th);
        !            96:        th->t_pos = *new_loc;
        !            97:        moat(new_loc->y, new_loc->x) = th;
        !            98:     }
        !            99:     move(new_loc->y, new_loc->x);
        !           100:     if (see_monst(th))
        !           101:        addch(th->t_disguise);
        !           102:     else if (on(player, SEEMONST))
        !           103:     {
        !           104:        standout();
        !           105:        addch(th->t_type);
        !           106:        standend();
        !           107:     }
        !           108: }
        !           109:
        !           110: /*
        !           111:  * do_chase:
        !           112:  *     Make one thing chase another.
        !           113:  */
        !           114: int
        !           115: do_chase(THING *th)
        !           116: {
        !           117:     coord *cp;
        !           118:     struct room *rer, *ree;    /* room of chaser, room of chasee */
        !           119:     int mindist = 32767, curdist;
        !           120:     int stoprun = FALSE;       /* TRUE means we are there */
        !           121:     int door;
        !           122:     THING *obj;
        !           123:     coord this;                        /* Temporary destination for chaser */
        !           124:
        !           125:     rer = th->t_room;          /* Find room of chaser */
        !           126:     if (on(*th, ISGREED) && rer->r_goldval == 0)
        !           127:        th->t_dest = &hero;     /* If gold has been taken, run after hero */
        !           128:     if (th->t_dest == &hero)   /* Find room of chasee */
        !           129:        ree = proom;
        !           130:     else
        !           131:        ree = roomin(th->t_dest);
        !           132:     /*
        !           133:      * We don't count doors as inside rooms for this routine
        !           134:      */
        !           135:     door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
        !           136:     /*
        !           137:      * If the object of our desire is in a different room,
        !           138:      * and we are not in a corridor, run to the door nearest to
        !           139:      * our goal.
        !           140:      */
        !           141: over:
        !           142:     if (rer != ree)
        !           143:     {
        !           144:        for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++)
        !           145:        {
        !           146:            curdist = dist_cp(th->t_dest, cp);
        !           147:            if (curdist < mindist)
        !           148:            {
        !           149:                this = *cp;
        !           150:                mindist = curdist;
        !           151:            }
        !           152:        }
        !           153:        if (door)
        !           154:        {
        !           155:            rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
        !           156:            door = FALSE;
        !           157:            goto over;
        !           158:        }
        !           159:     }
        !           160:     else
        !           161:     {
        !           162:        this = *th->t_dest;
        !           163:        /*
        !           164:         * For dragons check and see if (a) the hero is on a straight
        !           165:         * line from it, and (b) that it is within shooting distance,
        !           166:         * but outside of striking range.
        !           167:         */
        !           168:        if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
        !           169:            || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
        !           170:            && dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH
        !           171:            && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
        !           172:        {
        !           173:            delta.y = sign(hero.y - th->t_pos.y);
        !           174:            delta.x = sign(hero.x - th->t_pos.x);
        !           175:            if (has_hit)
        !           176:                endmsg();
        !           177:            fire_bolt(&th->t_pos, &delta, "flame");
        !           178:            running = FALSE;
        !           179:            count = 0;
        !           180:            quiet = 0;
        !           181:            if (to_death && !on(*th, ISTARGET))
        !           182:            {
        !           183:                to_death = FALSE;
        !           184:                kamikaze = FALSE;
        !           185:            }
        !           186:            return(0);
        !           187:        }
        !           188:     }
        !           189:     /*
        !           190:      * This now contains what we want to run to this time
        !           191:      * so we run to it.  If we hit it we either want to fight it
        !           192:      * or stop running
        !           193:      */
        !           194:     if (!chase(th, &this))
        !           195:     {
        !           196:        if (ce(this, hero))
        !           197:        {
        !           198:            return( attack(th) );
        !           199:        }
        !           200:        else if (ce(this, *th->t_dest))
        !           201:        {
        !           202:            for (obj = lvl_obj; obj != NULL; obj = next(obj))
        !           203:                if (th->t_dest == &obj->o_pos)
        !           204:                {
        !           205:                    detach(lvl_obj, obj);
        !           206:                    attach(th->t_pack, obj);
        !           207:                    chat(obj->o_pos.y, obj->o_pos.x) =
        !           208:                        (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
        !           209:                    th->t_dest = find_dest(th);
        !           210:                    break;
        !           211:                }
        !           212:            if (th->t_type != 'F')
        !           213:                stoprun = TRUE;
        !           214:        }
        !           215:     }
        !           216:     else
        !           217:     {
        !           218:        if (th->t_type == 'F')
        !           219:            return(0);
        !           220:     }
        !           221:     relocate(th, &ch_ret);
        !           222:     /*
        !           223:      * And stop running if need be
        !           224:      */
        !           225:     if (stoprun && ce(th->t_pos, *(th->t_dest)))
        !           226:        th->t_flags &= ~ISRUN;
        !           227:     return(0);
        !           228: }
        !           229:
        !           230: /*
        !           231:  * set_oldch:
        !           232:  *     Set the oldch character for the monster
        !           233:  */
        !           234: void
        !           235: set_oldch(THING *tp, const coord *cp)
        !           236: {
        !           237:     int sch;
        !           238:
        !           239:     if (ce(tp->t_pos, *cp))
        !           240:         return;
        !           241:
        !           242:     sch = tp->t_oldch;
        !           243:     tp->t_oldch = CCHAR( mvinch(cp->y,cp->x) );
        !           244:     if (!on(player, ISBLIND))
        !           245:     {
        !           246:            if ((sch == FLOOR || tp->t_oldch == FLOOR) &&
        !           247:                (tp->t_room->r_flags & ISDARK))
        !           248:                    tp->t_oldch = ' ';
        !           249:            else if (dist_cp(cp, &hero) <= LAMPDIST && see_floor)
        !           250:                tp->t_oldch = chat(cp->y, cp->x);
        !           251:     }
        !           252: }
        !           253:
        !           254: /*
        !           255:  * see_monst:
        !           256:  *     Return TRUE if the hero can see the monster
        !           257:  */
        !           258: int
        !           259: see_monst(const THING *mp)
        !           260: {
        !           261:     int y, x;
        !           262:
        !           263:     if (on(player, ISBLIND))
        !           264:        return FALSE;
        !           265:     if (on(*mp, ISINVIS) && !on(player, CANSEE))
        !           266:        return FALSE;
        !           267:     y = mp->t_pos.y;
        !           268:     x = mp->t_pos.x;
        !           269:     if (dist(y, x, hero.y, hero.x) < LAMPDIST)
        !           270:     {
        !           271:        if (y != hero.y && x != hero.x &&
        !           272:            !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
        !           273:                return FALSE;
        !           274:        return TRUE;
        !           275:     }
        !           276:     if (mp->t_room != proom)
        !           277:        return FALSE;
        !           278:     return (!(mp->t_room->r_flags & ISDARK));
        !           279: }
        !           280:
        !           281: /*
        !           282:  * runto:
        !           283:  *     Set a monster running after the hero.
        !           284:  */
        !           285: void
        !           286: runto(const coord *runner)
        !           287: {
        !           288:     THING *tp;
        !           289:
        !           290:     /*
        !           291:      * If we couldn't find him, something is funny
        !           292:      */
        !           293:     if ((tp = moat(runner->y, runner->x)) == NULL)
        !           294:        {
        !           295: #ifdef MASTER
        !           296:                msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
        !           297: #endif
        !           298:                return;
        !           299:        }
        !           300:
        !           301:        /*
        !           302:      * Start the beastie running
        !           303:      */
        !           304:     tp->t_flags |= ISRUN;
        !           305:     tp->t_flags &= ~ISHELD;
        !           306:     tp->t_dest = find_dest(tp);
        !           307: }
        !           308:
        !           309: /*
        !           310:  * chase:
        !           311:  *     Find the spot for the chaser(er) to move closer to the
        !           312:  *     chasee(ee).  Returns TRUE if we want to keep on chasing later
        !           313:  *     FALSE if we reach the goal.
        !           314:  */
        !           315: int
        !           316: chase(THING *tp, const coord *ee)
        !           317: {
        !           318:     THING *obj;
        !           319:     int x, y;
        !           320:     int curdist, thisdist;
        !           321:     const coord *er = &tp->t_pos;
        !           322:     int ch;
        !           323:     int plcnt = 1;
        !           324:     coord tryp;
        !           325:
        !           326:     /*
        !           327:      * If the thing is confused, let it move randomly. Invisible
        !           328:      * Stalkers are slightly confused all of the time, and bats are
        !           329:      * quite confused all the time
        !           330:      */
        !           331:     if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0)
        !           332:        || (tp->t_type == 'B' && rnd(2) == 0))
        !           333:     {
        !           334:        /*
        !           335:         * get a valid random move
        !           336:         */
        !           337:        ch_ret = rndmove(tp);
        !           338:        curdist = dist_cp(&ch_ret, ee);
        !           339:        /*
        !           340:         * Small chance that it will become un-confused
        !           341:         */
        !           342:        if (rnd(20) == 0)
        !           343:            tp->t_flags &= ~ISHUH;
        !           344:     }
        !           345:     /*
        !           346:      * Otherwise, find the empty spot next to the chaser that is
        !           347:      * closest to the chasee.
        !           348:      */
        !           349:     else
        !           350:     {
        !           351:        int ey, ex;
        !           352:        /*
        !           353:         * This will eventually hold where we move to get closer
        !           354:         * If we can't find an empty spot, we stay where we are.
        !           355:         */
        !           356:        curdist = dist_cp(er, ee);
        !           357:        ch_ret = *er;
        !           358:
        !           359:        ey = er->y + 1;
        !           360:        if (ey >= NUMLINES - 1)
        !           361:            ey = NUMLINES - 2;
        !           362:        ex = er->x + 1;
        !           363:        if (ex >= NUMCOLS)
        !           364:            ex = NUMCOLS - 1;
        !           365:
        !           366:        for (x = er->x - 1; x <= ex; x++)
        !           367:        {
        !           368:            if (x < 0)
        !           369:                continue;
        !           370:            tryp.x = x;
        !           371:            for (y = er->y - 1; y <= ey; y++)
        !           372:            {
        !           373:                tryp.y = y;
        !           374:                if (!diag_ok(er, &tryp))
        !           375:                    continue;
        !           376:                ch = winat(y, x);
        !           377:                if (step_ok(ch))
        !           378:                {
        !           379:                    /*
        !           380:                     * If it is a scroll, it might be a scare monster scroll
        !           381:                     * so we need to look it up to see what type it is.
        !           382:                     */
        !           383:                    if (ch == SCROLL)
        !           384:                    {
        !           385:                        for (obj = lvl_obj; obj != NULL; obj = next(obj))
        !           386:                        {
        !           387:                            if (y == obj->o_pos.y && x == obj->o_pos.x)
        !           388:                                break;
        !           389:                        }
        !           390:                        if (obj != NULL && obj->o_which == S_SCARE)
        !           391:                            continue;
        !           392:                    }
        !           393:                    /*
        !           394:                     * It can also be a Xeroc, which we shouldn't step on
        !           395:                     */
        !           396:                    if ((obj = moat(y, x)) != NULL && obj->t_type == 'X')
        !           397:                        continue;
        !           398:                    /*
        !           399:                     * If we didn't find any scrolls at this place or it
        !           400:                     * wasn't a scare scroll, then this place counts
        !           401:                     */
        !           402:                    thisdist = dist(y, x, ee->y, ee->x);
        !           403:                    if (thisdist < curdist)
        !           404:                    {
        !           405:                        plcnt = 1;
        !           406:                        ch_ret = tryp;
        !           407:                        curdist = thisdist;
        !           408:                    }
        !           409:                    else if (thisdist == curdist && rnd(++plcnt) == 0)
        !           410:                    {
        !           411:                        ch_ret = tryp;
        !           412:                        curdist = thisdist;
        !           413:                    }
        !           414:                }
        !           415:            }
        !           416:        }
        !           417:     }
        !           418:     return (curdist != 0 && !ce(ch_ret, hero));
        !           419: }
        !           420:
        !           421: /*
        !           422:  * roomin:
        !           423:  *     Find what room some coordinates are in. NULL means they aren't
        !           424:  *     in any room.
        !           425:  */
        !           426: struct room *
        !           427: roomin(const coord *cp)
        !           428: {
        !           429:     struct room *rp;
        !           430:     int *fp;
        !           431:
        !           432:     fp = &flat(cp->y, cp->x);
        !           433:     if (*fp & F_PASS)
        !           434:        return &passages[*fp & F_PNUM];
        !           435:
        !           436:     for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
        !           437:        if (cp->x <= rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
        !           438:         && cp->y <= rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
        !           439:            return rp;
        !           440:
        !           441:     msg("in some bizarre place (%d, %d)", unc(*cp));
        !           442: #ifdef MASTER
        !           443:     abort();
        !           444:     return NULL;
        !           445: #else
        !           446:     return NULL;
        !           447: #endif
        !           448: }
        !           449:
        !           450: /*
        !           451:  * diag_ok:
        !           452:  *     Check to see if the move is legal if it is diagonal
        !           453:  */
        !           454: int
        !           455: diag_ok(const coord *sp, const coord *ep)
        !           456: {
        !           457:     if (ep->x < 0 || ep->x >= NUMCOLS || ep->y <= 0 || ep->y >= NUMLINES - 1)
        !           458:        return FALSE;
        !           459:     if (ep->x == sp->x || ep->y == sp->y)
        !           460:        return TRUE;
        !           461:     return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
        !           462: }
        !           463:
        !           464: /*
        !           465:  * cansee:
        !           466:  *     Returns true if the hero can see a certain coordinate.
        !           467:  */
        !           468: int
        !           469: cansee(int y, int x)
        !           470: {
        !           471:     struct room *rer;
        !           472:     coord tp;
        !           473:
        !           474:     if (on(player, ISBLIND))
        !           475:        return FALSE;
        !           476:     if (dist(y, x, hero.y, hero.x) < LAMPDIST)
        !           477:     {
        !           478:        if (flat(y, x) & F_PASS)
        !           479:            if (y != hero.y && x != hero.x &&
        !           480:                !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
        !           481:                    return FALSE;
        !           482:        return TRUE;
        !           483:     }
        !           484:     /*
        !           485:      * We can only see if the hero in the same room as
        !           486:      * the coordinate and the room is lit or if it is close.
        !           487:      */
        !           488:     tp.y = y;
        !           489:     tp.x = x;
        !           490:     return ((rer = roomin(&tp)) == proom && !(rer->r_flags & ISDARK));
        !           491: }
        !           492:
        !           493: /*
        !           494:  * find_dest:
        !           495:  *     find the proper destination for the monster
        !           496:  */
        !           497: const coord *
        !           498: find_dest(const THING *tp)
        !           499: {
        !           500:     THING *obj;
        !           501:     int prob;
        !           502:
        !           503:     if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
        !           504:        || see_monst(tp))
        !           505:            return &hero;
        !           506:     for (obj = lvl_obj; obj != NULL; obj = next(obj))
        !           507:     {
        !           508:        if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
        !           509:            continue;
        !           510:        if (roomin(&obj->o_pos) == tp->t_room && rnd(100) < prob)
        !           511:        {
        !           512:            for (tp = mlist; tp != NULL; tp = next(tp))
        !           513:                if (tp->t_dest == &obj->o_pos)
        !           514:                    break;
        !           515:            if (tp == NULL)
        !           516:                return &obj->o_pos;
        !           517:        }
        !           518:     }
        !           519:     return &hero;
        !           520: }
        !           521:
        !           522: /*
        !           523:  * dist:
        !           524:  *     Calculate the "distance" between to points.  Actually,
        !           525:  *     this calculates d^2, not d, but that's good enough for
        !           526:  *     our purposes, since it's only used comparitively.
        !           527:  */
        !           528: int
        !           529: dist(int y1, int x1, int y2, int x2)
        !           530: {
        !           531:     return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
        !           532: }
        !           533:
        !           534: /*
        !           535:  * dist_cp:
        !           536:  *     Call dist() with appropriate arguments for coord pointers
        !           537:  */
        !           538: int
        !           539: dist_cp(const coord *c1, const coord *c2)
        !           540: {
        !           541:     return dist(c1->y, c1->x, c2->y, c2->x);
        !           542: }

CVSweb