int diag_ok(coord *sp, coord *ep) { if (ep->x == sp->x || ep->y == sp->y) return TRUE; return (step_ok(CMVINCH(ep->y, sp->x)) && step_ok(CMVINCH(sp->y, ep->x))); }
/* * diag_ok: * Check to see if the move is legal if it is diagonal */ int diag_ok(coord *sp, coord *ep, struct thing *flgptr) { if (ep->x == sp->x || ep->y == sp->y) return TRUE; return (step_ok(ep->y, sp->x, MONSTOK, flgptr) && step_ok(sp->y, ep->x, MONSTOK, flgptr)); }
/* * diag_ok: * Check to see if the move is legal if it is diagonal */ int diag_ok(const coord *sp, const coord *ep) { if (ep->x < 0 || ep->x >= NUMCOLS || ep->y <= 0 || ep->y >= NUMLINES - 1) return FALSE; if (ep->x == sp->x || ep->y == sp->y) return TRUE; return (step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x))); }
bool plop_monster(int r, int c, Coord *cp) { int y, x; int appear = 0; byte ch; for (y = r - 1; y <= r + 1; y++) { for (x = c - 1; x <= c + 1; x++) { Coord pos = { x, y }; //Don't put a monster on top of the player. if (pos == game->hero().position() || offmap({ x,y })) continue; //Or anything else nasty if (step_ok(ch = game->level().get_tile_or_monster(pos)))//todo:bug: on mimic? { if (ch == SCROLL && is_scare_monster_scroll(find_obj(pos, false))) continue; if (rnd(++appear) == 0) { *cp = pos; } } } } return appear != 0; }
/* * unphase: * Player can no longer walk through walls */ void unphase(void) { turn_off(player, CANINWALL); msg("Your dizzy feeling leaves you."); if (!step_ok(hero.y, hero.x, NOMONST, &player)) death(D_PETRIFY); }
Monster* get_monster_in_direction(Coord dir, bool check_distant) { Coord pos = game->hero().position() + dir; bool throws_affect_mimics(game->options.throws_affect_mimics()); while (check_distant && step_ok(game->level().get_tile_or_monster(pos, throws_affect_mimics))) { pos = pos + dir; } return game->level().monster_at(pos); }
fuse unphase(fuse_arg *arg) { NOOP(arg); turn_off(player, CANINWALL); msg("Your dizzy feeling leaves you."); if (!step_ok(hero.y, hero.x, NOMONST, &player)) death(D_PETRIFY); }
/* * see_monst: * Return TRUE if the hero can see the monster */ int see_monst(const THING *mp) { int y, x; if (on(player, ISBLIND)) return FALSE; if (on(*mp, ISINVIS) && !on(player, CANSEE)) return FALSE; y = mp->t_pos.y; x = mp->t_pos.x; if (dist(y, x, hero.y, hero.x) < LAMPDIST) { if (y != hero.y && x != hero.x && !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) return FALSE; return TRUE; } if (mp->t_room != proom) return FALSE; return (!(mp->t_room->r_flags & ISDARK)); }
/* * cansee: * Returns true if the hero can see a certain coordinate. */ int cansee(int y, int x) { struct room *rer; coord tp; if (on(player, ISBLIND)) return FALSE; if (dist(y, x, hero.y, hero.x) < LAMPDIST) { if (flat(y, x) & F_PASS) if (y != hero.y && x != hero.x && !step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x))) return FALSE; return TRUE; } /* * We can only see if the hero in the same room as * the coordinate and the room is lit or if it is close. */ tp.y = y; tp.x = x; return ((rer = roomin(&tp)) == proom && !(rer->r_flags & ISDARK)); }
void do_motion(THING *obj, int ydelta, int xdelta) { int ch; /* * Come fly with us ... */ obj->o_pos = hero; for (;;) { /* * Erase the old one */ if (!ce(obj->o_pos, hero) && cansee(unc(obj->o_pos)) && !terse) { ch = chat(obj->o_pos.y, obj->o_pos.x); if (ch == FLOOR && !show_floor()) ch = ' '; mvaddch(obj->o_pos.y, obj->o_pos.x, ch); } /* * Get the new position */ obj->o_pos.y += ydelta; obj->o_pos.x += xdelta; if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR) { /* * It hasn't hit anything yet, so display it * If it alright. */ if (cansee(unc(obj->o_pos)) && !terse) { mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type); refresh(); } continue; } break; } }
/* * do the actual motion on the screen done by an object traveling * across the room */ void do_motion(struct object *obj, int ydelta, int xdelta) { /* * Come fly with us ... */ obj->o_pos = hero; for (;;) { int ch; /* * Erase the old one */ if (!ce(obj->o_pos, hero) && cansee(unc(obj->o_pos)) && CMVWINCH(cw, obj->o_pos.y, obj->o_pos.x) != ' ') mvwaddrawch(cw, obj->o_pos.y, obj->o_pos.x, show(obj->o_pos.y, obj->o_pos.x)); /* * Get the new position */ obj->o_pos.y += ydelta; obj->o_pos.x += xdelta; if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR) { /* * It hasn't hit anything yet, so display it * If it alright. */ if (cansee(unc(obj->o_pos)) && CMVWINCH(cw, obj->o_pos.y, obj->o_pos.x) != ' ') { mvwaddrawch(cw, obj->o_pos.y, obj->o_pos.x, obj->o_type); draw(cw); } continue; } break; } }
/* * chase: * Find the spot for the chaser(er) to move closer to the * chasee(ee). Returns TRUE if we want to keep on chasing later * FALSE if we reach the goal. */ int chase(THING *tp, const coord *ee) { THING *obj; int x, y; int curdist, thisdist; const coord *er = &tp->t_pos; int ch; int plcnt = 1; coord tryp; /* * If the thing is confused, let it move randomly. Invisible * Stalkers are slightly confused all of the time, and bats are * quite confused all the time */ if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0) || (tp->t_type == 'B' && rnd(2) == 0)) { /* * get a valid random move */ ch_ret = rndmove(tp); curdist = dist_cp(&ch_ret, ee); /* * Small chance that it will become un-confused */ if (rnd(20) == 0) tp->t_flags &= ~ISHUH; } /* * Otherwise, find the empty spot next to the chaser that is * closest to the chasee. */ else { int ey, ex; /* * This will eventually hold where we move to get closer * If we can't find an empty spot, we stay where we are. */ curdist = dist_cp(er, ee); ch_ret = *er; ey = er->y + 1; if (ey >= NUMLINES - 1) ey = NUMLINES - 2; ex = er->x + 1; if (ex >= NUMCOLS) ex = NUMCOLS - 1; for (x = er->x - 1; x <= ex; x++) { if (x < 0) continue; tryp.x = x; for (y = er->y - 1; y <= ey; y++) { tryp.y = y; if (!diag_ok(er, &tryp)) continue; ch = winat(y, x); if (step_ok(ch)) { /* * If it is a scroll, it might be a scare monster scroll * so we need to look it up to see what type it is. */ if (ch == SCROLL) { for (obj = lvl_obj; obj != NULL; obj = next(obj)) { if (y == obj->o_pos.y && x == obj->o_pos.x) break; } if (obj != NULL && obj->o_which == S_SCARE) continue; } /* * It can also be a Xeroc, which we shouldn't step on */ if ((obj = moat(y, x)) != NULL && obj->t_type == 'X') continue; /* * If we didn't find any scrolls at this place or it * wasn't a scare scroll, then this place counts */ thisdist = dist(y, x, ee->y, ee->x); if (thisdist < curdist) { plcnt = 1; ch_ret = tryp; curdist = thisdist; } else if (thisdist == curdist && rnd(++plcnt) == 0) { ch_ret = tryp; curdist = thisdist; } } } } } return (curdist != 0 && !ce(ch_ret, hero)); }
int can_blink(struct thing *tp) { int y, x, index = 9; coord tryp; /* To hold the coordinates for use in diag_ok */ int spots[9], found_one = FALSE; /* * First, can the monster even blink? And if so, there is only a 30% * chance that it will do so. And it won't blink if it is running. */ if (off(*tp, CANBLINK) || (on(*tp, ISHELD)) || on(*tp, ISFLEE) || (on(*tp, ISSLOW) && off(*tp, ISHASTE) && !(tp->t_turn)) || (rnd(10) < 9)) return (FALSE); /* Initialize the spots as illegal */ do { spots[--index] = FALSE; } while (index > 0); /* Find a suitable spot next to the player */ for (y = hero.y - 1; y < hero.y + 2; y++) for (x = hero.x - 1; x < hero.x + 2; x++, index++) { /* * Make sure x coordinate is in range and that we are * not at the player's position */ if (x < 0 || x >= COLS || index == 4) continue; /* Is it OK to move there? */ if (!step_ok(y, x, NOMONST, tp)) spots[index] = FALSE; else { /* * OK, we can go here. But don't go there if * monster can't get at player from there */ tryp.y = y; tryp.x = x; if (diag_ok(&tryp, &hero, tp)) { spots[index] = TRUE; found_one = TRUE; } } } /* If we found one, go to it */ if (found_one) { /* Find a legal spot */ while (spots[index = rnd(9)] == FALSE) continue; /* Get the coordinates */ y = hero.y + (index / 3) - 1; x = hero.x + (index % 3) - 1; /* Move the monster from the old space */ mvwaddch(cw, tp->t_pos.y, tp->t_pos.x, tp->t_oldch); /* Move it to the new space */ tp->t_oldch = CCHAR( mvwinch(cw, y, x) ); if (cansee(y, x) && off(*tp, ISINWALL) && ((off(*tp, ISINVIS) && (off(*tp, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) && off(*tp, CANSURPRISE)) mvwaddch(cw, y, x, tp->t_type); mvwaddch(mw, tp->t_pos.y,tp->t_pos.x,' '); /*Clear old position */ mvwaddch(mw, y, x, tp->t_type); tp->t_pos.y = y; tp->t_pos.x = x; } return (found_one); }
int chase(struct thing *tp, coord *ee) { int x, y; int dist, thisdist; struct linked_list *item; struct object *obj; coord *er = &tp->t_pos; int ch; /* * If the thing is confused, let it move randomly. Invisible * Stalkers are slightly confused all of the time, and bats are * quite confused all the time */ if ((on(*tp, ISHUH) && rnd(10) < 8) || (tp->t_type == 'I' && rnd(100) < 20) || (tp->t_type == 'B' && rnd(100) < 50)) { /* * get a valid random move */ ch_ret = *rndmove(tp); dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); /* * Small chance that it will become un-confused */ if (rnd(1000) < 50) tp->t_flags &= ~ISHUH; } /* * Otherwise, find the empty spot next to the chaser that is * closest to the chasee. */ else { int ey, ex; /* * This will eventually hold where we move to get closer * If we can't find an empty spot, we stay where we are. */ dist = DISTANCE(er->y, er->x, ee->y, ee->x); ch_ret = *er; ey = er->y + 1; ex = er->x + 1; for (x = er->x - 1; x <= ex; x++) for (y = er->y - 1; y <= ey; y++) { coord tryp; tryp.x = x; tryp.y = y; if (!diag_ok(er, &tryp)) continue; ch = winat(y, x); if (step_ok(ch)) { /* * If it is a scroll, it might be a scare monster scroll * so we need to look it up to see what type it is. */ if (ch == SCROLL) { for (item = lvl_obj; item != NULL; item = next(item)) { obj = (struct object *) ldata(item); if (y == obj->o_pos.y && x == obj->o_pos.x) break; } if (item != NULL && obj->o_which == S_SCARE) continue; } /* * If we didn't find any scrolls at this place or it * wasn't a scare scroll, then this place counts */ thisdist = DISTANCE(y, x, ee->y, ee->x); if (thisdist < dist) { ch_ret = tryp; dist = thisdist; } } } } return (dist != 0); }
/* * chase: * Find the spot for the chaser(er) to move closer to the * chasee(ee). Returns TRUE if we want to keep on chasing later * FALSE if we reach the goal. */ int chase(struct thing *tp, coord *ee, int flee, int *mdead) { register int x, y; register int dist, thisdist, monst_dist = MAXINT; register struct linked_list *weapon; register coord *er = &tp->t_pos, *shoot_dir; register int ch, mch; register int next_player = FALSE; int deadflg; if (mdead != NULL) *mdead = 0; shoot_dir = can_shoot(er, ee); weapon = get_hurl(tp); /* * If the thing is confused, let it move randomly. Invisible * Stalkers are slightly confused all of the time. */ if ((on(*tp, ISHUH) && rnd(10) < 8) || ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) || (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */ /* * get a valid random move */ ch_ret = *rndmove(tp); dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */ turn_off(*tp, ISHUH); /* * check to see if random move takes creature away from player * if it does then turn off ISHELD */ if (dist > 1 && on(*tp, DIDHOLD)) { turn_off(*tp, DIDHOLD); turn_on(*tp, CANHOLD); if (--hold_count <= 0) { hold_count = 0; turn_off(player, ISHELD); } } } /* If we can breathe, we may do so */ else if (on(*tp, CANBREATHE) && (shoot_dir) && (rnd(100) < 67) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (DISTANCE(er->y, er->x, ee->y, ee->x) < BOLT_LENGTH*BOLT_LENGTH)) { register int chance; register char *breath; /* Will it breathe at random */ if (on(*tp, CANBRANDOM)) { if (rnd(level/20) == 0 && tp->t_index != NUMMONST+1) turn_off(*tp, CANBRANDOM); /* Select type of breath */ chance = rnd(100); if (chance < 11) breath = "acid"; else if (chance < 22) breath = "flame"; else if (chance < 33) breath = "lightning bolt"; else if (chance < 44) breath = "chlorine gas"; else if (chance < 55) breath = "ice"; else if (chance < 66) breath = "nerve gas"; else if (chance < 77) breath = "sleeping gas"; else if (chance < 88) breath = "slow gas"; else breath = "fear gas"; } /* Or can it breathe acid? */ else if (on(*tp, CANBACID)) { if (rnd(level/20) == 0) turn_off(*tp, CANBACID); breath = "acid"; } /* Or can it breathe fire */ else if (on(*tp, CANBFIRE)) { if (rnd(level/20) == 0) turn_off(*tp, CANBFIRE); breath = "flame"; } /* Or can it breathe electricity? */ else if (on(*tp, CANBBOLT)) { if (rnd(level/20) == 0) turn_off(*tp, CANBBOLT); breath = "lightning bolt"; } /* Or can it breathe gas? */ else if (on(*tp, CANBGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBGAS); breath = "chlorine gas"; } /* Or can it breathe ice? */ else if (on(*tp, CANBICE)) { if (rnd(level/20) == 0) turn_off(*tp, CANBICE); breath = "ice"; } else if (on(*tp, CANBPGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBPGAS); breath = "nerve gas"; } else if (on(*tp, CANBSGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBSGAS); breath = "sleeping gas"; } else if (on(*tp, CANBSLGAS)) { if (rnd(level/20) == 0) turn_off(*tp, CANBSLGAS); breath = "slow gas"; } else { if (rnd(level/20) == 0) turn_off(*tp, CANBFGAS); breath = "fear gas"; } /* Now breathe -- returns TRUE if kills itself */ deadflg = shoot_bolt(tp, *er, *shoot_dir, FALSE, tp->t_index, breath, (save(VS_BREATH) ? tp->t_stats.s_hpt/2 : tp->t_stats.s_hpt)); if (deadflg && mdead != NULL) *mdead = 1; ch_ret = *er; dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); if (deadflg) return(TRUE); } /* * If we can shoot or throw something, we might do so * if we are running away, we may decide to shoot anyway if we are far * enough */ else if((off(*tp, ISFLEE) || rnd(DISTANCE(er->y,er->x,ee->y,ee->x)) > 2) && on(*tp, CANSHOOT) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (shoot_dir) && (weapon)) { missile(shoot_dir->y, shoot_dir->x, weapon, tp); ch_ret = *er; dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); } /* * Otherwise, find the empty spot next to the chaser that is * closest to the chasee. */ else { register int ey, ex; register struct room *rer, *ree; register int dist_to_old = MININT; /* Dist from goal to old position */ /* Get rooms */ rer = roomin(er); ree = roomin(ee); /* * This will eventually hold where we move to get closer * If we can't find an empty spot, we stay where we are. */ dist = flee ? 0 : MAXINT; ch_ret = *er; /* Are we at our goal already? */ if (!flee && ce(ch_ret, *ee)) return(FALSE); ey = er->y + 1; ex = er->x + 1; for (x = er->x - 1; x <= ex; x++) for (y = er->y - 1; y <= ey; y++) { coord tryp; /* Don't try off the board */ if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2)) continue; /* Don't try the player if not going after the player */ /* or he's disguised */ if ( ((off(*tp, ISFLEE) && !ce(hero, *ee)) || (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6))) && x == hero.x && y == hero.y) continue; tryp.x = x; tryp.y = y; /* Is there a monster on this spot closer to our goal? * Don't look in our spot or where we were. */ if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && isalpha(mch = CCHAR( mvwinch(mw, y, x) ))) { register int test_dist; test_dist = DISTANCE(y, x, ee->y, ee->x); if (test_dist <= 25 && /* Let's be fairly close */ test_dist < monst_dist) { /* Could we really move there? */ mvwaddch(mw, y, x, ' '); /* Temporarily blank monst */ if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; mvwaddch(mw, y, x, mch); /* Restore monster */ } } if (!diag_ok(er, &tryp, tp)) continue; ch = CCHAR( mvwinch(cw, y, x) ); /* Screen character */ if (on(*tp, ISFLEE) && (ch == PLAYER)) next_player = TRUE; /* Stepping on player is NOT okay if we are fleeing */ if (step_ok(y, x, NOMONST, tp) && (off(*tp, ISFLEE) || ch != PLAYER)) { /* * If it is a trap, an intelligent monster may not * step on it (unless our hero is on top!) */ if (isatrap(ch)) { if (!(ch == RUSTTRAP) && !(ch == FIRETRAP && on(*tp,NOFIRE)) && rnd(10) < tp->t_stats.s_intel && (y != hero.y || x != hero.x)) continue; } /* * OK -- this place counts */ thisdist = DISTANCE(y, x, ee->y, ee->x); /* Adjust distance if we are being shot at */ if (tp->t_wasshot && tp->t_stats.s_intel > 5 && ce(hero, *ee)) { /* Move out of line of sight */ if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) { if (flee) thisdist -= SHOTPENALTY; else thisdist += SHOTPENALTY; } /* But do we want to leave the room? */ else if (rer && rer == ree && ch == DOOR) thisdist += DOORPENALTY; } /* Don't move to the last position if we can help it */ if (ce(tryp, tp->t_oldpos)) dist_to_old = thisdist; else if ((flee && (thisdist > dist)) || (!flee && (thisdist < dist))) { ch_ret = tryp; dist = thisdist; } } } /* If we are running from the player and he is in our way, * go ahead and slug him. */ if (next_player && DISTANCE(er->y, er->x, ee->y, ee->x) < dist && step_ok(tp->t_dest->y, tp->t_dest->x, NOMONST, tp)) { ch_ret = *(tp->t_dest); /* Okay to hit player */ return FALSE; } /* If we can't get closer to the player (if that's our goal) * because other monsters are in the way, just stay put */ if (!flee && ce(hero, *ee) && monst_dist < MAXINT && DISTANCE(er->y, er->x, hero.y, hero.x) < dist) ch_ret = *er; /* Do we want to go back to the last position? */ else if (dist_to_old != MININT && /* It is possible to move back */ ((flee && dist == 0) || /* No other possible moves */ (!flee && dist == MAXINT))) { /* Do we move back or just stay put (default)? */ dist = DISTANCE(er->y, er->x, ee->y, ee->x); /* Current distance */ if (!flee || (flee && (dist_to_old > dist))) ch_ret = tp->t_oldpos; } } /* Make sure we have the real distance now */ dist = DISTANCE(ch_ret.y, ch_ret.x, ee->y, ee->x); /* Mark monsters in a wall */ if (isrock(CCHAR( mvinch(ch_ret.y, ch_ret.x) ))) turn_on(*tp, ISINWALL); else turn_off(*tp, ISINWALL); if (off(*tp, ISFLEE) && ((tp->t_dest != &hero) || off(player, ISINWALL) || on(*tp, CANINWALL))) return (dist != 0); /* May actually hit here from a confused move */ else return(!ce(ch_ret, hero)); }
void read_scroll(void) { THING *obj; PLACE *pp; int y, x; int ch; int i; int discardit = FALSE; struct room *cur_room; THING *orig_obj; coord mp; obj = get_item("read", SCROLL); if (obj == NULL) return; if (obj->o_type != SCROLL) { if (!terse) msg("there is nothing on it to read"); else msg("nothing to read"); return; } /* * Calculate the effect it has on the poor guy. */ if (obj == cur_weapon) cur_weapon = NULL; /* * Get rid of the thing */ discardit = (obj->o_count == 1); leave_pack(obj, FALSE, FALSE); orig_obj = obj; switch (obj->o_which) { case S_CONFUSE: /* * Scroll of monster confusion. Give him that power. */ player.t_flags |= CANHUH; msg("your hands begin to glow %s", pick_color("red")); when S_ARMOR: if (cur_armor != NULL) { cur_armor->o_arm--; cur_armor->o_flags &= ~ISCURSED; msg("your armor glows %s for a moment", pick_color("silver")); } when S_HOLD: /* * Hold monster scroll. Stop all monsters within two spaces * from chasing after the hero. */ ch = 0; for (x = hero.x - 2; x <= hero.x + 2; x++) if (x >= 0 && x < NUMCOLS) for (y = hero.y - 2; y <= hero.y + 2; y++) if (y >= 0 && y <= NUMLINES - 1) if ((obj = moat(y, x)) != NULL && on(*obj, ISRUN)) { obj->t_flags &= ~ISRUN; obj->t_flags |= ISHELD; ch++; } if (ch) { addmsg("the monster"); if (ch > 1) addmsg("s around you"); addmsg(" freeze"); if (ch == 1) addmsg("s"); endmsg(); scr_info[S_HOLD].oi_know = TRUE; } else msg("you feel a strange sense of loss"); when S_SLEEP: /* * Scroll which makes you fall asleep */ scr_info[S_SLEEP].oi_know = TRUE; no_command += rnd(SLEEPTIME) + 4; player.t_flags &= ~ISRUN; msg("you fall asleep"); when S_CREATE: /* * Create a monster: * First look in a circle around him, next try his room * otherwise give up */ i = 0; for (y = hero.y - 1; y <= hero.y + 1; y++) for (x = hero.x - 1; x <= hero.x + 1; x++) /* * Don't put a monster in top of the player. */ if (y == hero.y && x == hero.x) continue; /* * Or anything else nasty * Also avoid a xeroc which is disguised as scroll */ else if (moat(y, x) == NULL && step_ok(ch = winat(y, x))) { if (ch == SCROLL && find_obj(y, x)->o_which == S_SCARE) continue; else if (rnd(++i) == 0) { mp.y = y; mp.x = x; } } if (i == 0) msg("you hear a faint cry of anguish in the distance"); else { obj = new_item(); new_monster(obj, randmonster(FALSE), &mp); } when S_ID_POTION: case S_ID_SCROLL: case S_ID_WEAPON: case S_ID_ARMOR: case S_ID_R_OR_S: { int id_type[S_ID_R_OR_S + 1] = { 0, 0, 0, 0, 0, POTION, SCROLL, WEAPON, ARMOR, R_OR_S }; /* * Identify, let him figure something out */ scr_info[obj->o_which].oi_know = TRUE; msg("this scroll is an %s scroll", scr_info[obj->o_which].oi_name); /* whatis(TRUE, id_type[obj->o_which]); */ if (idscr_md != TRUE) whatis(TRUE, id_type[obj->o_which]); else whatis(FALSE, 0); } when S_MAP: /* * Scroll of magic mapping. */ scr_info[S_MAP].oi_know = TRUE; msg("oh, now this scroll has a map on it"); /* * take all the things we want to keep hidden out of the window */ for (y = 1; y < NUMLINES - 1; y++) for (x = 0; x < NUMCOLS; x++) { pp = INDEX(y, x); switch (ch = pp->p_ch) { case DOOR: case STAIRS: break; case '-': case '|': if (!(pp->p_flags & F_REAL)) { ch = pp->p_ch = DOOR; pp->p_flags |= F_REAL; } break; case ' ': if (pp->p_flags & F_REAL) goto def; pp->p_flags |= F_REAL; ch = pp->p_ch = PASSAGE; /* FALLTHROUGH */ case PASSAGE: pass: if (!(pp->p_flags & F_REAL)) pp->p_ch = PASSAGE; pp->p_flags |= (F_SEEN|F_REAL); ch = PASSAGE; break; case FLOOR: if (pp->p_flags & F_REAL) ch = ' '; else { ch = TRAP; pp->p_ch = TRAP; pp->p_flags |= (F_SEEN|F_REAL); } break; default: def: if (pp->p_flags & F_PASS) goto pass; ch = ' '; break; } if (ch != ' ') { if ((obj = pp->p_monst) != NULL) obj->t_oldch = ch; if (obj == NULL || !on(player, SEEMONST)) mvaddch2(y, x, ch); } } when S_FDET: /* * Potion of gold detection */ ch = FALSE; wclear(hw); for (obj = lvl_obj; obj != NULL; obj = next(obj)) if (obj->o_type == FOOD) { ch = TRUE; wmove(hw, obj->o_pos.y, obj->o_pos.x); waddch2(hw, FOOD); } if (ch) { scr_info[S_FDET].oi_know = TRUE; show_win("Your nose tingles and you smell food.--More--"); } else msg("your nose tingles"); when S_TELEP: /* * Scroll of teleportation: * Make him dissapear and reappear */ { cur_room = proom; teleport(); if (cur_room != proom) scr_info[S_TELEP].oi_know = TRUE; } when S_ENCH: if (cur_weapon == NULL || cur_weapon->o_type != WEAPON) msg("you feel a strange sense of loss"); else { cur_weapon->o_flags &= ~ISCURSED; if (rnd(2) == 0) cur_weapon->o_hplus++; else cur_weapon->o_dplus++; msg("your %s glows %s for a moment", weap_info[cur_weapon->o_which].oi_name, pick_color("blue")); } when S_SCARE: /* * Reading it is a mistake and produces laughter at her * poor boo boo. */ msg("you hear maniacal laughter in the distance"); when S_REMOVE: uncurse(cur_armor); uncurse(cur_weapon); uncurse(cur_ring[LEFT]); uncurse(cur_ring[RIGHT]); msg(choose_str("you feel in touch with the Universal Onenes", "you feel as if somebody is watching over you")); when S_AGGR: /* * This scroll aggravates all the monsters on the current * level and sets them running towards the hero */ aggravate(); msg("you hear a high pitched humming noise"); when S_PROTECT: if (cur_armor != NULL) { cur_armor->o_flags |= ISPROT; msg("your armor is covered by a shimmering %s shield", pick_color("gold")); } else msg("you feel a strange sense of loss"); #ifdef MASTER otherwise: msg("what a puzzling scroll!"); return; #endif } obj = orig_obj; look(TRUE); /* put the result of the scroll on the screen */ status(); call_it(&scr_info[obj->o_which]); if (discardit) discard(obj); }
int chase(struct thing *tp, coord *ee, int flee) { int x, y; int dist, thisdist, monst_dist = INT_MAX; struct linked_list *weapon; coord *er = &tp->t_pos; coord shoot; coord *shootit_dir = NULL; int ch; char mch; int next_player = FALSE; /* Take care of shooting directions */ if (on(*tp, CANBREATHE) || on(*tp, CANSHOOT) || on(*tp, CANCAST)) { if (good_monster(*tp)) { shootit_dir = find_shoot(tp, &shoot); /* find a mean monster */ if (wizard && shootit_dir) msg("Found monster to attack towards (%d,%d).", shootit_dir->x, shootit_dir->y); } else shootit_dir = can_shoot(er, ee, &shoot); /* shoot hero */ } /* * If the thing is confused, let it move randomly. Some monsters are * slightly confused all of the time. */ if ((on(*tp, ISHUH) && rnd(10) < 8) || ((on(*tp, ISINVIS) || on(*tp, ISSHADOW)) && rnd(100) < 20) || (on(player, ISINVIS) && off(*tp, CANSEE))) { /* Player is invisible */ /* get a valid random move */ tp->t_nxtpos = rndmove(tp); dist = DISTANCE(tp->t_nxtpos, *ee); if (on(*tp, ISHUH) && rnd(20) == 0) /* monster might lose confusion */ turn_off(*tp, ISHUH); /* * check to see if random move takes creature away from * player if it does then turn off ISHELD */ if (dist > 1 && on(*tp, DIDHOLD)) { turn_off(*tp, DIDHOLD); turn_on(*tp, CANHOLD); if (--hold_count == 0) turn_off(player, ISHELD); } } /* If we can breathe, we may do so */ else if (on(*tp, CANBREATHE) && (shootit_dir) && (rnd(100) < 67) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6)) && (DISTANCE(*er, *ee) < BOLT_LENGTH * BOLT_LENGTH)) { int chance; char *breath; /* Will it breathe at random */ if (on(*tp, CANBRANDOM)) { if (rnd(level / 20) == 0 && tp->t_index != nummonst + 1 && !(good_monster(*tp))) turn_off(*tp, CANBRANDOM); /* Select type of breath */ chance = rnd(100); if (chance < 11) breath = "acid"; else if (chance < 22) breath = "flame"; else if (chance < 33) breath = "lightning bolt"; else if (chance < 44) breath = "chlorine gas"; else if (chance < 55) breath = "ice"; else if (chance < 66) breath = "nerve gas"; else if (chance < 77) breath = "sleeping gas"; else if (chance < 88) breath = "slow gas"; else breath = "fear gas"; } /* Or can it breathe acid? */ else if (on(*tp, CANBACID)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBACID); breath = "acid"; } /* Or can it breathe fire */ else if (on(*tp, CANBFIRE)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBFIRE); breath = "flame"; } /* Or can it breathe electricity? */ else if (on(*tp, CANBBOLT)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBBOLT); breath = "lightning bolt"; } /* Or can it breathe gas? */ else if (on(*tp, CANBGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBGAS); breath = "chlorine gas"; } /* Or can it breathe ice? */ else if (on(*tp, CANBICE)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBICE); breath = "ice"; } else if (on(*tp, CANBPGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBPGAS); breath = "nerve gas"; } else if (on(*tp, CANBSGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBSGAS); breath = "sleeping gas"; } else if (on(*tp, CANBSLGAS)) { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBSLGAS); breath = "slow gas"; } else { if (!good_monster(*tp) && rnd(level / 15) == 0) turn_off(*tp, CANBFGAS); breath = "fear gas"; } shoot_bolt(tp, *er, *shootit_dir, (tp == THINGPTR(fam_ptr)), tp->t_index, breath, roll(tp->t_stats.s_lvl, 6)); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); if (!curr_mons) return (TRUE); } else if (shootit_dir && on(*tp, CANCAST) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6))) { /* If we can cast spells we might do so - even if adjacent fleeing monsters are restricted to certain spells */ incant(tp, *shootit_dir); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); } else if (shootit_dir && on(*tp, CANSHOOT)) { weapon = get_hurl(tp); if (weapon && (off(*tp, ISFLEE) || rnd(DISTANCE(*er, *ee)) > 2) && (off(player, ISDISGUISE) || (rnd(tp->t_stats.s_lvl) > 6))) { /* Should we shoot or throw something? fleeing monsters may to shoot anyway if far enough away */ missile(shootit_dir->y, shootit_dir->x, weapon, tp); tp->t_nxtpos = *er; dist = DISTANCE(tp->t_nxtpos, *ee); } } else { /* Otherwise, find the empty spot next to the chaser that is closest to the chasee. */ int ey, ex; struct room *rer, *ree; int dist_to_old = INT_MIN; /* Dist from goal to old position */ /* Get rooms */ rer = roomin(*er); ree = roomin(*ee); /* * This will eventually hold where we move to get closer. If * we can't find an empty spot, we stay where we are. */ dist = flee ? 0 : INT_MAX; tp->t_nxtpos = *er; /* Are we at our goal already? */ if (!flee && ce(tp->t_nxtpos, *ee)) return (FALSE); ey = er->y + 1; ex = er->x + 1; for (x = er->x - 1; x <= ex; x++) for (y = er->y - 1; y <= ey; y++) { coord tryp; /* test position */ /* Don't try off the screen */ if ((x < 0) || (x >= COLS) || (y < 1) || (y >= LINES - 2)) continue; /* * Don't try the player if not going after * the player or he's disguised and monster is dumb */ if (((off(*tp, ISFLEE) && !ce(hero, *ee)) || (on(player, ISDISGUISE) && (rnd(tp->t_stats.s_lvl) < 6)) || good_monster(*tp)) && x == hero.x && y == hero.y) continue; tryp.x = x; tryp.y = y; /* * Is there a monster on this spot closer to * our goal? Don't look in our spot or where * we were. */ if (!ce(tryp, *er) && !ce(tryp, tp->t_oldpos) && isalpha( (mch = CCHAR(mvwinch(mw, y, x))) ) ) { int test_dist; test_dist = DISTANCE(tryp,*ee); if (test_dist <= 25 && /* Let's be fairly close */ test_dist < monst_dist) { /* Could we really move there? */ mvwaddch(mw, y, x, ' '); /* Temp blank monst */ if (diag_ok(er, &tryp, tp)) monst_dist = test_dist; mvwaddch(mw, y, x, mch); /* Restore monster */ } } if (!diag_ok(er, &tryp, tp)) continue; ch = mvwinch(cw, y, x); /* Screen character */ /* * Stepping on player is NOT okay if we are * fleeing */ if (on(*tp, ISFLEE) && (ch == PLAYER)) next_player = TRUE; if (step_ok(y, x, NOMONST, tp) && (off(*tp, ISFLEE) || ch != PLAYER)) { /* * If it is a trap, an intelligent * monster may not step on it (unless * our hero is on top!) */ if (isatrap(ch)) { if (!(ch == RUSTTRAP) && !(ch == FIRETRAP && on(*tp, NOFIRE)) && rnd(10) < tp->t_stats.s_intel && (y != hero.y || x != hero.x)) continue; } /* * OK -- this place counts */ thisdist = DISTANCE(tryp, *ee); /* * Adjust distance if we are being * shot at to moving out of line of sight. */ if (tp->t_wasshot && tp->t_stats.s_intel > 5 && ce(hero, *ee)) { /* Move out of line of sight */ if (straight_shot(tryp.y, tryp.x, ee->y, ee->x, NULL)) { if (flee) thisdist -= SHOTPENALTY; else thisdist += SHOTPENALTY; } /* * But do we want to leave * the room? */ else if (rer && rer == ree && ch == DOOR) thisdist += DOORPENALTY; } /* * Don't move to the last position if * we can help it */ if (ce(tryp, tp->t_oldpos)) dist_to_old = thisdist; else if ((flee && (thisdist > dist)) || (!flee && (thisdist < dist))) { tp->t_nxtpos = tryp; dist = thisdist; } } } /* * If we are running from the player and he is in our way, go * ahead and slug him. */ if (next_player && DISTANCE(*er,*ee) < dist && step_ok(tp->t_chasee->t_pos.y, tp->t_chasee->t_pos.x, NOMONST, tp)) { tp->t_nxtpos = tp->t_chasee->t_pos; /* Okay to hit player */ return(FALSE); } /* * If we can't get closer to the player (if that's our goal) * because other monsters are in the way, just stay put */ if (!flee && ce(hero, *ee) && monst_dist < INT_MAX && DISTANCE(*er, hero) < dist) tp->t_nxtpos = *er; /* Do we want to go back to the last position? */ else if (dist_to_old != INT_MIN && /* It is possible to move back */ ((flee && dist == 0) || /* No other possible moves */ (!flee && dist == INT_MAX))) { /* Do we move back or just stay put (default)? */ dist = DISTANCE(*er,*ee); /* Current distance */ if (!flee || (flee && (dist_to_old > dist))) tp->t_nxtpos = tp->t_oldpos; } } /* Make sure we have the real distance now */ dist = DISTANCE(tp->t_nxtpos, *ee); /* Mark monsters in a wall */ switch(mvinch(tp->t_nxtpos.y, tp->t_nxtpos.x)) { case WALL: case '-': case '|': turn_on(*tp, ISINWALL); break; default: turn_off(*tp, ISINWALL); } if (off(*tp, ISFLEE) && !(!SAME_POS((tp->t_chasee->t_pos),hero) || off(player, ISINWALL) || on(*tp, CANINWALL))) return(dist != 0); else /* May actually hit here from a confused move */ return(!ce(tp->t_nxtpos, hero)); }
void wanderer(void) { int i, cnt = 0; struct room *hr = roomin(hero); struct linked_list *item; struct thing *tp; coord cp; char *loc; int which; /* Find a place for it -- avoid the player's room */ do { do { cnt++; i = rnd_room(); } while (!(hr != &rooms[i] || levtype == MAZELEV || levtype == THRONE || cnt > 5000)); rnd_pos(&rooms[i], &cp); } while(!step_ok(cp.y, cp.x, NOMONST, NULL)); /* Create a new wandering monster */ item = new_item(sizeof *tp); which = randmonster(TRUE, FALSE); new_monster(item, which, &cp, FALSE); tp = THINGPTR(item); tp->t_pos = cp; /* Assign the position to the monster */ chase_it(&tp->t_pos, &player); i = rnd(7); if (on(*tp, ISSWARM) && i < 5) cnt = roll(2, 4); else if (on(*tp, ISFLOCK) && i < 5) cnt = roll(1, 4); else cnt = 0; for (i = 1; i <= cnt; i++) { struct linked_list *ip = creat_mons(tp, which, NOMESSAGE); if (ip != NULL) { struct thing *mp = THINGPTR(ip); if (on(*tp, ISFRIENDLY)) turn_on(*mp, ISFRIENDLY); else turn_off(*mp, ISFRIENDLY); } } if (cnt > 0) { if (on(*tp, LOWCAST) || on(*tp, MEDCAST) || on(*tp, HIGHCAST)) turn_on(*tp, CANCAST); tp->t_stats.s_hpt += roll(2, 8); tp->t_stats.s_lvl += roll(2, 3); tp->t_stats.s_arm -= roll(1, 6); tp->t_stats.s_str += roll(2, 3); tp->t_stats.s_intel += roll(2, 3); tp->t_stats.s_exp += roll(2, 8) * monsters[which].m_add_exp; } i = DISTANCE(cp, hero); if (i < 20) loc = "very close to you"; else if (i < 400) loc = "nearby"; else loc = "in the distance"; if (wizard) msg("Started a wandering %s.", monsters[tp->t_index].m_name); else if (on(*tp, ISUNDEAD) && (player.t_ctype == C_CLERIC || player.t_ctype == C_PALADIN || is_wearing(R_PIETY))) msg("You sense a new ungodly monster %s.", loc); else if (on(player, CANHEAR) || (player.t_ctype == C_THIEF && rnd(20) == 0)) msg("You hear a new %s moving %s.", monsters[tp->t_index].m_name, loc); else if (on(player, CANSCENT) || (player.t_ctype == C_THIEF && rnd(20) == 0)) msg("You smell a new %s %s.", monsters[tp->t_index].m_name, loc); }
read_scroll() { register struct object *obj; register struct linked_list *item; register struct room *rp; register int i,j; register char ch, nch; register struct linked_list *titem; char buf[80]; item = get_item("run", SCROLL); if (item == NULL) return; obj = (struct object *) ldata(item); if (obj->o_type != SCROLL) { if (!terse) msg("There is no way to run it"); else msg("Nothing to run"); return; } msg("As you run the device, it self-destructs."); /* * Calculate the effect it has on the poor guy. */ if (obj == cur_weapon) cur_weapon = NULL; switch(obj->o_which) { when S_CONFUSE: /* * Scroll of monster confusion. Give him that power. */ msg("Your hands begin to glow red"); player.t_flags |= CANHUH; when S_LIGHT: s_know[S_LIGHT] = TRUE; if ((rp = roomin(&hero)) == NULL) msg("The corridor glows and then fades"); else { addmsg("The room is lit"); if (!terse) addmsg(" by a shimmering blue light."); endmsg(); rp->r_flags &= ~ISDARK; /* * Light the room and put the player back up */ light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } when S_ARMOR: if (cur_armor != NULL) { msg("Your armor glows faintly for a moment"); cur_armor->o_ac--; cur_armor->o_flags &= ~ISCURSED; } when S_HOLD: /* * Hold monster scroll. Stop all monsters within two spaces * from chasing after the hero. */ { register int x,y; register struct linked_list *mon; for (x = hero.x-2; x <= hero.x+2; x++) for (y = hero.y-2; y <= hero.y+2; y++) if (y > 0 && x > 0 && isupper(mvwinch(mw, y, x))) if ((mon = find_mons(y, x)) != NULL) { register struct thing *th; th = (struct thing *) ldata(mon); th->t_flags &= ~ISRUN; th->t_flags |= ISHELD; } } when S_SLEEP: /* * Scroll which makes you fall asleep */ s_know[S_SLEEP] = TRUE; msg("You fall asleep."); no_command += 4 + rnd(SLEEPTIME); when S_CREATE: /* * Create a monster * First look in a circle around him, next try his room * otherwise give up */ { register int x, y; register bool appear = 0; coord mp; /* * Search for an open place */ for (y = hero.y; y <= hero.y+1; y++) for (x = hero.x; x <= hero.x+1; x++) { /* * Don't put a monster in top of the player. */ if (y == hero.y && x == hero.x) continue; /* * Or anything else nasty */ if (step_ok(winat(y, x))) { if (rnd(++appear) == 0) { mp.y = y; mp.x = x; } } } if (appear) { titem = new_item(sizeof (struct thing)); new_monster(titem, randmonster(FALSE), &mp); } else msg("You hear a faint cry of anguish in the distance."); } when S_IDENT: /* * Identify, let the rogue figure something out */ msg("This nanodevice is an identify nanodevice"); s_know[S_IDENT] = TRUE; whatis(); when S_MAP: /* * Scroll of magic mapping. */ s_know[S_MAP] = TRUE; msg("Oh, now this nanodevice has a map on it."); overwrite(stdscr, hw); /* * Take all the things we want to keep hidden out of the window */ for (i = 0; i < lines(); i++) for (j = 0; j < cols(); j++) { switch (nch = ch = mvwinch(hw, i, j)) { case SECRETDOOR: mvaddch(i, j, nch = DOOR); case '-': case '|': case DOOR: case PASSAGE: case ' ': case STAIRS: if (mvwinch(mw, i, j) != ' ') { register struct thing *it; it = (struct thing *) ldata(find_mons(i, j)); if (it->t_oldch == ' ') it->t_oldch = nch; } break; default: nch = ' '; } if (nch != ch) waddch(hw, nch); } /* * Copy in what he has discovered */ overlay(cw, hw); /* * And set up for display */ overwrite(hw, cw); when S_GFIND: /* * Potion of gold detection */ { int gtotal = 0; wclear(hw); for (i = 0; i < MAXROOMS; i++) { gtotal += rooms[i].r_goldval; if (rooms[i].r_goldval != 0 && mvwinch(stdscr, rooms[i].r_gold.y, rooms[i].r_gold.x) == GOLD) mvwaddch(hw,rooms[i].r_gold.y,rooms[i].r_gold.x,GOLD); } if (gtotal) { s_know[S_GFIND] = TRUE; show_win(hw, "You connect to the Net and detect credits locations.--More--"); } else msg("You begin to feel a pull downward"); } when S_TELEP: /* * Scroll of teleportation: * Make him dissapear and reappear */ { int rm; struct room *cur_room; cur_room = roomin(&hero); rm = teleport(); if (cur_room != &rooms[rm]) s_know[S_TELEP] = TRUE; } when S_ENCH: if (cur_weapon == NULL) msg("You feel a strange sense of loss."); else { cur_weapon->o_flags &= ~ISCURSED; if (rnd(100) > 50) cur_weapon->o_hplus++; else cur_weapon->o_dplus++; msg("Your %s glows blue for a moment.", w_names[cur_weapon->o_which]); } when S_SCARE: /* * A monster will refuse to step on a scare monster scroll * if it is dropped. Thus reading it is a mistake and produces * laughter at the poor rogue's boo boo. */ msg("You hear maniacal laughter in the distance."); when S_REMOVE: if (cur_armor != NULL) cur_armor->o_flags &= ~ISCURSED; if (cur_weapon != NULL) cur_weapon->o_flags &= ~ISCURSED; if (cur_ring[LEFT] != NULL) cur_ring[LEFT]->o_flags &= ~ISCURSED; if (cur_ring[RIGHT] != NULL) cur_ring[RIGHT]->o_flags &= ~ISCURSED; msg("You feel as if somebody is watching over you."); when S_AGGR: /* * This scroll aggravates all the monsters on the current * level and sets them running towards the hero */ aggravate(); msg("You hear a high pitched humming noise."); when S_NOP: msg("This nanodevice seems to be empty."); when S_GENOCIDE: msg("You have been granted the boon of genocide"); genocide(); s_know[S_GENOCIDE] = TRUE; otherwise: msg("What a puzzling nanodevice!"); return; } look(TRUE); /* put the result of the scroll on the screen */ status(); if (s_know[obj->o_which] && s_guess[obj->o_which]) { cfree(s_guess[obj->o_which]); s_guess[obj->o_which] = NULL; } else if (!s_know[obj->o_which] && askme && s_guess[obj->o_which] == NULL) { msg(terse ? "Call it: " : "What do you want to call it? "); if (get_str(buf, cw) == NORM) { s_guess[obj->o_which] = malloc((unsigned int) strlen(buf) + 1); strcpy(s_guess[obj->o_which], buf); } } /* * Get rid of the thing */ inpack--; if (obj->o_count > 1) obj->o_count--; else { detach(pack, item); discard(item); } }