Monster list iterator

Add some basic functions to iterate through the monster list,
ignoring dead monsters. Mainly just to allow splitting up code
into discrete functions.

Not quite happy with the get_iter_mons_xy - should probably have
a pointer to iterator data struct, which gets passed through instead,
but this works for now.
This commit is contained in:
Pasi Kallinen
2022-04-24 13:03:43 +03:00
parent f886e0d6ce
commit 4a01c8fbd7
10 changed files with 418 additions and 309 deletions

View File

@@ -12,6 +12,7 @@ static int use_stethoscope(struct obj *);
static void use_whistle(struct obj *);
static void use_magic_whistle(struct obj *);
static int use_leash(struct obj *);
static boolean mleashed_next2u(struct monst *);
static int use_mirror(struct obj *);
static void use_bell(struct obj **);
static void use_candelabrum(struct obj *);
@@ -718,33 +719,38 @@ get_mleash(struct monst *mtmp)
return otmp;
}
static boolean
mleashed_next2u(struct monst *mtmp)
{
if (mtmp->mleashed) {
if (!next2u(mtmp->mx, mtmp->my))
mnexto(mtmp, RLOC_NOMSG);
if (!next2u(mtmp->mx, mtmp->my)) {
struct obj *otmp = get_mleash(mtmp);
if (!otmp) {
impossible("leashed-unleashed mon?");
return TRUE;
}
if (otmp->cursed)
return TRUE;
mtmp->mleashed = 0;
otmp->leashmon = 0;
update_inventory();
You_feel("%s leash go slack.",
(number_leashed() > 1) ? "a" : "the");
}
}
return FALSE;
}
boolean
next_to_u(void)
{
register struct monst *mtmp;
register struct obj *otmp;
if (get_iter_mons(mleashed_next2u))
return FALSE;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (mtmp->mleashed) {
if (!next2u(mtmp->mx, mtmp->my))
mnexto(mtmp, RLOC_NOMSG);
if (!next2u(mtmp->mx, mtmp->my)) {
for (otmp = g.invent; otmp; otmp = otmp->nobj)
if (otmp->otyp == LEASH
&& (unsigned) otmp->leashmon == mtmp->m_id) {
if (otmp->cursed)
return FALSE;
mtmp->mleashed = 0;
otmp->leashmon = 0;
update_inventory();
You_feel("%s leash go slack.",
(number_leashed() > 1) ? "a" : "the");
}
}
}
}
/* no pack mules for the Amulet */
if (u.usteed && mon_has_amulet(u.usteed))
return FALSE;

View File

@@ -10,6 +10,7 @@ static void goodfruit(int);
static void resetobjs(struct obj *, boolean);
static void give_to_nearby_mon(struct obj *, int, int);
static boolean fixuporacle(struct monst *);
static void remove_mon_from_bones(struct monst *);
static boolean
no_bones_level(d_level *lev)
@@ -377,6 +378,20 @@ can_make_bones(void)
return TRUE;
}
/* monster removed before saving a bones file,
in case these characters are not in their home bases */
static void
remove_mon_from_bones(struct monst *mtmp)
{
struct permonst *mptr = mtmp->data;
if (mtmp->iswiz || mptr == &mons[PM_MEDUSA]
|| mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER
|| mptr == &mons[PM_VLAD_THE_IMPALER]
|| (mptr == &mons[PM_ORACLE] && !fixuporacle(mtmp)))
mongone(mtmp);
}
/* save bones and possessions of a deceased adventurer */
void
savebones(int how, time_t when, struct obj *corpse)
@@ -384,7 +399,6 @@ savebones(int how, time_t when, struct obj *corpse)
int x, y;
struct trap *ttmp;
struct monst *mtmp;
struct permonst *mptr;
struct fruit *f;
struct cemetery *newbones;
char c, *bonesid;
@@ -413,17 +427,8 @@ savebones(int how, time_t when, struct obj *corpse)
make_bones:
unleash_all();
/* in case these characters are not in their home bases */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
mptr = mtmp->data;
if (mtmp->iswiz || mptr == &mons[PM_MEDUSA]
|| mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER
|| mptr == &mons[PM_VLAD_THE_IMPALER]
|| (mptr == &mons[PM_ORACLE] && !fixuporacle(mtmp)))
mongone(mtmp);
}
iter_mons(remove_mon_from_bones);
if (u.usteed)
dismount_steed(DISMOUNT_BONES);
dmonsfree(); /* discard dead or gone monsters */

