in src/muse.c [96:1483]
Hallucination ? rndmonnam(NULL)
: (const char *) "ghost");
pline("%s is frightened to death, and unable to move.",
Monnam(mon));
}
paralyze_monst(mon, 3);
}
return 2;
}
}
if (potion_descr && !strcmp(potion_descr, "smoky")
&& !(mvitals[PM_DJINNI].mvflags & G_GONE)
&& !rn2(POTION_OCCUPANT_CHANCE(mvitals[PM_DJINNI].born))) {
if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI]))
return 0;
mquaffmsg(mon, obj);
m_useup(mon, obj);
mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS);
if (!mtmp) {
if (vis)
pline1(empty);
} else {
if (vis)
pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp));
pline("%s speaks.", vis ? Monnam(mtmp) : Something);
/* I suspect few players will be upset that monsters */
/* can't wish for wands of death here.... */
if (rn2(2)) {
verbalize("You freed me!");
mtmp->mpeaceful = 1;
set_malign(mtmp);
} else {
verbalize("It is about time.");
if (vis)
pline("%s vanishes.", Monnam(mtmp));
mongone(mtmp);
}
}
return 2;
}
}
if (obj->oclass == WAND_CLASS && obj->cursed
&& !rn2(WAND_BACKFIRE_CHANCE)) {
int dam = d(obj->spe + 2, 6);
/* 3.6.1: no Deaf filter; 'if' message doesn't warrant it, 'else'
message doesn't need it since You_hear() has one of its own */
if (vis) {
pline("%s zaps %s, which suddenly explodes!", Monnam(mon),
an(xname(obj)));
} else {
/* same near/far threshold as mzapwand() */
int range = couldsee(mon->mx, mon->my) /* 9 or 5 */
? (BOLT_LIM + 1) : (BOLT_LIM - 3);
You_hear("a zap and an explosion %s.",
(distu(mon->mx, mon->my) <= range * range)
? "nearby" : "in the distance");
}
m_useup(mon, obj);
mon->mhp -= dam;
if (DEADMONSTER(mon)) {
monkilled(mon, "", AD_RBRE);
return 1;
}
m.has_defense = m.has_offense = m.has_misc = 0;
/* Only one needed to be set to 0 but the others are harmless */
}
return 0;
}
/* when a monster zaps a wand give a message, deduct a charge, and if it
isn't directly seen, remove hero's memory of the number of charges */
STATIC_OVL void
mzapwand(mtmp, otmp, self)
struct monst *mtmp;
struct obj *otmp;
boolean self;
{
if (!canseemon(mtmp)) {
int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */
? (BOLT_LIM + 1) : (BOLT_LIM - 3);
You_hear("a %s zap.", (distu(mtmp->mx, mtmp->my) <= range * range)
? "nearby" : "distant");
otmp->known = 0;
} else if (self) {
pline("%s zaps %sself with %s!", Monnam(mtmp), mhim(mtmp),
doname(otmp));
} else {
pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp)));
stop_occupation();
}
otmp->spe -= 1;
}
/* similar to mzapwand() but for magical horns (only instrument mons play) */
STATIC_OVL void
mplayhorn(mtmp, otmp, self)
struct monst *mtmp;
struct obj *otmp;
boolean self;
{
if (!canseemon(mtmp)) {
int range = couldsee(mtmp->mx, mtmp->my) /* 9 or 5 */
? (BOLT_LIM + 1) : (BOLT_LIM - 3);
You_hear("a horn being played %s.",
(distu(mtmp->mx, mtmp->my) <= range * range)
? "nearby" : "in the distance");
otmp->known = 0; /* hero doesn't know how many charges are left */
} else {
otmp->dknown = 1;
pline("%s plays a %s directed at %s!", Monnam(mtmp), xname(otmp),
self ? mon_nam_too(mtmp, mtmp) : (char *) "you");
makeknown(otmp->otyp); /* (wands handle this slightly differently) */
if (!self)
stop_occupation();
}
otmp->spe -= 1; /* use a charge */
}
STATIC_OVL void
mreadmsg(mtmp, otmp)
struct monst *mtmp;
struct obj *otmp;
{
boolean vismon = canseemon(mtmp);
char onambuf[BUFSZ];
short saverole;
unsigned savebknown;
if (!vismon && Deaf)
return; /* no feedback */
otmp->dknown = 1; /* seeing or hearing it read reveals its label */
/* shouldn't be able to hear curse/bless status of unseen scrolls;
for priest characters, bknown will always be set during naming */
savebknown = otmp->bknown;
saverole = Role_switch;
if (!vismon) {
otmp->bknown = 0;
if (Role_if(PM_PRIEST))
Role_switch = 0;
}
Strcpy(onambuf, singular(otmp, doname));
Role_switch = saverole;
otmp->bknown = savebknown;
if (vismon)
pline("%s reads %s!", Monnam(mtmp), onambuf);
else
You_hear("%s reading %s.",
x_monnam(mtmp, ARTICLE_A, (char *) 0,
(SUPPRESS_IT | SUPPRESS_INVISIBLE | SUPPRESS_SADDLE),
FALSE),
onambuf);
if (mtmp->mconf)
pline("Being confused, %s mispronounces the magic words...",
vismon ? mon_nam(mtmp) : mhe(mtmp));
}
STATIC_OVL void
mquaffmsg(mtmp, otmp)
struct monst *mtmp;
struct obj *otmp;
{
if (canseemon(mtmp)) {
otmp->dknown = 1;
pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname));
} else if (!Deaf)
You_hear("a chugging sound.");
}
/* Defines for various types of stuff. The order in which monsters prefer
* to use them is determined by the order of the code logic, not the
* numerical order in which they are defined.
*/
#define MUSE_SCR_TELEPORTATION 1
#define MUSE_WAN_TELEPORTATION_SELF 2
#define MUSE_POT_HEALING 3
#define MUSE_POT_EXTRA_HEALING 4
#define MUSE_WAN_DIGGING 5
#define MUSE_TRAPDOOR 6
#define MUSE_TELEPORT_TRAP 7
#define MUSE_UPSTAIRS 8
#define MUSE_DOWNSTAIRS 9
#define MUSE_WAN_CREATE_MONSTER 10
#define MUSE_SCR_CREATE_MONSTER 11
#define MUSE_UP_LADDER 12
#define MUSE_DN_LADDER 13
#define MUSE_SSTAIRS 14
#define MUSE_WAN_TELEPORTATION 15
#define MUSE_BUGLE 16
#define MUSE_UNICORN_HORN 17
#define MUSE_POT_FULL_HEALING 18
#define MUSE_LIZARD_CORPSE 19
/*
#define MUSE_INNATE_TPT 9999
* We cannot use this. Since monsters get unlimited teleportation, if they
* were allowed to teleport at will you could never catch them. Instead,
* assume they only teleport at random times, despite the inconsistency
* that if you polymorph into one you teleport at will.
*/
STATIC_OVL boolean
m_use_healing(mtmp)
struct monst *mtmp;
{
struct obj *obj = 0;
if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_EXTRA_HEALING;
return TRUE;
}
if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) {
m.defensive = obj;
m.has_defense = MUSE_POT_HEALING;
return TRUE;
}
return FALSE;
}
/* Select a defensive item/action for a monster. Returns TRUE iff one is
found. */
boolean
find_defensive(mtmp)
struct monst *mtmp;
{
register struct obj *obj = 0;
struct trap *t;
int x = mtmp->mx, y = mtmp->my;
boolean stuck = (mtmp == u.ustuck);
boolean immobile = (mtmp->data->mmove == 0);
int fraction;
if (is_animal(mtmp->data) || mindless(mtmp->data))
return FALSE;
if (dist2(x, y, mtmp->mux, mtmp->muy) > 25)
return FALSE;
if (u.uswallow && stuck)
return FALSE;
m.defensive = (struct obj *) 0;
m.has_defense = 0;
/* since unicorn horns don't get used up, the monster would look
* silly trying to use the same cursed horn round after round
*/
if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) {
if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) {
for (obj = mtmp->minvent; obj; obj = obj->nobj)
if (obj->otyp == UNICORN_HORN && !obj->cursed)
break;
}
if (obj || is_unicorn(mtmp->data)) {
m.defensive = obj;
m.has_defense = MUSE_UNICORN_HORN;
return TRUE;
}
}
if (mtmp->mconf || mtmp->mstun) {
struct obj *liztin = 0;
for (obj = mtmp->minvent; obj; obj = obj->nobj) {
if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) {
m.defensive = obj;
m.has_defense = MUSE_LIZARD_CORPSE;
return TRUE;
} else if (obj->otyp == TIN && obj->corpsenm == PM_LIZARD) {
liztin = obj;
}
}
/* confused or stunned monster might not be able to open tin */
if (liztin && mcould_eat_tin(mtmp) && rn2(3)) {
m.defensive = liztin;
/* tin and corpse ultimately end up being handled the same */
m.has_defense = MUSE_LIZARD_CORPSE;
return TRUE;
}
}
/* It so happens there are two unrelated cases when we might want to
* check specifically for healing alone. The first is when the monster
* is blind (healing cures blindness). The second is when the monster
* is peaceful; then we don't want to flee the player, and by
* coincidence healing is all there is that doesn't involve fleeing.
* These would be hard to combine because of the control flow.
* Pestilence won't use healing even when blind.
*/
if (!mtmp->mcansee && !nohands(mtmp->data)
&& mtmp->data != &mons[PM_PESTILENCE]) {
if (m_use_healing(mtmp))
return TRUE;
}
fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3;
if (mtmp->mhp >= mtmp->mhpmax
|| (mtmp->mhp >= 10 && mtmp->mhp * fraction >= mtmp->mhpmax))
return FALSE;
if (mtmp->mpeaceful) {
if (!nohands(mtmp->data)) {
if (m_use_healing(mtmp))
return TRUE;
}
return FALSE;
}
if (stuck || immobile) {
; /* fleeing by stairs or traps is not possible */
} else if (levl[x][y].typ == STAIRS) {
if (x == xdnstair && y == ydnstair) {
if (!is_floater(mtmp->data))
m.has_defense = MUSE_DOWNSTAIRS;
} else if (x == xupstair && y == yupstair) {
m.has_defense = MUSE_UPSTAIRS;
} else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) {
if (sstairs.up || !is_floater(mtmp->data))
m.has_defense = MUSE_SSTAIRS;
}
} else if (levl[x][y].typ == LADDER) {
if (x == xupladder && y == yupladder) {
m.has_defense = MUSE_UP_LADDER;
} else if (x == xdnladder && y == ydnladder) {
if (!is_floater(mtmp->data))
m.has_defense = MUSE_DN_LADDER;
} else if (sstairs.sx && x == sstairs.sx && y == sstairs.sy) {
if (sstairs.up || !is_floater(mtmp->data))
m.has_defense = MUSE_SSTAIRS;
}
} else {
/* Note: trap doors take precedence over teleport traps. */
int xx, yy, i, locs[10][2];
boolean ignore_boulders = (verysmall(mtmp->data)
|| throws_rocks(mtmp->data)
|| passes_walls(mtmp->data)),
diag_ok = !NODIAG(monsndx(mtmp->data));
for (i = 0; i < 10; ++i) /* 10: 9 spots plus sentinel */
locs[i][0] = locs[i][1] = 0;
/* collect viable spots; monster's <mx,my> comes first */
locs[0][0] = x, locs[0][1] = y;
i = 1;
for (xx = x - 1; xx <= x + 1; xx++)
for (yy = y - 1; yy <= y + 1; yy++)
if (isok(xx, yy) && (xx != x || yy != y)) {
locs[i][0] = xx, locs[i][1] = yy;
++i;
}
/* look for a suitable trap among the viable spots */
for (i = 0; i < 10; ++i) {
xx = locs[i][0], yy = locs[i][1];
if (!xx)
break; /* we've run out of spots */
/* skip if it's hero's location
or a diagonal spot and monster can't move diagonally
or some other monster is there */
if ((xx == u.ux && yy == u.uy)
|| (xx != x && yy != y && !diag_ok)
|| (level.monsters[xx][yy] && !(xx == x && yy == y)))
continue;
/* skip if there's no trap or can't/won't move onto trap */
if ((t = t_at(xx, yy)) == 0
|| (!ignore_boulders && sobj_at(BOULDER, xx, yy))
|| onscary(xx, yy, mtmp))
continue;
/* use trap if it's the correct type */
if (is_hole(t->ttyp)
&& !is_floater(mtmp->data)
&& !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
&& Can_fall_thru(&u.uz)) {
trapx = xx;
trapy = yy;
m.has_defense = MUSE_TRAPDOOR;
break; /* no need to look at any other spots */
} else if (t->ttyp == TELEP_TRAP) {
trapx = xx;
trapy = yy;
m.has_defense = MUSE_TELEPORT_TRAP;
}
}
}
if (nohands(mtmp->data)) /* can't use objects */
goto botm;
if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE)) != 0) {
int xx, yy;
struct monst *mon;
/* Distance is arbitrary. What we really want to do is
* have the soldier play the bugle when it sees or
* remembers soldiers nearby...
*/
for (xx = x - 3; xx <= x + 3; xx++) {
for (yy = y - 3; yy <= y + 3; yy++) {
if (!isok(xx, yy) || (xx == x && yy == y))
continue;
if ((mon = m_at(xx, yy)) != 0 && is_mercenary(mon->data)
&& mon->data != &mons[PM_GUARD]
&& (mon->msleeping || !mon->mcanmove)) {
m.defensive = obj;
m.has_defense = MUSE_BUGLE;
goto toot; /* double break */
}
}
}
toot:
;
}
/* use immediate physical escape prior to attempting magic */
if (m.has_defense) /* stairs, trap door or tele-trap, bugle alert */
goto botm;
/* kludge to cut down on trap destruction (particularly portals) */
t = t_at(x, y);
if (t && (is_pit(t->ttyp) || t->ttyp == WEB
|| t->ttyp == BEAR_TRAP))
t = 0; /* ok for monster to dig here */
#define nomore(x) if (m.has_defense == x) continue;
/* selection could be improved by collecting all possibilities
into an array and then picking one at random */
for (obj = mtmp->minvent; obj; obj = obj->nobj) {
/* don't always use the same selection pattern */
if (m.has_defense && !rn2(3))
break;
/* nomore(MUSE_WAN_DIGGING); */
if (m.has_defense == MUSE_WAN_DIGGING)
break;
if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t
&& !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest
&& !is_floater(mtmp->data)
/* monsters digging in Sokoban can ruin things */
&& !Sokoban
/* digging wouldn't be effective; assume they know that */
&& !(levl[x][y].wall_info & W_NONDIGGABLE)
&& !(Is_botlevel(&u.uz) || In_endgame(&u.uz))
&& !(is_ice(x, y) || is_pool(x, y) || is_lava(x, y))
&& !(mtmp->data == &mons[PM_VLAD_THE_IMPALER]
&& In_V_tower(&u.uz))) {
m.defensive = obj;
m.has_defense = MUSE_WAN_DIGGING;
}
nomore(MUSE_WAN_TELEPORTATION_SELF);
nomore(MUSE_WAN_TELEPORTATION);
if (obj->otyp == WAN_TELEPORTATION && obj->spe > 0) {
/* use the TELEP_TRAP bit to determine if they know
* about noteleport on this level or not. Avoids
* ineffective re-use of teleportation. This does
* mean if the monster leaves the level, they'll know
* about teleport traps.
*/
if (!level.flags.noteleport
|| !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) {
m.defensive = obj;
m.has_defense = (mon_has_amulet(mtmp))
? MUSE_WAN_TELEPORTATION
: MUSE_WAN_TELEPORTATION_SELF;
}
}
nomore(MUSE_SCR_TELEPORTATION);
if (obj->otyp == SCR_TELEPORTATION && mtmp->mcansee
&& haseyes(mtmp->data)
&& (!obj->cursed || (!(mtmp->isshk && inhishop(mtmp))
&& !mtmp->isgd && !mtmp->ispriest))) {
/* see WAN_TELEPORTATION case above */
if (!level.flags.noteleport
|| !(mtmp->mtrapseen & (1 << (TELEP_TRAP - 1)))) {
m.defensive = obj;
m.has_defense = MUSE_SCR_TELEPORTATION;
}
}
if (mtmp->data != &mons[PM_PESTILENCE]) {
nomore(MUSE_POT_FULL_HEALING);
if (obj->otyp == POT_FULL_HEALING) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
}
nomore(MUSE_POT_EXTRA_HEALING);
if (obj->otyp == POT_EXTRA_HEALING) {
m.defensive = obj;
m.has_defense = MUSE_POT_EXTRA_HEALING;
}
nomore(MUSE_WAN_CREATE_MONSTER);
if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
m.defensive = obj;
m.has_defense = MUSE_WAN_CREATE_MONSTER;
}
nomore(MUSE_POT_HEALING);
if (obj->otyp == POT_HEALING) {
m.defensive = obj;
m.has_defense = MUSE_POT_HEALING;
}
} else { /* Pestilence */
nomore(MUSE_POT_FULL_HEALING);
if (obj->otyp == POT_SICKNESS) {
m.defensive = obj;
m.has_defense = MUSE_POT_FULL_HEALING;
}
nomore(MUSE_WAN_CREATE_MONSTER);
if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) {
m.defensive = obj;
m.has_defense = MUSE_WAN_CREATE_MONSTER;
}
}
nomore(MUSE_SCR_CREATE_MONSTER);
if (obj->otyp == SCR_CREATE_MONSTER) {
m.defensive = obj;
m.has_defense = MUSE_SCR_CREATE_MONSTER;
}
}
botm:
return (boolean) !!m.has_defense;
#undef nomore
}
/* Perform a defensive action for a monster. Must be called immediately
* after find_defensive(). Return values are 0: did something, 1: died,
* 2: did something and can't attack again (i.e. teleported).
*/
int
use_defensive(mtmp)
struct monst *mtmp;
{
int i, fleetim, how = 0;
struct obj *otmp = m.defensive;
boolean vis, vismon, oseen;
const char *Mnam;
if ((i = precheck(mtmp, otmp)) != 0)
return i;
vis = cansee(mtmp->mx, mtmp->my);
vismon = canseemon(mtmp);
oseen = otmp && vismon;
/* when using defensive choice to run away, we want monster to avoid
rushing right straight back; don't override if already scared */
fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0;
#define m_flee(m) \
if (fleetim && !m->iswiz) { \
monflee(m, fleetim, FALSE, FALSE); \
}
switch (m.has_defense) {
case MUSE_UNICORN_HORN:
if (vismon) {
if (otmp)
pline("%s uses a unicorn horn!", Monnam(mtmp));
else
pline_The("tip of %s's horn glows!", mon_nam(mtmp));
}
if (!mtmp->mcansee) {
mcureblindness(mtmp, vismon);
} else if (mtmp->mconf || mtmp->mstun) {
mtmp->mconf = mtmp->mstun = 0;
if (vismon)
pline("%s seems steadier now.", Monnam(mtmp));
} else
impossible("No need for unicorn horn?");
return 2;
case MUSE_BUGLE:
if (vismon)
pline("%s plays %s!", Monnam(mtmp), doname(otmp));
else if (!Deaf)
You_hear("a bugle playing reveille!");
awaken_soldiers(mtmp);
return 2;
case MUSE_WAN_TELEPORTATION_SELF:
if ((mtmp->isshk && inhishop(mtmp)) || mtmp->isgd || mtmp->ispriest)
return 2;
m_flee(mtmp);
mzapwand(mtmp, otmp, TRUE);
how = WAN_TELEPORTATION;
mon_tele:
if (tele_restrict(mtmp)) { /* mysterious force... */
if (vismon && how) /* mentions 'teleport' */
makeknown(how);
/* monster learns that teleportation isn't useful here */
if (level.flags.noteleport)
mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1));
return 2;
}
if ((mon_has_amulet(mtmp) || On_W_tower_level(&u.uz)) && !rn2(3)) {
if (vismon)
pline("%s seems disoriented for a moment.", Monnam(mtmp));
return 2;
}
if (oseen && how)
makeknown(how);
(void) rloc(mtmp, TRUE);
return 2;
case MUSE_WAN_TELEPORTATION:
zap_oseen = oseen;
mzapwand(mtmp, otmp, FALSE);
m_using = TRUE;
mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp);
/* monster learns that teleportation isn't useful here */
if (level.flags.noteleport)
mtmp->mtrapseen |= (1 << (TELEP_TRAP - 1));
m_using = FALSE;
return 2;
case MUSE_SCR_TELEPORTATION: {
int obj_is_cursed = otmp->cursed;
if (mtmp->isshk || mtmp->isgd || mtmp->ispriest)
return 2;
m_flee(mtmp);
mreadmsg(mtmp, otmp);
m_useup(mtmp, otmp); /* otmp might be free'ed */
how = SCR_TELEPORTATION;
if (obj_is_cursed || mtmp->mconf) {
int nlev;
d_level flev;
if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) {
if (vismon)
pline("%s seems very disoriented for a moment.",
Monnam(mtmp));
return 2;
}
nlev = random_teleport_level();
if (nlev == depth(&u.uz)) {
if (vismon)
pline("%s shudders for a moment.", Monnam(mtmp));
return 2;
}
get_level(&flev, nlev);
migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM,
(coord *) 0);
if (oseen)
makeknown(SCR_TELEPORTATION);
} else
goto mon_tele;
return 2;
}
case MUSE_WAN_DIGGING: {
struct trap *ttmp;
m_flee(mtmp);
mzapwand(mtmp, otmp, FALSE);
if (oseen)
makeknown(WAN_DIGGING);
if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ)
|| IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ)
|| (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0)
|| (sstairs.sx && sstairs.sx == mtmp->mx
&& sstairs.sy == mtmp->my)) {
pline_The("digging ray is ineffective.");
return 2;
}
if (!Can_dig_down(&u.uz) && !levl[mtmp->mx][mtmp->my].candig) {
if (canseemon(mtmp))
pline_The("%s here is too hard to dig in.",
surface(mtmp->mx, mtmp->my));
return 2;
}
ttmp = maketrap(mtmp->mx, mtmp->my, HOLE);
if (!ttmp)
return 2;
seetrap(ttmp);
if (vis) {
pline("%s has made a hole in the %s.", Monnam(mtmp),
surface(mtmp->mx, mtmp->my));
pline("%s %s through...", Monnam(mtmp),
is_flyer(mtmp->data) ? "dives" : "falls");
} else if (!Deaf)
You_hear("%s crash through the %s.", something,
surface(mtmp->mx, mtmp->my));
/* we made sure that there is a level for mtmp to go to */
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
(coord *) 0);
return 2;
}
case MUSE_WAN_CREATE_MONSTER: {
coord cc;
/* pm: 0 => random, eel => aquatic, croc => amphibious */
struct permonst *pm =
!is_pool(mtmp->mx, mtmp->my)
? 0
: &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
struct monst *mon;
if (!enexto(&cc, mtmp->mx, mtmp->my, pm))
return 0;
mzapwand(mtmp, otmp, FALSE);
mon = makemon((struct permonst *) 0, cc.x, cc.y, NO_MM_FLAGS);
if (mon && canspotmon(mon) && oseen)
makeknown(WAN_CREATE_MONSTER);
return 2;
}
case MUSE_SCR_CREATE_MONSTER: {
coord cc;
struct permonst *pm = 0, *fish = 0;
int cnt = 1;
struct monst *mon;
boolean known = FALSE;
if (!rn2(73))
cnt += rnd(4);
if (mtmp->mconf || otmp->cursed)
cnt += 12;
if (mtmp->mconf)
pm = fish = &mons[PM_ACID_BLOB];
else if (is_pool(mtmp->mx, mtmp->my))
fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE];
mreadmsg(mtmp, otmp);
while (cnt--) {
/* `fish' potentially gives bias towards water locations;
`pm' is what to actually create (0 => random) */
if (!enexto(&cc, mtmp->mx, mtmp->my, fish))
break;
mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS);
if (mon && canspotmon(mon))
known = TRUE;
}
/* The only case where we don't use oseen. For wands, you
* have to be able to see the monster zap the wand to know
* what type it is. For teleport scrolls, you have to see
* the monster to know it teleported.
*/
if (known)
makeknown(SCR_CREATE_MONSTER);
else if (!objects[SCR_CREATE_MONSTER].oc_name_known
&& !objects[SCR_CREATE_MONSTER].oc_uname)
docall(otmp);
m_useup(mtmp, otmp);
return 2;
}
case MUSE_TRAPDOOR:
/* trap doors on "bottom" levels of dungeons are rock-drop
* trap doors, not holes in the floor. We check here for
* safety.
*/
if (Is_botlevel(&u.uz))
return 0;
m_flee(mtmp);
if (vis) {
struct trap *t = t_at(trapx, trapy);
Mnam = Monnam(mtmp);
pline("%s %s into a %s!", Mnam,
vtense(fakename[0], locomotion(mtmp->data, "jump")),
(t->ttyp == TRAPDOOR) ? "trap door" : "hole");
if (levl[trapx][trapy].typ == SCORR) {
levl[trapx][trapy].typ = CORR;
unblock_point(trapx, trapy);
}
seetrap(t_at(trapx, trapy));
}
/* don't use rloc_to() because worm tails must "move" */
remove_monster(mtmp->mx, mtmp->my);
newsym(mtmp->mx, mtmp->my); /* update old location */
place_monster(mtmp, trapx, trapy);
if (mtmp->wormno)
worm_move(mtmp);
newsym(trapx, trapy);
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
(coord *) 0);
return 2;
case MUSE_UPSTAIRS:
m_flee(mtmp);
if (ledger_no(&u.uz) == 1)
goto escape; /* impossible; level 1 upstairs are SSTAIRS */
if (Inhell && mon_has_amulet(mtmp) && !rn2(4)
&& (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) {
if (vismon)
pline(
"As %s climbs the stairs, a mysterious force momentarily surrounds %s...",
mon_nam(mtmp), mhim(mtmp));
/* simpler than for the player; this will usually be
the Wizard and he'll immediately go right to the
upstairs, so there's not much point in having any
chance for a random position on the current level */
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM,
(coord *) 0);
} else {
if (vismon)
pline("%s escapes upstairs!", Monnam(mtmp));
migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN,
(coord *) 0);
}
return 2;
case MUSE_DOWNSTAIRS:
m_flee(mtmp);
if (vismon)
pline("%s escapes downstairs!", Monnam(mtmp));
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP,
(coord *) 0);
return 2;
case MUSE_UP_LADDER:
m_flee(mtmp);
if (vismon)
pline("%s escapes up the ladder!", Monnam(mtmp));
migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN,
(coord *) 0);
return 2;
case MUSE_DN_LADDER:
m_flee(mtmp);
if (vismon)
pline("%s escapes down the ladder!", Monnam(mtmp));
migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP,
(coord *) 0);
return 2;
case MUSE_SSTAIRS:
m_flee(mtmp);
if (ledger_no(&u.uz) == 1) {
escape:
/* Monsters without the Amulet escape the dungeon and
* are gone for good when they leave up the up stairs.
* A monster with the Amulet would leave it behind
* (mongone -> mdrop_special_objs) but we force any
* monster who manages to acquire it or the invocation
* tools to stick around instead of letting it escape.
*/
if (mon_has_special(mtmp))
return 0;
if (vismon)
pline("%s escapes the dungeon!", Monnam(mtmp));
mongone(mtmp);
return 2;
}
if (vismon)
pline("%s escapes %sstairs!", Monnam(mtmp),
sstairs.up ? "up" : "down");
/* going from the Valley to Castle (Stronghold) has no sstairs
to target, but having sstairs.<sx,sy> == <0,0> will work the
same as specifying MIGR_RANDOM when mon_arrive() eventually
places the monster, so we can use MIGR_SSTAIRS unconditionally */
migrate_to_level(mtmp, ledger_no(&sstairs.tolev), MIGR_SSTAIRS,
(coord *) 0);
return 2;
case MUSE_TELEPORT_TRAP:
m_flee(mtmp);
if (vis) {
Mnam = Monnam(mtmp);
pline("%s %s onto a teleport trap!", Mnam,
vtense(fakename[0], locomotion(mtmp->data, "jump")));
seetrap(t_at(trapx, trapy));
}
/* don't use rloc_to() because worm tails must "move" */
remove_monster(mtmp->mx, mtmp->my);
newsym(mtmp->mx, mtmp->my); /* update old location */
place_monster(mtmp, trapx, trapy);
if (mtmp->wormno)
worm_move(mtmp);
newsym(trapx, trapy);
goto mon_tele;
case MUSE_POT_HEALING:
mquaffmsg(mtmp, otmp);
i = d(6 + 2 * bcsign(otmp), 4);
mtmp->mhp += i;
if (mtmp->mhp > mtmp->mhpmax)
mtmp->mhp = ++mtmp->mhpmax;
if (!otmp->cursed && !mtmp->mcansee)
mcureblindness(mtmp, vismon);
if (vismon)
pline("%s looks better.", Monnam(mtmp));
if (oseen)
makeknown(POT_HEALING);
m_useup(mtmp, otmp);
return 2;
case MUSE_POT_EXTRA_HEALING:
mquaffmsg(mtmp, otmp);
i = d(6 + 2 * bcsign(otmp), 8);
mtmp->mhp += i;
if (mtmp->mhp > mtmp->mhpmax)
mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2));
if (!mtmp->mcansee)
mcureblindness(mtmp, vismon);
if (vismon)
pline("%s looks much better.", Monnam(mtmp));
if (oseen)
makeknown(POT_EXTRA_HEALING);
m_useup(mtmp, otmp);
return 2;
case MUSE_POT_FULL_HEALING:
mquaffmsg(mtmp, otmp);
if (otmp->otyp == POT_SICKNESS)
unbless(otmp); /* Pestilence */
mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4));
if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS)
mcureblindness(mtmp, vismon);
if (vismon)
pline("%s looks completely healed.", Monnam(mtmp));
if (oseen)
makeknown(otmp->otyp);
m_useup(mtmp, otmp);
return 2;
case MUSE_LIZARD_CORPSE:
/* not actually called for its unstoning effect */
mon_consume_unstone(mtmp, otmp, FALSE, FALSE);
return 2;
case 0:
return 0; /* i.e. an exploded wand */
default:
impossible("%s wanted to perform action %d?", Monnam(mtmp),
m.has_defense);
break;
}
return 0;
#undef m_flee
}
int
rnd_defensive_item(mtmp)
struct monst *mtmp;
{
struct permonst *pm = mtmp->data;
int difficulty = mons[(monsndx(pm))].difficulty;
int trycnt = 0;
if (is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data)
|| pm->mlet == S_GHOST || pm->mlet == S_KOP)
return 0;
try_again:
switch (rn2(8 + (difficulty > 3) + (difficulty > 6) + (difficulty > 8))) {
case 6:
case 9:
if (level.flags.noteleport && ++trycnt < 2)
goto try_again;
if (!rn2(3))
return WAN_TELEPORTATION;
/*FALLTHRU*/
case 0:
case 1:
return SCR_TELEPORTATION;
case 8:
case 10:
if (!rn2(3))
return WAN_CREATE_MONSTER;
/*FALLTHRU*/
case 2:
return SCR_CREATE_MONSTER;
case 3:
return POT_HEALING;
case 4:
return POT_EXTRA_HEALING;
case 5:
return (mtmp->data != &mons[PM_PESTILENCE]) ? POT_FULL_HEALING
: POT_SICKNESS;
case 7:
if (is_floater(pm) || mtmp->isshk || mtmp->isgd || mtmp->ispriest)
return 0;
else
return WAN_DIGGING;
}
/*NOTREACHED*/
return 0;
}
#define MUSE_WAN_DEATH 1
#define MUSE_WAN_SLEEP 2
#define MUSE_WAN_FIRE 3
#define MUSE_WAN_COLD 4
#define MUSE_WAN_LIGHTNING 5
#define MUSE_WAN_MAGIC_MISSILE 6
#define MUSE_WAN_STRIKING 7
#define MUSE_SCR_FIRE 8
#define MUSE_POT_PARALYSIS 9
#define MUSE_POT_BLINDNESS 10
#define MUSE_POT_CONFUSION 11
#define MUSE_FROST_HORN 12
#define MUSE_FIRE_HORN 13
#define MUSE_POT_ACID 14
/*#define MUSE_WAN_TELEPORTATION 15*/
#define MUSE_POT_SLEEPING 16
#define MUSE_SCR_EARTH 17
/* Select an offensive item/action for a monster. Returns TRUE iff one is
* found.
*/
boolean
find_offensive(mtmp)
struct monst *mtmp;
{
register struct obj *obj;
boolean reflection_skip = (Reflecting && rn2(2));
struct obj *helmet = which_armor(mtmp, W_ARMH);
m.offensive = (struct obj *) 0;
m.has_offense = 0;
if (mtmp->mpeaceful || is_animal(mtmp->data) || mindless(mtmp->data)
|| nohands(mtmp->data))
return FALSE;
if (u.uswallow)
return FALSE;
if (in_your_sanctuary(mtmp, 0, 0))
return FALSE;
if (dmgtype(mtmp->data, AD_HEAL)
&& !uwep && !uarmu && !uarm && !uarmh
&& !uarms && !uarmg && !uarmc && !uarmf)
return FALSE;
/* all offensive items require orthogonal or diagonal targetting */
if (!lined_up(mtmp))
return FALSE;
#define nomore(x) if (m.has_offense == x) continue;
/* this picks the last viable item rather than prioritizing choices */
for (obj = mtmp->minvent; obj; obj = obj->nobj) {
if (!reflection_skip) {
nomore(MUSE_WAN_DEATH);
if (obj->otyp == WAN_DEATH && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_DEATH;
}
nomore(MUSE_WAN_SLEEP);
if (obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_SLEEP;
}
nomore(MUSE_WAN_FIRE);
if (obj->otyp == WAN_FIRE && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_FIRE;
}
nomore(MUSE_FIRE_HORN);
if (obj->otyp == FIRE_HORN && obj->spe > 0 && can_blow(mtmp)) {
m.offensive = obj;
m.has_offense = MUSE_FIRE_HORN;
}
nomore(MUSE_WAN_COLD);
if (obj->otyp == WAN_COLD && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_COLD;
}
nomore(MUSE_FROST_HORN);
if (obj->otyp == FROST_HORN && obj->spe > 0 && can_blow(mtmp)) {
m.offensive = obj;
m.has_offense = MUSE_FROST_HORN;
}
nomore(MUSE_WAN_LIGHTNING);
if (obj->otyp == WAN_LIGHTNING && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_LIGHTNING;
}
nomore(MUSE_WAN_MAGIC_MISSILE);
if (obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_MAGIC_MISSILE;
}
}
nomore(MUSE_WAN_STRIKING);
if (obj->otyp == WAN_STRIKING && obj->spe > 0) {
m.offensive = obj;
m.has_offense = MUSE_WAN_STRIKING;
}
#if 0 /* use_offensive() has had some code to support wand of teleportation
* for a long time, but find_offensive() never selected one;
* so for the time being, this is still disabled */
nomore(MUSE_WAN_TELEPORTATION);
if (obj->otyp == WAN_TELEPORTATION && obj->spe > 0
/* don't give controlled hero a free teleport */
&& !Teleport_control
/* do try to move hero to a more vulnerable spot */
&& (onscary(u.ux, u.uy, mtmp)
|| (u.ux == xupstair && u.uy == yupstair)
|| (u.ux == xdnstair && u.uy == ydnstair)
|| (u.ux == sstairs.sx && u.uy == sstairs.sy)
|| (u.ux == xupladder && u.uy == yupladder)
|| (u.ux == xdnladder && u.uy == ydnladder))) {
m.offensive = obj;
m.has_offense = MUSE_WAN_TELEPORTATION;
}
#endif
nomore(MUSE_POT_PARALYSIS);
if (obj->otyp == POT_PARALYSIS && multi >= 0) {
m.offensive = obj;
m.has_offense = MUSE_POT_PARALYSIS;
}
nomore(MUSE_POT_BLINDNESS);
if (obj->otyp == POT_BLINDNESS && !attacktype(mtmp->data, AT_GAZE)) {
m.offensive = obj;
m.has_offense = MUSE_POT_BLINDNESS;
}
nomore(MUSE_POT_CONFUSION);
if (obj->otyp == POT_CONFUSION) {
m.offensive = obj;
m.has_offense = MUSE_POT_CONFUSION;
}
nomore(MUSE_POT_SLEEPING);
if (obj->otyp == POT_SLEEPING) {
m.offensive = obj;
m.has_offense = MUSE_POT_SLEEPING;
}
nomore(MUSE_POT_ACID);
if (obj->otyp == POT_ACID) {
m.offensive = obj;
m.has_offense = MUSE_POT_ACID;
}
/* we can safely put this scroll here since the locations that
* are in a 1 square radius are a subset of the locations that
* are in wand or throwing range (in other words, always lined_up())
*/
nomore(MUSE_SCR_EARTH);
if (obj->otyp == SCR_EARTH
&& ((helmet && is_metallic(helmet)) || mtmp->mconf
|| amorphous(mtmp->data) || passes_walls(mtmp->data)
|| noncorporeal(mtmp->data) || unsolid(mtmp->data)
|| !rn2(10))
&& dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2
&& mtmp->mcansee && haseyes(mtmp->data)
&& !Is_rogue_level(&u.uz)
&& (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) {
m.offensive = obj;
m.has_offense = MUSE_SCR_EARTH;
}
#if 0
nomore(MUSE_SCR_FIRE);
if (obj->otyp == SCR_FIRE && resists_fire(mtmp)
&& dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2
&& mtmp->mcansee && haseyes(mtmp->data)) {
m.offensive = obj;
m.has_offense = MUSE_SCR_FIRE;
}
#endif /* 0 */
}
return (boolean) !!m.has_offense;
#undef nomore
}
STATIC_PTR
int
mbhitm(mtmp, otmp)
register struct monst *mtmp;
register struct obj *otmp;
{
int tmp;
boolean reveal_invis = FALSE;
if (mtmp != &youmonst) {
mtmp->msleeping = 0;
if (mtmp->m_ap_type)
seemimic(mtmp);
}
switch (otmp->otyp) {
case WAN_STRIKING:
reveal_invis = TRUE;
if (mtmp == &youmonst) {
if (zap_oseen)
makeknown(WAN_STRIKING);
if (Antimagic) {
shieldeff(u.ux, u.uy);
pline("Boing!");
} else if (rnd(20) < 10 + u.uac) {
pline_The("wand hits you!");
tmp = d(2, 12);
if (Half_spell_damage)
tmp = (tmp + 1) / 2;
losehp(tmp, "wand", KILLED_BY_AN);
} else
pline_The("wand misses you.");
stop_occupation();
nomul(0);
} else if (resists_magm(mtmp)) {
shieldeff(mtmp->mx, mtmp->my);
pline("Boing!");
} else if (rnd(20) < 10 + find_mac(mtmp)) {
tmp = d(2, 12);
hit("wand", mtmp, exclam(tmp));
(void) resist(mtmp, otmp->oclass, tmp, TELL);
if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
makeknown(WAN_STRIKING);
} else {
miss("wand", mtmp);
if (cansee(mtmp->mx, mtmp->my) && zap_oseen)
makeknown(WAN_STRIKING);
}
break;
#if 0 /* disabled because find_offensive() never picks WAN_TELEPORTATION */
case WAN_TELEPORTATION:
if (mtmp == &youmonst) {
if (zap_oseen)
makeknown(WAN_TELEPORTATION);
tele();
} else {
/* for consistency with zap.c, don't identify */
if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) {
if (cansee(mtmp->mx, mtmp->my))
pline("%s resists the magic!", Monnam(mtmp));
} else if (!tele_restrict(mtmp))
(void) rloc(mtmp, TRUE);
}
break;
#endif
case WAN_CANCELLATION:
case SPE_CANCELLATION:
(void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE);
break;
}
if (reveal_invis) {
if (!DEADMONSTER(mtmp) && cansee(bhitpos.x, bhitpos.y)
&& !canspotmon(mtmp))
map_invisible(bhitpos.x, bhitpos.y);
}
return 0;
}
/* A modified bhit() for monsters. Based on bhit() in zap.c. Unlike
* buzz(), bhit() doesn't take into account the possibility of a monster
* zapping you, so we need a special function for it. (Unless someone wants
* to merge the two functions...)
*/
STATIC_OVL void
mbhit(mon, range, fhitm, fhito, obj)
struct monst *mon; /* monster shooting the wand */
register int range; /* direction and range */
int FDECL((*fhitm), (MONST_P, OBJ_P));
int FDECL((*fhito), (OBJ_P, OBJ_P)); /* fns called when mon/obj hit */
struct obj *obj; /* 2nd arg to fhitm/fhito */
{
register struct monst *mtmp;
register struct obj *otmp;
register uchar typ;
int ddx, ddy;
bhitpos.x = mon->mx;
bhitpos.y = mon->my;
ddx = sgn(mon->mux - mon->mx);
ddy = sgn(mon->muy - mon->my);
while (range-- > 0) {
int x, y;
bhitpos.x += ddx;
bhitpos.y += ddy;
x = bhitpos.x;
y = bhitpos.y;
if (!isok(x, y)) {
bhitpos.x -= ddx;
bhitpos.y -= ddy;
break;
}
if (find_drawbridge(&x, &y))
switch (obj->otyp) {
case WAN_STRIKING:
destroy_drawbridge(x, y);
}
if (bhitpos.x == u.ux && bhitpos.y == u.uy) {
(*fhitm)(&youmonst, obj);
range -= 3;
} else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) {
if (cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp))
map_invisible(bhitpos.x, bhitpos.y);
(*fhitm)(mtmp, obj);
range -= 3;
}
/* modified by GAN to hit all objects */
if (fhito) {
int hitanything = 0;
register struct obj *next_obj;
for (otmp = level.objects[bhitpos.x][bhitpos.y]; otmp;
otmp = next_obj) {
/* Fix for polymorph bug, Tim Wright */
next_obj = otmp->nexthere;
hitanything += (*fhito)(otmp, obj);
}
if (hitanything)
range--;
}
typ = levl[bhitpos.x][bhitpos.y].typ;
if (IS_DOOR(typ) || typ == SDOOR) {
switch (obj->otyp) {
/* note: monsters don't use opening or locking magic
at present, but keep these as placeholders */
case WAN_OPENING:
case WAN_LOCKING:
case WAN_STRIKING:
if (doorlock(obj, bhitpos.x, bhitpos.y)) {
if (zap_oseen)
makeknown(obj->otyp);
/* if a shop door gets broken, add it to
the shk's fix list (no cost to player) */
if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN
&& *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE))
add_damage(bhitpos.x, bhitpos.y, 0L);
}
break;
}
}
if (!ZAP_POS(typ)
|| (IS_DOOR(typ) && (levl[bhitpos.x][bhitpos.y].doormask
& (D_LOCKED | D_CLOSED)))) {
bhitpos.x -= ddx;
bhitpos.y -= ddy;
break;
}
}
}
/* Perform an offensive action for a monster. Must be called immediately
* after find_offensive(). Return values are same as use_defensive().
*/
int
use_offensive(mtmp)
struct monst *mtmp;
{
int i;
struct obj *otmp = m.offensive;
boolean oseen;
/* offensive potions are not drunk, they're thrown */
if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0)
return i;
oseen = otmp && canseemon(mtmp);
switch (m.has_offense) {
case MUSE_WAN_DEATH:
case MUSE_WAN_SLEEP:
case MUSE_WAN_FIRE:
case MUSE_WAN_COLD:
case MUSE_WAN_LIGHTNING:
case MUSE_WAN_MAGIC_MISSILE:
mzapwand(mtmp, otmp, FALSE);
if (oseen)
makeknown(otmp->otyp);
m_using = TRUE;
buzz((int) (-30 - (otmp->otyp - WAN_MAGIC_MISSILE)),
(otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my,
sgn(mtmp->mux - mtmp->mx), sgn(mtmp->muy - mtmp->my));
m_using = FALSE;
return (DEADMONSTER(mtmp)) ? 1 : 2;
case MUSE_FIRE_HORN:
case MUSE_FROST_HORN:
mplayhorn(mtmp, otmp, FALSE);
m_using = TRUE;
buzz(-30 - ((otmp->otyp == FROST_HORN) ? AD_COLD - 1 : AD_FIRE - 1),
rn1(6, 6), mtmp->mx, mtmp->my, sgn(mtmp->mux - mtmp->mx),
sgn(mtmp->muy - mtmp->my));
m_using = FALSE;
return (DEADMONSTER(mtmp)) ? 1 : 2;
case MUSE_WAN_TELEPORTATION:
case MUSE_WAN_STRIKING:
zap_oseen = oseen;
mzapwand(mtmp, otmp, FALSE);
m_using = TRUE;
mbhit(mtmp, rn1(8, 6), mbhitm, bhito, otmp);
m_using = FALSE;
return 2;
case MUSE_SCR_EARTH: {
/* TODO: handle steeds */
register int x, y;
/* don't use monster fields after killing it */
boolean confused = (mtmp->mconf ? TRUE : FALSE);
int mmx = mtmp->mx, mmy = mtmp->my;
boolean is_cursed = otmp->cursed;
mreadmsg(mtmp, otmp);
/* Identify the scroll */
if (canspotmon(mtmp)) {
pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my),
otmp->blessed ? "around" : "above", mon_nam(mtmp));
if (oseen)
makeknown(otmp->otyp);
} else if (cansee(mtmp->mx, mtmp->my)) {
pline_The("%s rumbles in the middle of nowhere!",
ceiling(mtmp->mx, mtmp->my));
if (mtmp->minvis)
map_invisible(mtmp->mx, mtmp->my);
if (oseen)
makeknown(otmp->otyp);
}
/* Loop through the surrounding squares */
for (x = mmx - 1; x <= mmx + 1; x++) {
for (y = mmy - 1; y <= mmy + 1; y++) {
/* Is this a suitable spot? */
if (isok(x, y) && !closed_door(x, y)
&& !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ)
&& (((x == mmx) && (y == mmy)) ? !otmp->blessed
: !otmp->cursed)
&& (x != u.ux || y != u.uy)) {