int cansee(int y, int x) { struct room *rer; coord tp; if (on(player, ISBLIND)) return FALSE; tp.y = y; tp.x = x; rer = roomin(tp); /* * We can only see if the hero in the same room as the coordinate and * the room is lit or if it is close. */ return ((rer != NULL && rer == roomin(hero) && (!(rer->r_flags & ISDARK) || (rer->r_flags & HASFIRE)) && (levtype != MAZELEV || /* Maze level needs direct line */ maze_view(tp.y, tp.x))) || DISTANCE(tp,hero) < see_dist); }
coord * can_shoot(coord *er, coord *ee, coord *dir) { int ery, erx, eey, eex; /* Make sure we are chasing the player */ if (!ce((*ee), hero)) return(NULL); /* They must be in the same room */ if (roomin(*er) != roomin(hero)) return(NULL); ery = er->y; erx = er->x; eey = ee->y; eex = ee->x; /* Will shoot unless next to player, then 80% prob will fight */ if ((DISTANCE(*er,*ee) < 4) && (rnd(100) < 80)) return(NULL); /* Do we have a straight shot? */ if (!straight_shot(ery, erx, eey, eex, dir)) return(NULL); else return(dir); }
void check_residue(struct thing *tp) { /* Take care of special abilities */ if (on(*tp, DIDHOLD) && (--hold_count == 0)) turn_off(player, ISHELD); /* If it has lowered player, give him back a level, maybe */ if (on(*tp, DIDDRAIN) && rnd(3) == 0) raise_level(); /* If frightened of this monster, stop */ if (on(player, ISFLEE) && (player.t_chasee==tp)) turn_off(player, ISFLEE); /* If monster was suffocating player, stop it */ if (on(*tp, DIDSUFFOCATE)) extinguish_fuse(FUSE_SUFFOCATE); /* If something with fire, may darken */ if (on(*tp, HASFIRE)) { struct room *rp = roomin(tp->t_pos); if (rp && (--(rp->r_fires) <= 0)) { rp->r_flags &= ~HASFIRE; light(&tp->t_pos); } } }
void playit(void) { char *opts; /* * set up defaults for slow terminals */ if (baudrate() <= 1200) { terse = TRUE; jump = TRUE; see_floor = FALSE; } if (md_hasclreol()) inv_type = INV_CLEAR; /* * parse environment declaration of options */ if ((opts = getenv("ROGUEOPTS")) != NULL) parse_opts(opts); oldpos = hero; oldrp = roomin(&hero); while (playing) command(); /* Command execution */ endit(0); }
void fall(struct linked_list *item, int pr) { struct object *obj; struct room *rp; static coord fpos; obj = (struct object *) ldata(item); if (fallpos(&obj->o_pos, &fpos, TRUE)) { mvaddrawch(fpos.y, fpos.x, obj->o_type); obj->o_pos = fpos; if ((rp = roomin(&hero)) != NULL && !(rp->r_flags & ISDARK)) { light(&hero); mvwaddrawch(cw, hero.y, hero.x, PLAYER); } attach(lvl_obj, item); return; } if (pr) if (obj->o_type == WEAPON) /* BUGFUX: Identification trick */ msg("Your %s vanishes as it hits the ground.", w_names[obj->o_which]); else msg("%s vanishes as it hits the ground.", inv_name(obj,TRUE)); discard(item); }
/* * relocate: * Make the monster's new location be the specified one, updating * all the relevant state. */ void relocate(THING *th, const coord *new_loc) { struct room *oroom; if (!ce(*new_loc, th->t_pos)) { mvaddch2(th->t_pos.y, th->t_pos.x, th->t_oldch); th->t_room = roomin(new_loc); set_oldch(th, new_loc); oroom = th->t_room; moat(th->t_pos.y, th->t_pos.x) = NULL; if (oroom != th->t_room) th->t_dest = find_dest(th); th->t_pos = *new_loc; moat(new_loc->y, new_loc->x) = th; } move(new_loc->y, new_loc->x); if (see_monst(th)) addch2(th->t_disguise); else if (on(player, SEEMONST)) { standout(); addch2(th->t_type); standend2(); } }
void new_monster(THING *tp, int type, const coord *cp) { struct monster *mp; int lev_add; if ((lev_add = level - AMULETLEVEL) < 0) lev_add = 0; attach(mlist, tp); tp->t_type = type; tp->t_disguise = type; tp->t_pos = *cp; move(cp->y, cp->x); tp->t_oldch = CCHAR( inch() ); tp->t_room = roomin(cp); moat(cp->y, cp->x) = tp; mp = &monsters[tp->t_type-'A']; tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add; tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8); tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add; strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg); tp->t_stats.s_str = mp->m_stats.s_str; tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp); tp->t_flags = mp->m_flags; if (level > 29) tp->t_flags |= ISHASTE; tp->t_turn = TRUE; tp->t_pack = NULL; if (ISWEARING(R_AGGR)) runto(cp); if (type == 'X') tp->t_disguise = rnd_thing(); }
struct room * roomin_rc(int r, int c) { coord coord; coord.x = c; coord.y = r; return roomin(&coord); }
void ring_off(void) { struct object *obj; struct linked_list *item; if (cur_ring[LEFT_1] == NULL && cur_ring[LEFT_2] == NULL && cur_ring[LEFT_3] == NULL && cur_ring[LEFT_4] == NULL && cur_ring[LEFT_5] == NULL && cur_ring[RIGHT_1] == NULL && cur_ring[RIGHT_2] == NULL && cur_ring[RIGHT_3] == NULL && cur_ring[RIGHT_4] == NULL && cur_ring[RIGHT_5] == NULL) { msg("You aren't wearing any rings."); return; } else if ((item = get_item("remove", RING)) == NULL) return; mpos = 0; obj = OBJPTR(item); if ((obj = OBJPTR(item)) == NULL) msg("You are not wearing that!"); if (dropcheck(obj)) { switch (obj->o_which) { case R_SEEINVIS: msg("Your eyes stop tingling."); break; case R_CARRYING: updpack(); break; case R_LEVITATION: msg("You float gently to the ground."); break; case R_LIGHT: if (roomin(hero) != NULL) { light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } break; case R_TRUESEE: msg("Your sensory perceptions return to normal."); break; } msg("Was wearing %s.", inv_name(obj, LOWERCASE)); } }
int cansee(int y, int x) { struct room *rer; coord tp; if (on(player, ISBLIND)) return FALSE; tp.y = y; tp.x = x; rer = roomin(&tp); /* * We can only see if the hero in the same room as * the coordinate and the room is lit or if it is close. */ return (rer != NULL && rer == roomin(&hero) && !(rer->r_flags&ISDARK)) || DISTANCE(y, x, hero.y, hero.x) < 3; }
/* * fall: * Drop an item someplace around here. */ int fall(struct linked_list *item, int pr) { register struct object *obj ; register struct room *rp ; static coord fpos ; int ret; obj = (struct object *) ldata(item) ; rp = roomin(&hero); if (obj->o_flags & CANRETURN) { add_pack(item, TRUE); return TRUE; } else if (fallpos(&obj->o_pos, &fpos, TRUE)) { if (obj->o_flags & CANBURN && ntraps + 1 < MAXTRAPS + MAXTRAPS) { mvaddch(fpos.y, fpos.x, FIRETRAP); traps[ntraps].tr_type = FIRETRAP; traps[ntraps].tr_flags = ISFOUND; traps[ntraps].tr_show = FIRETRAP; traps[ntraps].tr_pos.y = fpos.y; traps[ntraps++].tr_pos.x = fpos.x; if (rp != NULL) rp->r_flags &= ~ISDARK; discard(item); ret = FALSE; } else { mvaddch(fpos.y, fpos.x, obj->o_type) ; obj->o_pos = fpos ; attach(lvl_obj, item) ; ret = TRUE; } if (rp != NULL && (!(rp->r_flags & ISDARK) || (rp->r_flags & HASFIRE))) { light(&hero) ; mvwaddch(cw, hero.y, hero.x, PLAYER) ; } return ret; } if (pr) { if (obj->o_type == WEAPON) addmsg("The %s", weaps[obj->o_which]); else addmsg(inv_name(obj, TRUE)); msg(" vanishes as it hits the ground."); } discard(item) ; return FALSE; }
coord * find_shoot(struct thing *tp, coord *dir) { struct room *rtp; int ulx, uly, xmx, ymx, xmon, ymon, tpx, tpy, row, col; struct linked_list *mon; struct thing *ick; rtp = roomin(tp->t_pos); /* Find room of chaser */ if (rtp == NULL) return NULL; ulx = rtp->r_pos.x; uly = rtp->r_pos.y; xmx = rtp->r_max.x; ymx = rtp->r_max.y; tpx = tp->t_pos.x; tpy = tp->t_pos.y; for (col = ulx; col < (ulx + xmx); col++) for (row = uly; row < (uly + ymx); row++) { if (row > 0 && col > 0 && isalpha(mvwinch(mw, row, col))) { mon = find_mons(row, col); if (mon) { ick = THINGPTR(mon); xmon = ick->t_pos.x; ymon = ick->t_pos.y; if (!(good_monster(*ick))) { if (straight_shot(tpy, tpx, ymon, xmon, dir)) return(dir); } } } } return(NULL); }
char secretdoor(int y, int x) { struct room *rp; coord cp; cp.x = x; cp.y = y; if ((rp = roomin(cp)) != NULL) { if (y == rp->r_pos.y || y == rp->r_pos.y + rp->r_max.y - 1) return ('-'); else return ('|'); } return ('p'); }
/* * find_dest: * find the proper destination for the monster */ const coord * find_dest(const THING *tp) { THING *obj; int prob; if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom || see_monst(tp)) return &hero; for (obj = lvl_obj; obj != NULL; obj = next(obj)) { if (obj->o_type == SCROLL && obj->o_which == S_SCARE) continue; if (roomin(&obj->o_pos) == tp->t_room && rnd(100) < prob) { for (tp = mlist; tp != NULL; tp = next(tp)) if (tp->t_dest == &obj->o_pos) break; if (tp == NULL) return &obj->o_pos; } } return &hero; }
void wanderer(void) { THING *tp; coord cp; int cnt = 0; tp = new_item(); do { /* Avoid endless loop when all rooms are filled with monsters * and the player room is not accessible to the monsters. */ if (cnt++ >= 500) { discard(tp); return; } find_floor(NULL, &cp, FALSE, TRUE); } while (roomin(&cp) == proom && moat(cp.y, cp.x) == NULL); new_monster(tp, randmonster(TRUE), &cp); if (on(player, SEEMONST)) { standout(); if (!on(player, ISHALU)) addch(tp->t_type); else addch(rnd(26) + 'A'); standend(); } runto(&tp->t_pos); #ifdef MASTER if (wizard) msg("started a wandering %s", monsters[tp->t_type-'A'].m_name); #endif }
/* * 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)); }
/* * add_pack: * Pick up an object and add it to the pack. If the argument is non-null * use it as the linked_list pointer instead of gettting it off the ground. */ void add_pack(struct linked_list *item, int silent) { struct linked_list *ip, *lp; struct object *obj, *op; int exact, from_floor; if (item == NULL) { from_floor = TRUE; if ((item = find_obj(hero.y, hero.x)) == NULL) return; } else from_floor = FALSE; obj = (struct object *) ldata(item); /* * Link it into the pack. Search the pack for a object of similar type * if there isn't one, stuff it at the beginning, if there is, look for one * that is exactly the same and just increment the count if there is. * it that. Food is always put at the beginning for ease of access, but * is not ordered so that you can't tell good food from bad. First check * to see if there is something in thr same group and if there is then * increment the count. */ if (obj->o_group) { for (ip = pack; ip != NULL; ip = next(ip)) { op = (struct object *) ldata(ip); if (op->o_group == obj->o_group) { /* * Put it in the pack and notify the user */ op->o_count++; if (from_floor) { detach(lvl_obj, item); mvaddch(hero.y, hero.x, (roomin(&hero) == NULL ? PASSAGE : FLOOR)); } discard(item); item = ip; goto picked_up; } } } /* * Check if there is room */ if (inpack == MAXPACK-1) { msg("You can't carry anything else."); return; } /* * Check for and deal with scare monster scrolls */ if (obj->o_type == SCROLL && obj->o_which == S_SCARE) if (obj->o_flags & ISFOUND) { msg("The scroll turns to dust as you pick it up."); detach(lvl_obj, item); mvaddch(hero.y, hero.x, FLOOR); return; } else obj->o_flags |= ISFOUND; inpack++; if (from_floor) { detach(lvl_obj, item); mvaddch(hero.y, hero.x, (roomin(&hero) == NULL ? PASSAGE : FLOOR)); } /* * Search for an object of the same type */ exact = FALSE; for (ip = pack; ip != NULL; ip = next(ip)) { op = (struct object *) ldata(ip); if (obj->o_type == op->o_type) break; } if (ip == NULL) { /* * Put it at the end of the pack since it is a new type */ for (ip = pack; ip != NULL; ip = next(ip)) { op = (struct object *) ldata(ip); if (op->o_type != FOOD) break; lp = ip; } } else { /* * Search for an object which is exactly the same */ while (ip != NULL && op->o_type == obj->o_type) { if (op->o_which == obj->o_which) { exact = TRUE; break; } lp = ip; if ((ip = next(ip)) == NULL) break; op = (struct object *) ldata(ip); } } if (ip == NULL) { /* * Didn't find an exact match, just stick it here */ if (pack == NULL) pack = item; else { lp->l_next = item; item->l_prev = lp; item->l_next = NULL; } } else { /* * If we found an exact match. If it is a potion, food, or a * scroll, increase the count, otherwise put it with its clones. */ if (exact && ISMULT(obj->o_type)) { op->o_count++; discard(item); item = ip; goto picked_up; } if ((item->l_prev = prev(ip)) != NULL) item->l_prev->l_next = item; else pack = item; item->l_next = ip; ip->l_prev = item; } picked_up: /* * Notify the user */ obj = (struct object *) ldata(item); if (notify && !silent) { if (!terse) addmsg("You now have "); msg("%s (%c)", inv_name(obj, !terse), pack_char(obj)); } if (obj->o_type == AMULET) amulet = TRUE; }
void look(int wakeup) { int x, y; char ch, och; int oldx, oldy; int inpass, horizontal, vertical, do_light = FALSE, do_blank = FALSE; int passcount = 0; struct room *rp; int ey, ex; /* Are we moving vertically or horizontally? */ if (runch == 'h' || runch == 'l') horizontal = TRUE; else horizontal = FALSE; if (runch == 'j' || runch == 'k') vertical = TRUE; else vertical = FALSE; getyx(cw, oldy, oldx); /* Save current position */ /* * Blank out the floor around our last position and check for moving * out of a corridor in a maze. */ if (oldrp != NULL && (oldrp->r_flags & ISDARK) && !(oldrp->r_flags & HASFIRE) && off(player, ISBLIND)) do_blank = TRUE; for (x = player.t_oldpos.x - 1; x <= player.t_oldpos.x + 1; x++) for (y = player.t_oldpos.y - 1; y <= player.t_oldpos.y + 1; y++) { ch = show(y, x); if (do_blank && (y != hero.y || x != hero.x) && ch == FLOOR) mvwaddch(cw, y, x, ' '); /* Moving out of a corridor? */ if (levtype == MAZELEV && (ch != '|' && ch != '-') && /* Not a wall */ ((vertical && x != player.t_oldpos.x && y == player.t_oldpos.y) || (horizontal && y != player.t_oldpos.y && x == player.t_oldpos.x))) do_light = TRUE; /* Just came to a turn */ } inpass = ((rp = roomin(hero)) == NULL); /* Are we in a passage? */ /* Are we coming out of a wall into a corridor in a maze? */ och = show(player.t_oldpos.y, player.t_oldpos.x); ch = show(hero.y, hero.x); if (levtype == MAZELEV && (och == '|' || och == '-' || och == SECRETDOOR) && (ch != '|' && ch != '-' && ch != SECRETDOOR)) { do_light = off(player, ISBLIND); /* Light it up if not blind */ } /* Look around the player */ ey = hero.y + 1; ex = hero.x + 1; for (x = hero.x - 1; x <= ex; x++) if (x >= 0 && x < COLS) for (y = hero.y - 1; y <= ey; y++) { if (y <= 0 || y >= LINES - 2) continue; if (isalpha(mvwinch(mw, y, x))) { struct linked_list *it; struct thing *tp; if (wakeup) it = wake_monster(y, x); else it = find_mons(y, x); if (it == NULL) continue; tp = THINGPTR(it); tp->t_oldch = CCHAR( mvinch(y, x) ); if (isatrap(tp->t_oldch)) { struct trap *trp = trap_at(y, x); tp->t_oldch = (trp->tr_flags & ISFOUND) ? tp->t_oldch : trp->tr_show; } if (tp->t_oldch == FLOOR && (rp->r_flags & ISDARK) && !(rp->r_flags & HASFIRE) && off(player, ISBLIND)) tp->t_oldch = ' '; } /* Secret doors show as walls */ if ((ch = show(y, x)) == SECRETDOOR) ch = secretdoor(y, x); /* * Don't show room walls if he is in a * passage and check for maze turns */ if (off(player, ISBLIND)) { if (y == hero.y && x == hero.x || (inpass && (ch == '-' || ch == '|'))) continue; /* Are we at a crossroads in a maze? */ if (levtype == MAZELEV && (ch != '|' && ch != '-') && /* Not a wall */ ((vertical && x != hero.x && y == hero.y) || (horizontal && y != hero.y && x == hero.x))) do_light = TRUE; /* Just came to a turn */ } else if (y != hero.y || x != hero.x) continue; wmove(cw, y, x); waddch(cw, ch); if (door_stop && !firstmove && running) { switch (runch) { case 'h': if (x == ex) continue; break; case 'j': if (y == hero.y - 1) continue; break; case 'k': if (y == ey) continue; break; case 'l': if (x == hero.x - 1) continue; break; case 'y': if ((x + y) - (hero.x + hero.y) >= 1) continue; break; case 'u': if ((y - x) - (hero.y - hero.x) >= 1) continue; break; case 'n': if ((x + y) - (hero.x + hero.y) <= -1) continue; break; case 'b': if ((y - x) - (hero.y - hero.x) <= -1) continue; break; } switch (ch) { case DOOR: if (x == hero.x || y == hero.y) running = FALSE; break; case PASSAGE: if (x == hero.x || y == hero.y) passcount++; break; case FLOOR: /* * Stop by new passages in a * maze (floor next to us) */ if ((levtype == MAZELEV) && ((horizontal && x == hero.x && y != hero.y) || (vertical && y == hero.y && x != hero.x))) running = FALSE; case '|': case '-': case ' ': break; default: running = FALSE; break; } } } if (door_stop && !firstmove && passcount > 1) running = FALSE; /* * Do we have to light up the area (just stepped into a new * corridor)? */ if (do_light && wakeup && /* wakeup will be true on a normal move */ !(rp->r_flags & ISDARK) && /* We have some light */ !ce(hero, player.t_oldpos)) /* Don't do anything if we didn't move */ light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); wmove(cw, oldy, oldx); if (wakeup) { player.t_oldpos = hero; /* Don't change if we didn't move */ oldrp = rp; } }
/* * missile: * Fire a missile in a given direction */ void missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp) { register struct object *obj ; register struct linked_list *nitem ; /* * Get which thing we are hurling */ if (item == NULL) { return ; } obj = (struct object *) ldata(item) ; if (!dropcheck(obj) || is_current(obj)) { return ; } /* * Get rid of the thing. If it is a non-multiple item object, or * if it is the last thing, just drop it. Otherwise, create a new * item with a count of one. */ if (obj->o_count < 2) { detach(tp->t_pack, item) ; if (tp->t_pack == pack) { inpack-- ; freeletter(item); } } else { obj->o_count-- ; nitem = (struct linked_list *) new_item(sizeof *obj) ; obj = (struct object *) ldata(nitem) ; *obj = *((struct object *) ldata(item)) ; obj->o_count = 1 ; item = nitem ; } if (obj->o_type == ARTIFACT) has_artifact &= ~(1 << obj->o_which); if (obj->o_type == SCROLL && obj->o_which == S_SCARE) { if (obj->o_flags & ISBLESSED) obj->o_flags &= ~ISBLESSED; else obj->o_flags |= ISCURSED; } updpack (FALSE); do_motion(obj, ydelta, xdelta, tp) ; /* * AHA! Here it has hit something. If it is a wall or a door, * or if it misses (combat) the monster, put it on the floor */ if (!hit_monster(unc(obj->o_pos), obj, tp)) { if (obj->o_type == WEAPON && obj->o_which == GRENADE) { register struct room *rp; static coord fpos; msg("BOOOM!"); aggravate(); rp = roomin(&obj->o_pos); if (ntraps + 1 < MAXTRAPS + MAXTRAPS && fallpos(&obj->o_pos, &fpos, TRUE)) { mvaddch(fpos.y, fpos.x, TRAPDOOR); traps[ntraps].tr_type = TRAPDOOR; traps[ntraps].tr_flags = ISFOUND; traps[ntraps].tr_show = TRAPDOOR; traps[ntraps].tr_pos.y = fpos.y; traps[ntraps++].tr_pos.x = fpos.x; light(&hero); } discard(item); } else if (obj->o_flags & ISLOST) { if (obj->o_type == WEAPON) addmsg("The %s", weaps[obj->o_which].w_name); else addmsg(inv_name(obj, TRUE)); msg(" vanishes in a puff of greasy smoke."); discard(item); } else { if (fall(item, TRUE)) if (obj->o_flags & CANRETURN) msg("You have %s.", inv_name(obj, TRUE)); } } else if (obj->o_flags & ISOWNED) { add_pack(item, TRUE); msg("You have %s.", inv_name(obj, TRUE)); } mvwaddch(cw, hero.y, hero.x, PLAYER) ; }
/* * do_chase: * Make one thing chase another. */ int do_chase(THING *th) { coord *cp; struct room *rer, *ree; /* room of chaser, room of chasee */ int mindist = 32767, curdist; int stoprun = FALSE; /* TRUE means we are there */ int door; THING *obj; coord this; /* Temporary destination for chaser */ rer = th->t_room; /* Find room of chaser */ if (on(*th, ISGREED) && rer->r_goldval == 0) th->t_dest = &hero; /* If gold has been taken, run after hero */ if (th->t_dest == &hero) /* Find room of chasee */ ree = proom; else ree = roomin(th->t_dest); /* * We don't count doors as inside rooms for this routine */ door = (chat(th->t_pos.y, th->t_pos.x) == DOOR); /* * If the object of our desire is in a different room, * and we are not in a corridor, run to the door nearest to * our goal. */ over: if (rer != ree) { for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++) { curdist = dist_cp(th->t_dest, cp); if (curdist < mindist) { this = *cp; mindist = curdist; } } if (door) { rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM]; door = FALSE; goto over; } } else { this = *th->t_dest; /* * For dragons check and see if (a) the hero is on a straight * line from it, and (b) that it is within shooting distance, * but outside of striking range. */ if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x || abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x)) && dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH && !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0) { delta.y = sign(hero.y - th->t_pos.y); delta.x = sign(hero.x - th->t_pos.x); if (has_hit) endmsg(); fire_bolt(&th->t_pos, &delta, "flame"); running = FALSE; count = 0; quiet = 0; if (to_death && !on(*th, ISTARGET)) { to_death = FALSE; kamikaze = FALSE; } return(0); } } /* * This now contains what we want to run to this time * so we run to it. If we hit it we either want to fight it * or stop running */ if (!chase(th, &this)) { if (ce(this, hero)) { return( attack(th) ); } else if (ce(this, *th->t_dest)) { for (obj = lvl_obj; obj != NULL; obj = next(obj)) if (th->t_dest == &obj->o_pos) { detach(lvl_obj, obj); attach(th->t_pack, obj); chat(obj->o_pos.y, obj->o_pos.x) = (th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR; th->t_dest = find_dest(th); break; } if (th->t_type != 'F') stoprun = TRUE; } } else { if (th->t_type == 'F') return(0); } relocate(th, &ch_ret); /* * And stop running if need be */ if (stoprun && ce(th->t_pos, *(th->t_dest))) th->t_flags &= ~ISRUN; return(0); }
int do_chase(struct thing *th) { struct room *rer, *ree; /* room of chaser, room of chasee */ int mindist = 32767, i, dist; int stoprun = FALSE; /* TRUE means we are there */ int sch; coord this; /* Temporary destination for chaser */ rer = roomin(&th->t_pos); /* Find room of chaser */ ree = roomin(th->t_dest); /* Find room of chasee */ /* * We don't count doors as inside rooms for this routine */ if (CMVWINCH(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) rer = NULL; this = *th->t_dest; /* * If the object of our desire is in a different room, * than we are and we ar not in a corridor, run to the * door nearest to our goal. */ if (rer != NULL && rer != ree) for (i = 0; i < rer->r_nexits; i++) /* loop through doors */ { dist = DISTANCE(th->t_dest->y, th->t_dest->x, rer->r_exit[i].y, rer->r_exit[i].x); if (dist < mindist) /* minimize distance */ { this = rer->r_exit[i]; mindist = dist; } } /* * this now contains what we want to run to this time * so we run to it. If we hit it we either want to fight it * or stop running */ if (!chase(th, &this)) { if (ce(this, hero)) { return( attack(th) ); } else if (th->t_type != 'F') stoprun = TRUE; } else if (th->t_type == 'F') return(0); mvwaddrawch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); sch = CMVWINCH(cw, ch_ret.y, ch_ret.x); if (rer != NULL && (rer->r_flags & ISDARK) && sch == FLOOR && DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < 3 && off(player, ISBLIND)) th->t_oldch = ' '; else th->t_oldch = sch; if (cansee(unc(ch_ret)) && !on(*th, ISINVIS)) mvwaddrawch(cw, ch_ret.y, ch_ret.x, th->t_type); mvwaddrawch(mw, th->t_pos.y, th->t_pos.x, ' '); mvwaddrawch(mw, ch_ret.y, ch_ret.x, th->t_type); th->t_pos = ch_ret; /* * And stop running if need be */ if (stoprun && ce(th->t_pos, *(th->t_dest))) th->t_flags &= ~ISRUN; return(0); }
void teleport(void) { struct room *new_rp = NULL, *old_rp = roomin(hero); int rm, which; coord c; int is_lit = FALSE; /* For saving room light state */ int rand_position = TRUE; c = hero; mvwaddch(cw, hero.y, hero.x, mvwinch(stdscr, hero.y, hero.x)); if (is_wearing(R_TELCONTROL)) { msg("Where do you wish to teleport to? (* for help)"); wmove(cw, hero.y, hero.x); wrefresh(cw); which = (short) (readchar() & 0177); while (which != (short) ESCAPE && which != (short) LINEFEED && which != (short) CARRIAGE_RETURN) { switch(which) { case 'h': c.x--; break; case 'j': c.y++; break; case 'k': c.y--; break; case 'l': c.x++; break; case 'y': c.x--; c.y--; break; case 'u': c.x++; c.y--; break; case 'b': c.x--; c.y++; break; case 'n': c.x++; c.y++; break; case '*': msg("Use h,j,k,l,y,u,b,n to position cursor, then hit" "return."); } c.y = max(c.y, 1); c.y = min(c.y, LINES - 3); c.x = max(c.x, 1); c.x = min(c.x, COLS - 1); wmove(cw, c.y, c.x); wrefresh(cw); which = (short) (readchar() & 0177); } which = winat(c.y, c.x); if ((which == FLOOR || which == PASSAGE || which == DOOR) && ((ring_value(R_TELCONTROL) == 0 && rnd(10) < 6) || (ring_value(R_TELCONTROL) > 0 && rnd(10) < 9))) { rand_position = FALSE; msg("You attempt succeeds."); hero = c; new_rp = roomin(hero); } else msg("Your attempt fails."); } if (rand_position) { do { rm = rnd_room(); rnd_pos(&rooms[rm], &hero); } while (winat(hero.y, hero.x) != FLOOR); new_rp = &rooms[rm]; } /* If hero gets moved, darken old room */ if (old_rp && old_rp != new_rp) { if (!(old_rp->r_flags & ISDARK)) is_lit = TRUE; old_rp->r_flags |= ISDARK; /* Fake darkness */ light(&c); if (is_lit) old_rp->r_flags &= ~ISDARK; /* Restore light state */ } light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); /* turn off ISHELD in case teleportation was done while fighting */ if (on(player, ISHELD)) { struct linked_list *ip, *nip; struct thing *mp; turn_off(player, ISHELD); hold_count = 0; for (ip = mlist; ip; ip = nip) { mp = THINGPTR(ip); nip = next(ip); if (on(*mp, DIDHOLD)) { turn_off(*mp, DIDHOLD); turn_on(*mp, CANHOLD); } turn_off(*mp, DIDSUFFOCATE); } } extinguish_fuse(FUSE_SUFFOCATE); player.t_no_move = 0; /* not trapped anymore */ count = 0; running = FALSE; return; }
void ring_on(void) { struct object *obj; struct linked_list *item; int ring; char buf[2 * LINELEN]; if ((item = get_item("put on", RING)) == NULL) return; obj = OBJPTR(item); if (obj->o_type != RING) { msg("You can't put that on!"); return; } /* find out which hand to put it on */ if (is_current(obj)) { msg("Already wearing that!"); return; } if (cur_ring[LEFT_1] == NULL) ring = LEFT_1; else if (cur_ring[LEFT_2] == NULL) ring = LEFT_2; else if (cur_ring[LEFT_3] == NULL) ring = LEFT_3; else if (cur_ring[LEFT_4] == NULL) ring = LEFT_4; else if (cur_ring[LEFT_5] == NULL) ring = LEFT_5; else if (cur_ring[RIGHT_1] == NULL) ring = RIGHT_1; else if (cur_ring[RIGHT_2] == NULL) ring = RIGHT_2; else if (cur_ring[RIGHT_3] == NULL) ring = RIGHT_3; else if (cur_ring[RIGHT_4] == NULL) ring = RIGHT_4; else if (cur_ring[RIGHT_5] == NULL) ring = RIGHT_5; else { msg("You already have on ten rings."); return; } cur_ring[ring] = obj; /* Calculate the effect it has on the poor guy. */ switch (obj->o_which) { case R_ADDSTR: pstats.s_str += obj->o_ac; break; case R_ADDHIT: pstats.s_dext += obj->o_ac; break; case R_ADDINTEL: pstats.s_intel += obj->o_ac; break; case R_ADDWISDOM: pstats.s_wisdom += obj->o_ac; break; case R_FREEDOM: turn_off(player, ISHELD); hold_count = 0; break; case R_TRUESEE: if (off(player, PERMBLIND)) { turn_on(player, CANTRUESEE); msg("You become more aware of your surroundings."); sight(NULL); light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } break; case R_SEEINVIS: if (off(player, PERMBLIND)) { turn_on(player, CANTRUESEE); msg("Your eyes begin to tingle."); sight(NULL); light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } break; case R_AGGR: aggravate(); break; case R_CARRYING: updpack(); break; case R_LEVITATION: msg("You begin to float in the air!"); break; case R_LIGHT: if (roomin(hero) != NULL) { light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } } status(FALSE); if (know_items[TYP_RING][obj->o_which] && guess_items[TYP_RING][obj->o_which]) { mem_free(guess_items[TYP_RING][obj->o_which]); guess_items[TYP_RING][obj->o_which] = NULL; } else if (!know_items[TYP_RING][obj->o_which] && askme && (obj->o_flags & ISKNOW) == 0 && guess_items[TYP_RING][obj->o_which] == NULL) { mpos = 0; msg("What do you want to call it? "); if (get_string(buf, cw) == NORM) { guess_items[TYP_RING][obj->o_which] = new_alloc(strlen(buf) + 1); strcpy(guess_items[TYP_RING][obj->o_which], buf); } msg(""); } }
struct linked_list * wake_monster(int y, int x) { struct thing *tp; struct linked_list *it; struct room *trp; char *mname; if ((it = find_mons(y, x)) == NULL) { debug("Can't find monster in show."); return(NULL); } tp = THINGPTR(it); if ((good_monster(*tp)) || on(player, SUMMONING)) { chase_it(&tp->t_pos, &player); turn_off(*tp, ISINVIS); turn_off(*tp, CANSURPRISE); return(it); } trp = roomin(tp->t_pos); /* Current room for monster */ mname = monsters[tp->t_index].m_name; /* Let greedy ones guard gold */ if (on(*tp, ISGREED) && off(*tp, ISRUN)) if ((trp != NULL) && (lvl_obj != NULL)) { struct linked_list *item; struct object *cur; for (item = lvl_obj; item != NULL; item = next(item)) { cur = OBJPTR(item); if ((cur->o_type == GOLD) && (roomin(cur->o_pos) == trp)) { /* Run to the gold */ tp->t_horde = cur; turn_on(*tp, ISRUN); turn_off(*tp, ISDISGUISE); tp->t_ischasing = FALSE; /* Make it worth protecting */ cur->o_count += roll(2, 3) * GOLDCALC; break; } } } /* * Every time he sees mean monster, it might start chasing him unique * monsters always do */ if ( (on(*tp, ISUNIQUE)) || ( (rnd(100) > 33) && on(*tp, ISMEAN) && off(*tp, ISHELD) && off(*tp, ISRUN) && !is_stealth(&player) && (off(player, ISINVIS) || on(*tp, CANSEE)) ) ) { chase_it(&tp->t_pos, &player); } /* Handle gaze attacks */ if (on(*tp, ISRUN) && cansee(tp->t_pos.y, tp->t_pos.x) && off(player, ISINVIS)) { if (on(*tp, CANHUH)) /* Confusion */ { if (on(player, CANREFLECT)) { msg("You reflect the bewildering stare of the %s.", mname); if (save_throw(VS_MAGIC, tp)) { msg("The %s is confused!", mname); turn_on(*tp, ISHUH); } else msg("The %s staggers for a moment.", mname); } else if (save(VS_MAGIC)) { msg("You feel dizzy for a moment, but it quickly passes."); if (rnd(100) < 67) turn_off(*tp, CANHUH); } else if (off(player, ISCLEAR)) { if (off(player, ISHUH)) { light_fuse(FUSE_UNCONFUSE, 0, rnd(20) + HUHDURATION, AFTER); msg("The %s's gaze has confused you.", mname); turn_on(player, ISHUH); } else lengthen_fuse(FUSE_UNCONFUSE, rnd(20) + HUHDURATION); } } if (on(*tp, CANSNORE)) /* Sleep */ { if (on(player, CANREFLECT)) { msg("You reflect the lethargic glance of the %s", mname); if (save_throw(VS_PARALYZATION, tp)) { msg("The %s falls asleep!", mname); tp->t_no_move += SLEEPTIME; } } else if (no_command == 0 && !save(VS_PARALYZATION)) { if (is_wearing(R_ALERT)) msg("You feel slightly drowsy for a moment."); else { msg("The %s's gaze puts you to sleep.", mname); no_command = SLEEPTIME; if (rnd(100) < 50) turn_off(*tp, CANSNORE); } } } if (on(*tp, CANFRIGHTEN)) /* Fear */ { turn_off(*tp, CANFRIGHTEN); if (on(player, CANREFLECT)) { msg("The %s sees its reflection. ", mname); if (save_throw(VS_MAGIC,tp)) { msg("The %s is terrified by its reflection!", mname); turn_on(*tp, ISFLEE); } } else { if (!save(VS_WAND) && !(on(player, ISFLEE) && (player.t_chasee==tp))) { if ((player.t_ctype != C_PALADIN) && off(player, SUPERHERO)) { turn_on(player, ISFLEE); player.t_ischasing = FALSE; player.t_chasee = tp; msg("The sight of the %s terrifies you.", mname); } else msg("My, the %s looks ugly.", mname); } } } if (on(*tp, LOOKSLOW)) /* Slow */ { turn_off(*tp, LOOKSLOW); if (on(player, CANREFLECT)) { msg("You reflect the mournful glare of the %s.", mname); if (save_throw(VS_MAGIC,tp)) { msg("The %s is slowing down!", mname); turn_on(*tp, ISSLOW); } } else if (is_wearing(R_FREEDOM) || save(VS_MAGIC)) msg("You feel run-down for a moment."); else { if (on(player, ISHASTE)) /* Already sped up */ { extinguish_fuse(FUSE_NOHASTE); nohaste(NULL); } else { msg("You feel yourself moving %sslower.", on(player, ISSLOW) ? "even " : ""); if (on(player, ISSLOW)) lengthen_fuse(FUSE_NOSLOW, rnd(4) + 4); else { turn_on(player, ISSLOW); player.t_turn = TRUE; light_fuse(FUSE_NOSLOW, 0, rnd(4) + 4, AFTER); } } } } if (on(*tp, CANBLIND)) /* Blinding */ { turn_off(*tp, CANBLIND); if (on(player, CANREFLECT)) { msg("You reflect the blinding stare of the %s.", mname); if (save_throw(VS_WAND, tp)) { msg("The %s is blinded!", mname); turn_on(*tp, ISHUH); } } else if (off(player, ISBLIND)) if (save(VS_WAND) || is_wearing(R_TRUESEE) || is_wearing(R_SEEINVIS)) msg("Your eyes film over for a moment."); else { msg("The gaze of the %s blinds you.", mname); turn_on(player, ISBLIND); light_fuse(FUSE_SIGHT, 0, rnd(30) + 20, AFTER); look(FALSE); } } if (on(*tp, LOOKSTONE)) /* Stoning */ { turn_off(*tp, LOOKSTONE); if (on(player, CANREFLECT)) { msg("You reflect the flinty look of the %s.", mname); if (save_throw(VS_PETRIFICATION,tp)) { msg("The %s suddenly stiffens", mname); tp->t_no_move += STONETIME; } else { msg("The %s is turned to stone!", mname); killed(&player, it, NOMESSAGE, POINTS); } } else { if (on(player, CANINWALL)) msg("The %s cannot focus on you.", mname); else { msg("The gaze of the %s stiffens your limbs.", mname); if (save(VS_PETRIFICATION)) no_command = STONETIME; else if (rnd(100)) no_command = STONETIME * 3; else { msg("The gaze of the %s petrifies you.", mname); msg("You are turned to stone!!! --More--"); wait_for(' '); death(D_PETRIFY); return(it); } } } } } /* * True Sight sees all Never see ISINWALL or CANSURPRISE See ISSHADOW * 80% See ISINVIS with See Invisibilty */ if (off(player, CANTRUESEE) && on(*tp, ISINWALL) || on(*tp, CANSURPRISE) || (on(*tp, ISSHADOW) && rnd(100) < 80) || (on(*tp, ISINVIS) && off(player, CANSEE))) { /* TODO: incomplete - need to finish logic int ch = mvwinch(stdscr, y, x); */ } /* hero might be able to hear or smell monster if he can't see it */ if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || on(player, CANHEAR)) && !cansee(tp->t_pos.y, tp->t_pos.x)) msg("You hear a %s nearby.", mname); else if ((rnd(player.t_ctype == C_THIEF ? 40 : 200) == 0 || on(player, CANSCENT)) && !cansee(tp->t_pos.y, tp->t_pos.x)) msg("You smell a %s nearby.", mname); return(it); }
void do_chase(struct thing *th, int flee) { struct room *rer; /* room of chaser */ struct room *ree; /* room of chasee */ struct room *old_room; /* old room of monster */ struct room *new_room; /* new room of monster */ int i, mindist = INT_MAX, maxdist = INT_MIN, dist = INT_MIN; int last_door = -1; /* Door we just came from */ int stoprun = FALSE; /* TRUE means we are there */ int rundoor; /* TRUE means run to a door */ int hit_bad = FALSE; /* TRUE means hit bad monster */ int mon_attack; /* TRUE means find a monster to hit */ char sch; struct linked_list *item; coord this; /* Temporary destination for chaser */ if (!th->t_ischasing) return; /* Make sure the monster can move */ if (th->t_no_move != 0) { th->t_no_move--; return; } /* * Bad monsters check for a good monster to hit, friendly monsters * check for a bad monster to hit. */ mon_attack = FALSE; if (good_monster(*th)) { hit_bad = TRUE; mon_attack = TRUE; } else if (on(*th, ISMEAN)) { hit_bad = FALSE; mon_attack = TRUE; } if (mon_attack) { struct linked_list *mon_to_hit; mon_to_hit = f_mons_a(th->t_pos.y, th->t_pos.x, hit_bad); if (mon_to_hit) { mon_mon_attack(th, mon_to_hit, pick_weap(th), NOTHROWN); return; } } /* no nearby monster to hit */ rer = roomin(th->t_pos); /* Find room of chaser */ ree = roomin(th->t_chasee->t_pos); /* Find room of chasee */ /* * We don't count doors as inside rooms for this routine */ if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) rer = NULL; this = th->t_chasee->t_pos; /* * If we are not in a corridor and not a phasing monster, then if we * are running after the player, we run to a door if he is not in the * same room. If we are fleeing, we run to a door if he IS in the * same room. Note: We don't bother with doors in mazes. Phasing * monsters don't need to look for doors. There are no doors in mazes * and throne rooms. */ if (levtype != MAZELEV && levtype != THRONE && rer != NULL && off(*th, CANINWALL)) { if (flee) rundoor = (rer == ree); else rundoor = (rer != ree); } else rundoor = FALSE; if (rundoor) { coord d_exit; /* A particular door */ int exity, exitx; /* Door's coordinates */ if (th->t_doorgoal != -1) { /* Do we already have the goal? */ this = rer->r_exit[th->t_doorgoal]; dist = 0; /* Indicate that we have our door */ } else for (i = 0; i < rer->r_nexits; i++) { /* Loop through doors */ d_exit = rer->r_exit[i]; exity = d_exit.y; exitx = d_exit.x; /* Avoid secret doors */ if (mvwinch(stdscr, exity, exitx) == DOOR) { /* Were we just on this door? */ if (ce(d_exit, th->t_oldpos)) last_door = i; else { dist = DISTANCE(th->t_chasee->t_pos, d_exit); /* * If fleeing, we want to * maximize distance from * door to what we flee, and * minimize distance from * door to us. */ if (flee) dist-=DISTANCE(th->t_pos,d_exit); /* * Maximize distance if * fleeing, otherwise * minimize it */ if ((flee && (dist > maxdist)) || (!flee && (dist < mindist))) { th->t_doorgoal = i; /* Use this door */ this = d_exit; mindist = maxdist = dist; } } } } /* Could we not find a door? */ if (dist == INT_MIN) { /* If we were on a door, go ahead and use it */ if (last_door != -1) { th->t_doorgoal = last_door; this = th->t_oldpos; dist = 0; /* Indicate that we found a door */ } } /* Indicate that we do not want to flee from the door */ if (dist != INT_MIN) flee = FALSE; } else th->t_doorgoal = -1; /* Not going to any door */ /* * this now contains what we want to run to this time so we run to * it. If we hit it we either want to fight it or stop running */ if (!chase(th, &this, flee)) { if (ce(th->t_nxtpos, hero)) { /* merchants try to sell something */ if (on(*th, CANSELL)) { sell(th); return; } else if (off(*th, ISFRIENDLY) && off(*th, ISCHARMED) && (off(*th, CANFLY) || (on(*th, CANFLY) && rnd(2)))) attack(th, pick_weap(th), FALSE); return; } else if (on(*th, NOMOVE)) stoprun = TRUE; } if (!curr_mons) return; /* Did monster get itself killed? */ if (on(*th, NOMOVE)) return; /* If we have a scavenger, it can pick something up */ if ((item = find_obj(th->t_nxtpos.y, th->t_nxtpos.x)) != NULL) { struct linked_list *node, *top = item; struct object *obt; while(top) { /* grab all objects that qualify */ struct object *obj = OBJPTR(item); obt = OBJPTR(top); node = obt->next_obj; if (on(*th, ISSCAVENGE) || ((on(*th, CANWIELD) || on(*th, CANSHOOT)) && (obj->o_type == WEAPON || obj->o_type == ARMOR)) || (on(*th, CANCAST) && is_magic(obj))) { rem_obj(top, FALSE); attach(th->t_pack, top); } top = node; } light(&hero); } mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); sch = CCHAR( mvwinch(cw, th->t_nxtpos.y, th->t_nxtpos.x) ); /* Get old and new room of monster */ old_room = roomin(th->t_pos); new_room = roomin(th->t_nxtpos); /* If the monster can illuminate rooms, check for a change */ if (on(*th, HASFIRE)) { /* Is monster entering a room? */ if (old_room != new_room && new_room != NULL) { new_room->r_flags |= HASFIRE; new_room->r_fires++; if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && new_room->r_fires==1) light(&hero); } /* Is monster leaving a room? */ if (old_room != new_room && old_room != NULL) { if (--(old_room->r_fires) <= 0) { old_room->r_flags &= ~HASFIRE; if (cansee(th->t_pos.y, th->t_pos.x)) light(&th->t_pos); } } } /* * If monster is entering player's room and player can see it, stop * the player's running. */ if (new_room != old_room && new_room != NULL && new_room == ree && cansee(th->t_nxtpos.y, th->t_nxtpos.x) && (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) || on(player, CANSEE)) && off(*th, CANSURPRISE)) running = FALSE; if (rer != NULL && (rer->r_flags & ISDARK) && !(rer->r_flags & HASFIRE) && sch == FLOOR && DISTANCE(th->t_nxtpos, th->t_pos) < see_dist && off(player, ISBLIND)) th->t_oldch = ' '; else th->t_oldch = sch; if (cansee(th->t_nxtpos.y, th->t_nxtpos.x) && off(*th, ISINWALL) && ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) && off(*th, CANSURPRISE)) mvwaddch(cw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); mvwaddch(mw, th->t_nxtpos.y, th->t_nxtpos.x, th->t_type); /* Record monster's last position (if new one is different) */ if (!ce(th->t_nxtpos, th->t_pos)) th->t_oldpos = th->t_pos; th->t_pos = th->t_nxtpos; /* Mark the monster's new position */ /* If the monster is on a trap, trap it */ sch = CCHAR(mvinch(th->t_nxtpos.y, th->t_nxtpos.x)); if (isatrap(sch)) { debug("Monster trapped by %c.", sch); if (cansee(th->t_nxtpos.y, th->t_nxtpos.x)) th->t_oldch = sch; be_trapped(th, th->t_nxtpos); } /* And stop running if need be */ if (stoprun && ce(th->t_pos, th->t_chasee->t_pos)) { th->t_ischasing = FALSE; turn_off(*th, ISRUN); } }
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); }
do_rooms() { register int i; register struct room *rp; register struct linked_list *item; register struct thing *tp; register int left_out; coord top; coord bsze; coord mp; /* * bsze is the maximum room size */ bsze.x = cols()/3; bsze.y = lines()/3; /* * Clear things for a new level */ for (rp = rooms; rp < &rooms[MAXROOMS]; rp++) rp->r_goldval = rp->r_nexits = rp->r_flags = 0; /* * Put the gone rooms, if any, on the level */ left_out = rnd(4); for (i = 0; i < left_out; i++) rooms[rnd_room()].r_flags |= ISGONE; /* * dig and populate all the rooms on the level */ for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++) { /* * Find upper left corner of box that this room goes in */ top.x = (i%3)*bsze.x + 1; top.y = i/3*bsze.y; if (rp->r_flags & ISGONE) { /* * Place a gone room. Make certain that there is a blank line * for passage drawing. */ do { rp->r_pos.x = top.x + rnd(bsze.x-2) + 1; rp->r_pos.y = top.y + rnd(bsze.y-2) + 1; rp->r_max.x = -cols(); rp->r_max.x = -lines(); } until(rp->r_pos.y > 0 && rp->r_pos.y < lines()-1); continue; } if (rnd(10) < level-1) rp->r_flags |= ISDARK; /* * Find a place and size for a random room */ do { rp->r_max.x = rnd(bsze.x - 4) + 4; rp->r_max.y = rnd(bsze.y - 4) + 4; rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x); rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y); } until (rp->r_pos.y != 0); /* * Put the gold in */ if (rnd(100) < 50 && (!amulet || level >= max_level)) { rp->r_goldval = GOLDCALC; rnd_pos(rp, &rp->r_gold); if (roomin(&rp->r_gold) != rp) endwin(), abort(); } draw_room(rp); /* * Put the monster in */ if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25)) { item = new_item(sizeof *tp); tp = (struct thing *) ldata(item); do { rnd_pos(rp, &mp); } until(mvwinch(stdscr, mp.y, mp.x) == FLOOR); new_monster(item, randmonster(FALSE), &mp); /* * See if we want to give it a treasure to carry around. */ if (rnd(100) < monsters[tp->t_type-'A'].m_carry) attach(tp->t_pack, new_thing()); } }
void fall(struct thing *tp, struct linked_list *item, int pr, int player_owned) { struct object *obj; struct room *rp; coord fpos; obj = OBJPTR(item); rp = roomin(tp->t_pos); if (player_owned && obj->o_flags & CANRETURN) { add_pack(item, NOMESSAGE); msg("You have %s.", inv_name(obj, LOWERCASE)); return; } else if (fallpos(obj->o_pos, &fpos)) { if (obj->o_flags & CANBURN && obj->o_type == WEAPON && obj->o_which == MOLOTOV && ntraps + 1 < 2 * MAXTRAPS) { mvaddch(fpos.y, fpos.x, FIRETRAP); traps[ntraps].tr_type = FIRETRAP; traps[ntraps].tr_flags = ISFOUND; traps[ntraps].tr_show = FIRETRAP; traps[ntraps].tr_pos = fpos; ntraps++; if (rp != NULL) rp->r_flags &= ~ISDARK; } else { obj->o_pos = fpos; add_obj(item, fpos.y, fpos.x); } if (rp != NULL && (!(rp->r_flags & ISDARK) || (rp->r_flags & HASFIRE))) { light(&hero); mvwaddch(cw, hero.y, hero.x, PLAYER); } return; } /* get here only if there isn't a place to put it */ if (pr) { if (cansee(obj->o_pos.y, obj->o_pos.x)) { if (obj->o_type == WEAPON) addmsg("The %s", weaps[obj->o_which].w_name); else addmsg(inv_name(obj, LOWERCASE)); msg(" vanishes as it hits the ground."); } } discard(item); }
/* * do_chase: * Make one thing chase another. */ void do_chase(struct thing *th, int flee) { register struct room *rer, *ree, /* room of chaser, room of chasee */ *old_room, /* old room of monster */ *new_room; /* new room of monster */ register int mindist = MAXINT, maxdist = MININT, dist = MININT, i, last_door = -1; /* Door we just came from */ register int stoprun = FALSE, /* TRUE means we are there */ rundoor; /* TRUE means run to a door */ int mdead = 0; register int sch; coord this; /* Temporary destination for chaser */ /* Make sure the monster can move */ if (th->t_no_move != 0) { th->t_no_move--; return; } rer = roomin(&th->t_pos); /* Find room of chaser */ ree = roomin(th->t_dest); /* Find room of chasee */ /* * We don't count doors as inside rooms for this routine */ if (mvwinch(stdscr, th->t_pos.y, th->t_pos.x) == DOOR) rer = NULL; this = *th->t_dest; /* * If we are not in a corridor and not a Xorn, then if we are running * after the player, we run to a door if he is not in the same room. * If we are fleeing, we run to a door if he IS in the same room. * Note: We don't bother with doors in mazes. */ if (levtype != MAZELEV && rer != NULL && off(*th, CANINWALL)) { if (flee) rundoor = (rer == ree); else rundoor = (rer != ree); } else rundoor = FALSE; if (rundoor) { coord exit; /* A particular door */ int exity, exitx; /* Door's coordinates */ if (th->t_doorgoal != -1) { /* Do we already have the goal? */ this = rer->r_exit[th->t_doorgoal]; dist = 0; /* Indicate that we have our door */ } else for (i = 0; i < rer->r_nexits; i++) { /* Loop through doors */ exit = rer->r_exit[i]; exity = exit.y; exitx = exit.x; /* Avoid secret doors */ if (mvwinch(stdscr, exity, exitx) == DOOR) { /* Were we just on this door? */ if (ce(exit, th->t_oldpos)) last_door = i; else { dist = DISTANCE(th->t_dest->y, th->t_dest->x, exity, exitx); /* If fleeing, we want to maximize distance from door to * what we flee, and minimize distance from door to us. */ if (flee) dist -= DISTANCE(th->t_pos.y, th->t_pos.x, exity, exitx); /* Maximize distance if fleeing, otherwise minimize it */ if ((flee && (dist > maxdist)) || (!flee && (dist < mindist))) { th->t_doorgoal = i; /* Use this door */ this = exit; mindist = maxdist = dist; } } } } /* Could we not find a door? */ if (dist == MININT) { /* If we were on a door, go ahead and use it */ if (last_door != -1) { th->t_doorgoal = last_door; this = th->t_oldpos; dist = 0; /* Indicate that we found a door */ } } /* Indicate that we do not want to flee from the door */ if (dist != MININT) flee = FALSE; } else th->t_doorgoal = -1; /* Not going to any door */ /* * this now contains what we want to run to this time * so we run to it. If we hit it we either want to fight it * or stop running */ if (!chase(th, &this, flee, &mdead)) { if (ce(ch_ret, hero)) { /* merchants try to sell something */ if (on(*th, CANSELL)) sell(th); else if (on(*th, ISCHARMED)) {} /* future enhancements */ else if (on(*th, ISFRIENDLY)) {} else attack(th, NULL, FALSE); return; } else if (on(*th, NOMOVE)) stoprun = TRUE; } if (on(*th, ISDEAD)) return; /* Did monster get itself killed? */ if (on(*th, NOMOVE)) return; /* If we have a scavenger, it can pick something up */ if (on(*th, ISSCAVENGE)) { register struct linked_list *item; if ((item = find_obj(ch_ret.y, ch_ret.x)) != NULL) { register int floor = (roomin(&ch_ret) == NULL) ? PASSAGE : FLOOR; detach(lvl_obj, item); mvaddch(ch_ret.y, ch_ret.x, floor); mvwaddch(cw, ch_ret.y, ch_ret.x, floor); attach(th->t_pack, item); } } mvwaddch(cw, th->t_pos.y, th->t_pos.x, th->t_oldch); sch = CCHAR( mvwinch(cw, ch_ret.y, ch_ret.x) ); /* Get old and new room of monster */ old_room=roomin(&th->t_pos); new_room=roomin(&ch_ret); /* If the monster can illuminate rooms, check for a change */ if (on(*th, HASFIRE)) { /* Is monster entering a room? */ if (old_room != new_room && new_room != NULL) { new_room->r_flags |= HASFIRE; new_room->r_fires++; if (cansee(ch_ret.y, ch_ret.x) && new_room->r_fires == 1) light(&hero); } /* Is monster leaving a room? */ if (old_room != new_room && old_room != NULL) { if (--(old_room->r_fires) <= 0) { old_room->r_flags &= ~HASFIRE; if (cansee(th->t_pos.y, th->t_pos.x)) light(&th->t_pos); } } } /* If monster is entering player's room and player can see it, * stop the player's running. */ if (new_room != old_room && new_room != NULL && new_room == ree && cansee(unc(ch_ret)) && (off(*th, ISINVIS) || (off(*th, ISSHADOW) || rnd(10) == 0) || on(player, CANSEE)) && off(*th, CANSURPRISE)) running = FALSE; if (rer != NULL && (rer->r_flags & ISDARK) && !(rer->r_flags & HASFIRE) && sch == FLOOR && DISTANCE(ch_ret.y, ch_ret.x, th->t_pos.y, th->t_pos.x) < see_dist && off(player, ISBLIND)) th->t_oldch = ' '; else th->t_oldch = sch; if (cansee(unc(ch_ret)) && off(*th, ISINWALL) && ((off(*th, ISINVIS) && (off(*th, ISSHADOW) || rnd(100) < 10)) || on(player, CANSEE)) && off(*th, CANSURPRISE)) mvwaddch(cw, ch_ret.y, ch_ret.x, th->t_type); mvwaddch(mw, th->t_pos.y, th->t_pos.x, ' '); mvwaddch(mw, ch_ret.y, ch_ret.x, th->t_type); /* Record monster's last position (if new one is different) */ if (!ce(ch_ret, th->t_pos)) th->t_oldpos = th->t_pos; th->t_pos = ch_ret; /* Mark the monster's new position */ /* If the monster is on a trap, trap it */ sch = CCHAR( mvinch(ch_ret.y, ch_ret.x) ); if (isatrap(sch)) { debug("Monster trapped by %c.", sch); if (cansee(ch_ret.y, ch_ret.x)) th->t_oldch = sch; be_trapped(th, &ch_ret); } /* * And stop running if need be */ if (stoprun && ce(th->t_pos, *(th->t_dest))) turn_off(*th, ISRUN); }