Пример #1
0
void migrate_to_level(
	struct monst *mtmp,
	xchar tolev,	/* destination level */
	xchar xyloc,	/* MIGR_xxx destination xy location: */
	coord *cc)	/* optional destination coordinates */
{
	struct obj *obj;
	d_level new_lev;
	xchar xyflags;
	int num_segs = 0;	/* count of worm segments */

	if (mtmp->isshk)
	    set_residency(mtmp, TRUE);

	if (mtmp->wormno) {
	    int cnt;
	  /* **** NOTE: worm is truncated to # segs = max wormno size **** */
	    cnt = count_wsegs(mtmp);
	    num_segs = min(cnt, MAX_NUM_WORMS - 1);
	    wormgone(mtmp);
	}

	/* set minvent's obj->no_charge to 0 */
	for (obj = mtmp->minvent; obj; obj = obj->nobj) {
	    if (Has_contents(obj))
		picked_container(obj);	/* does the right thing */
	    obj->no_charge = 0;
	}

	if (mtmp->mleashed) {
		mtmp->mtame--;
		m_unleash(mtmp, TRUE);
	}
	relmon(mtmp);
	mtmp->nmon = migrating_mons;
	migrating_mons = mtmp;
	newsym(mtmp->mx,mtmp->my);

	new_lev.dnum = ledger_to_dnum((xchar)tolev);
	new_lev.dlevel = ledger_to_dlev((xchar)tolev);
	/* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */
	/* destination codes (setup flag bits before altering mx or my) */
	xyflags = (depth(&new_lev) < depth(&u.uz));	/* 1 => up */
	if (In_W_tower(mtmp->mx, mtmp->my, &u.uz)) xyflags |= 2;
	mtmp->wormno = num_segs;
	mtmp->mlstmv = moves;
	mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx;
	mtmp->mtrack[1].y = cc ? cc->y : mtmp->my;
	mtmp->mtrack[0].x = xyloc;
	mtmp->mtrack[0].y = xyflags;
	mtmp->mux = new_lev.dnum;
	mtmp->muy = new_lev.dlevel;
	mtmp->mx = mtmp->my = 0;	/* this implies migration */
}
Пример #2
0
/* return TRUE if successful, FALSE if not */
boolean
rloc(struct monst *mtmp,        /* mx==0 implies migrating monster arrival */
     boolean suppress_impossible)
{
    int x, y, trycount;

    if (mtmp == u.usteed) {
        tele();
        return TRUE;
    }

    if (mtmp->iswiz && mtmp->mx) {      /* Wizard, not just arriving */
        if (!In_W_tower(u.ux, u.uy, &u.uz))
            x = level->upstair.sx, y = level->upstair.sy;
        else if (!level->dnladder.sx)   /* bottom level of tower */
            x = level->upladder.sx, y = level->upladder.sy;
        else
            x = level->dnladder.sx, y = level->dnladder.sy;
        /* if the wiz teleports away to heal, try the up staircase, to block
           the player's escaping before he's healed (deliberately use `goodpos' 
           rather than `rloc_pos_ok' here) */
        if (goodpos(level, x, y, mtmp, 0))
            goto found_xy;
    }

    trycount = 0;
    do {
        x = rn1(COLNO - 3, 2);
        y = rn2(ROWNO);
        if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
            : goodpos(level, x, y, mtmp, 0))
            goto found_xy;
    } while (++trycount < 1000);

    /* last ditch attempt to find a good place */
    for (x = 2; x < COLNO - 1; x++)
        for (y = 0; y < ROWNO; y++)
            if (goodpos(level, x, y, mtmp, 0))
                goto found_xy;

    /* level either full of monsters or somehow faulty */
    if (!suppress_impossible)
        impossible("rloc(): couldn't relocate monster");
    return FALSE;

