Пример #1
0
/*
 *  remove_worm()
 *
 *  This function is equivalent to the remove_monster #define in
 *  rm.h, only it will take the worm *and* tail out of the levels array.
 *  It does not get rid of (dealloc) the worm tail structures, and it does
 *  not remove the mon from the level->monlist chain.
 */
void remove_worm(struct monst *worm)
{
    struct wseg *curr = level->wtails[worm->wormno];

/*  if (!mtmp->wormno) return;  bullet proofing */

    while (curr) {
	remove_monster(level, curr->wx, curr->wy);
	newsym(curr->wx, curr->wy);
	curr = curr->nseg;
    }
}
Пример #2
0
/*
 * rloc_to()
 *
 * Pulls a monster from its current position and places a monster at a new x and
 * y.  If oldx is COLNO, then the monster was not in the levels.monsters array.
 * However, if oldx is COLNO, oldy may still have a value because mtmp is a
 * migrating_mon.  Worm tails are always placed randomly around the head of the
 * worm.  This only works for monsters on the current level.
 */
void
rloc_to(struct monst *mtmp, int x, int y)
{
    int oldx = mtmp->mx, oldy = mtmp->my;
    boolean resident_shk = mtmp->isshk && inhishop(mtmp);

    if (x == mtmp->mx && y == mtmp->my) /* that was easy */
        return;

    if (oldx != COLNO) { /* "pick up" monster */
        if (mtmp->wormno)
            remove_worm(mtmp);
        else {
            remove_monster(mtmp->dlevel, oldx, oldy);
            if (mtmp->dlevel == level)
                newsym(oldx, oldy); /* update old location */
        }
    }

    place_monster(mtmp, x, y);  /* put monster down */
    update_monster_region(mtmp);

    if (mtmp->wormno)   /* now put down tail */
        place_worm_tail_randomly(mtmp, x, y, rng_main);

    if (u.ustuck == mtmp) { /* implies mtmp->dlevel == level */
        if (Engulfed) {
            u.ux = x;
            u.uy = y;
            doredraw();
        } else
            u.ustuck = 0;
    }

    if (mtmp->dlevel == level)
        newsym(x, y);       /* update new location */
    set_apparxy(mtmp);  /* orient monster */

    /* In some cases involving migration, the player and monster are currently
       on the same square. One of them will move, but we don't want the monster
       to have itself in its muxy. */
    if (mtmp->mux == mtmp->mx && mtmp->muy == mtmp->my) {
        mtmp->mux = COLNO;
        mtmp->muy = ROWNO;
    }

    /* shopkeepers will only teleport if you zap them with a wand of
       teleportation or if they've been transformed into a jumpy monster; the
       latter only happens if you've attacked them with polymorph */
    if (resident_shk && !inhishop(mtmp))
        make_angry_shk(mtmp, oldx, oldy);
}
Пример #3
0
/* called in mon.c */
bool grddead(struct monst *grd) {
    bool dispose = clear_fcorr(grd, true);

    if (!dispose) {
        /* see comment by newpos in gd_move() */
        remove_monster(grd->mx, grd->my);
        newsym(grd->mx, grd->my);
        place_monster(grd, 0, 0);
        EGD(grd)->ogx = grd->mx;
        EGD(grd)->ogy = grd->my;
        dispose = clear_fcorr(grd, true);
    }
    return (dispose);
}
Пример #4
0
/* called in mon.c */
boolean
grddead(struct monst *grd)
{
    boolean dispose = clear_fcorr(grd, TRUE);

    if (!dispose) {
        /* see comment by newpos in gd_move() */
        remove_monster(level, grd->mx, grd->my);
        newsym(grd->mx, grd->my);
        grd->mx = COLNO;
        grd->my = ROWNO;
        EGD(grd)->ogx = grd->mx;
        EGD(grd)->ogy = grd->my;
        dispose = clear_fcorr(grd, TRUE);
    }
    return dispose;
}
Пример #5
0
void
genocide(int flags)
{
    struct linked_list  *ip;
    struct thing    *mp;
    struct linked_list  *nip;
    int    which_monst;
    int    blessed = flags & ISBLESSED;
    int    cursed = flags & ISCURSED;

    while ((which_monst = get_monster_number("genocide")) == 0)
        ;

    if (cursed)    /* oops... */
    {
        new_level(THRONE, which_monst);
        msg("What's this I hear about you trying to wipe me out?");
        fighting = running = after = FALSE;
        return;
    }

    /* Remove this monster from the present level */

    for (ip = mlist; ip; ip = nip)
    {
        mp = THINGPTR(ip);
        nip = next(ip);

        if (mp->t_index == which_monst)
        {
            check_residue(mp);  /* Check for special features before removing */
            remove_monster(&mp->t_pos, ip);
        }
    }

    /* Remove from available monsters */

    monsters[which_monst].m_normal = FALSE;
    monsters[which_monst].m_wander = FALSE;
    mpos = 0;
    msg("You have wiped out the %s.", monsters[which_monst].m_name);

    if (blessed)
        genocide(ISNORMAL);
}
Пример #6
0
/*
 * rloc_to()
 *
 * Pulls a monster from its current position and places a monster at
 * a new x and y.  If oldx is 0, then the monster was not in the levels.monsters
 * array.  However, if oldx is 0, oldy may still have a value because mtmp is a
 * migrating_mon.  Worm tails are always placed randomly around the head of
 * the worm.
 */
