diff --git a/include/extern.h b/include/extern.h index 337d41e61..534f2a3ed 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1537,7 +1537,10 @@ extern void wakeup(struct monst *, boolean); extern void wake_nearby(void); extern void wake_nearto(int, int, int); extern void seemimic(struct monst *); -extern void normal_shape(struct monst *mon); +extern void normal_shape(struct monst *); +extern void iter_mons(void (*)(struct monst *)); +extern struct monst *get_iter_mons(boolean (*)(struct monst *)); +extern struct monst *get_iter_mons_xy(boolean (*)(struct monst *, xchar, xchar), xchar, xchar); extern void rescham(void); extern void restartcham(void); extern void restore_cham(struct monst *); diff --git a/src/apply.c b/src/apply.c index 2d025381e..e52c10133 100644 --- a/src/apply.c +++ b/src/apply.c @@ -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; diff --git a/src/bones.c b/src/bones.c index 5d11ffd15..b56be0303 100644 --- a/src/bones.c +++ b/src/bones.c @@ -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 */ diff --git a/src/display.c b/src/display.c index d09b47fba..5463de710 100644 --- a/src/display.c +++ b/src/display.c @@ -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); } /* diff --git a/src/do.c b/src/do.c index 079b163d5..d371dc26f 100644 --- a/src/do.c +++ b/src/do.c @@ -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); diff --git a/src/dokick.c b/src/dokick.c index c546b1bc1..32f3b2c5c 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -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; } diff --git a/src/fountain.c b/src/fountain.c index 7f315e972..46a0b8eb1 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -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."); diff --git a/src/mon.c b/src/mon.c index 93ec686e0..c7ea09be5 100644 --- a/src/mon.c +++ b/src/mon.c @@ -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 diff --git a/src/sounds.c b/src/sounds.c index 786d36f29..be921f91d 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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", diff --git a/src/teleport.c b/src/teleport.c index 2d3ffbc5e..82d49e425 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -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)