From 4a01c8fbd76e78e8a135f7e8e95ac5138b2bc3ed Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 24 Apr 2022 13:03:43 +0300 Subject: [PATCH] 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. --- include/extern.h | 5 +- src/apply.c | 52 ++++---- src/bones.c | 29 +++-- src/display.c | 25 ++-- src/do.c | 8 +- src/dokick.c | 60 +++++---- src/fountain.c | 44 ++++--- src/mon.c | 157 +++++++++++++++-------- src/sounds.c | 324 ++++++++++++++++++++++++++--------------------- src/teleport.c | 17 ++- 10 files changed, 415 insertions(+), 306 deletions(-) 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; } -boolean -next_to_u(void) +static boolean +mleashed_next2u(struct monst *mtmp) { - register struct monst *mtmp; - register struct obj *otmp; - - 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"); - } + 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) +{ + if (get_iter_mons(mleashed_next2u)) + return FALSE; + /* 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; - - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (DEADMONSTER(mtmp)) - continue; + iter_mons(m_calcdistress); +} - /* 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; - } +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); + /* 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); + /* 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; + /* 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 */ - } + /* FIXME: mtmp->mlstmv ought to be updated here */ } int @@ -3801,38 +3803,81 @@ normal_shape(struct monst *mon) } } -/* 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 */ +/* iterate all living monsters on current level, calling func for each. */ void -rescham(void) +iter_mons(void (*func)(struct monst *)) { - register struct monst *mtmp; + struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - normal_shape(mtmp); + func(mtmp); } } -/* let chameleons change and mimics hide again; called when taking off - ring of protection from shape changers */ -void -restartcham(void) + +/* 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 *)) { - register struct monst *mtmp; + 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); - } + 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) +{ + iter_mons(normal_shape); +} + +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); + } +} + +/* let chameleons change and mimics hide again; called when taking off + ring of protection from shape changers */ +void +restartcham(void) +{ + 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) -- 2.50.1