void
rloc_to(struct monst *mtmp, int x, int y)
{
    int oldx = mtmp->mx, oldy = mtmp->my;
    boolean resident_shk = mtmp->isshk && inhishop(mtmp);

    if (x == mtmp->mx && y == mtmp->my) /* that was easy */
        return;

    if (oldx) { /* "pick up" monster */
        if (mtmp->wormno)
            remove_worm(mtmp);
        else {
            remove_monster(level, oldx, oldy);
            newsym(oldx, oldy); /* update old location */
        }
    }

    place_monster(mtmp, x, y);  /* put monster down */
    update_monster_region(mtmp);

    if (mtmp->wormno)   /* now put down tail */
        place_worm_tail_randomly(mtmp, x, y);

    if (u.ustuck == mtmp) {
        if (u.uswallow) {
            u.ux = x;
            u.uy = y;
            doredraw();
        } else
            u.ustuck = 0;
    }

    newsym(x, y);       /* update new location */
    set_apparxy(mtmp);  /* orient monster */

    /* shopkeepers will only teleport if you zap them with a wand of
       teleportation or if they've been transformed into a jumpy monster; the
       latter only happens if you've attacked them with polymorph */
    if (resident_shk && !inhishop(mtmp))
        make_angry_shk(mtmp, oldx, oldy);
}
Пример #7
0
static void do_entity(struct entity *etmp)
{
	int newx, newy, at_portcullis, oldx, oldy;
	boolean must_jump = FALSE, relocates = FALSE, e_inview;
	struct rm *crm;

	if (!etmp->edata)
		return;

	e_inview = e_canseemon(level, etmp);
	oldx = etmp->ex;
	oldy = etmp->ey;
	at_portcullis = is_db_wall(oldx, oldy);
	crm = &level->locations[oldx][oldy];

	if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) {
		if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ)))
			pline("The %s passes through %s!",
			      at_portcullis ? "portcullis" : "drawbridge",
			      e_nam(etmp));
		if (is_u(etmp)) spoteffects(FALSE);
		return;
	}
	if (e_missed(etmp, FALSE)) {
		if (at_portcullis)
			pline("The portcullis misses %s!",
			      e_nam(etmp));
		if (e_survives_at(etmp, oldx, oldy))
			return;
		else {
			if (at_portcullis)
				must_jump = TRUE;
			else
				relocates = TRUE; /* just ride drawbridge in */
		}
	} else {
		if (crm->typ == DRAWBRIDGE_DOWN) {
			pline("%s crushed underneath the drawbridge.",
			      E_phrase(etmp, "are"));		  /* no jump */
			e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */
			return;   /* Note: Beyond this point, we know we're  */
		}		  /* not at an opened drawbridge, since all  */
		must_jump = TRUE; /* *missable* creatures survive on the     */
	}			  /* square, and all the unmissed ones die.  */
	if (must_jump) {
	    if (at_portcullis) {
		if (e_jumps(etmp)) {
		    relocates = TRUE;
		} else {
		    if (e_inview)
			pline("%s crushed by the falling portcullis!",
			      E_phrase(etmp, "are"));
		    else if (flags.soundok)
			You_hear("a crushing sound.");
		    e_died(etmp, e_inview? 3 : 2, CRUSHING);
		    /* no corpse */
		    return;
		}
	    } else { /* tries to jump off bridge to original square */
		relocates = !e_jumps(etmp);
	    }
	}

/*
 * Here's where we try to do relocation.  Assumes that etmp is not arriving
 * at the portcullis square while the drawbridge is falling, since this square
 * would be inaccessible (i.e. etmp started on drawbridge square) or
 * unnecessary (i.e. etmp started here) in such a situation.
 */
	newx = oldx;
	newy = oldy;
	find_drawbridge(&newx, &newy);
	if ((newx == oldx) && (newy == oldy))
		get_wall_for_db(&newx, &newy);
	if (relocates && (e_at(newx, newy))) {

/*
 * Standoff problem:  one or both entities must die, and/or both switch
 * places.  Avoid infinite recursion by checking first whether the other
 * entity is staying put.  Clean up if we happen to move/die in recursion.
 */
		struct entity *other;

		other = e_at(newx, newy);
		if (e_survives_at(other, newx, newy) && automiss(other)) {
			relocates = FALSE;	      /* "other" won't budge */
		} else {

			while ((e_at(newx, newy) != 0) &&
			       (e_at(newx, newy) != etmp))
				do_entity(other);
			if (e_at(oldx, oldy) != etmp) {
			    return;
			}
		}
	}
	if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */
		if (!is_u(etmp)) {
			remove_monster(level, etmp->ex, etmp->ey);
			place_monster(etmp->emon, newx, newy);
			update_monster_region(etmp->emon);
		} else {
			u.ux = newx;
			u.uy = newy;
		}
		etmp->ex = newx;
		etmp->ey = newy;
		e_inview = e_canseemon(level, etmp);
	}
	if (is_db_wall(etmp->ex, etmp->ey)) {
		if (e_inview) {
			if (is_u(etmp)) {
				pline("You tumble towards the closed portcullis!");
				if (automiss(etmp))
					pline("You pass through it!");
				else
					pline("The drawbridge closes in...");
			} else
				pline("%s behind the drawbridge.",
				      E_phrase(etmp, "disappear"));
		}
		if (!e_survives_at(etmp, etmp->ex, etmp->ey)) {
			killer_format = KILLED_BY_AN;
			killer = "closing drawbridge";
			e_died(etmp, 0, CRUSHING);	       /* no message */
			return;
		}
	} else {
		if (is_pool(level, etmp->ex, etmp->ey) && !e_inview)
			if (flags.soundok)
				You_hear("a splash.");
		if (e_survives_at(etmp, etmp->ex, etmp->ey)) {
			if (e_inview && !is_flyer(etmp->edata) &&
			    !is_floater(etmp->edata))
				pline("%s from the bridge.",
				      E_phrase(etmp, "fall"));
			return;
		}
		if (is_pool(level, etmp->ex, etmp->ey) || is_lava(level, etmp->ex, etmp->ey))
		    if (e_inview && !is_u(etmp)) {
			/* drown() will supply msgs if nec. */
			boolean lava = is_lava(level, etmp->ex, etmp->ey);

			if (Hallucination)
			    pline("%s the %s and disappears.",
				  E_phrase(etmp, "drink"),
				  lava ? "lava" : "moat");
			else
			    pline("%s into the %s.",
				  E_phrase(etmp, "fall"),
				  lava ? "lava" : "moat");
		    }
		killer_format = NO_KILLER_PREFIX;
		killer = "fell from a drawbridge";
		e_died(etmp, e_inview ? 3 : 2,      /* CRUSHING is arbitrary */
		       (is_pool(level, etmp->ex, etmp->ey)) ? DROWNING :
		       (is_lava(level, etmp->ex, etmp->ey)) ? BURNING :
						       CRUSHING); /*no corpse*/
		return;
	}
}
Пример #8
0
/*
 * Move for priests and shopkeepers.  Called from shk_move() and pri_move().
 * Valid returns are  1: moved  0: didn't  -1: let m_move do it  -2: died.
 */