View File

@@ -131,6 +131,7 @@ static void display_warning(struct monst *);
static int check_pos(int, int, int);
static int get_bk_glyph(xchar x, xchar y);
static int tether_glyph(int, int);
static void mimic_light_blocking(struct monst *);
#ifdef UNBUFFERED_GLYPHINFO
static glyph_info *glyphinfo_at(xchar, xchar, int);
#endif
@@ -1304,6 +1305,17 @@ see_monsters(void)
newsym(u.ux, u.uy);
}
static void
mimic_light_blocking(struct monst *mtmp)
{
if (mtmp->minvis && is_lightblocker_mappear(mtmp)) {
if (See_invisible)
block_point(mtmp->mx, mtmp->my);
else
unblock_point(mtmp->mx, mtmp->my);
}
}
/*
* Block/unblock light depending on what a mimic is mimicing and if it's
* invisible or not. Should be called only when the state of See_invisible
@@ -1312,18 +1324,7 @@ see_monsters(void)
void
set_mimic_blocking(void)
{
register struct monst *mon;
for (mon = fmon; mon; mon = mon->nmon) {
if (DEADMONSTER(mon))
continue;
if (mon->minvis && is_lightblocker_mappear(mon)) {
if (See_invisible)
block_point(mon->mx, mon->my);
else
unblock_point(mon->mx, mon->my);
}
}
iter_mons(mimic_light_blocking);
}
/*

View File

@@ -1839,14 +1839,8 @@ maybe_lvltport_feedback(void)
static void
final_level(void)
{
struct monst *mtmp;
/* reset monster hostility relative to player */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
reset_hostility(mtmp);
}
iter_mons(reset_hostility);
/* create some player-monsters */
create_mplayers(rn1(4, 3), TRUE);

View File

@@ -17,6 +17,8 @@ static void kick_monster(struct monst *, xchar, xchar);
static int kick_object(xchar, xchar, char *);
static int really_kick_object(xchar, xchar);
static char *kickstr(char *, const char *);
static boolean watchman_thief_arrest(struct monst *);
static boolean watchman_door_damage(struct monst *, xchar, xchar);
static void otransit_msg(struct obj *, boolean, boolean, long);
static void drop_to(coord *, schar, xchar, xchar);
@@ -768,6 +770,36 @@ kickstr(char *buf, const char *kickobjnam)
return strcat(strcpy(buf, "kicking "), what);
}
static boolean
watchman_thief_arrest(struct monst *mtmp)
{
if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
&& mtmp->mpeaceful) {
mon_yells(mtmp, "Halt, thief! You're under arrest!");
(void) angry_guards(FALSE);
return TRUE;
}
return FALSE;
}
static boolean
watchman_door_damage(struct monst *mtmp, xchar x, xchar y)
{
if (is_watch(mtmp->data) && mtmp->mpeaceful
&& couldsee(mtmp->mx, mtmp->my)) {
if (levl[x][y].looted & D_WARNED) {
mon_yells(mtmp,
"Halt, vandal! You're under arrest!");
(void) angry_guards(FALSE);
} else {
mon_yells(mtmp, "Hey, stop damaging that door!");
levl[x][y].looted |= D_WARNED;
}
return TRUE;
}
return FALSE;
}
/* the #kick command */
int
dokick(void)
@@ -1291,16 +1323,7 @@ dokick(void)
pay_for_damage("break", FALSE);
}
if (in_town(x, y))
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
&& mtmp->mpeaceful) {
mon_yells(mtmp, "Halt, thief! You're under arrest!");
(void) angry_guards(FALSE);
break;
}
}
(void) get_iter_mons(watchman_thief_arrest);
} else {
if (Blind)
feel_location(x, y); /* we know we hit it */
@@ -1310,22 +1333,7 @@ dokick(void)
hear; we've kept the extra 'm's and one of the extra '!'s */
pline("%s!!", (Deaf || !rn2(3)) ? "Thwack" : "Whammm");
if (in_town(x, y))
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (is_watch(mtmp->data) && mtmp->mpeaceful
&& couldsee(mtmp->mx, mtmp->my)) {
if (levl[x][y].looted & D_WARNED) {
mon_yells(mtmp,
"Halt, vandal! You're under arrest!");
(void) angry_guards(FALSE);
} else {
mon_yells(mtmp, "Hey, stop damaging that door!");
levl[x][y].looted |= D_WARNED;
}
break;
}
}
(void) get_iter_mons_xy(watchman_door_damage, x, y);
}
return ECMD_TIME;
}

