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

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

1.1     ! rubenllo    1: /*
        !             2:  * Code for one object to chase another
        !             3:  *
        !             4:  * @(#)chase.c 9.0     (rdk)    7/17/84
        !             5:  *
        !             6:  * Super-Rogue
        !             7:  * Copyright (C) 1984 Robert D. Kindelberger
        !             8:  * All rights reserved.
        !             9:  *
        !            10:  * Based on "Rogue: Exploring the Dungeons of Doom"
        !            11:  * Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
        !            12:  * All rights reserved.
        !            13:  *
        !            14:  * See the file LICENSE.TXT for full copyright and licensing information.
        !            15:  */
        !            16:
        !            17: #include <stdlib.h>
        !            18: #include "rogue.h"
        !            19: #include "rogue.ext"
        !            20:
        !            21: #define FARAWAY        32767
        !            22: #define RDIST(a, b)    (DISTANCE((a)->y, (a)->x, (b).y, (b).x))
        !            23:
        !            24: int do_chase(struct linked_list *mon);
        !            25: int chase(struct thing *tp, struct coord *ee, bool runaway, bool dofight);
        !            26:
        !            27: struct coord ch_ret;   /* Where chasing takes you */
        !            28:
        !            29: /*
        !            30:  * runners:
        !            31:  *     Make all the running monsters move.
        !            32:  */
        !            33: void
        !            34: runners(void)
        !            35: {
        !            36:        reg struct thing *tp;
        !            37:        reg struct linked_list *mon,*nextmon;
        !            38:
        !            39:        for (mon = mlist; mon != NULL; mon = nextmon) {
        !            40:                tp = THINGPTR(mon);
        !            41:                nextmon = next(mon);
        !            42:                if (off(*tp, ISHELD) && on(*tp, ISRUN)) {
        !            43:                        if (tp->t_nomove > 0)
        !            44:                                if (--tp->t_nomove > 0)
        !            45:                                        continue;
        !            46:                        if (on(*tp, ISHASTE))
        !            47:                                if (do_chase(mon) == -1)
        !            48:                                        continue;
        !            49:                        if (off(*tp, ISSLOW) || tp->t_turn)
        !            50:                                if (do_chase(mon) == -1)
        !            51:                                        continue;
        !            52:                        tp->t_turn ^= TRUE;
        !            53:                }
        !            54:        }
        !            55: }
        !            56:
        !            57:
        !            58: /*
        !            59:  * do_chase:
        !            60:  *     Make one thing chase another.
        !            61:  */
        !            62: int
        !            63: do_chase(struct linked_list *mon)
        !            64: {
        !            65:        reg struct thing *th;
        !            66:        reg struct room *rer, *ree, *rxx;
        !            67:        reg int mindist, i, dist;
        !            68:        struct stats *st;
        !            69:        bool stoprun = FALSE, ondoor = FALSE, link = FALSE;
        !            70:        char runaway, dofight, wound, sch, ch;
        !            71:        struct coord this;
        !            72:        struct trap *trp;
        !            73:
        !            74:        th = THINGPTR(mon);
        !            75:        wound = th->t_flags & ISWOUND;
        !            76:        if (wound)
        !            77:                mindist = 0;
        !            78:        else
        !            79:                mindist = FARAWAY;
        !            80:        runaway = wound;
        !            81:        dofight = !runaway;
        !            82:        rer = th->t_room;
        !            83:        if (th->t_type == 'V') {
        !            84:                if (rer != NULL && !rf_on(rer, ISDARK)) {
        !            85:                        /*
        !            86:                         * Vampires can't stand the light
        !            87:                         */
        !            88:                        if (cansee(th->t_pos.y, th->t_pos.x))
        !            89:                                msg("The vampire vaporizes into thin air !");
        !            90:                        killed(mon, FALSE);
        !            91:                        return(-1);
        !            92:                }
        !            93:        }
        !            94:        ree = roomin(th->t_dest);       /* room of chasee */
        !            95:        this = *th->t_dest;
        !            96:        /*
        !            97:         * If the object of our desire is in a different
        !            98:         * room, then run to the door nearest to our goal.
        !            99:         */
        !           100:        if (mvinch(th->t_pos.y, th->t_pos.x) == DOOR)
        !           101:                ondoor = TRUE;
        !           102:        rxx = NULL;
        !           103:        if (rer != NULL || ree != NULL) {
        !           104:                /*
        !           105:                 * Monster not in room, hero in room. Run to closest door
        !           106:                 * in hero's room if not wounded. Run away if wounded.
        !           107:                 */
        !           108:                if (rer == NULL && ree != NULL) {
        !           109:                        if (!wound)
        !           110:                                rxx = ree;
        !           111:                }
        !           112:                /*
        !           113:                 * Monster in a room, hero not in room. If on a door,
        !           114:                 * then use closest distance. If not on a door, then
        !           115:                 * run to closest door in monsters room.
        !           116:                 */
        !           117:                else if (rer != NULL && ree == NULL) {
        !           118:                        if (!ondoor) {
        !           119:                                rxx = rer;
        !           120:                                if (wound)
        !           121:                                        runaway = FALSE;
        !           122:                        }
        !           123:                }
        !           124:                /*
        !           125:                 * Both hero and monster in a DIFFERENT room. Set flag to
        !           126:                 * check for links between the monster's and hero's rooms.
        !           127:                 * If no links are found, then the closest door in the
        !           128:                 * monster's room is used.
        !           129:                 */
        !           130:                else if (rer != ree) {
        !           131:                        if (!wound) {
        !           132:                                link = TRUE;
        !           133:                                if (ondoor)
        !           134:                                        rxx = ree;      /* if on door, run to heros room */
        !           135:                                else
        !           136:                                        rxx = rer;      /* else to nearest door this room */
        !           137:                        }
        !           138:                }
        !           139:                /*
        !           140:                 * Both hero and monster in same room. If monster is
        !           141:                 * wounded, find the best door to run to.
        !           142:                 */
        !           143:                else if (wound) {
        !           144:                        struct coord *ex;
        !           145:                        int poss, mdtd, hdtd, ghdtd, nx, gx = 0, best;
        !           146:
        !           147:                        best = ghdtd = -FARAWAY;
        !           148:                        for (nx = 0; nx < ree->r_nexits; nx++) {
        !           149:                                ex = &ree->r_exit[nx];
        !           150:                                if (mvinch(ex->y, ex->x) == SECRETDOOR)
        !           151:                                        continue;
        !           152:                                gx += 1;
        !           153:                                mdtd = abs(th->t_pos.y - ex->y) + abs(th->t_pos.x - ex->x);
        !           154:                                hdtd = abs(hero.y - ex->y) + abs(hero.x - ex->x);
        !           155:                                poss = hdtd - mdtd;                             /* possible move */
        !           156:                                if (poss > best) {
        !           157:                                        best = poss;
        !           158:                                        this = *ex;
        !           159:                                }
        !           160:                                else if (poss == best && hdtd > ghdtd) {
        !           161:                                        ghdtd = hdtd;
        !           162:                                        best = poss;
        !           163:                                        this = *ex;
        !           164:                                }
        !           165:                        }
        !           166:                        runaway = FALSE;                /* go for target */
        !           167:                        if (best < 1)
        !           168:                                dofight = TRUE;         /* fight if we must */
        !           169:                        mdtd = (gx <= 1 && best < 1);
        !           170:                        if (ondoor || mdtd) {
        !           171:                                this = hero;
        !           172:                                runaway = TRUE;
        !           173:                                if (!mdtd)
        !           174:                                        dofight = FALSE;
        !           175:                        }
        !           176:                }
        !           177:                if (rxx != NULL) {
        !           178:                        for (i = 0; i < rxx->r_nexits; i += 1) {
        !           179:                                dist = RDIST(th->t_dest, rxx->r_exit[i]);
        !           180:                                if (link && rxx->r_ptr[i] == ree)
        !           181:                                        dist = -1;
        !           182:                                if ((!wound && dist < mindist) ||
        !           183:                                    (wound && dist > mindist)) {
        !           184:                                        this = rxx->r_exit[i];
        !           185:                                        mindist = dist;
        !           186:                                }
        !           187:                        }
        !           188:                }
        !           189:        }
        !           190:        else if (DISTANCE(hero.y, hero.x, th->t_pos.y, th->t_pos.x) <= 3)
        !           191:                dofight = TRUE;
        !           192:        /*
        !           193:         * this now contains what we want to run to this time
        !           194:         * so we run to it.  If we hit it we either want to
        !           195:         * fight it or stop running.
        !           196:         */
        !           197:        if (chase(th, &this, runaway, dofight) == FIGHT) {
        !           198:                return( attack(th) );
        !           199:        }
        !           200:        else if ((th->t_flags & (ISSTUCK | ISPARA)))
        !           201:                return(0);                              /* if paralyzed or stuck */
        !           202:        if ((trp = trap_at(ch_ret.y, ch_ret.x)) != NULL) {
        !           203:                ch = be_trapped(&ch_ret, th);
        !           204:                if (ch == GONER || nlmove) {
        !           205:                        if (ch == GONER)
        !           206:                                remove_monster(&th->t_pos, mon);
        !           207:                        nlmove = FALSE;
        !           208:                        return((ch == GONER) ? -1 : 0);
        !           209:                }
        !           210:        }
        !           211:        if (pl_off(ISBLIND))
        !           212:                mvwaddch(cw,th->t_pos.y,th->t_pos.x,th->t_oldch);
        !           213:        sch = mvwinch(cw, ch_ret.y, ch_ret.x);
        !           214:        if (rer != NULL && rf_on(rer,ISDARK) && sch == FLOOR &&
        !           215:          DISTANCE(ch_ret.y,ch_ret.x,th->t_pos.y,th->t_pos.x) < 3 &&
        !           216:          pl_off(ISBLIND))
        !           217:                th->t_oldch = ' ';
        !           218:        else
        !           219:                th->t_oldch = sch;
        !           220:        if (cansee(unc(ch_ret)) && off(*th, ISINVIS))
        !           221:                mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
        !           222:        mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
        !           223:        mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
        !           224:        th->t_oldpos = th->t_pos;
        !           225:        th->t_pos = ch_ret;
        !           226:        th->t_room = roomin(&ch_ret);
        !           227:        i = 5;
        !           228:        if (th->t_flags & ISREGEN)
        !           229:                i = 40;
        !           230:        st = &th->t_stats;
        !           231:        if (rnd(100) < i) {
        !           232:                if (++st->s_hpt > st->s_maxhp)
        !           233:                        st->s_hpt = st->s_maxhp;
        !           234:                if (!monhurt(th))
        !           235:                        th->t_flags &= ~ISWOUND;
        !           236:        }
        !           237:        if (stoprun && ce(th->t_pos, *(th->t_dest)))
        !           238:                th->t_flags &= ~ISRUN;
        !           239:        return CHASE;
        !           240: }
        !           241:
        !           242:
        !           243: /*
        !           244:  * chase:
        !           245:  *     Find the spot for the chaser to move closer to the
        !           246:  *     chasee.  Returns TRUE if we want to keep on chasing
        !           247:  *     later FALSE if we reach the goal.
        !           248:  */
        !           249: int
        !           250: chase(struct thing *tp, struct coord *ee, bool runaway, bool dofight)
        !           251: {
        !           252:        reg int x, y, ch;
        !           253:        reg int dist, thisdist, closest;
        !           254:        reg struct coord *er = &tp->t_pos;
        !           255:        struct coord try, closecoord;
        !           256:        int numsteps, onscare;
        !           257:
        !           258:        /*
        !           259:         * If the thing is confused, let it move randomly.
        !           260:         */
        !           261:        ch = CHASE;
        !           262:        onscare = FALSE;
        !           263:        if (on(*tp, ISHUH)) {
        !           264:                ch_ret = *rndmove(tp);
        !           265:                dist = DISTANCE(hero.y, hero.x, ch_ret.y, ch_ret.x);
        !           266:                if (rnd(1000) < 5)
        !           267:                        tp->t_flags &= ~ISHUH;
        !           268:                if (dist == 0)
        !           269:                        ch = FIGHT;
        !           270:        }
        !           271:        else {
        !           272:                /*
        !           273:                 * Otherwise, find the the best spot to run to
        !           274:                 * in order to get to your goal.
        !           275:                 */
        !           276:                numsteps = 0;
        !           277:                if (runaway)
        !           278:                        closest = 0;
        !           279:                else
        !           280:                        closest = FARAWAY;
        !           281:                ch_ret = *er;
        !           282:                closecoord = tp->t_oldpos;
        !           283:                for (y = er->y - 1; y <= er->y + 1; y += 1) {
        !           284:                        for (x = er->x - 1; x <= er->x + 1; x += 1) {
        !           285:                                if (!cordok(y, x))
        !           286:                                        continue;
        !           287:                                try.x = x;
        !           288:                                try.y = y;
        !           289:                                if (!diag_ok(er, &try))
        !           290:                                        continue;
        !           291:                                ch = winat(y, x);
        !           292:                                if (step_ok(ch)) {
        !           293:                                        struct trap *trp;
        !           294:
        !           295:                                        if (isatrap(ch)) {
        !           296:                                                trp = trap_at(y, x);
        !           297:                                                if (trp != NULL && off(*tp, ISHUH)) {
        !           298:                                                        /*
        !           299:                                                         * Dont run over found traps unless
        !           300:                                                         * the hero is standing on it. If confused,
        !           301:                                                         * then he can run into them.
        !           302:                                                         */
        !           303:                                                        if (trp->tr_flags & ISFOUND) {
        !           304:                                                                if (trp->tr_type == POOL && rnd(100) < 80)
        !           305:                                                                        continue;
        !           306:                                                                else if (y != hero.y || x != hero.x)
        !           307:                                                                        continue;
        !           308:                                                        }
        !           309:                                                }
        !           310:                                        }
        !           311:                                        /*
        !           312:                                         * Check for scare monster scrolls.
        !           313:                                         */
        !           314:                                        if (ch == SCROLL) {
        !           315:                                                struct linked_list *item;
        !           316:
        !           317:                                                item = find_obj(y, x);
        !           318:                                                if (item != NULL)
        !           319:                                                        if ((OBJPTR(item))->o_which == S_SCARE) {
        !           320:                                                                if (ce(hero, try))
        !           321:                                                                        onscare = TRUE;
        !           322:                                                                continue;
        !           323:                                                        }
        !           324:                                        }
        !           325:                                        /*
        !           326:                                         * Vampires will not run into a lit room.
        !           327:                                         */
        !           328:                                        if (tp->t_type == 'V') {
        !           329:                                                struct room *lr;
        !           330:
        !           331:                                                lr = roomin(&try);
        !           332:                                                if (lr != NULL && !rf_on(lr, ISDARK))
        !           333:                                                        continue;
        !           334:                                        }
        !           335:                                        /*
        !           336:                                         * This is a valid place to step
        !           337:                                         */
        !           338:                                        if (y == hero.y && x == hero.x) {
        !           339:                                                if (dofight) {
        !           340:                                                        ch_ret = try;   /* if fighting */
        !           341:                                                        return FIGHT;   /* hit hero */
        !           342:                                                }
        !           343:                                                else
        !           344:                                                        continue;
        !           345:                                        }
        !           346:                                        thisdist = DISTANCE(y, x, ee->y, ee->x);
        !           347:                                        if (thisdist <= 0) {
        !           348:                                                ch_ret = try;   /* got here but */
        !           349:                                                return CHASE;   /* dont fight */
        !           350:                                        }
        !           351:                                        numsteps += 1;
        !           352:                                        if ((!runaway && thisdist < closest) ||
        !           353:                                                (runaway && thisdist > closest)) {
        !           354:                                                /*
        !           355:                                                 * dont count the monsters last position as
        !           356:                                                 * the closest spot, unless running away and
        !           357:                                                 * in the same room.
        !           358:                                                 */
        !           359:                                                if (!ce(try, tp->t_oldpos) || (runaway
        !           360:                                                  && player.t_room == tp->t_room
        !           361:                                                  && tp->t_room != NULL)) {
        !           362:                                                        closest = thisdist;
        !           363:                                                        closecoord = try;
        !           364:                                                }
        !           365:                                        }
        !           366:                                }
        !           367:                        }
        !           368:                }
        !           369:                /*
        !           370:                 * If dead end, then go back from whence you came.
        !           371:                 * Otherwise, pick the closest of the remaining spots.
        !           372:                 */
        !           373:                if (numsteps > 0)                       /* move to best spot */
        !           374:                        ch_ret = closecoord;
        !           375:                else {                                          /* nowhere to go */
        !           376:                        if (DISTANCE(tp->t_pos.y, tp->t_pos.x, hero.y, hero.x) < 2)
        !           377:                                if (!onscare)
        !           378:                                        ch_ret = hero;
        !           379:                }
        !           380:                if (ce(hero, ch_ret))
        !           381:                        ch = FIGHT;
        !           382:        }
        !           383:        return ch;
        !           384: }
        !           385:
        !           386:
        !           387: /*
        !           388:  * runto:
        !           389:  *     Set a monster running after something
        !           390:  */
        !           391: void
        !           392: runto(struct coord *runner, struct coord *spot)
        !           393: {
        !           394:        reg struct linked_list *item;
        !           395:        reg struct thing *tp;
        !           396:
        !           397:        if ((item = find_mons(runner->y, runner->x)) == NULL)
        !           398:                return;
        !           399:        tp = THINGPTR(item);
        !           400:        if (tp->t_flags & ISPARA)
        !           401:                return;
        !           402:        tp->t_dest = spot;
        !           403:        tp->t_flags |= ISRUN;
        !           404:        tp->t_flags &= ~ISHELD;
        !           405: }
        !           406:
        !           407:
        !           408: /*
        !           409:  * roomin:
        !           410:  *     Find what room some coordinates are in.
        !           411:  *     NULL means they aren't in any room.
        !           412:  */
        !           413: struct room *
        !           414: roomin(struct coord *cp)
        !           415: {
        !           416:        reg struct room *rp;
        !           417:
        !           418:        if (cordok(cp->y, cp->x)) {
        !           419:                for (rp = rooms; rp < &rooms[MAXROOMS]; rp += 1)
        !           420:                        if (inroom(rp, cp))
        !           421:                                return rp;
        !           422:        }
        !           423:        return NULL;
        !           424: }
        !           425:
        !           426:
        !           427: /*
        !           428:  * find_mons:
        !           429:  *     Find the monster from his coordinates
        !           430:  */
        !           431: struct linked_list *
        !           432: find_mons(int y, int x)
        !           433: {
        !           434:        reg struct linked_list *item;
        !           435:        reg struct thing *th;
        !           436:
        !           437:        for (item = mlist; item != NULL; item = next(item)) {
        !           438:                th = THINGPTR(item);
        !           439:                if (th->t_pos.y == y && th->t_pos.x == x)
        !           440:                        return item;
        !           441:        }
        !           442:        return NULL;
        !           443: }
        !           444:
        !           445:
        !           446: /*
        !           447:  * diag_ok:
        !           448:  *     Check to see if the move is legal if it is diagonal
        !           449:  */
        !           450: bool
        !           451: diag_ok(struct coord *sp, struct coord *ep)
        !           452: {
        !           453:        if (ep->x == sp->x || ep->y == sp->y)
        !           454:                return TRUE;
        !           455:        if (step_ok(mvinch(ep->y,sp->x)) && step_ok(mvinch(sp->y,ep->x)))
        !           456:                return TRUE;
        !           457:        return FALSE;
        !           458: }
        !           459:
        !           460:
        !           461: /*
        !           462:  * cansee:
        !           463:  *     returns true if the hero can see a certain coordinate.
        !           464:  */
        !           465: bool
        !           466: cansee(int y, int x)
        !           467: {
        !           468:        reg struct room *rer;
        !           469:        struct coord tp;
        !           470:
        !           471:        if (pl_on(ISBLIND))
        !           472:                return FALSE;
        !           473:        /*
        !           474:         * We can only see if the hero in the same room as
        !           475:         * the coordinate and the room is lit or if it is close.
        !           476:         */
        !           477:        if (DISTANCE(y, x, hero.y, hero.x) < 3)
        !           478:                return TRUE;
        !           479:        tp.y = y;
        !           480:        tp.x = x;
        !           481:        rer = roomin(&tp);
        !           482:        if (rer != NULL && levtype != MAZELEV)
        !           483:                if (rer == player.t_room && !rf_on(rer,ISDARK))
        !           484:                        return TRUE;
        !           485:        return FALSE;
        !           486: }

CVSweb