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

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

1.1     ! rubenllo    1: /*
        !             2:     chase.c  -  Code for one object to chase another
        !             3:
        !             4:     XRogue: Expeditions into the Dungeons of Doom
        !             5:     Copyright (C) 1991 Robert Pietkivitch
        !             6:     All rights reserved.
        !             7:
        !             8:     Based on "Advanced Rogue"
        !             9:     Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka and AT&T
        !            10:     All rights reserved.
        !            11:
        !            12:     Based on "Rogue: Exploring the Dungeons of Doom"
        !            13:     Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
        !            14:     All rights reserved.
        !            15:
        !            16:     See the file LICENSE.TXT for full copyright and licensing information.
        !            17: */
        !            18:
        !            19: #include <ctype.h>
        !            20: #include <curses.h>
        !            21: #include <limits.h>
        !            22: #include <stdlib.h>
        !            23: #include "rogue.h"
        !            24:
        !            25: bool straight_shot(int ery, int erx, int eey, int eex, coord *shooting);
        !            26:
        !            27: /*
        !            28:  * Canblink checks if the monster can teleport (blink).  If so, it will
        !            29:  * try to blink the monster next to the player.
        !            30:  */
        !            31:
        !            32: bool
        !            33: can_blink(struct thing *tp)
        !            34: {
        !            35:     register int y, x, index=9;
        !            36:     coord tryp; /* To hold the coordinates for use in diag_ok */
        !            37:     bool spots[9], found_one=FALSE;
        !            38:
        !            39:     /*
        !            40:      * First, can the monster even blink?  And if so, there is only a 50%
        !            41:      * chance that it will do so.  And it won't blink if it is running or
        !            42:      * held.
        !            43:      */
        !            44:     if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
        !            45:         on(*tp, ISFLEE) ||
        !            46:         tp->t_action == A_FREEZE ||
        !            47:         (rnd(12) < 6)) return(FALSE);
        !            48:
        !            49:
        !            50:     /* Initialize the spots as illegal */
        !            51:     do {
        !            52:         spots[--index] = FALSE;
        !            53:     } while (index > 0);
        !            54:
        !            55:     /* Find a suitable spot next to the player */
        !            56:     for (y=hero.y-1; y<hero.y+2; y++)
        !            57:         for (x=hero.x-1; x<hero.x+2; x++, index++) {
        !            58:             /* Make sure x coordinate is in range and that we are
        !            59:              * not at the player's position
        !            60:              */
        !            61:             if (x<0 || x >= cols || index == 4) continue;
        !            62:
        !            63:             /* Is it OK to move there? */
        !            64:             if (step_ok(y, x, NOMONST, tp) &&
        !            65:                 (!isatrap(mvwinch(cw, y, x)) ||
        !            66:                   rnd(10) >= tp->t_stats.s_intel ||
        !            67:                   on(*tp, ISFLY))) {
        !            68:                 /* OK, we can go here.  But don't go there if
        !            69:                  * monster can't get at player from there
        !            70:                  */
        !            71:                 tryp.y = y;
        !            72:                 tryp.x = x;
        !            73:                 if (diag_ok(&tryp, &hero, tp)) {
        !            74:                     spots[index] = TRUE;
        !            75:                     found_one = TRUE;
        !            76:                 }
        !            77:             }
        !            78:         }
        !            79:
        !            80:     /* If we found one, go to it */
        !            81:     if (found_one) {
        !            82:         unsigned char rch;       /* What's really where the creatures moves to */
        !            83:
        !            84:         /* Find a legal spot */
        !            85:         while (spots[index=rnd(9)] == FALSE) continue;
        !            86:
        !            87:         /* Get the coordinates */
        !            88:         y = hero.y + (index/3) - 1;
        !            89:         x = hero.x + (index % 3) - 1;
        !            90:
        !            91:         /* Move the monster from the old space */
        !            92:         mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
        !            93:
        !            94:         /* Move it to the new space */
        !            95:         tp->t_oldch = mvwinch(cw, y, x);
        !            96:
        !            97:         /* Display the creature if our hero can see it */
        !            98:         if (cansee(y, x) &&
        !            99:             off(*tp, ISINWALL) &&
        !           100:             !invisible(tp))
        !           101:             mvwaddch(cw, y, x, tp->t_type);
        !           102:
        !           103:         /* Fix the monster window */
        !           104:         mvwaddch(mw, tp->t_pos.y, tp->t_pos.x, ' '); /* Clear old position */
        !           105:         mvwaddch(mw, y, x, tp->t_type);
        !           106:
        !           107:         /* Record the new position */
        !           108:         tp->t_pos.y = y;
        !           109:         tp->t_pos.x = x;
        !           110:
        !           111:         /* If the monster is on a trap, trap it */
        !           112:         rch = mvinch(y, x);
        !           113:         if (isatrap(rch)) {
        !           114:             if (cansee(y, x)) tp->t_oldch = rch;
        !           115:             be_trapped(tp, &(tp->t_pos));
        !           116:         }
        !           117:     }
        !           118:
        !           119:     return(found_one);
        !           120: }
        !           121:
        !           122: /*
        !           123:  * Can_shoot determines if the monster (er) has a direct line of shot
        !           124:  * at the prey (ee).  If so, it returns the direction in which to shoot.
        !           125:  */
        !           126:
        !           127: int
        !           128: can_shoot(coord *er, coord *ee, coord *shoot_dir)
        !           129: {
        !           130:     /*
        !           131:      * They must be in the same room or very close (at door)
        !           132:      */
        !           133:     if (roomin(er) != roomin(ee) && DISTANCE(er->y,er->x,ee->y,ee->x) > 1)
        !           134:     {
        !           135:         shoot_dir->x = shoot_dir->y = 0;
        !           136:         return(-1);
        !           137:     }
        !           138:
        !           139:     /* Do we have a straight shot? */
        !           140:     if (!straight_shot(er->y, er->x, ee->y, ee->x, shoot_dir))
        !           141:     {
        !           142:         shoot_dir->x = shoot_dir->y = 0;
        !           143:         return(-2);
        !           144:     }
        !           145:     else
        !           146:         return(0);
        !           147: }
        !           148:
        !           149: /*
        !           150:  * chase:
        !           151:  *      Find the spot for the chaser(er) to move closer to the
        !           152:  *      chasee(ee).  Rer is the room of the chaser, and ree is the
        !           153:  *      room of the creature being chased (chasee).
        !           154:  *     flee: True if destination (ee) is player and monster is running away
        !           155:  *     or the player is in a wall and the monster can't get to it
        !           156:  */
        !           157:
        !           158: void
        !           159: chase(struct thing *tp, coord *ee, struct room *rer, struct room *ree,
        !           160:       bool flee)
        !           161: {
        !           162:     int dist, thisdist, monst_dist = INT_MAX;
        !           163:     register coord *er = &tp->t_pos;
        !           164:     struct thing *prey;                 /* What we are chasing */
        !           165:     coord ch_ret;                       /* Where chasing takes you */
        !           166:     unsigned char ch, mch;
        !           167:     bool next_player = FALSE;
        !           168:
        !           169:     /*
        !           170:      * set the distance from the chas(er) to the chas(ee) here and then
        !           171:      * we won't have to reset it unless the chas(er) moves (instead of shoots)
        !           172:      */
        !           173:     dist = DISTANCE(er->y, er->x, ee->y, ee->x);
        !           174:
        !           175:     /*
        !           176:      * See if our destination is a monster or player.  If so, make "prey" point
        !           177:      * to it.
        !           178:      */
        !           179:     if (ce(hero, *ee)) prey = &player;  /* Is it the player? */
        !           180:     else if (tp->t_dest && ce(*(tp->t_dest), *ee)) {    /* Is it a monster? */
        !           181:         struct linked_list *item;
        !           182:
        !           183:         /* What is the monster we're chasing? */
        !           184:         item = find_mons(ee->y, ee->x);
        !           185:         if (item != NULL) prey = THINGPTR(item);
        !           186:         else prey = NULL;
        !           187:     }
        !           188:     else prey = NULL;
        !           189:
        !           190:     /* We will use at least one movement period */
        !           191:     tp->t_no_move = movement(tp);
        !           192:     if (on(*tp, ISFLY)) /* If the creature is flying, speed it up */
        !           193:         tp->t_no_move /= 2;
        !           194:
        !           195:     /*
        !           196:      * If the thing is confused or it can't see the player,
        !           197:      * let it move randomly.
        !           198:      */
        !           199:     if ((on(*tp, ISHUH) && rnd(10) < 8) ||
        !           200:         (prey && on(*prey, ISINVIS) && off(*tp, CANSEE))) { /* invisible prey */
        !           201:         /*
        !           202:          * get a valid random move
        !           203:          */
        !           204:         tp->t_newpos = rndmove(tp);
        !           205:         dist = DISTANCE(tp->t_newpos.y, tp->t_newpos.x, ee->y, ee->x);
        !           206:     }
        !           207:
        !           208:     /*
        !           209:      * Otherwise, find the empty spot next to the chaser that is
        !           210:      * closest to the chasee.
        !           211:      */
        !           212:     else {
        !           213:         register int ey, ex, x, y;
        !           214:         int dist_to_old = INT_MIN; /* Dist from goal to old position */
        !           215:
        !           216:         /*
        !           217:          * This will eventually hold where we move to get closer
        !           218:          * If we can't find an empty spot, we stay where we are.
        !           219:          */
        !           220:         dist = flee ? 0 : INT_MAX;
        !           221:         ch_ret = *er;
        !           222:
        !           223:         /* Are we at our goal already? */
        !           224:         if (!flee && ce(ch_ret, *ee)) {
        !           225:             turn_off(*tp, ISRUN);       /* So stop running! */
        !           226:             return;
        !           227:         }
        !           228:
        !           229:         ey = er->y + 1;
        !           230:         ex = er->x + 1;
        !           231:
        !           232:         /* Check all possible moves */
        !           233:         for (x = er->x - 1; x <= ex; x++) {
        !           234:             if (x < 0 || x >= cols) /* Don't try off the board */
        !           235:                 continue;
        !           236:             for (y = er->y - 1; y <= ey; y++) {
        !           237:                 coord tryp;
        !           238:
        !           239:                 if ((y < 1) || (y >= lines - 2)) /* Don't try off the board */
        !           240:                     continue;
        !           241:
        !           242:                 /* Don't try the player if not going after the player */
        !           243:                 if ((flee || !ce(hero, *ee) || on(*tp, ISFRIENDLY)) &&
        !           244:                     x == hero.x && y == hero.y) {
        !           245:                     next_player = TRUE;
        !           246:                     continue;
        !           247:                 }
        !           248:
        !           249:                 tryp.x = x;
        !           250:                 tryp.y = y;
        !           251:
        !           252:                 /* Is there a monster on this spot closer to our goal?
        !           253:                  * Don't look in our spot or where we were.
        !           254:                  */
        !           255:                 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
        !           256:                     isalpha(mch = mvwinch(mw, y, x))) {
        !           257:                     int test_dist;
        !           258:
        !           259:                     test_dist = DISTANCE(y, x, ee->y, ee->x);
        !           260:                     if (test_dist <= 25 &&   /* Let's be fairly close */
        !           261:                         test_dist < monst_dist) {
        !           262:                         /* Could we really move there? */
        !           263:                         mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */
        !           264:                         if (diag_ok(er, &tryp, tp)) monst_dist = test_dist;
        !           265:                         mvwaddch(mw, y, x, mch); /* Restore monster */
        !           266:                     }
        !           267:                 }
        !           268:
        !           269:                 /* Can we move onto the spot? */
        !           270:                 if (!diag_ok(er, &tryp, tp)) continue;
        !           271:
        !           272:                 ch = mvwinch(cw, y, x); /* Screen character */
        !           273:
        !           274:                 /*
        !           275:                  * Stepping on player is NOT okay if we are fleeing.
        !           276:                  * If we are friendly to the player and there is a monster
        !           277:                  * in the way that is not of our race, it is okay to move
        !           278:                  * there.
        !           279:                  */
        !           280:                 if (step_ok(y, x, FIGHTOK, tp) &&
        !           281:                     (off(*tp, ISFLEE) || ch != PLAYER))
        !           282:                 {
        !           283:                     /*
        !           284:                      * If it is a trap, an intelligent monster may not
        !           285:                      * step on it (unless our hero is on top!)
        !           286:                      */
        !           287:                     if ((isatrap(ch))                   &&
        !           288:                         (rnd(10) < tp->t_stats.s_intel) &&
        !           289:                         (!on(*tp, ISFLY))               &&
        !           290:                         (y != hero.y || x != hero.x))
        !           291:                             continue;
        !           292:
        !           293:                     /*
        !           294:                      * OK -- this place counts
        !           295:                      */
        !           296:                     thisdist = DISTANCE(y, x, ee->y, ee->x);
        !           297:
        !           298:                     /* Adjust distance if we are being shot at */
        !           299:                     if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
        !           300:                         prey != NULL) {
        !           301:                         /* Move out of line of sight */
        !           302:                         if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, (coord *)NULL)) {
        !           303:                             if (flee) thisdist -= SHOTPENALTY;
        !           304:                             else thisdist += SHOTPENALTY;
        !           305:                         }
        !           306:
        !           307:                         /* But do we want to leave the room? */
        !           308:                         else if (rer && rer == ree && ch == DOOR)
        !           309:                             thisdist += DOORPENALTY;
        !           310:                     }
        !           311:
        !           312:                     /* Don't move to the last position if we can help it
        !           313:                      * (unless out prey just moved there)
        !           314:                      */
        !           315:                     if (ce(tryp, tp->t_oldpos) && (flee || !ce(tryp, hero)))
        !           316:                         dist_to_old = thisdist;
        !           317:
        !           318:                     else if ((flee && (thisdist > dist)) ||
        !           319:                         (!flee && (thisdist < dist)))
        !           320:                     {
        !           321:                         ch_ret = tryp;
        !           322:                         dist = thisdist;
        !           323:                     }
        !           324:                 }
        !           325:             }
        !           326:         }
        !           327:
        !           328:         /* If we aren't trying to get the player, but he is in our way,
        !           329:          * hit him (unless we have been turned or are friendly).  next_player
        !           330:          * being TRUE -> we are next to the player but don't want to hit him.
        !           331:          *
        !           332:          * If we are friendly to the player, following him, and standing next
        !           333:          * to him, we will try to help him out in battle.
        !           334:          */
        !           335:         if (next_player && off(*tp, WASTURNED)) {
        !           336:             if (off(*tp, ISFRIENDLY) &&
        !           337:                 ((flee && ce(ch_ret, *er)) ||
        !           338:                  (!flee && DISTANCE(er->y, er->x, ee->y, ee->x) < dist)) &&
        !           339:                 step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) {
        !           340:                 /* Okay to hit player */
        !           341:                 debug("Switching to hero.");
        !           342:                 tp->t_newpos = hero;
        !           343:                 tp->t_action = A_MOVE;
        !           344:                 return;
        !           345:             }
        !           346:             else if (on(*tp, ISFRIENDLY) && !flee && ce(*ee, hero)) {
        !           347:                 /*
        !           348:                  * Look all around the player.  If there is a fightable
        !           349:                  * creature next to both of us, hit it.  Otherwise, if
        !           350:                  * there is a fightable creature next to the player, try
        !           351:                  * to move next to it.
        !           352:                  */
        !           353:                 dist = INT_MAX;
        !           354:                 for (x = hero.x - 1; x <= hero.x + 1; x++) {
        !           355:                     if (x < 0 || x >= cols) /* Don't try off the board */
        !           356:                         continue;
        !           357:                     for (y = hero.y - 1; y <= hero.y + 1; y++) {
        !           358:                         if ((y < 1) || (y >= lines - 2)) /* Stay on the board */
        !           359:                             continue;
        !           360:
        !           361:                         /* Is there a fightable monster here? */
        !           362:                         if (isalpha(mvwinch(mw, y, x)) &&
        !           363:                             step_ok(y, x, FIGHTOK, tp) &&
        !           364:                             off(*tp, ISSTONE)) {
        !           365:                             thisdist = DISTANCE(er->y, er->x, y, x);
        !           366:                             if (thisdist < dist) {
        !           367:                                 dist = thisdist;
        !           368:                                 ch_ret.y = y;
        !           369:                                 ch_ret.x = x;
        !           370:                             }
        !           371:                         }
        !           372:                     }
        !           373:                 }
        !           374:
        !           375:                 /* Are we next to a bad guy? */
        !           376:                 if (dist <= 2) {        /* Get him! */
        !           377:                     tp->t_newpos = ch_ret;
        !           378:                     tp->t_action = A_MOVE;
        !           379:                 }
        !           380:
        !           381:                 /* Try to move to the bad guy */
        !           382:                 else if (dist < INT_MAX)
        !           383:                     chase(tp, &ch_ret,
        !           384:                           roomin(&tp->t_pos), roomin(&ch_ret), FALSE);
        !           385:
        !           386:                 else tp->t_action = A_NIL;
        !           387:
        !           388:                 return;
        !           389:             }
        !           390:         }
        !           391:
        !           392:         /*
        !           393:          * If we have decided that we can move onto a monster (we are
        !           394:          * friendly to the player, go to it.
        !           395:          */
        !           396:         if (!ce(ch_ret, *er) && isalpha(mvwinch(mw, ch_ret.y, ch_ret.x))) {
        !           397:             debug("Attack monster");
        !           398:             tp->t_newpos = ch_ret;
        !           399:             tp->t_action = A_MOVE;
        !           400:             return;
        !           401:         }
        !           402:
        !           403:         /* If we can't get closer to the player (if that's our goal)
        !           404:          * because other monsters are in the way, just stay put
        !           405:          */
        !           406:         if (!flee && ce(hero, *ee) && monst_dist < INT_MAX &&
        !           407:             DISTANCE(er->y, er->x, hero.y, hero.x) < dist) {
        !           408:                 tp->t_action = A_NIL; /* do nothing for awhile */
        !           409:                 return;
        !           410:         }
        !           411:
        !           412:         /* Do we want to go back to the last position? */
        !           413:         else if (dist_to_old != INT_MIN &&      /* It is possible to move back */
        !           414:             ((flee && dist == 0) ||     /* No other possible moves */
        !           415:              (!flee && dist == INT_MAX))) {
        !           416:             /* Do we move back or just stay put (default)? */
        !           417:             dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */
        !           418:             if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos;
        !           419:         }
        !           420:
        !           421:         /* Record the new destination */
        !           422:         tp->t_newpos = ch_ret;
        !           423:     }
        !           424:
        !           425:     /*
        !           426:      * Do we want to fight or move?  If our selected destination (ch_ret)
        !           427:      * is our hero, then we want to fight.  Otherwise, we want to move.
        !           428:      */
        !           429:     if (ce(tp->t_newpos, hero)) {
        !           430:         /* Fight! (or sell) */
        !           431:         if (on(*tp, CANSELL)) {
        !           432:             tp->t_action = A_SELL;
        !           433:             tp->t_no_move += movement(tp); /* takes a little time to sell */
        !           434:         }
        !           435:         else {
        !           436:             tp->t_action = A_ATTACK;
        !           437:
        !           438:             /*
        !           439:              * Try to find a weapon to wield.  Wield_weap will return a
        !           440:              * projector if weapon is a projectile (eg. bow for arrow).
        !           441:              * If weapon is NULL (the case here), it will try to find
        !           442:              * a suitable weapon.
        !           443:              *
        !           444:              *          Add in rest of time. Fight is
        !           445:              *          movement() + weap_move() + FIGHTBASE
        !           446:              */
        !           447:             tp->t_using = wield_weap((struct object *)NULL, tp);
        !           448:             if (tp->t_using == NULL)
        !           449:                 tp->t_no_move += weap_move(tp, (struct object *)NULL);
        !           450:             else
        !           451:                 tp->t_no_move += weap_move(tp, OBJPTR(tp->t_using));
        !           452:
        !           453:             if (on(*tp, ISHASTE))
        !           454:                     tp->t_no_move += FIGHTBASE/2;
        !           455:             else if (on(*tp, ISSLOW))
        !           456:                     tp->t_no_move += FIGHTBASE*2;
        !           457:             else
        !           458:                     tp->t_no_move += FIGHTBASE;
        !           459:         }
        !           460:     }
        !           461:     else {
        !           462:         /* Move */
        !           463:         tp->t_action = A_MOVE;
        !           464:
        !           465:         /*
        !           466:          * Check if the creature is not next to the player.  If it
        !           467:          * is not and has held or suffocated the player, then stop it!
        !           468:          * Note that this code should more appropriately appear in
        !           469:          * the area that actually moves the monster, but for now it
        !           470:          * is okay here because the player can't move while held or
        !           471:          * suffocating.
        !           472:          */
        !           473:         if (dist > 2) {
        !           474:             if (on(*tp, DIDHOLD)) {
        !           475:                  turn_off(*tp, DIDHOLD);
        !           476:                  turn_on(*tp, CANHOLD);
        !           477:                  if (--hold_count == 0)
        !           478:                      turn_off(player, ISHELD);
        !           479:             }
        !           480:
        !           481:             /* If monster was suffocating, stop it */
        !           482:             if (on(*tp, DIDSUFFOCATE)) {
        !           483:                 turn_off(*tp, DIDSUFFOCATE);
        !           484:                 turn_on(*tp, CANSUFFOCATE);
        !           485:                 extinguish(suffocate);
        !           486:                 msg("You can breathe again.....Whew!");
        !           487:             }
        !           488:         }
        !           489:     }
        !           490: }
        !           491:
        !           492: /*
        !           493:  * do_chase:
        !           494:  *      Make one thing chase another.
        !           495:  */
        !           496:
        !           497: void
        !           498: do_chase(struct thing *th)
        !           499: {
        !           500:     register struct room *orig_rer,     /* Original room of chaser */
        !           501:                          *new_room;     /* new room of monster */
        !           502:     unsigned char floor, rch, sch;
        !           503:     coord old_pos,                      /* Old position of monster */
        !           504:           ch_ret;                       /* Where we want to go */
        !           505:
        !           506:     if (on(*th, NOMOVE)) return;
        !           507:
        !           508:     ch_ret = th->t_newpos;      /* Record our desired new position */
        !           509:
        !           510:     /*
        !           511:      * Make sure we have an open spot (no other monster's gotten in our way,
        !           512:      * someone didn't just drop a scare monster there, our prey didn't just
        !           513:      * get there, etc.)
        !           514:      */
        !           515:     if (!step_ok(th->t_newpos.y, th->t_newpos.x, FIGHTOK, th)) {
        !           516:         /*
        !           517:          * Most monsters get upset now.  Guardians are all friends,
        !           518:          * and we don't want to see 50 messages in a row!
        !           519:          */
        !           520:         if (th->t_stats.s_intel > 4 &&
        !           521:             off(*th, ISUNDEAD)      &&
        !           522:             off(*th, ISGUARDIAN)    &&
        !           523:             off(*th, AREMANY)       &&
        !           524:             off(*th, ISHUH)         &&
        !           525:             off(*th, ISCHARMED)     &&
        !           526:             off(player, ISBLIND)    &&
        !           527:             cansee(unc(th->t_pos))  &&
        !           528:         !invisible(th) && (rnd(15) < 5)) {
        !           529:             switch (rnd(10)) {
        !           530:               case 0: case 1:
        !           531:             msg("%s lashes out at you! ",prname(monster_name(th),TRUE));
        !           532:           when 2: case 3:
        !           533:             msg("%s scrambles around. ",prname(monster_name(th), TRUE));
        !           534:                   otherwise:
        !           535:             msg("%s motions angrily. ", prname(monster_name(th), TRUE));
        !           536:             }
        !           537:     }
        !           538:         return;
        !           539:     }
        !           540:     else if (ce(th->t_newpos, hero) ||  /* Player just got in our way */
        !           541:              isalpha(mvwinch(mw, th->t_newpos.y, th->t_newpos.x))) {
        !           542:         bool fightplayer = ce(th->t_newpos, hero);
        !           543:
        !           544:         /* If we were turned or are friendly, we just have to sit here! */
        !           545:         if (fightplayer && (on(*th, WASTURNED) || on(*th, ISFRIENDLY))) return;
        !           546:
        !           547:         /* Do we want to sell something? */
        !           548:         if (fightplayer && on(*th, CANSELL)) {
        !           549:             th->t_action = A_SELL;
        !           550:             th->t_no_move += movement(th); /* takes a little time to sell */
        !           551:             return;
        !           552:         }
        !           553:
        !           554:         /* Let's hit him */
        !           555:         th->t_action = A_ATTACK;
        !           556:
        !           557:         /*
        !           558:          * Try to find a weapon to wield.  Wield_weap will return a
        !           559:          * projector if weapon is a projectile (eg. bow for arrow).
        !           560:          * If weapon is NULL (the case here), it will try to find
        !           561:          * a suitable weapon.
        !           562:          */
        !           563:         th->t_using = wield_weap((struct object *)NULL, th);
        !           564:         /*
        !           565:          * add in rest of time
        !           566:          */
        !           567:         if (th->t_using == NULL)
        !           568:             th->t_no_move += weap_move(th, (struct object *)NULL);
        !           569:         else
        !           570:             th->t_no_move += weap_move(th, OBJPTR(th->t_using));
        !           571:         if (on(*th, ISHASTE))
        !           572:                 th->t_no_move += FIGHTBASE/2;
        !           573:         else if (on(*th, ISSLOW))
        !           574:                 th->t_no_move += FIGHTBASE*2;
        !           575:         else
        !           576:                 th->t_no_move += FIGHTBASE;
        !           577:         return;
        !           578:     }
        !           579:
        !           580:     /*
        !           581:      * Blank out the old position and record the new position --
        !           582:      * the blanking must be done first in case the positions are the same.
        !           583:      */
        !           584:     mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
        !           585:     mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type);
        !           586:
        !           587:     /* Get new and old rooms of monster */
        !           588:     new_room = roomin(&ch_ret);
        !           589:     orig_rer = roomin(&th->t_pos);
        !           590:
        !           591:     /* Store the critter's old position and update the current one */
        !           592:     old_pos = th->t_pos;
        !           593:     th->t_pos = ch_ret;
        !           594:     floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR;
        !           595:
        !           596:     /* If we have a scavenger, it can pick something up */
        !           597:     if (off(*th, ISGUARDIAN)) {
        !           598:         register struct linked_list *n_item, *o_item;
        !           599:         register int item_count = 0;
        !           600:         bool want_something = FALSE;
        !           601:
        !           602:         while ((n_item = find_obj(ch_ret.y, ch_ret.x)) != NULL) {
        !           603:             register struct object *n_obj, *o_obj;
        !           604:             bool wants_it;
        !           605:
        !           606:             /* Does this monster want anything? */
        !           607:             if (want_something == FALSE) {
        !           608:                 if (on(*th, ISSCAVENGE)  || on(*th, CARRYFOOD)   ||
        !           609:                     on(*th, CARRYGOLD)   || on(*th, CARRYSCROLL) ||
        !           610:                     on(*th, CARRYPOTION) || on(*th, CARRYRING)   ||
        !           611:                     on(*th, CARRYSTICK)  || on(*th, CARRYMISC)   ||
        !           612:                     on(*th, CARRYWEAPON) || on(*th, CARRYARMOR)  ||
        !           613:                     on(*th, CARRYDAGGER))  {
        !           614:                         want_something = TRUE;
        !           615:
        !           616:                         /*
        !           617:                          * Blank the area.  We have to do it only before the
        !           618:                          * first item in case an item gets dropped in same
        !           619:                          * place.  We don't want to blank it out after it get
        !           620:                          * dropped.
        !           621:                          */
        !           622:                         mvaddch(ch_ret.y, ch_ret.x, floor);
        !           623:
        !           624:                         /* Were we specifically after something here? */
        !           625:                         if (ce(*th->t_dest, ch_ret)) {
        !           626:                             /* If we're mean, we go after the hero */
        !           627:                             if (on(*th, ISMEAN)) runto(th, &hero);
        !           628:
        !           629:                             /* Otherwise just go back to sleep */
        !           630:                             else {
        !           631:                                 turn_off(*th, ISRUN);
        !           632:                                 th->t_dest = NULL;
        !           633:                             }
        !           634:                         }
        !           635:                 }
        !           636:                 else break;
        !           637:             }
        !           638:
        !           639:             item_count++;       /* Count the number of items */
        !           640:
        !           641:             /*
        !           642:              * see if he's got one of this group already
        !           643:              */
        !           644:             o_item = NULL;
        !           645:             n_obj = OBJPTR(n_item);
        !           646:             detach(lvl_obj, n_item);
        !           647:
        !           648:             /* See if he wants it */
        !           649:             if (n_obj->o_type == SCROLL && n_obj->o_which == S_SCARE &&
        !           650:                 th->t_stats.s_intel < 16)
        !           651:                 wants_it = FALSE; /* Most monsters don't want a scare monster */
        !           652:             else if (on(*th, ISSCAVENGE)) wants_it = TRUE;
        !           653:             else {
        !           654:                 wants_it = FALSE;       /* Default case */
        !           655:                 switch (n_obj->o_type) {
        !           656:                     case FOOD:  if(on(*th, CARRYFOOD))   wants_it = TRUE;
        !           657:                     when GOLD:  if(on(*th, CARRYGOLD))   wants_it = TRUE;
        !           658:                     when SCROLL:if(on(*th, CARRYSCROLL)) wants_it = TRUE;
        !           659:                     when POTION:if(on(*th, CARRYPOTION)) wants_it = TRUE;
        !           660:                     when RING:  if(on(*th, CARRYRING))   wants_it = TRUE;
        !           661:                     when STICK: if(on(*th, CARRYSTICK))  wants_it = TRUE;
        !           662:                     when MM:    if(on(*th, CARRYMISC))   wants_it = TRUE;
        !           663:                     when ARMOR: if(on(*th, CARRYARMOR))  wants_it = TRUE;
        !           664:                     when WEAPON:if(on(*th, CARRYWEAPON) ||
        !           665:                                   (on(*th,CARRYDAGGER)&&n_obj->o_which==DAGGER))
        !           666:                                         wants_it = TRUE;
        !           667:                 }
        !           668:             }
        !           669:             /*
        !           670:              * The quartermaster doesn't sell cursed stuff so he won't
        !           671:              * pick it up
        !           672:              */
        !           673:             if (on(*th, CANSELL) && (n_obj->o_flags & ISCURSED))
        !           674:                 wants_it = FALSE;
        !           675:
        !           676:             /* If he doesn't want it, throw it away */
        !           677:             if (wants_it == FALSE) {
        !           678:                 fall(n_item, FALSE);
        !           679:                 continue;
        !           680:             }
        !           681:
        !           682:             /* Otherwise, let's pick it up */
        !           683:             if (n_obj->o_group) {
        !           684:                 for(o_item = th->t_pack; o_item != NULL; o_item = next(o_item)){
        !           685:                     o_obj = OBJPTR(o_item);
        !           686:                     if (o_obj->o_group == n_obj->o_group) {
        !           687:                         o_obj->o_count += n_obj->o_count;
        !           688:                         o_discard(n_item);
        !           689:                         break;
        !           690:                     }
        !           691:                 }
        !           692:             }
        !           693:             if (o_item == NULL) {       /* didn't find it */
        !           694:                 attach(th->t_pack, n_item);
        !           695:             }
        !           696:         }
        !           697:
        !           698:         /* If there was anything here, we may have to update the screen */
        !           699:         if (item_count) {
        !           700:             if (cansee(ch_ret.y, ch_ret.x))
        !           701:                 mvwaddch(cw, ch_ret.y, ch_ret.x, mvinch(ch_ret.y, ch_ret.x));
        !           702:             updpack(TRUE, th); /* Update the monster's encumberance, too */
        !           703:         }
        !           704:     }
        !           705:
        !           706:     rch = mvwinch(stdscr, old_pos.y, old_pos.x);
        !           707:     if (th->t_oldch == floor && rch != floor && !isatrap(rch))
        !           708:         mvwaddch(cw, old_pos.y, old_pos.x, rch);
        !           709:     else
        !           710:         mvwaddch(cw, old_pos.y, old_pos.x, th->t_oldch);
        !           711:     sch = mvwinch(cw, ch_ret.y, ch_ret.x); /* What player sees */
        !           712:     rch = mvwinch(stdscr, ch_ret.y, ch_ret.x); /* What's really there */
        !           713:
        !           714:     /* If we have a tunneling monster, it may be making a tunnel */
        !           715:     if (on(*th, CANTUNNEL)      &&
        !           716:         (rch==SECRETDOOR || rch==WALL || rch==VERTWALL || rch==HORZWALL)) {
        !           717:         unsigned char nch;       /* The new look to the tunnel */
        !           718:
        !           719:         if (rch == WALL && levtype == OUTSIDE) nch = FLOOR;
        !           720:         else if (rch == WALL) nch = PASSAGE;
        !           721:         else if (levtype == MAZELEV || levtype == OUTSIDE) nch = FLOOR;
        !           722:         else nch = DOOR;
        !           723:         addch(nch);
        !           724:
        !           725:         if (cansee(ch_ret.y, ch_ret.x)) sch = nch; /* Can player see this? */
        !           726:
        !           727:         /* Does this make a new exit? */
        !           728:         if (rch == VERTWALL || rch == HORZWALL) {
        !           729:             struct linked_list *newroom;
        !           730:             coord *exit;
        !           731:
        !           732:             newroom = new_item(sizeof(coord));
        !           733:             exit = DOORPTR(newroom);
        !           734:             *exit = ch_ret;
        !           735:             attach(new_room->r_exit, newroom);
        !           736:         }
        !           737:     }
        !           738:
        !           739:     /* Mark if the monster is inside a wall */
        !           740:     if (isrock(mvinch(ch_ret.y, ch_ret.x))) turn_on(*th, ISINWALL);
        !           741:     else turn_off(*th, ISINWALL);
        !           742:
        !           743:     /* If the monster can illuminate rooms, check for a change */
        !           744:     if (on(*th, HASFIRE)) {
        !           745:         register struct linked_list *fire_item;
        !           746:
        !           747:         /* Is monster entering a room? */
        !           748:         if (orig_rer != new_room && new_room != NULL) {
        !           749:             fire_item = creat_item();   /* Get an item-only structure */
        !           750:             ldata(fire_item) = (char *) th;
        !           751:
        !           752:             attach(new_room->r_fires, fire_item);
        !           753:             new_room->r_flags |= HASFIRE;
        !           754:
        !           755:             if (cansee(ch_ret.y, ch_ret.x) && next(new_room->r_fires) == NULL)
        !           756:                 light(&hero);
        !           757:         }
        !           758:
        !           759:         /* Is monster leaving a room? */
        !           760:         if (orig_rer != new_room && orig_rer != NULL) {
        !           761:             /* Find the bugger in the list and delete him */
        !           762:             for (fire_item = orig_rer->r_fires; fire_item != NULL;
        !           763:                  fire_item = next(fire_item)) {
        !           764:                 if (THINGPTR(fire_item) == th)  {       /* Found him! */
        !           765:                     detach(orig_rer->r_fires, fire_item);
        !           766:                     destroy_item(fire_item);
        !           767:                     if (orig_rer->r_fires == NULL) {
        !           768:                         orig_rer->r_flags &= ~HASFIRE;
        !           769:                         if (cansee(old_pos.y, old_pos.x))
        !           770:                             light(&old_pos);
        !           771:                     }
        !           772:                     break;
        !           773:                 }
        !           774:             }
        !           775:         }
        !           776:     }
        !           777:
        !           778:     /* If monster is entering player's room and player can see it,
        !           779:      * stop the player's running.
        !           780:      */
        !           781:     if (new_room != orig_rer && new_room != NULL  &&
        !           782:         new_room == roomin(th->t_dest) && cansee(unc(ch_ret))    &&
        !           783:         (off(*th, ISINVIS)     || on(player, CANSEE)) &&
        !           784:         (off(*th, ISSHADOW)    || on(player, CANSEE)) &&
        !           785:         (off(*th, CANSURPRISE) || ISWEARING(R_ALERT))) {
        !           786:                 running = FALSE;
        !           787:                 if (fight_flush) flushinp();
        !           788:     }
        !           789:
        !           790:     th->t_oldch = sch;
        !           791:
        !           792:     /* Let's display those creatures that we can see. */
        !           793:     if (cansee(unc(ch_ret)) &&
        !           794:         off(*th, ISINWALL) &&
        !           795:         !invisible(th))
        !           796:         mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type);
        !           797:
        !           798:     /* Record monster's last position (if new one is different) */
        !           799:     if (!ce(ch_ret, old_pos)) th->t_oldpos = old_pos;
        !           800:
        !           801:     /* If the monster is on a trap, trap it */
        !           802:     sch = mvinch(ch_ret.y, ch_ret.x);
        !           803:     if (isatrap(sch)) {
        !           804:         if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch;
        !           805:         be_trapped(th, &ch_ret);
        !           806:     }
        !           807: }
        !           808:
        !           809: /*
        !           810:  * Get_hurl returns the weapon that the monster will "throw" if he has one
        !           811:  */
        !           812:
        !           813: struct linked_list *
        !           814: get_hurl(struct thing *tp)
        !           815: {
        !           816:     struct linked_list *arrow=NULL, *bolt=NULL, *rock=NULL,
        !           817:         *spear = NULL, *dagger=NULL, *dart=NULL, *aklad=NULL;
        !           818:     register struct linked_list *pitem;
        !           819:     register struct object *obj;
        !           820:     bool bow=FALSE, crossbow=FALSE, sling=FALSE;
        !           821:
        !           822:     for (pitem=tp->t_pack; pitem; pitem=next(pitem)) {
        !           823:         obj = OBJPTR(pitem);
        !           824:         if (obj->o_type == WEAPON)
        !           825:             switch (obj->o_which) {
        !           826:                 case BOW:       bow = TRUE;
        !           827:                 when CROSSBOW:  crossbow = TRUE;
        !           828:                 when SLING:     sling = TRUE;
        !           829:                 when ROCK:      rock = pitem;
        !           830:                 when ARROW:     arrow = pitem;
        !           831:                 when BOLT:      bolt = pitem;
        !           832:                 when SPEAR:     spear = pitem;
        !           833:                 when DAGGER:
        !           834:                     /* Don't throw the dagger if it's our last one */
        !           835:                     if (obj->o_count > 1) dagger = pitem;
        !           836:                 when DART:      dart = pitem;
        !           837:             }
        !           838:         else if (obj->o_type == RELIC &&
        !           839:                  obj->o_which == AXE_AKLAD)
        !           840:                     aklad = pitem;
        !           841:     }
        !           842:
        !           843:     /* Do we have that all-powerful Aklad Axe? */
        !           844:     if (aklad) return(aklad);
        !           845:
        !           846:     /* Use crossbow bolt if possible */
        !           847:     if (crossbow && bolt) return(bolt);
        !           848:     if (bow && arrow) return(arrow);
        !           849:     if (spear) return(spear);
        !           850:     if (dagger) return(dagger);
        !           851:     if (sling && rock) return(rock);
        !           852:     if (dart) return(dart);
        !           853:     return(NULL);
        !           854: }
        !           855:
        !           856: /*
        !           857:  * runto:
        !           858:  *      Set a monster running after something
        !           859:  */
        !           860:
        !           861: void
        !           862: runto(struct thing *runner, coord *spot)
        !           863: {
        !           864:     if (on(*runner, ISSTONE))
        !           865:         return;
        !           866:
        !           867:     /* If we are chasing a new creature, forget about thrown weapons */
        !           868:     if (runner->t_dest && !ce(*runner->t_dest, *spot)) runner->t_wasshot=FALSE;
        !           869:
        !           870:     /*
        !           871:      * Start the beastie running
        !           872:      */
        !           873:     runner->t_dest = spot;
        !           874:     turn_on(*runner, ISRUN);
        !           875:     turn_off(*runner, ISDISGUISE);
        !           876: }
        !           877:
        !           878: /*
        !           879:  * straight_shot:
        !           880:  *      See if there is a straight line of sight between the two
        !           881:  *      given coordinates.  If shooting is not NULL, it is a pointer
        !           882:  *      to a structure which should be filled with the direction
        !           883:  *      to shoot (if there is a line of sight).  If shooting, monsters
        !           884:  *      get in the way.  Otherwise, they do not.
        !           885:  */
        !           886:
        !           887: bool
        !           888: straight_shot(int ery, int erx, int eey, int eex, coord *shooting)
        !           889: {
        !           890:     register int dy, dx;        /* Deltas */
        !           891:     unsigned char ch;
        !           892:
        !           893:     /* Does the monster have a straight shot at prey */
        !           894:     if ((ery != eey) && (erx != eex) &&
        !           895:         (abs(ery - eey) != abs(erx - eex))) return(FALSE);
        !           896:
        !           897:     /* Get the direction to shoot */
        !           898:     if (eey > ery) dy = 1;
        !           899:     else if (eey == ery) dy = 0;
        !           900:     else dy = -1;
        !           901:
        !           902:     if (eex > erx) dx = 1;
        !           903:     else if (eex == erx) dx = 0;
        !           904:     else dx = -1;
        !           905:
        !           906:     /* Make sure we have free area all the way to the player */
        !           907:     ery += dy;
        !           908:     erx += dx;
        !           909:     while ((ery != eey) || (erx != eex)) {
        !           910:         switch (ch = winat(ery, erx)) {
        !           911:             case VERTWALL:
        !           912:             case HORZWALL:
        !           913:             case WALL:
        !           914:             case DOOR:
        !           915:             case SECRETDOOR:
        !           916:             case FOREST:
        !           917:                 return(FALSE);
        !           918:             default:
        !           919:                 if (shooting && isalpha(ch)) return(FALSE);
        !           920:         }
        !           921:         ery += dy;
        !           922:         erx += dx;
        !           923:     }
        !           924:
        !           925:     if (shooting) {     /* If we are shooting -- put in the directions */
        !           926:         shooting->y = dy;
        !           927:         shooting->x = dx;
        !           928:     }
        !           929:     return(TRUE);
        !           930: }
        !           931:

CVSweb