View File

@@ -11,6 +11,7 @@ static void dowaterdemon(void);
static void dowaternymph(void);
static void gush(int, int, genericptr_t);
static void dofindgem(void);
static boolean watchman_warn_fountain(struct monst *);
DISABLE_WARNING_FORMAT_NONLITERAL
@@ -163,6 +164,28 @@ dofindgem(void)
exercise(A_WIS, TRUE); /* a discovery! */
}
static boolean
watchman_warn_fountain(struct monst *mtmp)
{
if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
&& mtmp->mpeaceful) {
if (!Deaf) {
pline("%s yells:", Amonnam(mtmp));
verbalize("Hey, stop using that fountain!");
} else {
pline("%s earnestly %s %s %s!",
Amonnam(mtmp),
nolimbs(mtmp->data) ? "shakes" : "waves",
mhis(mtmp),
nolimbs(mtmp->data)
? mbodypart(mtmp, HEAD)
: makeplural(mbodypart(mtmp, ARM)));
}
return TRUE;
}
return FALSE;
}
void
dryup(xchar x, xchar y, boolean isyou)
{
@@ -173,26 +196,7 @@ dryup(xchar x, xchar y, boolean isyou)
SET_FOUNTAIN_WARNED(x, y);
/* Warn about future fountain use. */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (is_watch(mtmp->data) && couldsee(mtmp->mx, mtmp->my)
&& mtmp->mpeaceful) {
if (!Deaf) {
pline("%s yells:", Amonnam(mtmp));
verbalize("Hey, stop using that fountain!");
} else {
pline("%s earnestly %s %s %s!",
Amonnam(mtmp),
nolimbs(mtmp->data) ? "shakes" : "waves",
mhis(mtmp),
nolimbs(mtmp->data)
? mbodypart(mtmp, HEAD)
: makeplural(mbodypart(mtmp, ARM)));
}
break;
}
}
mtmp = get_iter_mons(watchman_warn_fountain);
/* You can see or hear this effect */
if (!mtmp)
pline_The("flow reduces to a trickle.");

163
src/mon.c
View File

