[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

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