int
move_special(struct monst *mtmp, boolean in_his_shop, schar appr,
             boolean uondoor, boolean avoid, xchar omx, xchar omy, xchar gx,
             xchar gy)
{
    xchar nx, ny, nix, niy;
    schar i;
    schar chcnt, cnt;
    coord poss[9];
    long info[9];
    long allowflags;
    struct obj *ib = NULL;

    if (omx == gx && omy == gy)
        return 0;
    if (mtmp->mconf) {
        avoid = FALSE;
        appr = 0;
    }

    nix = omx;
    niy = omy;
    if (mtmp->isshk)
        allowflags = ALLOW_SSM;
    else
        allowflags = ALLOW_SSM | ALLOW_SANCT;
    if (passes_walls(mtmp->data))
        allowflags |= (ALLOW_ROCK | ALLOW_WALL);
    if (throws_rocks(mtmp->data))
        allowflags |= ALLOW_ROCK;
    if (tunnels(mtmp->data))
        allowflags |= ALLOW_DIG;
    if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
        allowflags |= OPENDOOR;
        if (m_carrying(mtmp, SKELETON_KEY))
            allowflags |= BUSTDOOR;
    }
    if (is_giant(mtmp->data))
        allowflags |= BUSTDOOR;
    cnt = mfndpos(mtmp, poss, info, allowflags);

    if (mtmp->isshk && avoid && uondoor) {    /* perhaps we cannot avoid him */
        for (i = 0; i < cnt; i++)
            if (!(info[i] & NOTONL))
                goto pick_move;
        avoid = FALSE;
    }
#define GDIST(x,y)      (dist2(x,y,gx,gy))
pick_move:
    chcnt = 0;
    for (i = 0; i < cnt; i++) {
        nx = poss[i].x;
        ny = poss[i].y;
        if (IS_ROOM(level->locations[nx][ny].typ) ||
            (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) {
            if (avoid && (info[i] & NOTONL))
                continue;
            if ((!appr && !rn2(++chcnt)) ||
                (appr && GDIST(nx, ny) < GDIST(nix, niy))) {
                nix = nx;
                niy = ny;
            }
        }
    }
    if (mtmp->ispriest && avoid && nix == omx && niy == omy &&
        onlineu(omx, omy)) {
        /* might as well move closer as long it's going to stay lined up */
        avoid = FALSE;
        goto pick_move;
    }

    if (nix != omx || niy != omy) {
        remove_monster(level, omx, omy);
        place_monster(mtmp, nix, niy);
        newsym(nix, niy);
        if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
            check_special_room(FALSE);
        if (ib) {
            if (cansee(mtmp->mx, mtmp->my))
                pline("%s picks up %s.", Monnam(mtmp),
                      distant_name(ib, doname));
            obj_extract_self(ib);
            mpickobj(mtmp, ib);
        }
        return 1;
    }
    return 0;
}
Пример #9
0
/*  cutworm()
 *
 *  Check for mon->wormno before calling this function!
 *
 *  When hitting a worm (worm) at position x, y, with a weapon (weap),
 *  there is a chance that the worm will be cut in half, and a chance
 *  that both halves will survive.
 */
