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);
}
Example #5
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);
}
Example #6
0
/*
 * 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();
}
Example #8
0
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));
    }
}
Example #10
0
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);
}
Example #13
0
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');
}
Example #14
0
/*
 * 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
}
Example #16
0
/*
 * 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;
}
Example #18
0
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) ;
}
Example #20
0
/*
 * 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);
}
Example #21
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);
}
Example #28
0
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);
}