Esempio n. 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 */
}
Esempio n. 2
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 */
}
Esempio n. 3
0
/* called when you move to another level
 * pets_only: true for ascension or final escape */
void
keepdogs(boolean pets_only)
{
    struct monst *mtmp, *mtmp2;
    struct obj *obj;
    int num_segs;
    boolean stay_behind;

    for (mtmp = level->monlist; mtmp; mtmp = mtmp2) {
        mtmp2 = mtmp->nmon;
        if (DEADMONSTER(mtmp))
            continue;
        if (pets_only && !mtmp->mtame)
            continue;
        if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) ||
             (mtmp == u.usteed) ||
             /* the wiz will level t-port from anywhere to chase the amulet; if
                you don't have it, will chase you only if in range. -3. */
             (Uhave_amulet && mtmp->iswiz))
            && ((!mtmp->msleeping && mtmp->mcanmove)
                /* eg if level teleport or new trap, steed has no control to
                   avoid following */
                || (mtmp == u.usteed))
            /* monster won't follow if it hasn't noticed you yet */
            && !(mtmp->mstrategy & STRAT_WAITFORU)) {
            stay_behind = FALSE;
            if (!pets_only && mtmp->mtame && mtmp->meating) {
                if (canseemon(mtmp))
                    pline("%s is still eating.", Monnam(mtmp));
                stay_behind = TRUE;
            } else if (mon_has_amulet(mtmp)) {
                if (canseemon(mtmp))
                    pline("%s seems very disoriented for a moment.",
                          Monnam(mtmp));
                stay_behind = TRUE;
            } else if (!pets_only && mtmp->mtame && mtmp->mtrapped) {
                if (canseemon(mtmp))
                    pline("%s is still trapped.", Monnam(mtmp));
                stay_behind = TRUE;
            }
            if (mtmp == u.usteed)
                stay_behind = FALSE;

            if (stay_behind) {
                if (mtmp->mleashed) {
                    pline("%s leash suddenly comes loose.", humanoid(mtmp->data)
                          ? (mtmp->female ? "Her" : "His")
                          : "Its");
                    m_unleash(mtmp, FALSE);
                }
                continue;
            }
            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);
            } else
                num_segs = 0;

            /* 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;
            }

            relmon(mtmp);
            newsym(mtmp->mx, mtmp->my);
            mtmp->mx = COLNO;    /* avoid mnexto()/MON_AT() problem */
            mtmp->my = ROWNO;
            mtmp->wormno = num_segs;
            mtmp->mlstmv = moves;
            mtmp->nmon = turnstate.migrating_pets;
            turnstate.migrating_pets = mtmp;
        } else if (mtmp->iswiz) {
            /* we want to be able to find him when his next resurrection chance
               comes up, but have him resume his present location if player
               returns to this level before that time */
            migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_EXACT_XY, NULL);
        } else if (mtmp->mleashed) {
            /* this can happen if your quest leader ejects you from the "home"
               level while a leashed pet isn't next to you */
            pline("%s leash goes slack.", s_suffix(Monnam(mtmp)));
            m_unleash(mtmp, FALSE);
        }
    }
}
Esempio n. 4
0
/* called from resurrect() in addition to losedogs() */
void
mon_arrive(struct monst *mtmp, boolean with_you)
{
    struct trap *t;
    struct obj *otmp;
    xchar xlocale, ylocale, xyloc, xyflags, wander;
    int num_segs;

    mtmp->dlevel = level;
    mtmp->nmon = level->monlist;
    level->monlist = mtmp;
    if (mtmp->isshk)
        set_residency(mtmp, FALSE);

    num_segs = mtmp->wormno;
    /* baby long worms have no tail so don't use is_longworm() */
    if ((mtmp->data == &mons[PM_LONG_WORM]) &&
        (mtmp->wormno = get_wormno(mtmp->dlevel)) != 0) {
        initworm(mtmp, num_segs);
        /* tail segs are not yet initialized or displayed */
    } else
        mtmp->wormno = 0;

    /* some monsters might need to do something special upon arrival _after_
       the current level has been fully set up; see dochug() */
    mtmp->mstrategy |= STRAT_ARRIVE;

    xyloc = mtmp->xyloc;
    xyflags = mtmp->xyflags;
    xlocale = mtmp->xlocale;
    ylocale = mtmp->ylocale;

    for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj)
        set_obj_level(mtmp->dlevel, otmp);

    if (mtmp == u.usteed)
        return; /* don't place steed on the map */
    if (with_you) {
        /* When a monster accompanies you, sometimes it will arrive at your
           intended destination and you'll end up next to that spot.  This code
           doesn't control the final outcome; goto_level(do.c) decides who ends
           up at your target spot when there is a monster there too. */
        if (!MON_AT(level, u.ux, u.uy) &&
            !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2))
            rloc_to(mtmp, u.ux, u.uy);
        else
            mnexto(mtmp);
        return;
    }
    /*
     * The monster arrived on this level independently of the player.
     * Its coordinate fields were overloaded for use as flags that
     * specify its final destination.
     */

    if (mtmp->mlstmv < moves - 1L) {
        /* heal monster for time spent in limbo */
        long nmv = moves - 1L - mtmp->mlstmv;

        mon_catchup_elapsed_time(mtmp, nmv);
        mtmp->mlstmv = moves - 1L;

        /* let monster move a bit on new level (see placement code below) */
        wander = (xchar) min(nmv, 8);
    } else
        wander = 0;

    switch (xyloc) {
    case MIGR_APPROX_XY:       /* {x,y}locale set above */
        break;
    case MIGR_EXACT_XY:
        wander = 0;
        break;
    case MIGR_NEAR_PLAYER:
        xlocale = u.ux, ylocale = u.uy;
        break;
    case MIGR_STAIRS_UP:
        xlocale = level->upstair.sx, ylocale = level->upstair.sy;
        break;
    case MIGR_STAIRS_DOWN:
        xlocale = level->dnstair.sx, ylocale = level->dnstair.sy;
        break;
    case MIGR_LADDER_UP:
        xlocale = level->upladder.sx, ylocale = level->upladder.sy;
        break;
    case MIGR_LADDER_DOWN:
        xlocale = level->dnladder.sx, ylocale = level->dnladder.sy;
        break;
    case MIGR_SSTAIRS:
        xlocale = level->sstairs.sx, ylocale = level->sstairs.sy;
        break;
    case MIGR_PORTAL:
        if (In_endgame(&u.uz)) {
            /* there is no arrival portal for endgame levels */
            /* BUG[?]: for simplicity, this code relies on the fact that we
               know that the current endgame levels always build upwards and
               never have any exclusion subregion inside their TELEPORT_REGION
               settings. */
            xlocale =
                rn1(level->updest.hx - level->updest.lx + 1, level->updest.lx);
            ylocale =
                rn1(level->updest.hy - level->updest.ly + 1, level->updest.ly);
            break;
        }
        /* find the arrival portal */
        for (t = level->lev_traps; t; t = t->ntrap)
            if (t->ttyp == MAGIC_PORTAL)
                break;
        if (t) {
            xlocale = t->tx, ylocale = t->ty;
            break;
        } else {
            impossible("mon_arrive: no corresponding portal?");
        }
     /*FALLTHRU*/ default:
    case MIGR_RANDOM:
        xlocale = COLNO;
        ylocale = ROWNO;
        break;
    }

    if ((xlocale != COLNO) && wander) {
        /* monster moved a bit; pick a nearby location */
        /* mnearto() deals w/stone, et al */
        char *r = in_rooms(level, xlocale, ylocale, 0);

        if (r && *r) {
            coord c;

            /* somexy() handles irregular level->rooms */
            if (somexy(level, &level->rooms[*r - ROOMOFFSET], &c, rng_main))
                xlocale = c.x, ylocale = c.y;
            else {
                xlocale = COLNO;
                ylocale = ROWNO;
            }
        } else {        /* not in a room */
            int i, j;

            i = max(0, xlocale - wander);
            j = min(COLNO - 1, xlocale + wander);
            xlocale = rn1(j - i, i);
            i = max(0, ylocale - wander);
            j = min(ROWNO - 1, ylocale + wander);
            ylocale = rn1(j - i, i);
        }
    }
    /* moved a bit */
    mtmp->mx = COLNO;       /* (already is 0) */
    mtmp->my = xyflags;
    if (xlocale != COLNO)
        mnearto(mtmp, xlocale, ylocale, FALSE);
    else {
        if (!rloc(mtmp, TRUE)) {
            /* Failed to place migrating monster, probably because the level is
               full.  Dump the monster's cargo and leave the monster dead. */
            struct obj *obj;

            while ((obj = mtmp->minvent) != 0) {
                obj_extract_self(obj);
                obj_no_longer_held(obj);
                if (obj->owornmask & W_MASK(os_wep))
                    setmnotwielded(mtmp, obj);
                obj->owornmask = 0L;
                if (xlocale != COLNO && ylocale != ROWNO)
                    place_object(obj, level, xlocale, ylocale);
                else {
                    rloco(obj);
                    get_obj_location(obj, &xlocale, &ylocale, 0);
                }
            }
            mkcorpstat(CORPSE, NULL, mtmp->data, level, xlocale, ylocale,
                       FALSE, rng_main);
            mongone(mtmp);
        }
    }

    mtmp->mux = COLNO;
    mtmp->muy = ROWNO;
}