[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

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