found_xy:
    rloc_to(mtmp, x, y);
    return TRUE;
}
Пример #3
0
/* return TRUE if successful, FALSE if not */
boolean
rloc(struct monst *mtmp,        /* mx==COLNO implies migrating monster arrival */
     boolean suppress_impossible)
{
    int x, y, trycount;
    int relaxed_goodpos;

    if (mtmp == u.usteed) {
        tele();
        return TRUE;
    }

    if (!(mtmp->dlevel))
        panic("trying to teleport monster onto which level?");

    struct level *mdl = mtmp->dlevel;

    if (mtmp->iswiz && mtmp->mx != COLNO &&
        mdl == level) {      /* Wizard, not just arriving */
        if (!In_W_tower(u.ux, u.uy, &u.uz))
            x = mdl->upstair.sx, y = mdl->upstair.sy;
        else if (!isok(mdl->dnladder.sx, mdl->dnladder.sy))
            x = mdl->upladder.sx, y = mdl->upladder.sy;/* bottom of tower */
        else
            x = mdl->dnladder.sx, y = mdl->dnladder.sy;
        /* if the wiz teleports away to heal, try the up staircase, to block
           the player's escaping before he's healed (deliberately use `goodpos'
           rather than `rloc_pos_ok' here) */
        if (goodpos(mdl, x, y, mtmp, 0))
            goto found_xy;
    }

    for (relaxed_goodpos = 0; relaxed_goodpos < 2; relaxed_goodpos++) {

        /* first try sensible terrain; if none exists, ignore water,
           doors and boulders */
        int gpflags = relaxed_goodpos ? MM_IGNOREWATER | MM_IGNOREDOORS : 0;

        /* try several pairs of positions; try the more restrictive rloc_pos_ok
           before we use the less restrictive goodpos */
        trycount = 0;
        do {
            x = rn2(COLNO);
            y = rn2(ROWNO);
            if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
                : goodpos(mdl, x, y, mtmp, gpflags))
                goto found_xy;
        } while (++trycount < 1000);

        /* try every square on the mdl as a fallback */
        for (x = 0; x < COLNO; x++)
            for (y = 0; y < ROWNO; y++)
                if (goodpos(mdl, x, y, mtmp, gpflags))
                    goto found_xy;
    }

    /* level either full of monsters or somehow faulty */
    if (!suppress_impossible)
        impossible("rloc(): couldn't relocate monster");
    return FALSE;

found_xy:
    rloc_to(mtmp, x, y);
    return TRUE;
}
Пример #4
0
/* return TRUE if successful, FALSE if not */
boolean
rloc(struct monst *mtmp,        /* mx==COLNO implies migrating monster arrival */
     boolean suppress_impossible)
{
    int x, y, trycount;
    int relaxed_goodpos;

    if (mtmp == u.usteed) {
        tele();
        return TRUE;
    }

    if (mtmp->iswiz && mtmp->mx != COLNO) {      /* Wizard, not just arriving */
        if (!In_W_tower(u.ux, u.uy, &u.uz))
            x = level->upstair.sx, y = level->upstair.sy;
        else if (!isok(level->dnladder.sx, level->dnladder.sy))
            x = level->upladder.sx, y = level->upladder.sy;/* bottom of tower */
        else
            x = level->dnladder.sx, y = level->dnladder.sy;
        /* if the wiz teleports away to heal, try the up staircase, to block
           the player's escaping before he's healed (deliberately use `goodpos'
           rather than `rloc_pos_ok' here) */
        if (goodpos(level, x, y, mtmp, 0))
            goto found_xy;
    }

    for (relaxed_goodpos = -1; relaxed_goodpos < 2; relaxed_goodpos++) {

        /* If this is a monster that blinks, try to do that first. */
        if (relaxed_goodpos < 0) {
            if ((isok(mtmp->mx, mtmp->my)) &&
                mtmp->data->mflags3 & M3_BLINKAWAY) {
                /* We're going to do a polar-to-rectangular conversion here,
                   because it's a convenient way to select positions at the
                   correct distance from where we're starting.  We'll try
                   with the maximum radius then back it off. */
                int maxradius = 2 * mtmp->data->mlevel;
                int minradius = 2;
                int theta[24] = {   0,  15,  30,  45,  60,  75,
                                    90, 105, 120, 135, 150, 165,
                                    180, 195, 210, 225, 240, 255,
                                    270, 285, 300, 315, 330, 345 };
                int angle, fineangle, swi, sw;
                coord rectcoord;
                if (maxradius < minradius + 3)
                    maxradius = minradius + 3;
                /* Shuffle the order of the angles so we don't always get the same
                   one tried first. */
                for (angle = 0; angle < 24; angle++) {
                    swi          = rn2(24);
                    sw           = theta[swi];
                    theta[swi]   = theta[angle];
                    theta[angle] = sw;
                }
                for (trycount = maxradius; trycount >= minradius; trycount--) {
                    for (angle = 0; angle < 24; angle++)
                        for (fineangle = 0; fineangle < 15; fineangle += 3) {
                            /* theta is shuffled so that the angle isn't the
                               same all the time, but it isn't necessary to
                               shuffle over a hundred different angles; we use
                               fineangle to allow positions that don't line up
                               to the 15-degree increments, but the randomness
                               of the blink direction doesn't need that much
                               precision. */
                            rectcoord = polartorect(trycount, theta[angle] +
                                                    fineangle);
                            x = mtmp->mx + rectcoord.x;
                            y = mtmp->my + rectcoord.y;
                            if (isok(x,y) && !m_at(level,x,y) &&
                                /* TODO: evaluate whether goodpos() should be
                                 * used here */
                                (level->locations[x][y].typ >= CORR) &&
                                /* Blinking only works with line-of-sight, but
                                   for now I am not requiring the monster to
                                   actually _see_ the tile, so e.g. blinking
                                   into the dark works ok. */
                                clear_path(mtmp->mx, mtmp->my, x, y, viz_array)
                                ) {
                                goto found_xy;
                            }
                        }
                }
            }
            continue;
        }

        /* first try sensible terrain; if none exists, ignore water,
           doors and boulders */
        int gpflags = relaxed_goodpos ? MM_IGNOREWATER | MM_IGNOREDOORS : 0;

        /* try several pairs of positions; try the more restrictive rloc_pos_ok
           before we use the less restrictive goodpos */
        trycount = 0;
        do {
            x = rn2(COLNO);
            y = rn2(ROWNO);
            if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp)
                : goodpos(level, x, y, mtmp, gpflags))
                goto found_xy;
        } while (++trycount < 1000);

        /* try every square on the level as a fallback */
        for (x = 0; x < COLNO; x++)
            for (y = 0; y < ROWNO; y++)
                if (goodpos(level, x, y, mtmp, gpflags))
                    goto found_xy;
    }

    /* level either full of monsters or somehow faulty */
    if (!suppress_impossible)
        impossible("rloc(): couldn't relocate monster");
    return FALSE;