@@ -10,6 +10,7 @@
static void sanity_check_single_mon(struct monst *, boolean, const char *);
static struct obj *make_corpse(struct monst *, unsigned);
static int minliquid_core(struct monst *);
static void m_calcdistress(struct monst *);
static boolean monlineu(struct monst *, int, int);
static long mm_2way_aggression(struct monst *, struct monst *);
static long mm_aggression(struct monst *, struct monst *);
@@ -21,6 +22,7 @@ static void lifesaved_monster(struct monst *);
static void migrate_mon(struct monst *, xchar, xchar);
static boolean ok_to_obliterate(struct monst *);
static void deal_with_overcrowding(struct monst *);
static void m_restartcham(struct monst *);
static boolean restrap(struct monst *);
static int pick_animal(void);
static int pickvampshape(struct monst *);
@@ -28,6 +30,7 @@ static boolean isspecmon(struct monst *);
static boolean validspecmon(struct monst *, int);
static struct permonst *accept_newcham_form(struct monst *, int);
static void kill_eggs(struct obj *);
static void pacify_guard(struct monst *);
#define LEVEL_SPECIFIC_NOCORPSE(mdat) \
(Is_rogue_level(&u.uz) \
@@ -907,42 +910,41 @@ mcalcmove(
void
mcalcdistress(void)
{
struct monst *mtmp;
iter_mons(m_calcdistress);
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
/* must check non-moving monsters once/turn in case they managed
to end up in water or lava; note: when not in liquid they regen,
shape-shift, timeout temporary maladies just like other monsters */
if (mtmp->data->mmove == 0) {
if (g.vision_full_recalc)
vision_recalc(0);
if (minliquid(mtmp))
continue;
}
/* regenerate hit points */
mon_regen(mtmp, FALSE);
/* possibly polymorph shapechangers and lycanthropes */
if (mtmp->cham >= LOW_PM)
decide_to_shapeshift(mtmp, (canspotmon(mtmp)
|| engulfing_u(mtmp))
? SHIFT_MSG : 0);
were_change(mtmp);
/* gradually time out temporary problems */
if (mtmp->mblinded && !--mtmp->mblinded)
mtmp->mcansee = 1;
if (mtmp->mfrozen && !--mtmp->mfrozen)
mtmp->mcanmove = 1;
if (mtmp->mfleetim && !--mtmp->mfleetim)
mtmp->mflee = 0;
/* FIXME: mtmp->mlstmv ought to be updated here */
static void
m_calcdistress(struct monst *mtmp)
{
/* must check non-moving monsters once/turn in case they managed
to end up in water or lava; note: when not in liquid they regen,
shape-shift, timeout temporary maladies just like other monsters */
if (mtmp->data->mmove == 0) {
if (g.vision_full_recalc)
vision_recalc(0);
if (minliquid(mtmp))
return;
}
/* regenerate hit points */
mon_regen(mtmp, FALSE);
/* possibly polymorph shapechangers and lycanthropes */
if (mtmp->cham >= LOW_PM)
decide_to_shapeshift(mtmp, (canspotmon(mtmp)
|| engulfing_u(mtmp))
? SHIFT_MSG : 0);
were_change(mtmp);
/* gradually time out temporary problems */
if (mtmp->mblinded && !--mtmp->mblinded)
mtmp->mcansee = 1;
if (mtmp->mfrozen && !--mtmp->mfrozen)
mtmp->mcanmove = 1;
if (mtmp->mfleetim && !--mtmp->mfleetim)
mtmp->mflee = 0;
/* FIXME: mtmp->mlstmv ought to be updated here */
}
int
@@ -3801,18 +3803,72 @@ normal_shape(struct monst *mon)
}
}
/* iterate all living monsters on current level, calling func for each. */
void
iter_mons(void (*func)(struct monst *))
{
struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
func(mtmp);
}
}
/* iterate all living monsters on current level, calling func for each.
if func returns TRUE, stop and return that monster. */
struct monst *
get_iter_mons(boolean (*func)(struct monst *))
{
struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (func(mtmp))
return mtmp;
}
return (struct monst *) 0;
}
/* iterate all living monsters on current level, calling func for each,
passing x,y to the function.
if func returns TRUE, stop and return that monster. */
struct monst *
get_iter_mons_xy(boolean (*func)(struct monst *, xchar, xchar),
xchar x, xchar y)
{
struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (func(mtmp, x, y))
return mtmp;
}
return (struct monst *) 0;
}
/* force all chameleons and mimics to become themselves and werecreatures
to revert to human form; called when Protection_from_shape_changers gets
activated via wearing or eating ring */
void
rescham(void)
{
register struct monst *mtmp;
iter_mons(normal_shape);
}
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
normal_shape(mtmp);
static void
m_restartcham(struct monst *mtmp)
{
if (!mtmp->mcan)
mtmp->cham = pm_to_cham(monsndx(mtmp->data));
if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping) {
set_mimic_sym(mtmp);
newsym(mtmp->mx, mtmp->my);
}
}
@@ -3821,18 +3877,7 @@ rescham(void)
void
restartcham(void)
{
register struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (!mtmp->mcan)
mtmp->cham = pm_to_cham(monsndx(mtmp->data));
if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping) {
set_mimic_sym(mtmp);
newsym(mtmp->mx, mtmp->my);
}
}
iter_mons(m_restartcham);
}
/* called when restoring a monster from a saved level; protection
@@ -4812,17 +4857,17 @@ angry_guards(boolean silent)
return FALSE;
}
static void
pacify_guard(struct monst *mtmp)
{
if (is_watch(mtmp->data))
mtmp->mpeaceful = 1;
}
void
pacify_guards(void)
{
struct monst *mtmp;
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (is_watch(mtmp->data))
mtmp->mpeaceful = 1;
}
iter_mons(pacify_guard);
}
void

View File

@@ -4,6 +4,11 @@
#include "hack.h"
static boolean throne_mon_sound(struct monst *);
static boolean beehive_mon_sound(struct monst *);
static boolean morgue_mon_sound(struct monst *);
static boolean zoo_mon_sound(struct monst *);
static boolean temple_priest_sound(struct monst *);
static boolean mon_is_gecko(struct monst *);
static int domonnoise(struct monst *);
static int dochat(void);
@@ -20,7 +25,170 @@ mon_in_room(struct monst* mon, int rmtyp)
return FALSE;
}
DISABLE_WARNING_FORMAT_NONLITERAL
static boolean
throne_mon_sound(struct monst *mtmp)
{
if ((mtmp->msleeping || is_lord(mtmp->data)
|| is_prince(mtmp->data)) && !is_animal(mtmp->data)
&& mon_in_room(mtmp, COURT)) {
static const char *const throne_msg[4] = {
"the tones of courtly conversation.",
"a sceptre pounded in judgment.",
"Someone shouts \"Off with %s head!\"",
"Queen Beruthiel's cats!",
};
int which = rn2(3) + (Hallucination ? 1 : 0);
if (which != 2)
You_hear1(throne_msg[which]);
else {
DISABLE_WARNING_FORMAT_NONLITERAL
pline(throne_msg[2], uhis());
RESTORE_WARNING_FORMAT_NONLITERAL
}
return TRUE;
}
return FALSE;
}
static boolean
beehive_mon_sound(struct monst *mtmp)
{
if ((mtmp->data->mlet == S_ANT && is_flyer(mtmp->data))
&& mon_in_room(mtmp, BEEHIVE)) {
int hallu = Hallucination ? 1 : 0;
switch (rn2(2) + hallu) {
case 0:
You_hear("a low buzzing.");
break;
case 1:
You_hear("an angry drone.");
break;
case 2:
You_hear("bees in your %sbonnet!",
uarmh ? "" : "(nonexistent) ");
break;
}
return TRUE;
}
return FALSE;
}
static boolean
morgue_mon_sound(struct monst *mtmp)
{
if ((is_undead(mtmp->data) || is_vampshifter(mtmp))
&& mon_in_room(mtmp, MORGUE)) {
int hallu = Hallucination ? 1 : 0;
const char *hair = body_part(HAIR); /* hair/fur/scales */
switch (rn2(2) + hallu) {
case 0:
You("suddenly realize it is unnaturally quiet.");
break;
case 1:
pline_The("%s on the back of your %s %s up.", hair,
body_part(NECK), vtense(hair, "stand"));
break;
case 2:
pline_The("%s on your %s %s to stand up.", hair,
body_part(HEAD), vtense(hair, "seem"));
break;
}
return TRUE;
}
return FALSE;
}
static boolean
zoo_mon_sound(struct monst *mtmp)
{
if ((mtmp->msleeping || is_animal(mtmp->data))
&& mon_in_room(mtmp, ZOO)) {
int hallu = Hallucination ? 1 : 0;
static const char *const zoo_msg[3] = {
"a sound reminiscent of an elephant stepping on a peanut.",
"a sound reminiscent of a seal barking.", "Doctor Dolittle!",
};
You_hear1(zoo_msg[rn2(2) + hallu]);
return TRUE;
}
return FALSE;
}
static boolean
temple_priest_sound(struct monst *mtmp)
{
if (mtmp->ispriest && inhistemple(mtmp)
/* priest must be active */
&& !helpless(mtmp)
/* hero must be outside this temple */
&& temple_occupied(u.urooms) != EPRI(mtmp)->shroom) {
/* Generic temple messages; no attempt to match topic or tone
to the pantheon involved, let alone to the specific deity.
These are assumed to be coming from the attending priest;
asterisk means that the priest must be capable of speech;
pound sign (octathorpe,&c--don't go there) means that the
priest and the altar must not be directly visible (we don't
care if telepathy or extended detection reveals that the
priest is not currently standing on the altar; he's mobile). */
static const char *const temple_msg[] = {
"*someone praising %s.", "*someone beseeching %s.",
"#an animal carcass being offered in sacrifice.",
"*a strident plea for donations.",
};
const char *msg;
int hallu = Hallucination ? 1 : 0;
int trycount = 0,
ax = EPRI(mtmp)->shrpos.x,
ay = EPRI(mtmp)->shrpos.y;
boolean speechless = (mtmp->data->msound <= MS_ANIMAL),
in_sight = canseemon(mtmp) || cansee(ax, ay);
do {
msg = temple_msg[rn2(SIZE(temple_msg) - 1 + hallu)];
if (index(msg, '*') && speechless)
continue;
if (index(msg, '#') && in_sight)
continue;
break; /* msg is acceptable */
} while (++trycount < 50);
while (!letter(*msg))
++msg; /* skip control flags */
if (index(msg, '%')) {
DISABLE_WARNING_FORMAT_NONLITERAL
You_hear(msg, halu_gname(EPRI(mtmp)->shralign));
RESTORE_WARNING_FORMAT_NONLITERAL
} else
You_hear1(msg);
return TRUE;
}
return FALSE;
}
static boolean
oracle_sound(struct monst *mtmp)
{
if (mtmp->data != &mons[PM_ORACLE])
return FALSE;
/* and don't produce silly effects when she's clearly visible */
if (Hallucination || !canseemon(mtmp)) {
int hallu = Hallucination ? 1 : 0;
static const char *const ora_msg[5] = {
"a strange wind.", /* Jupiter at Dodona */
"convulsive ravings.", /* Apollo at Delphi */
"snoring snakes.", /* AEsculapius at Epidaurus */
"someone say \"No more woodchucks!\"",
"a loud ZOT!" /* both rec.humor.oracle */
};
You_hear1(ora_msg[rn2(3) + hallu * 2]);
}
return TRUE;
}
void
dosounds(void)
@@ -48,27 +216,8 @@ dosounds(void)
You_hear1(sink_msg[rn2(2) + hallu]);
}
if (g.level.flags.has_court && !rn2(200)) {
static const char *const throne_msg[4] = {
"the tones of courtly conversation.",
"a sceptre pounded in judgment.",
"Someone shouts \"Off with %s head!\"", "Queen Beruthiel's cats!",
};
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if ((mtmp->msleeping || is_lord(mtmp->data)
|| is_prince(mtmp->data)) && !is_animal(mtmp->data)
&& mon_in_room(mtmp, COURT)) {
/* finding one is enough, at least for now */
int which = rn2(3) + hallu;
if (which != 2)
You_hear1(throne_msg[which]);
else
pline(throne_msg[2], uhis());
return;
}
}
if (get_iter_mons(throne_mon_sound))
return;
}
if (g.level.flags.has_swamp && !rn2(200)) {
static const char *const swamp_msg[3] = {
@@ -115,51 +264,12 @@ dosounds(void)
return;
}
if (g.level.flags.has_beehive && !rn2(200)) {
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if ((mtmp->data->mlet == S_ANT && is_flyer(mtmp->data))
&& mon_in_room(mtmp, BEEHIVE)) {
switch (rn2(2) + hallu) {
case 0:
You_hear("a low buzzing.");
break;
case 1:
You_hear("an angry drone.");
break;
case 2:
You_hear("bees in your %sbonnet!",
uarmh ? "" : "(nonexistent) ");
break;
}
return;
}
}
if (get_iter_mons(beehive_mon_sound))
return;
}
if (g.level.flags.has_morgue && !rn2(200)) {
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if ((is_undead(mtmp->data) || is_vampshifter(mtmp))
&& mon_in_room(mtmp, MORGUE)) {
const char *hair = body_part(HAIR); /* hair/fur/scales */
switch (rn2(2) + hallu) {
case 0:
You("suddenly realize it is unnaturally quiet.");
break;
case 1:
pline_The("%s on the back of your %s %s up.", hair,
body_part(NECK), vtense(hair, "stand"));
break;
case 2:
pline_The("%s on your %s %s to stand up.", hair,
body_part(HEAD), vtense(hair, "seem"));
break;
}
return;
}
}
if (get_iter_mons(morgue_mon_sound))
return;
}
if (g.level.flags.has_barracks && !rn2(200)) {
static const char *const barracks_msg[4] = {
@@ -185,19 +295,8 @@ dosounds(void)
}
}
if (g.level.flags.has_zoo && !rn2(200)) {
static const char *const zoo_msg[3] = {
"a sound reminiscent of an elephant stepping on a peanut.",
"a sound reminiscent of a seal barking.", "Doctor Dolittle!",
};
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if ((mtmp->msleeping || is_animal(mtmp->data))
&& mon_in_room(mtmp, ZOO)) {
You_hear1(zoo_msg[rn2(2) + hallu]);
return;
}
}
if (get_iter_mons(zoo_mon_sound))
return;
}
if (g.level.flags.has_shop && !rn2(200)) {
if (!(sroom = search_special(ANY_SHOP))) {
@@ -217,78 +316,15 @@ dosounds(void)
}
if (g.level.flags.has_temple && !rn2(200)
&& !(Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) {
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (mtmp->ispriest && inhistemple(mtmp)
/* priest must be active */
&& !helpless(mtmp)
/* hero must be outside this temple */
&& temple_occupied(u.urooms) != EPRI(mtmp)->shroom)
break;
}
if (mtmp) {
/* Generic temple messages; no attempt to match topic or tone
to the pantheon involved, let alone to the specific deity.
These are assumed to be coming from the attending priest;
asterisk means that the priest must be capable of speech;
pound sign (octathorpe,&c--don't go there) means that the
priest and the altar must not be directly visible (we don't
care if telepathy or extended detection reveals that the
priest is not currently standing on the altar; he's mobile). */
static const char *const temple_msg[] = {
"*someone praising %s.", "*someone beseeching %s.",
"#an animal carcass being offered in sacrifice.",
"*a strident plea for donations.",
};
const char *msg;
int trycount = 0, ax = EPRI(mtmp)->shrpos.x,
ay = EPRI(mtmp)->shrpos.y;
boolean speechless = (mtmp->data->msound <= MS_ANIMAL),
in_sight = canseemon(mtmp) || cansee(ax, ay);
do {
msg = temple_msg[rn2(SIZE(temple_msg) - 1 + hallu)];
if (index(msg, '*') && speechless)
continue;
if (index(msg, '#') && in_sight)
continue;
break; /* msg is acceptable */
} while (++trycount < 50);
while (!letter(*msg))
++msg; /* skip control flags */
if (index(msg, '%'))
You_hear(msg, halu_gname(EPRI(mtmp)->shralign));
else
You_hear1(msg);
if (get_iter_mons(temple_priest_sound))
return;
}
}
if (Is_oracle_level(&u.uz) && !rn2(400)) {
/* make sure the Oracle is still here */
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
if (DEADMONSTER(mtmp))
continue;
if (mtmp->data == &mons[PM_ORACLE])
break;
}
/* and don't produce silly effects when she's clearly visible */
if (mtmp && (hallu || !canseemon(mtmp))) {
static const char *const ora_msg[5] = {
"a strange wind.", /* Jupiter at Dodona */
"convulsive ravings.", /* Apollo at Delphi */
"snoring snakes.", /* AEsculapius at Epidaurus */
"someone say \"No more woodchucks!\"",
"a loud ZOT!" /* both rec.humor.oracle */
};
You_hear1(ora_msg[rn2(3) + hallu * 2]);
}
return;
if (get_iter_mons(oracle_sound))
return;
}
}
RESTORE_WARNING_FORMAT_NONLITERAL
static const char *const h_sounds[] = {
"beep", "boing", "sing", "belche", "creak", "cough",
"rattle", "ululate", "pop", "jingle", "sniffle", "tinkle",

View File

@@ -12,18 +12,25 @@ static void vault_tele(void);
static boolean rloc_pos_ok(int, int, struct monst *);
static void rloc_to_core(struct monst *, int, int, unsigned);
static void mvault_tele(struct monst *);
static boolean m_blocks_teleporting(struct monst *);
/* does monster block others from teleporting? */
static boolean
m_blocks_teleporting(struct monst *mtmp)
{
if (is_dlord(mtmp->data) || is_dprince(mtmp->data))
return TRUE;
return FALSE;
}
/* teleporting is prevented on this level for this monster? */
boolean
noteleport_level(struct monst* mon)
{
struct monst *mtmp;
/* demon court in Gehennom prevent others from teleporting */
if (In_hell(&u.uz) && !(is_dlord(mon->data) || is_dprince(mon->data)))
for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
if (is_dlord(mtmp->data) || is_dprince(mtmp->data))
return TRUE;
if (get_iter_mons(m_blocks_teleporting))
return TRUE;
/* natural no-teleport level */
if (g.level.flags.noteleport)