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

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

1.1       rubenllo    1: /*
                      2:  * Code for one creature to chase another
                      3:  *
                      4:  * @(#)chase.c 4.25 (Berkeley) 5/5/82
                      5:  *
                      6:  * Rogue: Exploring the Dungeons of Doom
                      7:  * Copyright (C) 1980, 1981, 1982 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: coord ch_ret;                          /* Where chasing takes you */
                     20:
                     21: bool chase(THING *tp, coord *ee);
                     22: int do_chase(THING *th);
                     23: coord *find_dest(THING *tp);
                     24:
                     25: /*
                     26:  * runners:
                     27:  *     Make all the running monsters move.
                     28:  */
                     29: void
                     30: runners(void)
                     31: {
                     32:     register THING *tp;
                     33:        register THING *ntp;
                     34:
                     35:     for (tp = mlist; tp != NULL; tp = ntp)
                     36:     {
                     37:        ntp = next(tp);
                     38:        if (!on(*tp, ISHELD) && on(*tp, ISRUN))
                     39:        {
                     40:            if (!on(*tp, ISSLOW) || tp->t_turn)
                     41:                if (do_chase(tp) == -1)
                     42:                        continue;
                     43:            if (on(*tp, ISHASTE))
                     44:                if (do_chase(tp) == -1)
                     45:                        continue;
                     46:            tp->t_turn ^= TRUE;
                     47:        }
                     48:     }
                     49: }
                     50:
                     51: /*
                     52:  * do_chase:
                     53:  *     Make one thing chase another.
                     54:  */
                     55: int
                     56: do_chase(THING *th)
                     57: {
                     58:     register struct room *rer, *ree;   /* room of chaser, room of chasee */
                     59:     register int mindist = 32767, i, dist;
                     60:     register bool stoprun = FALSE;     /* TRUE means we are there */
                     61:     register char sch;
                     62:     register bool door;
                     63:     register THING *obj;
                     64:     register struct room *oroom;
                     65:     coord this;                                /* Temporary destination for chaser */
                     66:
                     67:     rer = th->t_room;          /* Find room of chaser */
                     68:     if (on(*th, ISGREED) && rer->r_goldval == 0)
                     69:        th->t_dest = &hero;     /* If gold has been taken, run after hero */
                     70:     if (th->t_dest == &hero)   /* Find room of chasee */
                     71:        ree = proom;
                     72:     else
                     73:        ree = roomin(th->t_dest);
                     74:     /*
                     75:      * We don't count doors as inside rooms for this routine
                     76:      */
                     77:     door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
                     78:     /*
                     79:      * If the object of our desire is in a different room,
                     80:      * and we are not in a corridor, run to the door nearest to
                     81:      * our goal.
                     82:      */
                     83: over:
                     84:     if (rer != ree)
                     85:     {
                     86:        for (i = 0; i < rer->r_nexits; i++)     /* loop through doors */
                     87:        {
                     88:            dist = DISTANCE(th->t_dest->y, th->t_dest->x,
                     89:                            rer->r_exit[i].y, rer->r_exit[i].x);
                     90:            if (dist < mindist)
                     91:            {
                     92:                this = rer->r_exit[i];
                     93:                mindist = dist;
                     94:            }
                     95:        }
                     96:        if (door)
                     97:        {
                     98:            rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
                     99:            door = FALSE;
                    100:            goto over;
                    101:        }
                    102:     }
                    103:     else
                    104:     {
                    105:        this = *th->t_dest;
                    106:        /*
                    107:         * For dragons check and see if (a) the hero is on a straight
                    108:         * line from it, and (b) that it is within shooting distance,
                    109:         * but outside of striking range.
                    110:         */
                    111:        if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
                    112:            || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
                    113:            && DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x) <= BOLT_LENGTH * BOLT_LENGTH
                    114:            && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
                    115:        {
                    116:            delta.y = sign(hero.y - th->t_pos.y);
                    117:            delta.x = sign(hero.x - th->t_pos.x);
                    118:            fire_bolt(&th->t_pos, &delta, "flame");
                    119:            running = FALSE;
                    120:            count = quiet = 0;
                    121:            return 0;
                    122:        }
                    123:     }
                    124:     /*
                    125:      * This now contains what we want to run to this time
                    126:      * so we run to it.  If we hit it we either want to fight it
                    127:      * or stop running
                    128:      */
                    129:     if (!chase(th, &this))
                    130:     {
                    131:        if (ce(this, hero))
                    132:        {
                    133:            return ( attack(th) );
                    134:        }
                    135:        else if (ce(this, *th->t_dest))
                    136:        {
                    137:            for (obj = lvl_obj; obj != NULL; obj = next(obj))
                    138:                if (th->t_dest == &obj->o_pos)
                    139:                {
                    140:                    detach(lvl_obj, obj);
                    141:                    attach(th->t_pack, obj);
                    142:                    chat(obj->o_pos.y, obj->o_pos.x) =
                    143:                        (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
                    144:                    th->t_dest = find_dest(th);
                    145:                    break;
                    146:                }
                    147:            if (th->t_type != 'F')
                    148:                stoprun = TRUE;
                    149:        }
                    150:     }
                    151:     else if (th->t_type == 'F')
                    152:        return(0);
                    153:     mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
                    154:     if (!ce(ch_ret, th->t_pos))
                    155:     {
                    156:        sch = mvinch(ch_ret.y, ch_ret.x);
                    157:        if (sch == FLOOR && (th->t_room->r_flags & ISDARK)
                    158:            && DISTANCE(th->t_pos.y, th->t_pos.x, hero.y, hero.x)
                    159:            && !on(player, ISBLIND))
                    160:                th->t_oldch = ' ';
                    161:        else
                    162:            th->t_oldch = sch;
                    163:        oroom = th->t_room;
                    164:        th->t_room = roomin(&ch_ret);
                    165:        if (oroom != th->t_room)
                    166:            th->t_dest = find_dest(th);
                    167:
                    168:        moat(th->t_pos.y, th->t_pos.x) = NULL;
                    169:        moat(ch_ret.y, ch_ret.x) = th;
                    170:        th->t_pos = ch_ret;
                    171:     }
                    172:     if (see_monst(th))
                    173:        mvaddch(ch_ret.y, ch_ret.x, th->t_disguise);
                    174:     else if (on(player, SEEMONST))
                    175:     {
                    176:        standout();
                    177:        mvaddch(ch_ret.y, ch_ret.x, th->t_type);
                    178:        standend();
                    179:     }
                    180:     /*
                    181:      * And stop running if need be
                    182:      */
                    183:     if (stoprun && ce(th->t_pos, *(th->t_dest)))
                    184:        th->t_flags &= ~ISRUN;
                    185:
                    186:     return(0);
                    187: }
                    188:
                    189: /*
                    190:  * see_monst:
                    191:  *     Return TRUE if the hero can see the monster
                    192:  */
                    193: bool
                    194: see_monst(THING *mp)
                    195: {
                    196:     if (on(player, ISBLIND))
                    197:        return FALSE;
                    198:     if (on(*mp, ISINVIS) && !on(player, CANSEE))
                    199:        return FALSE;
                    200:     if (DISTANCE(mp->t_pos.y, mp->t_pos.x, hero.y, hero.x) < LAMPDIST)
                    201:        return TRUE;
                    202:     if (mp->t_room != proom)
                    203:        return FALSE;
                    204:     return (!(mp->t_room->r_flags & ISDARK));
                    205: }
                    206:
                    207: /*
                    208:  * runto:
                    209:  *     Set a mosnter running after something or stop it from running
                    210:  *     (for when it dies)
                    211:  */
                    212: void
                    213: runto(coord *runner, coord *spot)
                    214: {
                    215:     register THING *tp;
                    216:
                    217:     /*
                    218:      * If we couldn't find him, something is funny
                    219:      */
                    220: #ifdef WIZARD
                    221:     if ((tp = moat(runner->y, runner->x)) == NULL)
                    222:        msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
                    223: #else
                    224:     tp = moat(runner->y, runner->x);
                    225: #endif
                    226:     /*
                    227:      * Start the beastie running
                    228:      */
                    229:     if (tp == NULL)
                    230:         return;
                    231:     tp->t_flags |= ISRUN;
                    232:     tp->t_flags &= ~ISHELD;
                    233:     tp->t_dest = find_dest(tp);
                    234: }
                    235:
                    236: /*
                    237:  * chase:
                    238:  *     Find the spot for the chaser(er) to move closer to the
                    239:  *     chasee(ee).  Returns TRUE if we want to keep on chasing later
                    240:  *     FALSE if we reach the goal.
                    241:  */
                    242: bool
                    243: chase(THING *tp, coord *ee)
                    244: {
                    245:     register int x, y;
                    246:     register int dist, thisdist;
                    247:     register THING *obj;
                    248:     register coord *er = &tp->t_pos;
                    249:     register char ch;
                    250:     register int plcnt = 1;
                    251:
                    252:     /*
                    253:      * If the thing is confused, let it move randomly. Invisible
                    254:      * Stalkers are slightly confused all of the time, and bats are
                    255:      * quite confused all the time
                    256:      */
                    257:     if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'I' && rnd(5) == 0)
                    258:        || (tp->t_type == 'B' && rnd(2) == 0))
                    259:     {
                    260:        /*
                    261:         * get a valid random move
                    262:         */
                    263:        ch_ret = *rndmove(tp);
                    264:        dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x);
                    265:        /*
                    266:         * Small chance that it will become un-confused
                    267:         */
                    268:        if (rnd(20) == 0)
                    269:            tp->t_flags &= ~ISHUH;
                    270:     }
                    271:     /*
                    272:      * Otherwise, find the empty spot next to the chaser that is
                    273:      * closest to the chasee.
                    274:      */
                    275:     else
                    276:     {
                    277:        register int ey, ex;
                    278:        /*
                    279:         * This will eventually hold where we move to get closer
                    280:         * If we can't find an empty spot, we stay where we are.
                    281:         */
                    282:        dist = DISTANCE(er->y, er->x, ee->y, ee->x);
                    283:        ch_ret = *er;
                    284:
                    285:        ey = er->y + 1;
                    286:        ex = er->x + 1;
                    287:        for (x = er->x - 1; x <= ex; x++)
                    288:            for (y = er->y - 1; y <= ey; y++)
                    289:            {
                    290:                coord tryp;
                    291:
                    292:                tryp.x = x;
                    293:                tryp.y = y;
                    294:                if (!diag_ok(er, &tryp))
                    295:                    continue;
                    296:                ch = winat(y, x);
                    297:                if (step_ok(ch))
                    298:                {
                    299:                    /*
                    300:                     * If it is a scroll, it might be a scare monster scroll
                    301:                     * so we need to look it up to see what type it is.
                    302:                     */
                    303:                    if (ch == SCROLL)
                    304:                    {
                    305:                        for (obj = lvl_obj; obj != NULL; obj = next(obj))
                    306:                        {
                    307:                            if (y == obj->o_pos.y && x == obj->o_pos.x)
                    308:                                break;
                    309:                        }
                    310:                        if (obj != NULL && obj->o_which == S_SCARE)
                    311:                            continue;
                    312:                    }
                    313:                    /*
                    314:                     * It can also be a Mimic, which we shouldn't step on
                    315:                     */
                    316:                    if ((obj = moat(y, x)) != NULL && obj->t_type == 'M')
                    317:                        continue;
                    318:                    /*
                    319:                     * If we didn't find any scrolls at this place or it
                    320:                     * wasn't a scare scroll, then this place counts
                    321:                     */
                    322:                    thisdist = DISTANCE(y, x, ee->y, ee->x);
                    323:                    if (thisdist < dist)
                    324:                    {
                    325:                        plcnt = 1;
                    326:                        ch_ret = tryp;
                    327:                        dist = thisdist;
                    328:                    }
                    329:                    else if (thisdist == dist && rnd(++plcnt) == 0)
                    330:                    {
                    331:                        ch_ret = tryp;
                    332:                        dist = thisdist;
                    333:                    }
                    334:                }
                    335:            }
                    336:     }
                    337:     return (dist != 0 && !ce(ch_ret, hero));
                    338: }
                    339:
                    340: /*
                    341:  * roomin:
                    342:  *     Find what room some coordinates are in. NULL means they aren't
                    343:  *     in any room.
                    344:  */
                    345: struct room *
                    346: roomin(coord *cp)
                    347: {
                    348:     register struct room *rp;
                    349:     register char *fp;
                    350:
                    351:     for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
                    352:        if (cp->x < rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
                    353:         && cp->y < rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
                    354:            return rp;
                    355:     fp = &flat(cp->y, cp->x);
                    356:     if (*fp & F_PASS)
                    357:        return &passages[*fp & F_PNUM];
                    358:     msg("in some bizarre place (%d, %d)", unc(*cp));
                    359:     return NULL;
                    360: }
                    361:
                    362: /*
                    363:  * diag_ok:
                    364:  *     Check to see if the move is legal if it is diagonal
                    365:  */
                    366: bool
                    367: diag_ok(coord *sp, coord *ep)
                    368: {
                    369:     if (ep->x == sp->x || ep->y == sp->y)
                    370:        return TRUE;
                    371:     return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
                    372: }
                    373:
                    374: /*
                    375:  * cansee:
                    376:  *     Returns true if the hero can see a certain coordinate.
                    377:  */
                    378: bool
                    379: cansee(int y, int x)
                    380: {
                    381:     register struct room *rer;
                    382:     coord tp;
                    383:
                    384:     if (on(player, ISBLIND))
                    385:        return FALSE;
                    386:     if (DISTANCE(y, x, hero.y, hero.x) < LAMPDIST)
                    387:        return TRUE;
                    388:     /*
                    389:      * We can only see if the hero in the same room as
                    390:      * the coordinate and the room is lit or if it is close.
                    391:      */
                    392:     tp.y = y;
                    393:     tp.x = x;
                    394:     return ((rer = roomin(&tp)) == proom && !(rer->r_flags & ISDARK));
                    395: }
                    396:
                    397: /*
                    398:  * find_dest:
                    399:  *     find the proper destination for the monster
                    400:  */
                    401: coord *
                    402: find_dest(THING *tp)
                    403: {
                    404:     register THING *obj;
                    405:     register int prob;
                    406:     register struct room *rp;
                    407:
                    408:     if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
                    409:        || see_monst(tp))
                    410:            return &hero;
                    411:     rp = tp->t_room;
                    412:     for (obj = lvl_obj; obj != NULL; obj = next(obj))
                    413:     {
                    414:        if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
                    415:            continue;
                    416:        if (roomin(&obj->o_pos) == rp && rnd(100) < prob)
                    417:        {
                    418:            for (tp = mlist; tp != NULL; tp = next(tp))
                    419:                if (tp->t_dest == &obj->o_pos)
                    420:                    break;
                    421:            if (tp == NULL)
                    422:                return &obj->o_pos;
                    423:        }
                    424:     }
                    425:     return &hero;
                    426: }

CVSweb