found_xy:
    rloc_to(mtmp, x, y);
    return TRUE;
}
Пример #5
0
void
migrate_to_level(struct monst *mtmp, xchar tolev,       /* destination level */
                 xchar xyloc,   /* MIGR_xxx destination xy location: */
                 coord * cc)
{       /* optional destination coordinates */
    struct obj *obj;
    d_level new_lev;
    xchar xyflags;
    int num_segs = 0;   /* count of worm segments */

    if (mtmp->isshk)
        set_residency(mtmp, TRUE);

    if (mtmp->wormno) {
        int cnt;

        /* **** NOTE: worm is truncated to # segs = max wormno size **** */
        cnt = count_wsegs(mtmp);
        num_segs = min(cnt, MAX_NUM_WORMS - 1);
        wormgone(mtmp);
    }

    /* set minvent's obj->no_charge to 0 */
    for (obj = mtmp->minvent; obj; obj = obj->nobj) {
        if (Has_contents(obj))
            picked_container(obj);      /* does the right thing */
        obj->no_charge = 0;
    }

    if (mtmp->mleashed) {
        mtmp->mtame--;
        m_unleash(mtmp, TRUE);
    }
    relmon(mtmp);
    mtmp->nmon = migrating_mons;
    migrating_mons = mtmp;
    if (mtmp->dlevel == level)
        newsym(mtmp->mx, mtmp->my);

    /* The dlevel pointer is meaningless for a migrating monster. Set it to NULL
       so that any uses of it are detected quickly via the resulting
       segfault. */
    mtmp->dlevel = NULL;

    new_lev.dnum = ledger_to_dnum((xchar) tolev);
    new_lev.dlevel = ledger_to_dlev((xchar) tolev);

    /* set migration data */
    xyflags = (depth(&new_lev) < depth(&u.uz)); /* 1 => up */
    if (In_W_tower(mtmp->mx, mtmp->my, &u.uz))
        xyflags |= 2;
    mtmp->wormno = num_segs;
    mtmp->mlstmv = moves;
    mtmp->xlocale = cc ? cc->x : mtmp->mx;
    mtmp->ylocale = cc ? cc->y : mtmp->my;
    mtmp->xyloc = xyloc;
    mtmp->xyflags = xyflags;
    mtmp->mux = new_lev.dnum;
    mtmp->muy = new_lev.dlevel;
    mtmp->mx = COLNO;
    mtmp->my = ROWNO;    /* this implies migration */
}