void
cutworm(struct monst *worm, xchar x, xchar y, struct obj *weap)
{
    struct wseg *curr, *new_tail;
    struct monst *new_worm;
    int wnum = worm->wormno;
    int cut_chance, new_wnum;

    if (!wnum)
        return; /* bullet proofing */

    if (x == worm->mx && y == worm->my)
        return; /* hit on head */

    /* cutting goes best with a bladed weapon */
    cut_chance = rnd(20);       /* Normally 1-16 does not cut */
    /* Normally 17-20 does */

    if (weap && objects[weap->otyp].oc_dir & SLASH)
        cut_chance += 10;       /* With a slashing weapon 1- 6 does not cut */
    /* 7-20 does */

    if (cut_chance < 17)
        return; /* not good enough */

    /* Find the segment that was attacked. */
    curr = level->wtails[wnum];

    while ((curr->wx != x) || (curr->wy != y)) {
        curr = curr->nseg;
        if (!curr) {
            impossible("cutworm: no segment at (%d,%d)", (int)x, (int)y);
            return;
        }
    }

    /* If this is the tail segment, then the worm just loses it. */
    if (curr == level->wtails[wnum]) {
        shrink_worm(wnum);
        return;
    }

    /* 
     *  Split the worm.  The tail for the new worm is the old worm's tail.
     *  The tail for the old worm is the segment that follows "curr",
     *  and "curr" becomes the dummy segment under the new head.
     */
    new_tail = level->wtails[wnum];
    level->wtails[wnum] = curr->nseg;
    curr->nseg = NULL;  /* split the worm */

    /* 
     *  At this point, the old worm is correct.  Any new worm will have
     *  it's head at "curr" and its tail at "new_tail".
     */

    /* Sometimes the tail end dies. */
    if (rn2(3) || !(new_wnum = get_wormno(level)) || !worm->m_lev) {
        cutoff(worm, new_tail);
        return;
    }

    remove_monster(level, x, y);        /* clone_mon puts new head here */
    if (!(new_worm = clone_mon(worm, x, y))) {
        cutoff(worm, new_tail);
        return;
    }
    new_worm->wormno = new_wnum;        /* affix new worm number */

    /* Devalue the monster level of both halves of the worm. */
    worm->m_lev =
        ((unsigned)worm->m_lev <=
         3) ? (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
    new_worm->m_lev = worm->m_lev;

    /* Calculate the mhp on the new_worm for the (lower) monster level. */
    new_worm->mhpmax = new_worm->mhp = dice((int)new_worm->m_lev, 8);

    /* Calculate the mhp on the old worm for the (lower) monster level. */
    if (worm->m_lev > 3) {
        worm->mhpmax = dice((int)worm->m_lev, 8);
        if (worm->mhpmax < worm->mhp)
            worm->mhp = worm->mhpmax;
    }

    level->wtails[new_wnum] = new_tail; /* We've got all the info right now */
    level->wheads[new_wnum] = curr;     /* so we can do this faster than */
    level->wgrowtime[new_wnum] = 0L;    /* trying to call initworm().  */

    /* Place the new monster at all the segment locations. */
    place_wsegs(new_worm);

    if (flags.mon_moving)
        pline(msgc_monneutral, "%s is cut in half.", Monnam(worm));
    else
        pline(msgc_combatgood, "You cut %s in half.", mon_nam(worm));
}
Пример #10
0
/*
 * Make the mail daemon run through the dungeon.  The daemon will run over
 * any monsters that are in its path, but will replace them later.  Return
 * FALSE if the md gets stuck in a position where there is a monster.  Return
 * TRUE otherwise.
 */
STATIC_OVL boolean
md_rush(struct monst *md, register int tx, register int ty)
                 
                    		/* destination of mail daemon */
{
    struct monst *mon;			/* displaced monster */
    register int dx, dy;		/* direction counters */
    int fx = md->mx, fy = md->my;	/* current location */
    int nfx = fx, nfy = fy,		/* new location */
        d1, d2;				/* shortest distances */

    /*
     * It is possible that the monster at (fx,fy) is not the md when:
     * the md rushed the hero and failed, and is now starting back.
     */
    if (m_at(fx, fy) == md) {
        remove_monster(fx, fy);		/* pick up from orig position */
        newsym(fx, fy);
    }

    /*
     * At the beginning and exit of this loop, md is not placed in the
     * dungeon.
     */
    while (1) {
        /* Find a good location next to (fx,fy) closest to (tx,ty). */
        d1 = dist2(fx,fy,tx,ty);
        for (dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++)
                if ((dx || dy) && isok(fx+dx,fy+dy) &&
                        !IS_STWALL(levl[fx+dx][fy+dy].typ)) {
                    d2 = dist2(fx+dx,fy+dy,tx,ty);
                    if (d2 < d1) {
                        d1 = d2;
                        nfx = fx+dx;
                        nfy = fy+dy;
                    }
                }

        /* Break if the md couldn't find a new position. */
        if (nfx == fx && nfy == fy) break;

        fx = nfx;			/* this is our new position */
        fy = nfy;

        /* Break if the md reaches its destination. */
        if (fx == tx && fy == ty) break;

        if ((mon = m_at(fx,fy)) != 0)	/* save monster at this position */
            verbalize("%s", md_exclamations());
        else if (fx == u.ux && fy == u.uy)
            verbalize("Excuse me.");

        place_monster(md,fx,fy);	/* put md down */
        newsym(fx,fy);			/* see it */
        flush_screen(0);		/* make sure md shows up */
        delay_output();			/* wait a little bit */

        /* Remove md from the dungeon.  Restore original mon, if necessary. */
        if (mon) {
            if ((mon->mx != fx) || (mon->my != fy))
                place_worm_seg(mon, fx, fy);
            else
                place_monster(mon, fx, fy);
        } else
            remove_monster(fx, fy);
        newsym(fx,fy);
    }

    /*
     * Check for a monster at our stopping position (this is possible, but
     * very unlikely).  If one exists, then have the md leave in disgust.
     */
    if ((mon = m_at(fx, fy)) != 0) {
        place_monster(md, fx, fy);	/* display md with text below */
        newsym(fx, fy);
        verbalize("This place's too crowded.  I'm outta here.");

        if ((mon->mx != fx) || (mon->my != fy))	/* put mon back */
            place_worm_seg(mon, fx, fy);
        else
            place_monster(mon, fx, fy);

        newsym(fx, fy);
        return FALSE;
    }

    place_monster(md, fx, fy);	/* place at final spot */
    newsym(fx, fy);
    flush_screen(0);
    delay_output();			/* wait a little bit */

    return TRUE;
}
Пример #11
0
/*
 * return  1: guard moved,  0: guard didn't,  -1: let m_move do it,  -2: died
 */
int gd_move(struct monst *grd) {
    int x, y, nx, ny, m, n;
    int dx, dy, gx, gy, fci;
    unsigned char typ;
    struct fakecorridor *fcp;
    struct egd *egrd = EGD(grd);
    struct rm *crm;
    bool goldincorridor = false, u_in_vault = vault_occupied(u.urooms) ? true : false, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ?
    true :
                                                                                                                                           false;
    bool disappear_msg_seen = false, semi_dead = (grd->mhp <= 0);
    bool u_carry_gold = ((u.ugold + hidden_gold()) > 0L);
    bool see_guard;

    if (!on_level(&(egrd->gdlevel), &u.uz))
        return (-1);
    nx = ny = m = n = 0;
    if (!u_in_vault && !grd_in_vault)
        wallify_vault(grd);
    if (!grd->mpeaceful) {
        if (semi_dead) {
            egrd->gddone = 1;
            goto newpos;
        }
        if (!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) {
            (void)rloc(grd, false);
            wallify_vault(grd);
            (void)clear_fcorr(grd, true);
            goto letknow;
        }
        if (!in_fcorridor(grd, grd->mx, grd->my))
            (void)clear_fcorr(grd, true);
        return (-1);
    }
    if (abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1)
        return (-1); /* teleported guard - treat as monster */
    if (egrd->fcend == 1) {
        if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) {
            if (egrd->warncnt == 3)
                verbalize("I repeat, %sfollow me!", u_carry_gold ? (!u.ugold ? "drop that hidden gold and " : "drop that gold and ") : "");
            if (egrd->warncnt == 7) {
                m = grd->mx;
                n = grd->my;
                verbalize("You've been warned, knave!");
                mnexto(grd);
                levl[m][n].typ = egrd->fakecorr[0].ftyp;
                newsym(m, n);
                grd->mpeaceful = 0;
                return (-1);
            }
            /* not fair to get mad when (s)he's fainted or paralyzed */
            if (!is_fainted() && multi >= 0)
                egrd->warncnt++;
            return (0);
        }

        if (!u_in_vault) {
            if (u_carry_gold) { /* player teleported */
                m = grd->mx;
                n = grd->my;
                (void)rloc(grd, false);
                levl[m][n].typ = egrd->fakecorr[0].ftyp;
                newsym(m, n);
                grd->mpeaceful = 0;
                letknow: if (!cansee(grd->mx, grd->my) || !mon_visible(grd)) {
                    You_hear("the shrill sound of a guard's whistle.");
                } else {
                    const char * fmt = um_dist(grd->mx, grd->my, 2) ? "see an angry %s approaching." : "are confronted by an angry %s.";
                    char name[BUFSZ];
                    g_monnam(name, BUFSZ, grd);
                    You(fmt, name);
                }
                return (-1);
            } else {
                verbalize("Well, begone.");
                wallify_vault(grd);
                egrd->gddone = 1;
                goto cleanup;
            }
        }
    }

    if (egrd->fcend > 1) {
        if (egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) && !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) &&
        levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ == egrd->fakecorr[0].ftyp) {
            char name[BUFSZ];
            g_monnam(name, BUFSZ, grd);
            pline_The("%s, confused, disappears.", name);
            disappear_msg_seen = true;
            goto cleanup;
        }
        if (u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) ||
        /* cover a 'blind' spot */
        (egrd->fcend > 1 && u_in_vault))) {
            if (!grd->mx) {
                restfakecorr(grd);
                return (-2);
            }
            if (egrd->warncnt < 6) {
                egrd->warncnt = 6;
                verbalize("Drop all your gold, scoundrel!");
                return (0);
            } else {
                verbalize("So be it, rogue!");
                grd->mpeaceful = 0;
                return (-1);
            }
        }
    }
    for (fci = egrd->fcbeg; fci < egrd->fcend; fci++)
        if (g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)) {
            m = egrd->fakecorr[fci].fx;
            n = egrd->fakecorr[fci].fy;
            goldincorridor = true;
        }
    if (goldincorridor && !egrd->gddone) {
        x = grd->mx;
        y = grd->my;
        if (m == u.ux && n == u.uy) {
            struct obj *gold = g_at(m, n);
            /* Grab the gold from between the hero's feet.  */
            grd->mgold += gold->quan;
            delobj(gold);
            newsym(m, n);
        } else if (m == x && n == y) {
            mpickgold(grd); /* does a newsym */
        } else {
            /* just for insurance... */
            if (MON_AT(m, n) && m != grd->mx && n != grd->my) {
                verbalize("Out of my way, scum!");
                (void)rloc(m_at(m, n), false);
            }
            remove_monster(grd->mx, grd->my);
            newsym(grd->mx, grd->my);
            place_monster(grd, m, n);
            mpickgold(grd); /* does a newsym */
        }
        if (cansee(m, n)) {
            char name[BUFSZ];
            Monnam(name, BUFSZ, grd);
            pline("%s%s picks up the gold.", name, grd->mpeaceful ? " calms down and" : "");
        }
        if (x != grd->mx || y != grd->my) {
            remove_monster(grd->mx, grd->my);
            newsym(grd->mx, grd->my);
            place_monster(grd, x, y);
            newsym(x, y);
        }
        if (!grd->mpeaceful)
            return (-1);
        else {
            egrd->warncnt = 5;
            return (0);
        }
    }
    if (um_dist(grd->mx, grd->my, 1) || egrd->gddone) {
        if (!egrd->gddone && !rn2(10))
            verbalize("Move along!");
        restfakecorr(grd);
        return (0); /* didn't move */
    }
    x = grd->mx;
    y = grd->my;

    if (u_in_vault)
        goto nextpos;

    /* look around (hor & vert only) for accessible places */
    for (nx = x - 1; nx <= x + 1; nx++) {
        for (ny = y - 1; ny <= y + 1; ny++) {
            if ((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) {

                typ = (crm = &levl[nx][ny])->typ;
                if (!IS_STWALL(typ) && !IS_POOL(typ)) {

                    if (in_fcorridor(grd, nx, ny))
                        goto nextnxy;

                    if (*in_rooms(nx, ny, VAULT))
                        continue;

                    /* seems we found a good place to leave him alone */
                    egrd->gddone = 1;
                    if (ACCESSIBLE(typ))
                        goto newpos;
                    crm->typ = (typ == SCORR) ? CORR : DOOR;
                    if (crm->typ == DOOR)
                        crm->flags = D_NODOOR;
                    goto proceed;
                }
            }
            nextnxy: ;
        }
    }
    nextpos: nx = x;
    ny = y;
    gx = egrd->gdx;
    gy = egrd->gdy;
    dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
    dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
    if (abs(gx - x) >= abs(gy - y))
        nx += dx;
    else
        ny += dy;

    while ((typ = (crm = &levl[nx][ny])->typ) != 0) {
        /* in view of the above we must have IS_WALL(typ) or typ == POOL */
        /* must be a wall here */
        if (isok(nx + nx - x, ny + ny - y) && !IS_POOL(typ) && IS_ROOM(levl[nx+nx-x][ny+ny-y].typ)) {
            crm->typ = DOOR;
            crm->flags = D_NODOOR;
            goto proceed;
        }
        if (dy && nx != x) {
            nx = x;
            ny = y + dy;
            continue;
        }
        if (dx && ny != y) {
            ny = y;
            nx = x + dx;
            dy = 0;
            continue;
        }
        /* I don't like this, but ... */
        if (IS_ROOM(typ)) {
            crm->typ = DOOR;
            crm->flags = D_NODOOR;
            goto proceed;
        }
        break;
    }
    crm->typ = CORR;
    proceed: unblock_point(nx, ny); /* doesn't block light */
    if (cansee(nx, ny))
        newsym(nx, ny);

    fcp = &(egrd->fakecorr[egrd->fcend]);
    if (egrd->fcend++ == FCSIZ)
        impossible("fakecorr overflow");
    fcp->fx = nx;
    fcp->fy = ny;
    fcp->ftyp = typ;
    newpos: if (egrd->gddone) {
        /* The following is a kludge.  We need to keep    */
        /* the guard around in order to be able to make   */
        /* the fake corridor disappear as the player      */
        /* moves out of it, but we also need the guard    */
        /* out of the way.  We send the guard to never-   */
        /* never land.  We set ogx ogy to mx my in order  */
        /* to avoid a check at the top of this function.  */
        /* At the end of the process, the guard is killed */
        /* in restfakecorr().                             */
        cleanup: x = grd->mx;
        y = grd->my;

        see_guard = canspotmon(grd);
        wallify_vault(grd);
        remove_monster(grd->mx, grd->my);
        newsym(grd->mx, grd->my);
        place_monster(grd, 0, 0);
        egrd->ogx = grd->mx;
        egrd->ogy = grd->my;
        restfakecorr(grd);
        if (!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) {
            if (!disappear_msg_seen && see_guard) {
                char name[BUFSZ];
                g_monnam(name, BUFSZ, grd);
                pline("Suddenly, the %s disappears.", name);
            }
            return (1);
        }
        return (-2);
    }
    egrd->ogx = grd->mx; /* update old positions */
    egrd->ogy = grd->my;
    remove_monster(grd->mx, grd->my);
    place_monster(grd, nx, ny);
    newsym(grd->mx, grd->my);
    restfakecorr(grd);
    return (1);
}
Пример #12
0
/* Start riding, with the given monster */
boolean
mount_steed(struct monst * mtmp,        /* The animal */
            boolean force)
{   /* Quietly force this animal */
    struct obj *otmp;
    const struct permonst *ptr;

    /* Sanity checks */
    if (u.usteed) {
        pline("You are already riding %s.", mon_nam(u.usteed));
        return FALSE;
    }

    /* Is the player in the right form? */
    if (Hallucination && !force) {
        pline("Maybe you should find a designated driver.");
        return FALSE;
    }
    /* While riding Wounded_legs refers to the steed's, not the hero's legs.
       That opens up a potential abuse where the player can mount a steed, then
       dismount immediately to heal leg damage, because leg damage is always
       healed upon dismount (Wounded_legs context switch). By preventing a hero
       with Wounded_legs from mounting a steed, the potential for abuse is
       minimized, if not eliminated altogether. */
    if (Wounded_legs) {
        pline("Your %s are in no shape for riding.",
              makeplural(body_part(LEG)));
        if (force && wizard && yn("Heal your legs?") == 'y')
            LWounded_legs = RWounded_legs = 0;
        else
            return FALSE;
    }

    if (Upolyd &&
            (!humanoid(youmonst.data) || verysmall(youmonst.data) ||
             bigmonst(youmonst.data) || slithy(youmonst.data))) {
        pline("You won't fit on a saddle.");
        return FALSE;
    }
    if (!force && (near_capacity() > SLT_ENCUMBER)) {
        pline("You can't do that while carrying so much stuff.");
        return FALSE;
    }

    /* Can the player reach and see the monster? */
    if (!mtmp ||
            (!force &&
             ((Blind && !Blind_telepat) || mtmp->mundetected ||
              mtmp->m_ap_type == M_AP_FURNITURE ||
              mtmp->m_ap_type == M_AP_OBJECT))) {
        pline("I see nobody there.");
        return FALSE;
    }

    struct test_move_cache cache;
    init_test_move_cache(&cache);

    if (Engulfed || u.ustuck || u.utrap || Punished ||
            !test_move(u.ux, u.uy, mtmp->mx - u.ux, mtmp->my - u.uy, 0,
                       TEST_MOVE, &cache)) {
        if (Punished || !(Engulfed || u.ustuck || u.utrap))
            pline("You are unable to swing your %s over.", body_part(LEG));
        else
            pline("You are stuck here for now.");
        return FALSE;
    }

    /* Is this a valid monster? */
    otmp = which_armor(mtmp, os_saddle);
    if (!otmp) {
        pline("%s is not saddled.", Monnam(mtmp));
        return FALSE;
    }
    ptr = mtmp->data;
    if (touch_petrifies(ptr) && !Stone_resistance) {
        pline("You touch %s.", mon_nam(mtmp));
        instapetrify(killer_msg(STONING,
                                msgcat("attempting to ride ", an(mtmp->data->mname))));
    }
    if (!mtmp->mtame || mtmp->isminion) {
        pline("I think %s would mind.", mon_nam(mtmp));
        return FALSE;
    }
    if (mtmp->mtrapped) {
        struct trap *t = t_at(level, mtmp->mx, mtmp->my);

        pline("You can't mount %s while %s's trapped in %s.", mon_nam(mtmp),
              mhe(mtmp), t ? an(trapexplain[t->ttyp - 1]) : "ice");
        return FALSE;
    }

    if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) {
        /* no longer tame */
        newsym(mtmp->mx, mtmp->my);
        pline("%s resists%s!", Monnam(mtmp),
              mtmp->mleashed ? " and its leash comes off" : "");
        if (mtmp->mleashed)
            m_unleash(mtmp, FALSE);
        return FALSE;
    }
    if (!force && Underwater && !is_swimmer(ptr)) {
        pline("You can't ride that creature while under water.");
        return FALSE;
    }
    if (!can_saddle(mtmp) || !can_ride(mtmp)) {
        pline("You can't ride such a creature.");
        return 0;
    }

    /* Is the player impaired? */
    if (!force && !is_floater(ptr) && !is_flyer(ptr) && Levitation &&
            !Lev_at_will) {
        pline("You cannot reach %s.", mon_nam(mtmp));
        return FALSE;
    }
    if (!force && uarm && is_metallic(uarm) && greatest_erosion(uarm)) {
        pline("Your %s armor is too stiff to be able to mount %s.",
              uarm->oeroded ? "rusty" : "corroded", mon_nam(mtmp));
        return FALSE;
    }
    if (!force &&
            (Confusion || Fumbling || Glib || Wounded_legs || otmp->cursed ||
             ((u.ulevel + mtmp->mtame < rnd(MAXULEV / 2 + 5)) &&
              (!Role_if(PM_KNIGHT))))) {
        if (Levitation) {
            pline("%s slips away from you.", Monnam(mtmp));
            return FALSE;
        }
        pline("You slip while trying to get on %s.", mon_nam(mtmp));

        const char *buf = msgcat(
                              "slipped while mounting ",
                              /* "a saddled mumak" or "a saddled pony called Dobbin" */
                              x_monnam(mtmp, ARTICLE_A, NULL,
                                       SUPPRESS_IT | SUPPRESS_INVISIBLE |
                                       SUPPRESS_HALLUCINATION, TRUE));
        losehp(rn1(5, 10), buf);
        return FALSE;
    }

    /* Success */
    maybewakesteed(mtmp);
    if (!force) {
        if (Levitation && !is_floater(ptr) && !is_flyer(ptr))
            /* Must have Lev_at_will at this point */
            pline("%s magically floats up!", Monnam(mtmp));
        pline("You mount %s.", mon_nam(mtmp));
    }
    /* setuwep handles polearms differently when you're mounted */
    if (uwep && is_pole(uwep))
        u.bashmsg = TRUE;
    u.usteed = mtmp;
    remove_monster(level, mtmp->mx, mtmp->my);
    teleds(mtmp->mx, mtmp->my, TRUE);
    return TRUE;
}
Пример #13
0
/*
 * return  1: guard moved,  0: guard didn't,  -1: let m_move do it,  -2: died
 */
