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

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

1.1     ! rubenllo    1: /*
        !             2:     chase.c  -  Code for one creature to chase another
        !             3:
        !             4:     UltraRogue: The Ultimate Adventure in the Dungeons of Doom
        !             5:     Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
        !             6:     All rights reserved.
        !             7:
        !             8:     Based on "Advanced Rogue"
        !             9:     Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
        !            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 <stdlib.h>
        !            20: #include <ctype.h>
        !            21: #include <limits.h>
        !            22: #include "rogue.h"
        !            23:
        !            24: /*
        !            25:     do_chase()
        !            26:         Make one thing chase another.
        !            27: */
        !            28:
        !            29: void
        !            30: do_chase(struct thing *th, int flee)
        !            31: {
        !            32:     struct room    *rer;        /* room of chaser */
        !            33:     struct room    *ree;        /* room of chasee */
        !            34:     struct room    *old_room;   /* old room of monster */
        !            35:     struct room    *new_room;   /* new room of monster */
        !            36:
        !            37:     int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN;
        !            38:
        !            39:     int last_door = -1;     /* Door we just came from */
        !            40:     int stoprun = FALSE;    /* TRUE means we are there */
        !            41:     int rundoor;            /* TRUE means run to a door */
        !            42:     int hit_bad = FALSE;    /* TRUE means hit bad monster */
        !            43:     int mon_attack;         /* TRUE means find a monster to hit */
        !            44:
        !            45:     char    sch;
        !            46:     struct linked_list *item;
        !            47:     coord   this;           /* Temporary destination for chaser */
        !            48:
        !            49:     if (!th->t_ischasing)
        !            50:         return;
        !            51:
        !            52:     /* Make sure the monster can move */
        !            53:
        !            54:     if (th->t_no_move != 0)
        !            55:     {
        !            56:         th->t_no_move--;
        !            57:         return;
        !            58:     }
        !            59:
        !            60:     /*
        !            61:      * Bad monsters check for a good monster to hit, friendly monsters
        !            62:      * check for a bad monster to hit.
        !            63:      */
        !            64:
        !            65:     mon_attack = FALSE;
        !            66:
        !            67:     if (good_monster(*th))
        !            68:     {
        !            69:         hit_bad = TRUE;
        !            70:         mon_attack = TRUE;
        !            71:     }
        !            72:     else if (on(*th, ISMEAN))
        !            73:     {
        !            74:         hit_bad = FALSE;
        !            75:         mon_attack = TRUE;
        !            76:     }
        !            77:
        !            78:     if (mon_attack)
        !            79:     {
        !            80:         struct linked_list  *mon_to_hit;
        !            81:
        !            82:        mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad);
        !            83:
        !            84:         if (mon_to_hit)
        !            85:         {
        !            86:             mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN);
        !            87:             return;
        !            88:         }
        !            89:     }
        !            90:
        !            91:     /* no nearby monster to hit */
        !            92:
        !            93:     rer = roomin(th->t_pos);            /* Find room of chaser */
        !            94:     ree = roomin(th->t_chasee->t_pos);  /* Find room of chasee */
        !            95:
        !            96:     /*
        !            97:      * We don't count doors as inside rooms for this routine
        !            98:      */
        !            99:
        !           100:     if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR)
        !           101:         rer = NULL;
        !           102:
        !           103:     this = th->t_chasee->t_pos;
        !           104:
        !           105:     /*
        !           106:      * If we are not in a corridor and not a phasing monster, then if we
        !           107:      * are running after the player, we run to a door if he is not in the
        !           108:      * same room. If we are fleeing, we run to a door if he IS in the
        !           109:      * same room.  Note:  We don't bother with doors in mazes. Phasing
        !           110:      * monsters don't need to look for doors. There are no doors in mazes
        !           111:      * and throne rooms.
        !           112:      */
        !           113:
        !           114:     if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL))
        !           115:     {
        !           116:         if (flee)
        !           117:             rundoor = (rer == ree);
        !           118:         else
        !           119:             rundoor = (rer != ree);
        !           120:     }
        !           121:     else
        !           122:         rundoor = FALSE;
        !           123:
        !           124:     if (rundoor)
        !           125:     {
        !           126:         coord   d_exit;   /* A particular door */
        !           127:         int exity, exitx;   /* Door's coordinates */
        !           128:
        !           129:         if (th->t_doorgoal != -1)
        !           130:         { /* Do we already have the goal? */
        !           131:             this = rer->r_exit[th->t_doorgoal];
        !           132:             dist = 0;   /* Indicate that we have our door */
        !           133:         }
        !           134:         else
        !           135:             for (i = 0; i < rer->r_nexits; i++)
        !           136:             {   /* Loop through doors */
        !           137:                 d_exit = rer->r_exit[i];
        !           138:                 exity = d_exit.y;
        !           139:                 exitx = d_exit.x;
        !           140:
        !           141:                 /* Avoid secret doors */
        !           142:                 if (mvwinch(stdscr, exity, exitx) == DOOR)
        !           143:                 {
        !           144:                     /* Were we just on this door? */
        !           145:                     if (ce(d_exit, th->t_oldpos))
        !           146:                         last_door = i;
        !           147:                     else
        !           148:                     {
        !           149:                         dist = DISTANCE(th->t_chasee->t_pos, d_exit);
        !           150:
        !           151:                         /*
        !           152:                          * If fleeing, we want to
        !           153:                          * maximize distance from
        !           154:                          * door to what we flee, and
        !           155:                          * minimize distance from
        !           156:                          * door to us.
        !           157:                          */
        !           158:
        !           159:                         if (flee)
        !           160:                             dist-=DISTANCE(th->t_pos,d_exit);
        !           161:
        !           162:                         /*
        !           163:                          * Maximize distance if
        !           164:                          * fleeing, otherwise
        !           165:                          * minimize it
        !           166:                          */
        !           167:
        !           168:                         if ((flee && (dist > maxdist)) ||
        !           169:                             (!flee && (dist < mindist)))
        !           170:                         {
        !           171:                             th->t_doorgoal = i; /* Use this door */
        !           172:                             this = d_exit;
        !           173:                             mindist = maxdist = dist;
        !           174:                         }
        !           175:                     }
        !           176:                 }
        !           177:             }
        !           178:
        !           179:         /* Could we not find a door? */
        !           180:         if (dist == INT_MIN)
        !           181:         {
        !           182:             /* If we were on a door, go ahead and use it */
        !           183:             if (last_door != -1)
        !           184:             {
        !           185:                 th->t_doorgoal = last_door;
        !           186:                 this = th->t_oldpos;
        !           187:                 dist = 0;   /* Indicate that we found a door */
        !           188:             }
        !           189:         }
        !           190:
        !           191:         /* Indicate that we do not want to flee from the door */
        !           192:         if (dist != INT_MIN)
        !           193:             flee = FALSE;
        !           194:     }
        !           195:     else
        !           196:         th->t_doorgoal = -1;    /* Not going to any door */
        !           197:
        !           198:     /*
        !           199:      * this now contains what we want to run to this time so we run to
        !           200:      * it.  If we hit it we either want to fight it or stop running
        !           201:      */
        !           202:
        !           203:     if (!chase(th, &this, flee))
        !           204:     {
        !           205:         if (ce(th->t_nxtpos, hero))
        !           206:         {
        !           207:             /* merchants try to sell something */
        !           208:
        !           209:             if (on(*th, CANSELL))
        !           210:             {
        !           211:                 sell(th);
        !           212:                 return;
        !           213:             }
        !           214:             else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED)
        !           215:                     && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2))))
        !           216:                     attack(th, pick_weap(th), FALSE);
        !           217:                 return;
        !           218:         }
        !           219:         else if (on(*th, NOMOVE))
        !           220:             stoprun = TRUE;
        !           221:     }
        !           222:
        !           223:     if (!curr_mons)
        !           224:         return;     /* Did monster get itself killed? */
        !           225:
        !           226:     if (on(*th, NOMOVE))
        !           227:         return;
        !           228:
        !           229:     /* If we have a scavenger, it can pick something up */
        !           230:
        !           231:     if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL)
        !           232:     {
        !           233:                struct linked_list *node, *top = item;
        !           234:         struct object *obt;
        !           235:
        !           236:                while(top)
        !           237:                {
        !           238:                        /* grab all objects that qualify */
        !           239:
        !           240:                        struct object *obj = OBJPTR(item);
        !           241:
        !           242:                        obt = OBJPTR(top);
        !           243:                        node = obt->next_obj;
        !           244:
        !           245:                        if (on(*th, ISSCAVENGE) ||
        !           246:                 ((on(*th, CANWIELD) || on(*th, CANSHOOT)) &&
        !           247:                 (obj->o_type == WEAPON || obj->o_type == ARMOR)) ||
        !           248:                 (on(*th, CANCAST) && is_magic(obj)))
        !           249:                        {
        !           250:                 rem_obj(top, FALSE);
        !           251:                 attach(th->t_pack, top);
        !           252:             }
        !           253:
        !           254:                        top = node;
        !           255:                }
        !           256:
        !           257:                light(&hero);
        !           258:     }
        !           259:
        !           260:     mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch);
        !           261:     sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) );
        !           262:
        !           263:     /* Get old and new room of monster */
        !           264:     old_room = roomin(th->t_pos);
        !           265:     new_room = roomin(th->t_nxtpos);
        !           266:
        !           267:     /* If the monster can illuminate rooms, check for a change */
        !           268:     if (on(*th, HASFIRE))
        !           269:     {
        !           270:         /* Is monster entering a room? */
        !           271:         if (old_room != new_room && new_room != NULL)
        !           272:         {
        !           273:             new_room->r_flags |= HASFIRE;
        !           274:             new_room->r_fires++;
        !           275:             if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1)
        !           276:                 light(&hero);
        !           277:         }
        !           278:
        !           279:         /* Is monster leaving a room? */
        !           280:         if (old_room != new_room && old_room != NULL)
        !           281:         {
        !           282:             if (--(old_room->r_fires) <= 0)
        !           283:             {
        !           284:                 old_room->r_flags &= ~HASFIRE;
        !           285:                 if (cansee(th->t_pos.y, th->t_pos.x))
        !           286:                     light(&th->t_pos);
        !           287:             }
        !           288:         }
        !           289:     }
        !           290:
        !           291:     /*
        !           292:      * If monster is entering player's room and player can see it, stop
        !           293:      * the player's running.
        !           294:      */
        !           295:
        !           296:     if (new_room != old_room && new_room != NULL &&
        !           297:         new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
        !           298:         (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) ||
        !           299:          on(player, CANSEE)) && off(*th, CANSURPRISE))
        !           300:         running = FALSE;
        !           301:
        !           302:     if (rer != NULL && (rer->r_flags & ISDARK) &&
        !           303:         !(rer->r_flags & HASFIRE) && sch == FLOOR &&
        !           304:          DISTANCE(th->t_nxtpos, th->t_pos) < see_dist &&
        !           305:         off(player, ISBLIND))
        !           306:         th->t_oldch = ' ';
        !           307:     else
        !           308:         th->t_oldch = sch;
        !           309:
        !           310:     if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) &&
        !           311:       off(*th, ISINWALL) &&
        !           312:       ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) ||
        !           313:       on(player, CANSEE)) &&
        !           314:       off(*th, CANSURPRISE))
        !           315:         mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
        !           316:
        !           317:     mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' ');
        !           318:     mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type);
        !           319:
        !           320:     /* Record monster's last position (if new one is different) */
        !           321:
        !           322:     if (!ce(th->t_nxtpos, th->t_pos))
        !           323:         th->t_oldpos = th->t_pos;
        !           324:
        !           325:     th->t_pos = th->t_nxtpos; /* Mark the monster's new position */
        !           326:
        !           327:     /* If the monster is on a trap, trap it */
        !           328:
        !           329:     sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x));
        !           330:
        !           331:     if (isatrap(sch))
        !           332:     {
        !           333:         debug("Monster trapped by %c.", sch);
        !           334:
        !           335:         if (cansee(th->t_nxtpos.y, th->t_nxtpos.x))
        !           336:             th->t_oldch = sch;
        !           337:
        !           338:         be_trapped(th, th->t_nxtpos);
        !           339:     }
        !           340:
        !           341:     /* And stop running if need be */
        !           342:
        !           343:     if (stoprun && ce(th->t_pos, th->t_chasee->t_pos))
        !           344:     {
        !           345:         th->t_ischasing = FALSE;
        !           346:         turn_off(*th, ISRUN);
        !           347:     }
        !           348: }
        !           349:
        !           350: /*
        !           351:     chase_it()
        !           352:         Set a monster running after something or stop it from running (for
        !           353:         when it dies)
        !           354: */
        !           355:
        !           356: void
        !           357: chase_it(coord *runner, struct thing *th)
        !           358: {
        !           359:     struct linked_list  *item;
        !           360:     struct thing    *tp;
        !           361:
        !           362:     /* If we couldn't find him, something is funny */
        !           363:
        !           364:     if ((item = find_mons(runner->y, runner->x)) == NULL)
        !           365:     {
        !           366:         debug("CHASER '%s'", unctrl(winat(runner->y, runner->x)));
        !           367:         return;
        !           368:     }
        !           369:
        !           370:     tp = THINGPTR(item);
        !           371:
        !           372:     /* Start the beastie running */
        !           373:
        !           374:     tp->t_ischasing = TRUE;
        !           375:     tp->t_chasee    = th;
        !           376:
        !           377:     turn_on(*tp, ISRUN);
        !           378:     turn_off(*tp, ISDISGUISE);
        !           379:
        !           380:     return;
        !           381: }
        !           382:
        !           383: /*
        !           384:     chase()
        !           385:         Find the spot for the chaser(er) to move closer to the chasee(ee).
        !           386:         Returns TRUE if we want to keep on chasing later, FALSE if we reach the
        !           387:         goal.
        !           388: */
        !           389:
        !           390: int
        !           391: chase(struct thing *tp, coord *ee, int flee)
        !           392: {
        !           393:     int x, y;
        !           394:     int dist, thisdist, monst_dist = INT_MAX;
        !           395:     struct linked_list  *weapon;
        !           396:     coord   *er = &tp->t_pos;
        !           397:     coord shoot;
        !           398:     coord *shootit_dir = NULL;
        !           399:     int ch;
        !           400:     char   mch;
        !           401:     int    next_player = FALSE;
        !           402:
        !           403:     /* Take care of shooting directions */
        !           404:
        !           405:     if (on(*tp, CANBREATHE) || on(*tp, CANSHOOT) || on(*tp, CANCAST))
        !           406:     {
        !           407:         if (good_monster(*tp))
        !           408:         {
        !           409:             shootit_dir = find_shoot(tp, &shoot); /* find a mean monster */
        !           410:
        !           411:             if (wizard && shootit_dir)
        !           412:                 msg("Found monster to attack towards (%d,%d).",
        !           413:                     shootit_dir->x, shootit_dir->y);
        !           414:         }
        !           415:         else
        !           416:             shootit_dir = can_shoot(er, ee, &shoot);  /* shoot hero */
        !           417:     }
        !           418:
        !           419:     /*
        !           420:      * If the thing is confused, let it move randomly. Some monsters are
        !           421:      * slightly confused all of the time.
        !           422:      */
        !           423:
        !           424:     if ((on(*tp, ISHUH) && rnd(10) < 8) ||
        !           425:         ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) ||
        !           426:         (on(player, ISINVIS) && off(*tp, CANSEE)))
        !           427:     {   /* Player is invisible */
        !           428:
        !           429:         /* get a valid random move */
        !           430:
        !           431:         tp->t_nxtpos = rndmove(tp);
        !           432:
        !           433:         dist = DISTANCE(tp->t_nxtpos, *ee);
        !           434:
        !           435:         if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */
        !           436:             turn_off(*tp, ISHUH);
        !           437:
        !           438:         /*
        !           439:          * check to see if random move takes creature away from
        !           440:          * player if it does then turn off ISHELD
        !           441:          */
        !           442:
        !           443:         if (dist > 1 && on(*tp, DIDHOLD))
        !           444:         {
        !           445:             turn_off(*tp, DIDHOLD);
        !           446:             turn_on(*tp, CANHOLD);
        !           447:
        !           448:             if (--hold_count == 0)
        !           449:                 turn_off(player, ISHELD);
        !           450:         }
        !           451:     } /* If we can breathe, we may do so */
        !           452:     else if (on(*tp, CANBREATHE) && (shootit_dir) && (rnd(100) < 67) &&
        !           453:          (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) &&
        !           454:          (DISTANCE(*er, *ee) < BOLT_LENGTH * BOLT_LENGTH))
        !           455:     {
        !           456:         int   chance;
        !           457:         char    *breath;
        !           458:
        !           459:         /* Will it breathe at random */
        !           460:
        !           461:         if (on(*tp, CANBRANDOM))
        !           462:         {
        !           463:             if (rnd(level / 20) == 0 && tp->t_index != nummonst + 1
        !           464:                 && !(good_monster(*tp)))
        !           465:                 turn_off(*tp, CANBRANDOM);
        !           466:
        !           467:             /* Select type of breath */
        !           468:
        !           469:             chance = rnd(100);
        !           470:
        !           471:             if (chance < 11)
        !           472:                 breath = "acid";
        !           473:             else if (chance < 22)
        !           474:                 breath = "flame";
        !           475:             else if (chance < 33)
        !           476:                 breath = "lightning bolt";
        !           477:             else if (chance < 44)
        !           478:                 breath = "chlorine gas";
        !           479:             else if (chance < 55)
        !           480:                 breath = "ice";
        !           481:             else if (chance < 66)
        !           482:                 breath = "nerve gas";
        !           483:             else if (chance < 77)
        !           484:                 breath = "sleeping gas";
        !           485:             else if (chance < 88)
        !           486:                 breath = "slow gas";
        !           487:             else
        !           488:                 breath = "fear gas";
        !           489:         } /* Or can it breathe acid? */
        !           490:         else if (on(*tp, CANBACID))
        !           491:         {
        !           492:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           493:                 turn_off(*tp, CANBACID);
        !           494:
        !           495:             breath = "acid";
        !           496:         } /* Or can it breathe fire */
        !           497:         else if (on(*tp, CANBFIRE))
        !           498:         {
        !           499:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           500:                 turn_off(*tp, CANBFIRE);
        !           501:
        !           502:             breath = "flame";
        !           503:         } /* Or can it breathe electricity? */
        !           504:         else if (on(*tp, CANBBOLT))
        !           505:         {
        !           506:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           507:                 turn_off(*tp, CANBBOLT);
        !           508:
        !           509:             breath = "lightning bolt";
        !           510:         } /* Or can it breathe gas? */
        !           511:         else if (on(*tp, CANBGAS))
        !           512:         {
        !           513:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           514:                 turn_off(*tp, CANBGAS);
        !           515:
        !           516:             breath = "chlorine gas";
        !           517:         } /* Or can it breathe ice? */
        !           518:         else if (on(*tp, CANBICE))
        !           519:         {
        !           520:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           521:                 turn_off(*tp, CANBICE);
        !           522:
        !           523:             breath = "ice";
        !           524:         }
        !           525:         else if (on(*tp, CANBPGAS))
        !           526:         {
        !           527:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           528:                 turn_off(*tp, CANBPGAS);
        !           529:
        !           530:             breath = "nerve gas";
        !           531:         }
        !           532:         else if (on(*tp, CANBSGAS))
        !           533:         {
        !           534:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           535:                 turn_off(*tp, CANBSGAS);
        !           536:
        !           537:             breath = "sleeping gas";
        !           538:         }
        !           539:         else if (on(*tp, CANBSLGAS))
        !           540:         {
        !           541:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           542:                 turn_off(*tp, CANBSLGAS);
        !           543:
        !           544:             breath = "slow gas";
        !           545:         }
        !           546:         else
        !           547:         {
        !           548:             if (!good_monster(*tp) && rnd(level / 15) == 0)
        !           549:                 turn_off(*tp, CANBFGAS);
        !           550:
        !           551:             breath = "fear gas";
        !           552:         }
        !           553:
        !           554:         shoot_bolt(tp, *er, *shootit_dir, (tp == THINGPTR(fam_ptr)),
        !           555:                tp->t_index, breath, roll(tp->t_stats.s_lvl, 6));
        !           556:
        !           557:         tp->t_nxtpos = *er;
        !           558:
        !           559:         dist = DISTANCE(tp->t_nxtpos, *ee);
        !           560:
        !           561:         if (!curr_mons)
        !           562:             return (TRUE);
        !           563:     }
        !           564:     else if (shootit_dir && on(*tp, CANCAST) &&
        !           565:          (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
        !           566:     {
        !           567:         /*
        !           568:             If we can cast spells we might do so - even if adjacent fleeing
        !           569:             monsters are restricted to certain spells
        !           570:         */
        !           571:
        !           572:         incant(tp, *shootit_dir);
        !           573:         tp->t_nxtpos = *er;
        !           574:         dist = DISTANCE(tp->t_nxtpos, *ee);
        !           575:     }
        !           576:     else if (shootit_dir && on(*tp, CANSHOOT))
        !           577:     {
        !           578:        weapon = get_hurl(tp);
        !           579:
        !           580:        if (weapon &&
        !           581:          (off(*tp, ISFLEE) || rnd(DISTANCE(*er, *ee)) > 2) &&
        !           582:          (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)))
        !           583:        {
        !           584:            /*
        !           585:                Should we shoot or throw something? fleeing monsters
        !           586:                may to shoot anyway if far enough away
        !           587:            */
        !           588:
        !           589:            missile(shootit_dir->y, shootit_dir->x, weapon, tp);
        !           590:            tp->t_nxtpos = *er;
        !           591:            dist = DISTANCE(tp->t_nxtpos, *ee);
        !           592:        }
        !           593:     }
        !           594:     else
        !           595:     {
        !           596:         /*
        !           597:             Otherwise, find the empty spot next to the chaser that is closest
        !           598:             to the chasee.
        !           599:         */
        !           600:         int ey, ex;
        !           601:         struct room *rer, *ree;
        !           602:         int dist_to_old = INT_MIN;   /* Dist from goal to old position */
        !           603:
        !           604:         /* Get rooms */
        !           605:         rer = roomin(*er);
        !           606:         ree = roomin(*ee);
        !           607:
        !           608:         /*
        !           609:          * This will eventually hold where we move to get closer. If
        !           610:          * we can't find an empty spot, we stay where we are.
        !           611:          */
        !           612:
        !           613:         dist = flee ? 0 : INT_MAX;
        !           614:         tp->t_nxtpos = *er;
        !           615:
        !           616:         /* Are we at our goal already? */
        !           617:
        !           618:         if (!flee && ce(tp->t_nxtpos, *ee))
        !           619:             return (FALSE);
        !           620:
        !           621:         ey = er->y + 1;
        !           622:         ex = er->x + 1;
        !           623:
        !           624:         for (x = er->x - 1; x <= ex; x++)
        !           625:             for (y = er->y - 1; y <= ey; y++)
        !           626:             {
        !           627:                 coord   tryp; /* test position */
        !           628:
        !           629:                 /* Don't try off the screen */
        !           630:
        !           631:                 if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2))
        !           632:                     continue;
        !           633:
        !           634:                 /*
        !           635:                  * Don't try the player if not going after
        !           636:                  * the player or he's disguised and monster is dumb
        !           637:                  */
        !           638:
        !           639:                 if (((off(*tp, ISFLEE) && !ce(hero, *ee)) ||
        !           640:                      (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6))
        !           641:                      || good_monster(*tp))
        !           642:                     && x == hero.x && y == hero.y)
        !           643:                     continue;
        !           644:
        !           645:                 tryp.x = x;
        !           646:                 tryp.y = y;
        !           647:
        !           648:                 /*
        !           649:                  * Is there a monster on this spot closer to
        !           650:                  * our goal? Don't look in our spot or where
        !           651:                  * we were.
        !           652:                  */
        !           653:
        !           654:                 if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) &&
        !           655:                     isalpha( (mch = CCHAR(mvwinch(mw, y, x))) ) )
        !           656:                 {
        !           657:                     int test_dist;
        !           658:
        !           659:                     test_dist = DISTANCE(tryp,*ee);
        !           660:                     if (test_dist <= 25 &&  /* Let's be fairly close */
        !           661:                         test_dist < monst_dist)
        !           662:                     {
        !           663:
        !           664:                         /* Could we really move there? */
        !           665:
        !           666:                         mvwaddch(mw, y, x, ' '); /* Temp blank monst */
        !           667:
        !           668:                         if (diag_ok(er, &tryp, tp))
        !           669:                             monst_dist = test_dist;
        !           670:
        !           671:                         mvwaddch(mw, y, x, mch);    /* Restore monster */
        !           672:                     }
        !           673:                 }
        !           674:
        !           675:                 if (!diag_ok(er, &tryp, tp))
        !           676:                     continue;
        !           677:
        !           678:                 ch = mvwinch(cw, y, x); /* Screen character */
        !           679:
        !           680:                 /*
        !           681:                  * Stepping on player is NOT okay if we are
        !           682:                  * fleeing
        !           683:                  */
        !           684:
        !           685:                 if (on(*tp, ISFLEE) && (ch == PLAYER))
        !           686:                                    next_player = TRUE;
        !           687:
        !           688:                 if (step_ok(y, x, NOMONST, tp) &&
        !           689:                     (off(*tp, ISFLEE) || ch != PLAYER))
        !           690:                 {
        !           691:
        !           692:                     /*
        !           693:                      * If it is a trap, an intelligent
        !           694:                      * monster may not step on it (unless
        !           695:                      * our hero is on top!)
        !           696:                      */
        !           697:
        !           698:                     if (isatrap(ch))
        !           699:                     {
        !           700:                         if (!(ch == RUSTTRAP) &&
        !           701:                             !(ch == FIRETRAP && on(*tp, NOFIRE)) &&
        !           702:                             rnd(10) < tp->t_stats.s_intel &&
        !           703:                         (y != hero.y || x != hero.x))
        !           704:                             continue;
        !           705:                     }
        !           706:
        !           707:                     /*
        !           708:                      * OK -- this place counts
        !           709:                      */
        !           710:
        !           711:                     thisdist = DISTANCE(tryp, *ee);
        !           712:
        !           713:                     /*
        !           714:                      * Adjust distance if we are being
        !           715:                      * shot at to moving out of line of sight.
        !           716:                      */
        !           717:
        !           718:                     if (tp->t_wasshot && tp->t_stats.s_intel > 5 &&
        !           719:                         ce(hero, *ee))
        !           720:                     {
        !           721:                         /* Move out of line of sight */
        !           722:                         if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL))
        !           723:                         {
        !           724:                             if (flee)
        !           725:                                 thisdist -= SHOTPENALTY;
        !           726:                             else
        !           727:                                 thisdist += SHOTPENALTY;
        !           728:                         }
        !           729:
        !           730:                         /*
        !           731:                          * But do we want to leave
        !           732:                          * the room?
        !           733:                          */
        !           734:                         else if (rer && rer == ree && ch == DOOR)
        !           735:                             thisdist += DOORPENALTY;
        !           736:                     }
        !           737:
        !           738:                     /*
        !           739:                      * Don't move to the last position if
        !           740:                      * we can help it
        !           741:                      */
        !           742:
        !           743:                     if (ce(tryp, tp->t_oldpos))
        !           744:                         dist_to_old = thisdist;
        !           745:                     else if ((flee && (thisdist > dist)) ||
        !           746:                          (!flee && (thisdist < dist)))
        !           747:                     {
        !           748:                         tp->t_nxtpos = tryp;
        !           749:                         dist = thisdist;
        !           750:                     }
        !           751:                 }
        !           752:             }
        !           753:
        !           754:         /*
        !           755:          * If we are running from the player and he is in our way, go
        !           756:          * ahead and slug him.
        !           757:          */
        !           758:
        !           759:         if (next_player && DISTANCE(*er,*ee) < dist &&
        !           760:             step_ok(tp->t_chasee->t_pos.y, tp->t_chasee->t_pos.x, NOMONST, tp))
        !           761:         {
        !           762:             tp->t_nxtpos = tp->t_chasee->t_pos;    /* Okay to hit player */
        !           763:             return(FALSE);
        !           764:         }
        !           765:
        !           766:
        !           767:         /*
        !           768:          * If we can't get closer to the player (if that's our goal)
        !           769:          * because other monsters are in the way, just stay put
        !           770:          */
        !           771:
        !           772:         if (!flee && ce(hero, *ee) && monst_dist < INT_MAX &&
        !           773:             DISTANCE(*er, hero) < dist)
        !           774:             tp->t_nxtpos = *er;
        !           775:
        !           776:         /* Do we want to go back to the last position? */
        !           777:         else if (dist_to_old != INT_MIN &&   /* It is possible to move back */
        !           778:              ((flee && dist == 0) ||        /* No other possible moves */
        !           779:               (!flee && dist == INT_MAX)))
        !           780:         {
        !           781:             /* Do we move back or just stay put (default)? */
        !           782:
        !           783:             dist = DISTANCE(*er,*ee); /* Current distance */
        !           784:
        !           785:             if (!flee || (flee && (dist_to_old > dist)))
        !           786:                 tp->t_nxtpos = tp->t_oldpos;
        !           787:         }
        !           788:     }
        !           789:
        !           790:     /* Make sure we have the real distance now */
        !           791:     dist = DISTANCE(tp->t_nxtpos, *ee);
        !           792:
        !           793:     /* Mark monsters in a wall */
        !           794:
        !           795:     switch(mvinch(tp->t_nxtpos.y, tp->t_nxtpos.x))
        !           796:     {
        !           797:         case WALL:
        !           798:         case '-':
        !           799:         case '|':
        !           800:             turn_on(*tp, ISINWALL);
        !           801:             break;
        !           802:         default:
        !           803:             turn_off(*tp, ISINWALL);
        !           804:     }
        !           805:
        !           806:     if (off(*tp, ISFLEE) &&
        !           807:         !(!SAME_POS((tp->t_chasee->t_pos),hero) || off(player, ISINWALL) || on(*tp, CANINWALL)))
        !           808:         return(dist != 0);
        !           809:     else /* May actually hit here from a confused move */
        !           810:         return(!ce(tp->t_nxtpos, hero));
        !           811: }
        !           812:
        !           813: /*
        !           814:     roomin(coord *cp)
        !           815:
        !           816:         Find what room some coordinates are in.
        !           817:         NULL means they aren't in any room.
        !           818: */
        !           819:
        !           820: struct room *
        !           821: roomin(coord cp)
        !           822: {
        !           823:     struct room *rp;
        !           824:     int i;
        !           825:
        !           826:     for (i = 0; i < MAXROOMS; i++)
        !           827:     {
        !           828:         rp = &rooms[i];
        !           829:
        !           830:         if ((cp.x <= (rp->r_pos.x + (rp->r_max.x - 1))) &&
        !           831:             (cp.y <= (rp->r_pos.y + (rp->r_max.y - 1))) &&
        !           832:             (cp.x >= rp->r_pos.x)                       &&
        !           833:             (cp.y >= rp->r_pos.y))
        !           834:         {
        !           835:             return(rp);
        !           836:         }
        !           837:     }
        !           838:
        !           839:     return(NULL);
        !           840: }
        !           841:
        !           842: /*
        !           843:  * find_mons: Find the monster from his corrdinates
        !           844:  */
        !           845:
        !           846: struct linked_list  *
        !           847: find_mons(int y, int x)
        !           848: {
        !           849:     struct linked_list  *item;
        !           850:
        !           851:     for (item = mlist; item != NULL; item = next(item))
        !           852:     {
        !           853:         struct thing *th = THINGPTR(item);
        !           854:
        !           855:         if (th->t_pos.y == y && th->t_pos.x == x)
        !           856:             return item;
        !           857:     }
        !           858:     return NULL;
        !           859: }
        !           860:
        !           861: /*
        !           862:  * Find an unfriendly monster around us to hit
        !           863:  */
        !           864:
        !           865: struct linked_list  *
        !           866: f_mons_a(int y, int x, int hit_bad)
        !           867: {
        !           868:     int row, col;
        !           869:     struct linked_list  *item;
        !           870:     struct thing    *tp;
        !           871:
        !           872:     for (row = x - 1; row <= x + 1; row++)
        !           873:         for (col = y - 1; col <= y + 1; col++)
        !           874:             if (row == x && col == y)
        !           875:                 continue;
        !           876:             else if (col > 0 && row > 0 &&
        !           877:                 isalpha(mvwinch(mw, col, row)) &&
        !           878:                  ((item = find_mons(col, row)) != NULL))
        !           879:             {
        !           880:                 tp = THINGPTR(item);
        !           881:                 if ((good_monster(*tp) && !hit_bad) ||
        !           882:                     (!good_monster(*tp) && hit_bad))
        !           883:                     return (item);
        !           884:             }
        !           885:
        !           886:     return (NULL);
        !           887: }
        !           888:
        !           889:
        !           890: /*
        !           891:     diag_ok()
        !           892:         Check to see if the move is legal if it is diagonal
        !           893: */
        !           894:
        !           895: int
        !           896: diag_ok(coord *sp, coord *ep, struct thing *flgptr)
        !           897: {
        !           898:     if (ep->x == sp->x || ep->y == sp->y)
        !           899:         return TRUE;
        !           900:
        !           901:     return (step_ok(ep->y, sp->x, MONSTOK, flgptr) &&
        !           902:         step_ok(sp->y, ep->x, MONSTOK, flgptr));
        !           903: }
        !           904:
        !           905: /*
        !           906:     cansee()
        !           907:         returns true if the hero can see a certain coordinate.
        !           908: */
        !           909:
        !           910: int
        !           911: cansee(int y, int x)
        !           912: {
        !           913:     struct room *rer;
        !           914:     coord   tp;
        !           915:
        !           916:     if (on(player, ISBLIND))
        !           917:         return FALSE;
        !           918:
        !           919:     tp.y = y;
        !           920:     tp.x = x;
        !           921:     rer = roomin(tp);
        !           922:
        !           923:     /*
        !           924:      * We can only see if the hero in the same room as the coordinate and
        !           925:      * the room is lit or if it is close.
        !           926:      */
        !           927:
        !           928:     return ((rer != NULL &&
        !           929:          rer == roomin(hero) &&
        !           930:          (!(rer->r_flags & ISDARK) || (rer->r_flags & HASFIRE)) &&
        !           931:          (levtype != MAZELEV || /* Maze level needs direct line */
        !           932:           maze_view(tp.y, tp.x))) ||
        !           933:         DISTANCE(tp,hero) < see_dist);
        !           934: }
        !           935:
        !           936: coord   *
        !           937: find_shoot(struct thing *tp, coord *dir)
        !           938: {
        !           939:     struct room *rtp;
        !           940:     int ulx, uly, xmx, ymx, xmon, ymon, tpx, tpy, row, col;
        !           941:     struct linked_list  *mon;
        !           942:     struct thing    *ick;
        !           943:
        !           944:     rtp = roomin(tp->t_pos);   /* Find room of chaser */
        !           945:
        !           946:     if (rtp == NULL)
        !           947:         return NULL;
        !           948:
        !           949:     ulx = rtp->r_pos.x;
        !           950:     uly = rtp->r_pos.y;
        !           951:     xmx = rtp->r_max.x;
        !           952:     ymx = rtp->r_max.y;
        !           953:
        !           954:     tpx = tp->t_pos.x;
        !           955:     tpy = tp->t_pos.y;
        !           956:
        !           957:     for (col = ulx; col < (ulx + xmx); col++)
        !           958:         for (row = uly; row < (uly + ymx); row++)
        !           959:         {
        !           960:             if (row > 0 && col > 0 && isalpha(mvwinch(mw, row, col)))
        !           961:             {
        !           962:                mon = find_mons(row, col);
        !           963:
        !           964:                 if (mon)
        !           965:                 {
        !           966:                     ick = THINGPTR(mon);
        !           967:                     xmon = ick->t_pos.x;
        !           968:                     ymon = ick->t_pos.y;
        !           969:
        !           970:                     if (!(good_monster(*ick)))
        !           971:                     {
        !           972:                         if (straight_shot(tpy, tpx, ymon, xmon, dir))
        !           973:                             return(dir);
        !           974:                     }
        !           975:                 }
        !           976:             }
        !           977:         }
        !           978:
        !           979:     return(NULL);
        !           980: }
        !           981:
        !           982: /*
        !           983:     can_shoot()
        !           984:         determines if the monster (er) has a direct line of shot at the
        !           985:         player (ee).  If so, it returns the direction in which to shoot.
        !           986: */
        !           987:
        !           988: coord *
        !           989: can_shoot(coord *er, coord *ee, coord *dir)
        !           990: {
        !           991:     int ery, erx, eey, eex;
        !           992:
        !           993:     /* Make sure we are chasing the player */
        !           994:
        !           995:     if (!ce((*ee), hero))
        !           996:         return(NULL);
        !           997:
        !           998:     /* They must be in the same room */
        !           999:
        !          1000:     if (roomin(*er) != roomin(hero))
        !          1001:         return(NULL);
        !          1002:
        !          1003:     ery = er->y;
        !          1004:     erx = er->x;
        !          1005:     eey = ee->y;
        !          1006:     eex = ee->x;
        !          1007:
        !          1008:     /* Will shoot unless next to player, then 80% prob will fight */
        !          1009:
        !          1010:     if ((DISTANCE(*er,*ee) < 4) && (rnd(100) < 80))
        !          1011:         return(NULL);
        !          1012:
        !          1013:     /* Do we have a straight shot? */
        !          1014:
        !          1015:     if (!straight_shot(ery, erx, eey, eex, dir))
        !          1016:         return(NULL);
        !          1017:     else
        !          1018:         return(dir);
        !          1019: }
        !          1020:
        !          1021: /*
        !          1022:     straight_shot()
        !          1023:         See if there is a straight line of sight between the two
        !          1024:         given coordinates.  If shooting is not NULL, it is a pointer to a
        !          1025:         structure which should be filled with the direction to shoot (if
        !          1026:         there is a line of sight).  If shooting, monsters get in the way.
        !          1027:         Otherwise, they do not.
        !          1028: */
        !          1029:
        !          1030: int
        !          1031: straight_shot(int ery, int erx, int eey, int eex, coord *dir)
        !          1032: {
        !          1033:     int dy, dx; /* Deltas */
        !          1034:     int ch;
        !          1035:
        !          1036:     /* Does the monster have a straight shot at player */
        !          1037:
        !          1038:     if ((ery != eey) && (erx != eex) &&
        !          1039:         (abs(ery - eey) != abs(erx - eex)))
        !          1040:         return (FALSE);
        !          1041:
        !          1042:     /* Get the direction to shoot */
        !          1043:
        !          1044:     if (eey > ery)
        !          1045:         dy = 1;
        !          1046:     else if (eey == ery)
        !          1047:         dy = 0;
        !          1048:     else
        !          1049:         dy = -1;
        !          1050:
        !          1051:     if (eex > erx)
        !          1052:         dx = 1;
        !          1053:     else if (eex == erx)
        !          1054:         dx = 0;
        !          1055:     else
        !          1056:         dx = -1;
        !          1057:
        !          1058:     /* Make sure we have free area all the way to the player */
        !          1059:
        !          1060:     ery += dy;
        !          1061:     erx += dx;
        !          1062:
        !          1063:     while ((ery != eey) || (erx != eex))
        !          1064:     {
        !          1065:         switch(ch = winat(ery, erx))
        !          1066:         {
        !          1067:             case '|':
        !          1068:             case '-':
        !          1069:             case WALL:
        !          1070:             case DOOR:
        !          1071:             case SECRETDOOR:
        !          1072:                 return(FALSE);
        !          1073:             default:
        !          1074:                 if (dir && isalpha(ch))
        !          1075:                     return(FALSE);
        !          1076:         }
        !          1077:
        !          1078:         ery += dy;
        !          1079:         erx += dx;
        !          1080:     }
        !          1081:
        !          1082:     if (dir)
        !          1083:     {     /* If we are shooting -- put in the directions */
        !          1084:         dir->y = dy;
        !          1085:         dir->x = dx;
        !          1086:     }
        !          1087:
        !          1088:     return(TRUE);
        !          1089: }
        !          1090:
        !          1091: /*
        !          1092:     get_hurl
        !          1093:         returns the weapon that the monster will "throw" if it has one
        !          1094: */
        !          1095:
        !          1096: struct linked_list  *
        !          1097: get_hurl(struct thing *tp)
        !          1098: {
        !          1099:     struct linked_list  *arrow,  *bolt,      *rock, *silverarrow, *fbbolt;
        !          1100:     struct linked_list  *bullet, *firearrow, *dart, *dagger,      *shuriken;
        !          1101:     struct linked_list  *oil,    *grenade;
        !          1102:
        !          1103:     struct linked_list  *pitem;
        !          1104:     int bow = FALSE, crossbow = FALSE, sling = FALSE, footbow = FALSE;
        !          1105:
        !          1106:     /* Don't point to anything to begin with */
        !          1107:
        !          1108:     arrow = bolt = rock = silverarrow = fbbolt = NULL;
        !          1109:     bullet = firearrow = dart = dagger = shuriken = NULL;
        !          1110:     oil = grenade = NULL;
        !          1111:
        !          1112:     for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
        !          1113:         if ((OBJPTR(pitem))->o_type == WEAPON)
        !          1114:             switch ((OBJPTR(pitem))->o_which)
        !          1115:             {
        !          1116:                 case    BOW:bow = TRUE; break;
        !          1117:                 case    CROSSBOW:crossbow = TRUE; break;
        !          1118:                 case    SLING:sling = TRUE; break;
        !          1119:                 case    FOOTBOW:footbow = TRUE; break;
        !          1120:                 case    ROCK:rock = pitem; break;
        !          1121:                 case    ARROW:arrow = pitem; break;
        !          1122:                 case    SILVERARROW:silverarrow = pitem; break;
        !          1123:                 case    BOLT:bolt = pitem; break;
        !          1124:                 case    FBBOLT:fbbolt = pitem; break;
        !          1125:                 case    BULLET:bullet = pitem; break;
        !          1126:                 case    FLAMEARROW:firearrow = pitem; break;
        !          1127:                 case    DART:dart = pitem; break;
        !          1128:                 case    DAGGER:dagger = pitem; break;
        !          1129:                 case    SHURIKEN:shuriken = pitem; break;
        !          1130:                 case    MOLOTOV:oil = pitem; break;
        !          1131:                 case    GRENADE:shuriken = pitem; break;
        !          1132:             }
        !          1133:
        !          1134:     if (bow && silverarrow)
        !          1135:         return(silverarrow);
        !          1136:
        !          1137:     if (crossbow && bolt)
        !          1138:         return(bolt);
        !          1139:
        !          1140:     if (bow && firearrow)
        !          1141:         return(firearrow);
        !          1142:
        !          1143:     if (off(*tp, ISCHARMED) && oil)
        !          1144:         return(oil);
        !          1145:
        !          1146:     if (off(*tp, ISCHARMED) && grenade)
        !          1147:         return(grenade);
        !          1148:
        !          1149:     if (footbow && fbbolt)
        !          1150:         return(fbbolt);
        !          1151:
        !          1152:     if (bow && arrow)
        !          1153:         return(arrow);
        !          1154:
        !          1155:     if (sling && bullet)
        !          1156:         return(bullet);
        !          1157:
        !          1158:     if (sling && rock)
        !          1159:         return(rock);
        !          1160:
        !          1161:     if (shuriken)
        !          1162:         return(shuriken);
        !          1163:
        !          1164:     if (dagger)
        !          1165:         return(dagger);
        !          1166:
        !          1167:     if (silverarrow)
        !          1168:         return(silverarrow);
        !          1169:
        !          1170:     if (firearrow)
        !          1171:         return(firearrow);
        !          1172:
        !          1173:     if (fbbolt)
        !          1174:         return(fbbolt);
        !          1175:
        !          1176:     if (bolt)
        !          1177:         return(bolt);
        !          1178:
        !          1179:     if (bullet)
        !          1180:         return(bullet);
        !          1181:
        !          1182:     if (dart)
        !          1183:         return(dart);
        !          1184:
        !          1185:     if (rock)
        !          1186:         return(rock);
        !          1187:
        !          1188:     return(NULL);
        !          1189: }
        !          1190:
        !          1191: /*
        !          1192:     pick_weap()
        !          1193:         returns the biggest weapon that the monster will wield if it
        !          1194:         has a non-launching or non-missile weapon returns NULL if no weapon, or
        !          1195:         bare hands is better
        !          1196: */
        !          1197:
        !          1198: struct object *
        !          1199: pick_weap(struct thing *tp)
        !          1200: {
        !          1201:     int weap_dam = maxdamage(tp->t_stats.s_dmg);
        !          1202:     struct object   *ret_obj = NULL;
        !          1203:     struct linked_list  *pitem;
        !          1204:
        !          1205:     if (on(*tp, CANWIELD))
        !          1206:     {
        !          1207:         for (pitem = tp->t_pack; pitem != NULL; pitem = next(pitem))
        !          1208:         {
        !          1209:             struct object   *obj = OBJPTR(pitem);
        !          1210:
        !          1211:             if (obj->o_type != WEAPON && !(obj->o_flags&(ISLAUNCHER|ISMISL)) &&
        !          1212:                 maxdamage(obj->o_damage) > weap_dam)
        !          1213:             {
        !          1214:                 weap_dam = maxdamage(obj->o_damage);
        !          1215:                 ret_obj = obj;
        !          1216:             }
        !          1217:         }
        !          1218:     }
        !          1219:
        !          1220:     return (ret_obj);
        !          1221: }
        !          1222:
        !          1223: /*
        !          1224:     canblink()
        !          1225:         checks if the monster can teleport (blink).  If so, it will try
        !          1226:         to blink the monster next to the player.
        !          1227: */
        !          1228:
        !          1229: int
        !          1230: can_blink(struct thing *tp)
        !          1231: {
        !          1232:     int   y, x, index = 9;
        !          1233:     coord   tryp;       /* To hold the coordinates for use in diag_ok */
        !          1234:     int    spots[9], found_one = FALSE;
        !          1235:
        !          1236:     /*
        !          1237:      * First, can the monster even blink?  And if so, there is only a 30%
        !          1238:      * chance that it will do so.  And it won't blink if it is running.
        !          1239:      */
        !          1240:
        !          1241:     if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) ||
        !          1242:         on(*tp, ISFLEE) ||
        !          1243:         (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) ||
        !          1244:         (rnd(10) < 9))
        !          1245:         return (FALSE);
        !          1246:
        !          1247:     /* Initialize the spots as illegal */
        !          1248:
        !          1249:     do
        !          1250:     {
        !          1251:         spots[--index] = FALSE;
        !          1252:     }
        !          1253:     while (index > 0);
        !          1254:
        !          1255:     /* Find a suitable spot next to the player */
        !          1256:
        !          1257:     for (y = hero.y - 1; y < hero.y + 2; y++)
        !          1258:         for (x = hero.x - 1; x < hero.x + 2; x++, index++)
        !          1259:         {
        !          1260:             /*
        !          1261:              * Make sure x coordinate is in range and that we are
        !          1262:              * not at the player's position
        !          1263:              */
        !          1264:
        !          1265:             if (x < 0 || x >= COLS || index == 4)
        !          1266:                 continue;
        !          1267:
        !          1268:             /* Is it OK to move there? */
        !          1269:
        !          1270:             if (!step_ok(y, x, NOMONST, tp))
        !          1271:                 spots[index] = FALSE;
        !          1272:            else
        !          1273:            {
        !          1274:
        !          1275:                 /*
        !          1276:                  * OK, we can go here.  But don't go there if
        !          1277:                  * monster can't get at player from there
        !          1278:                  */
        !          1279:
        !          1280:                 tryp.y = y;
        !          1281:                 tryp.x = x;
        !          1282:                 if (diag_ok(&tryp, &hero, tp))
        !          1283:                 {
        !          1284:                     spots[index] = TRUE;
        !          1285:                     found_one = TRUE;
        !          1286:                 }
        !          1287:             }
        !          1288:         }
        !          1289:
        !          1290:     /* If we found one, go to it */
        !          1291:
        !          1292:     if (found_one)
        !          1293:     {
        !          1294:         /* Find a legal spot */
        !          1295:
        !          1296:         while (spots[index = rnd(9)] == FALSE)
        !          1297:             continue;
        !          1298:
        !          1299:         /* Get the coordinates */
        !          1300:
        !          1301:         y = hero.y + (index / 3) - 1;
        !          1302:         x = hero.x + (index % 3) - 1;
        !          1303:
        !          1304:         /* Move the monster from the old space */
        !          1305:
        !          1306:         mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch);
        !          1307:
        !          1308:         /* Move it to the new space */
        !          1309:
        !          1310:         tp->t_oldch = CCHAR( mvwinch(cw, y, x) );
        !          1311:
        !          1312:         if (cansee(y, x) &&
        !          1313:             off(*tp, ISINWALL) &&
        !          1314:             ((off(*tp, ISINVIS) &&
        !          1315:               (off(*tp, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) &&
        !          1316:             off(*tp, CANSURPRISE))
        !          1317:             mvwaddch(cw, y, x, tp->t_type);
        !          1318:
        !          1319:         mvwaddch(mw, tp->t_pos.y,tp->t_pos.x,' '); /*Clear old position */
        !          1320:         mvwaddch(mw, y, x, tp->t_type);
        !          1321:         tp->t_pos.y = y;
        !          1322:         tp->t_pos.x = x;
        !          1323:     }
        !          1324:
        !          1325:     return (found_one);
        !          1326: }

CVSweb