[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

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