int
gd_move(struct monst *grd)
{
    int x, y, nx, ny, m, n;
    int dx, dy, gx = 0, gy = 0, fci;
    uchar typ;
    struct fakecorridor *fcp;
    struct egd *egrd = EGD(grd);
    struct rm *crm;
    boolean goldincorridor = FALSE, u_in_vault =
        vault_occupied(u.urooms) ? TRUE : FALSE, grd_in_vault =
        *in_rooms(level, grd->mx, grd->my, VAULT) ? TRUE : FALSE;
    boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0);
    long umoney = money_cnt(invent);
    boolean u_carry_gold = ((umoney + hidden_gold()) > 0L);
    boolean see_guard;

    if (!on_level(&(egrd->gdlevel), &u.uz))
        return -1;
    nx = ny = m = n = 0;
    if (!u_in_vault && !grd_in_vault)
        wallify_vault(grd);
    if (!grd->mpeaceful) {
        if (semi_dead) {
            egrd->gddone = 1;
            goto newpos;
        }
        if (!u_in_vault &&
            (grd_in_vault ||
             (in_fcorridor(grd, grd->mx, grd->my) &&
              !in_fcorridor(grd, u.ux, u.uy)))) {
            rloc(grd, FALSE);
            wallify_vault(grd);
            clear_fcorr(grd, TRUE);
            goto letknow;
        }
        if (!in_fcorridor(grd, grd->mx, grd->my))
            clear_fcorr(grd, TRUE);
        return -1;
    }
    if (abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1)
        return -1;      /* teleported guard - treat as monster */
    if (egrd->fcend == 1) {
        if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) {
            if (egrd->warncnt == 3)
                verbalize("I repeat, %sfollow me!",
                          u_carry_gold ? (!umoney ?
                                          "drop that hidden money and " :
                                          "drop that money and ") : "");
            if (egrd->warncnt == 7) {
                m = grd->mx;
                n = grd->my;
                verbalize("You've been warned, knave!");
                mnexto(grd);
                level->locations[m][n].typ = egrd->fakecorr[0].ftyp;
                newsym(m, n);
                msethostility(grd, TRUE, FALSE);
                return -1;
            }
            /* not fair to get mad when (s)he's fainted or paralyzed */
            if (!u_helpless(hm_all))
                egrd->warncnt++;
            return 0;
        }

        if (!u_in_vault) {
            if (u_carry_gold) { /* player teleported */
                m = grd->mx;
                n = grd->my;
                rloc(grd, FALSE);
                level->locations[m][n].typ = egrd->fakecorr[0].ftyp;
                newsym(m, n);
                msethostility(grd, TRUE, FALSE);
            letknow:
                if (!cansee(grd->mx, grd->my) || !mon_visible(grd))
                    You_hear("the shrill sound of a guard's whistle.");
                else
                    pline(um_dist(grd->mx, grd->my, 2) ?
                          "You see an angry guard approaching." :
                          "You are confronted by an angry guard.");
                return -1;
            } else {
                verbalize("Well, begone.");
                wallify_vault(grd);
                egrd->gddone = 1;
                goto cleanup;
            }
        }
    }

    if (egrd->fcend > 1) {
        if (egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) &&
            !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) &&
            level->locations[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ ==
            egrd->fakecorr[0].ftyp) {
            if (canseemon(grd)) {
                pline("%s, confused, disappears.", Monnam(grd));
                disappear_msg_seen = TRUE;
            }
            goto cleanup;
        }
        if (u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) ||
                             /* cover a 'blind' spot */
                             (egrd->fcend > 1 && u_in_vault))) {
            if (!grd->mx) {
                restfakecorr(grd);
                return -2;
            }
            if (egrd->warncnt < 6) {
                egrd->warncnt = 6;
                verbalize("Drop all your gold, scoundrel!");
                return 0;
            } else {
                verbalize("So be it, rogue!");
                msethostility(grd, TRUE, FALSE);
                return -1;
            }
        }
    }
    for (fci = egrd->fcbeg; fci < egrd->fcend; fci++)
        if (gold_at(level, egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)) {
            m = egrd->fakecorr[fci].fx;
            n = egrd->fakecorr[fci].fy;
            goldincorridor = TRUE;
        }
    if (goldincorridor && !egrd->gddone) {
        boolean yours = FALSE;

        x = grd->mx;
        y = grd->my;
        if (m == u.ux && n == u.uy) {
            struct obj *gold = gold_at(level, m, n);

            yours = TRUE;
            /* Grab the gold from between the hero's feet.  */
            obj_extract_self(gold);
            add_to_minv(grd, gold);
            newsym(m, n);
        } else if (m == x && n == y) {
            mpickgold(grd);     /* does a newsym */
        } else {
            /* just for insurance... */
            if (MON_AT(level, m, n) && m != grd->mx && n != grd->my) {
                verbalize("Out of my way, scum!");
                rloc(m_at(level, m, n), FALSE);
            }
            remove_monster(level, grd->mx, grd->my);
            newsym(grd->mx, grd->my);
            place_monster(grd, m, n);
            mpickgold(grd);     /* does a newsym */
        }
        if (cansee(m, n)) {
            if (yours) {
                pline("%s%s picks up the gold.", Monnam(grd),
                      grd->mpeaceful ? " calms down and" : "");
            } else {
                pline("%s picks up some gold.", Monnam(grd));
            }
        }
        if (x != grd->mx || y != grd->my) {
            remove_monster(level, grd->mx, grd->my);
            newsym(grd->mx, grd->my);
            place_monster(grd, x, y);
            newsym(x, y);
        }
        if (!grd->mpeaceful)
            return -1;
        else {
            egrd->warncnt = 5;
            return 0;
        }
    }
    if (um_dist(grd->mx, grd->my, 1) || egrd->gddone) {
        if (!egrd->gddone && !rn2(10))
            verbalize("Move along!");
        restfakecorr(grd);
        return 0;       /* didn't move */
    }
    x = grd->mx;
    y = grd->my;

    if (u_in_vault)
        goto nextpos;

    /* look around (hor & vert only) for accessible places */
    for (nx = x - 1; nx <= x + 1; nx++)
        for (ny = y - 1; ny <= y + 1; ny++) {
            if ((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) {

                typ = (crm = &level->locations[nx][ny])->typ;
                if (!IS_STWALL(typ) && !IS_POOL(typ)) {

                    if (in_fcorridor(grd, nx, ny))
                        goto nextnxy;

                    if (*in_rooms(level, nx, ny, VAULT))
                        continue;

                    /* seems we found a good place to leave him alone */
                    egrd->gddone = 1;
                    if (ACCESSIBLE(typ))
                        goto newpos;
                    crm->typ = (typ == SCORR) ? CORR : DOOR;
                    if (crm->typ == DOOR)
                        crm->doormask = D_NODOOR;
                    goto proceed;
                }
            }
        nextnxy:;
        }
nextpos:
    nx = x;
    ny = y;
    gx = egrd->gdx;
    gy = egrd->gdy;
    dx = (gx > x) ? 1 : (gx < x) ? -1 : 0;
    dy = (gy > y) ? 1 : (gy < y) ? -1 : 0;
    if (abs(gx - x) >= abs(gy - y))
        nx += dx;
    else
        ny += dy;

    while ((typ = (crm = &level->locations[nx][ny])->typ) != 0) {
        /* in view of the above we must have IS_WALL(typ) or typ == POOL */
        /* must be a wall here */
        if (isok(nx + nx - x, ny + ny - y) && !IS_POOL(typ) &&
            IS_ROOM(level->locations[nx + nx - x][ny + ny - y].typ)) {
            crm->typ = DOOR;
            crm->doormask = D_NODOOR;
            goto proceed;
        }
        if (dy && nx != x) {
            nx = x;
            ny = y + dy;
            continue;
        }
        if (dx && ny != y) {
            ny = y;
            nx = x + dx;
            dy = 0;
            continue;
        }
        /* I don't like this, but ... */
        if (IS_ROOM(typ)) {
            crm->typ = DOOR;
            crm->doormask = D_NODOOR;
            goto proceed;
        }
        break;
    }
    crm->typ = CORR;
proceed:
    unblock_point(nx, ny);      /* doesn't block light */
    if (cansee(nx, ny))
        newsym(nx, ny);

    if ((nx != gx || ny != gy) || (grd->mx != gx || grd->my != gy)) {
        fcp = &(egrd->fakecorr[egrd->fcend]);
        if (egrd->fcend++ == FCSIZ)
            panic("fakecorr overflow");
        fcp->fx = nx;
        fcp->fy = ny;
        fcp->ftyp = typ;
    } else if (!egrd->gddone) {
        /* We're stuck, so try to find a new destination. */
        if (!find_guard_dest(grd, &egrd->gdx, &egrd->gdy) ||
            (egrd->gdx == gx && egrd->gdy == gy)) {
            pline("%s, confused, disappears.", Monnam(grd));
            disappear_msg_seen = TRUE;
            goto cleanup;
        } else
            goto nextpos;
    }
newpos:
    if (egrd->gddone) {
        /* The following is a kludge.  We need to keep the guard around in order
           to be able to make the fake corridor disappear as the player moves
           out of it, but we also need the guard out of the way.  We send the
           guard to never-never land.  We set ogx ogy to mx my in order to avoid
           a check at the top of this function.  At the end of the process, the
           guard is killed in restfakecorr().  */
    cleanup:
        x = grd->mx;
        y = grd->my;

        see_guard = canspotmon(grd);
        wallify_vault(grd);
        remove_monster(level, grd->mx, grd->my);
        newsym(grd->mx, grd->my);
        grd->mx = COLNO;
        grd->my = ROWNO;
        egrd->ogx = grd->mx;
        egrd->ogy = grd->my;
        restfakecorr(grd);
        if (!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) {
            if (!disappear_msg_seen && see_guard)
                pline("Suddenly, %s disappears.", noit_mon_nam(grd));
            return 1;
        }
        return -2;
    }
    egrd->ogx = grd->mx;        /* update old positions */
    egrd->ogy = grd->my;
    remove_monster(level, grd->mx, grd->my);
    place_monster(grd, nx, ny);
    newsym(grd->mx, grd->my);
    restfakecorr(grd);
    return 1;
}