/* * 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(); } }
/* * seen_stairs: * Return TRUE if the player has seen the stairs */ bool seen_stairs() { THING *tp; move(stairs.y, stairs.x); if (inch() == STAIRS) /* it's on the map */ return TRUE; if (ce(hero, stairs)) /* It's under him */ return TRUE; /* * if a monster is on the stairs, this gets hairy */ if ((tp = moat(stairs.y, stairs.x)) != NULL) { if (see_monst(tp) && on(*tp, ISRUN)) /* if it's visible and awake */ return TRUE; /* it must have moved there */ if (on(player, SEEMONST) /* if she can detect monster */ && tp->t_oldch == STAIRS) /* and there once were stairs */ return TRUE; /* it must have moved there */ } return FALSE; }
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(); }
void missile(int ydelta, int xdelta) { THING *obj; /* * Get which thing we are hurling */ if ((obj = get_item("throw", WEAPON)) == NULL) return; if (!dropcheck(obj) || is_current(obj)) return; obj = leave_pack(obj, TRUE, FALSE); do_motion(obj, ydelta, xdelta); /* * 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 (moat(obj->o_pos.y, obj->o_pos.x) == NULL || !hit_monster(unc(obj->o_pos), obj)) fall(obj, TRUE); }
/* * runto: * Set a monster running after the hero. */ void runto(const coord *runner) { THING *tp; /* * If we couldn't find him, something is funny */ if ((tp = moat(runner->y, runner->x)) == NULL) { #ifdef MASTER msg("couldn't find monster in runto at (%d,%d)", runner->y, runner->x); #endif return; } /* * Start the beastie running */ tp->t_flags |= ISRUN; tp->t_flags &= ~ISHELD; tp->t_dest = find_dest(tp); }
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 }
/* * 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)); }
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); }
/* * wake_monster: * What to do when the hero steps next to a monster */ const THING * wake_monster(int y, int x) { THING *tp; struct room *rp; int ch; const char *mname; if ((tp = moat(y, x)) == NULL) { #ifdef MASTER msg("can't find monster in wake_monster"); #endif return NULL; } ch = tp->t_type; /* * Every time he sees mean monster, it might start chasing him */ if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD) && !ISWEARING(R_STEALTH) && !on(player, ISLEVIT)) { tp->t_dest = &hero; tp->t_flags |= ISRUN; } if (ch == 'M' && !on(player, ISBLIND) && !on(player, ISHALU) && !on(*tp, ISFOUND) && !on(*tp, ISCANC) && on(*tp, ISRUN)) { rp = proom; if ((rp != NULL && !(rp->r_flags & ISDARK)) || dist(y, x, hero.y, hero.x) < LAMPDIST) { tp->t_flags |= ISFOUND; if (!save(VS_MAGIC)) { if (on(player, ISHUH)) lengthen(unconfuse, spread(HUHDURATION)); else fuse(unconfuse, 0, spread(HUHDURATION), AFTER); player.t_flags |= ISHUH; mname = set_mname(tp); addmsg("%s", mname); if (strcmp(mname, "it") != 0) addmsg("'"); msg("s gaze has confused you"); } } } /* * Let greedy ones guard gold */ if (on(*tp, ISGREED) && !on(*tp, ISRUN)) { tp->t_flags |= ISRUN; if (proom->r_goldval) tp->t_dest = &proom->r_gold; else tp->t_dest = &hero; } return tp; }