diff --git a/src/sounds.c b/src/sounds.c new file mode 100644 index 000000000..f2ad4ad70 --- /dev/null +++ b/src/sounds.c @@ -0,0 +1,1001 @@ +/* SCCS Id: @(#)sounds.c 3.3 2001/02/14 */ +/* Copyright (c) 1989 Janet Walz, Mike Threepoint */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include "edog.h" +#ifdef USER_SOUNDS +#include +#endif + +#ifdef OVLB + +static int FDECL(domonnoise,(struct monst *)); +static int NDECL(dochat); + +#endif /* OVLB */ + +#ifdef OVL0 + +static int FDECL(mon_in_room, (struct monst *,int)); + +/* this easily could be a macro, but it might overtax dumb compilers */ +static int +mon_in_room(mon, rmtyp) +struct monst *mon; +int rmtyp; +{ + int rno = levl[mon->mx][mon->my].roomno; + + return rooms[rno - ROOMOFFSET].rtype == rmtyp; +} + +void +dosounds() +{ + register struct mkroom *sroom; + register int hallu, vx, vy; +#if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) + int xx; +#endif + struct monst *mtmp; + + if (!flags.soundok || u.uswallow || Underwater) return; + + hallu = Hallucination ? 1 : 0; + + if (level.flags.nfountains && !rn2(400)) { + static const char *fountain_msg[4] = { + "bubbling water.", + "water falling on coins.", + "the splashing of a naiad.", + "a soda fountain!", + }; + You_hear(fountain_msg[rn2(3)+hallu]); + } +#ifdef SINK + if (level.flags.nsinks && !rn2(300)) { + static const char *sink_msg[3] = { + "a slow drip.", + "a gurgling noise.", + "dishes being washed!", + }; + You_hear(sink_msg[rn2(2)+hallu]); + } +#endif + if (level.flags.has_court && !rn2(200)) { + static const char *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_hear(throne_msg[which]); + else pline(throne_msg[2], uhis()); + return; + } + } + } + if (level.flags.has_swamp && !rn2(200)) { + static const char *swamp_msg[3] = { + "hear mosquitoes!", + "smell marsh gas!", /* so it's a smell...*/ + "hear Donald Duck!", + }; + You(swamp_msg[rn2(2)+hallu]); + return; + } + if (level.flags.has_vault && !rn2(200)) { + if (!(sroom = search_special(VAULT))) { + /* strange ... */ + level.flags.has_vault = 0; + return; + } + if(gd_sound()) + switch (rn2(2)+hallu) { + case 1: { + boolean gold_in_vault = FALSE; + + for (vx = sroom->lx;vx <= sroom->hx; vx++) + for (vy = sroom->ly; vy <= sroom->hy; vy++) + if (g_at(vx, vy)) + gold_in_vault = TRUE; +#if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) + /* Bug in aztec assembler here. Workaround below */ + xx = ROOM_INDEX(sroom) + ROOMOFFSET; + xx = (xx != vault_occupied(u.urooms)); + if(xx) +#else + if (vault_occupied(u.urooms) != + (ROOM_INDEX(sroom) + ROOMOFFSET)) +#endif /* AZTEC_C_WORKAROUND */ + { + if (gold_in_vault) + You_hear(!hallu ? "someone counting money." : + "the quarterback calling the play."); + else + You_hear("someone searching."); + break; + } + /* fall into... (yes, even for hallucination) */ + } + case 0: + You_hear("the footsteps of a guard on patrol."); + break; + case 2: + You_hear("Ebenezer Scrooge!"); + break; + } + return; + } + if (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 (level.flags.has_morgue && !rn2(200)) { + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (is_undead(mtmp->data) && + mon_in_room(mtmp, MORGUE)) { + 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 stands up.", + body_part(HAIR), body_part(NECK)); + break; + case 2: + pline_The("%s on your %s seems to stand up.", + body_part(HAIR), body_part(HEAD)); + break; + } + return; + } + } + } + if (level.flags.has_barracks && !rn2(200)) { + static const char *barracks_msg[4] = { + "blades being honed.", + "loud snoring.", + "dice being thrown.", + "General MacArthur!", + }; + int count = 0; + + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if (is_mercenary(mtmp->data) && +#if 0 /* don't bother excluding these */ + !strstri(mtmp->data->mname, "watch") && + !strstri(mtmp->data->mname, "guard") && +#endif + mon_in_room(mtmp, BARRACKS) && + /* sleeping implies not-yet-disturbed (usually) */ + (mtmp->msleeping || ++count > 5)) { + You_hear(barracks_msg[rn2(3)+hallu]); + return; + } + } + } + if (level.flags.has_zoo && !rn2(200)) { + static const char *zoo_msg[3] = { + "a sound reminiscent of an elephant stepping on a peanut.", + "a sound reminiscent of a seal barking.", + "Doctor Doolittle!", + }; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) continue; + if ((mtmp->msleeping || is_animal(mtmp->data)) && + mon_in_room(mtmp, ZOO)) { + You_hear(zoo_msg[rn2(2)+hallu]); + return; + } + } + } + if (level.flags.has_shop && !rn2(200)) { + if (!(sroom = search_special(ANY_SHOP))) { + /* strange... */ + level.flags.has_shop = 0; + return; + } + if (tended_shop(sroom) && + !index(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) { + static const char *shop_msg[3] = { + "someone cursing shoplifters.", + "the chime of a cash register.", + "Neiman and Marcus arguing!", + }; + You_hear(shop_msg[rn2(2)+hallu]); + } + 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) && 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 *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_hear(ora_msg[rn2(3)+hallu*2]); + } + return; + } +} + +#endif /* OVL0 */ +#ifdef OVLB + +static const char *h_sounds[] = { + "beep", "boing", "sing", "belche", "creak", "cough", "rattle", + "ululate", "pop", "jingle", "sniffle", "tinkle", "eep" +}; + +const char * +growl_sound(mtmp) +register struct monst *mtmp; +{ + const char *ret; + + switch (mtmp->data->msound) { + case MS_MEW: + case MS_HISS: + ret = "hiss"; + break; + case MS_BARK: + case MS_GROWL: + ret = "growl"; + break; + case MS_ROAR: + ret = "roar"; + break; + case MS_BUZZ: + ret = "buzz"; + break; + case MS_SQEEK: + ret = "squeal"; + break; + case MS_SQAWK: + ret = "screech"; + break; + case MS_NEIGH: + ret = "neigh"; + break; + case MS_WAIL: + ret = "wail"; + break; + case MS_SILENT: + ret = "commotion"; + break; + default: + ret = "scream"; + } + return ret; +} + +/* the sounds of a seriously abused pet, including player attacking it */ +void +growl(mtmp) +register struct monst *mtmp; +{ + register const char *growl_verb = 0; + + if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) + return; + + /* presumably nearness and soundok checks have already been made */ + if (Hallucination) + growl_verb = h_sounds[rn2(SIZE(h_sounds))]; + else + growl_verb = growl_sound(mtmp); + if (growl_verb) { + pline("%s %s!", Monnam(mtmp), makeplural(growl_verb)); + if(flags.run) nomul(0); + wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); + } +} + +/* the sounds of mistreated pets */ +void +yelp(mtmp) +register struct monst *mtmp; +{ + register const char *yelp_verb = 0; + + if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) + return; + + /* presumably nearness and soundok checks have already been made */ + if (Hallucination) + yelp_verb = h_sounds[rn2(SIZE(h_sounds))]; + else switch (mtmp->data->msound) { + case MS_MEW: + yelp_verb = "yowl"; + break; + case MS_BARK: + case MS_GROWL: + yelp_verb = "yelp"; + break; + case MS_ROAR: + yelp_verb = "snarl"; + break; + case MS_SQEEK: + yelp_verb = "squeal"; + break; + case MS_SQAWK: + yelp_verb = "screak"; + break; + case MS_WAIL: + yelp_verb = "wail"; + break; + } + if (yelp_verb) { + pline("%s %ss!", Monnam(mtmp), yelp_verb); + if(flags.run) nomul(0); + wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12); + } +} + +/* the sounds of distressed pets */ +void +whimper(mtmp) +register struct monst *mtmp; +{ + register const char *whimper_verb = 0; + + if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) + return; + + /* presumably nearness and soundok checks have already been made */ + if (Hallucination) + whimper_verb = h_sounds[rn2(SIZE(h_sounds))]; + else switch (mtmp->data->msound) { + case MS_MEW: + case MS_GROWL: + whimper_verb = "whimper"; + break; + case MS_BARK: + whimper_verb = "whine"; + break; + case MS_SQEEK: + whimper_verb = "squeal"; + break; + } + if (whimper_verb) { + pline("%s %ss.", Monnam(mtmp), whimper_verb); + if(flags.run) nomul(0); + wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6); + } +} + +/* pet makes "I'm hungry" noises */ +void +beg(mtmp) +register struct monst *mtmp; +{ + if (mtmp->msleeping || !mtmp->mcanmove || + !(carnivorous(mtmp->data) || herbivorous(mtmp->data))) + return; + + /* presumably nearness and soundok checks have already been made */ + if (!is_silent(mtmp->data) && mtmp->data->msound <= MS_ANIMAL) + (void) domonnoise(mtmp); + else if (mtmp->data->msound >= MS_HUMANOID) { + if (!canspotmon(mtmp)) + map_invisible(mtmp->mx, mtmp->my); + verbalize("I'm hungry."); + } +} + +static int +domonnoise(mtmp) +register struct monst *mtmp; +{ + register const char *pline_msg = 0, /* Monnam(mtmp) will be prepended */ + *verbl_msg = 0; /* verbalize() */ + struct permonst *ptr = mtmp->data; + char verbuf[BUFSZ]; + + /* presumably nearness and sleep checks have already been made */ + if (!flags.soundok) return(0); + if (is_silent(ptr)) return(0); + + /* be sure to do this before talking; the monster might teleport away, in + * which case we want to check its pre-teleport position + */ + if (!canspotmon(mtmp)) + map_invisible(mtmp->mx, mtmp->my); + + switch (ptr->msound) { + case MS_ORACLE: + return doconsult(mtmp); + case MS_PRIEST: + priest_talk(mtmp); + break; + case MS_LEADER: + case MS_NEMESIS: + case MS_GUARDIAN: + quest_chat(mtmp); + break; + case MS_SELL: /* pitch, pay, total */ + shk_chat(mtmp); + break; + case MS_VAMPIRE: + { + /* vampire messages are varied by tameness, peacefulness, and time of night */ + boolean isnight = night(); + boolean kindred = (Upolyd && (u.umonnum == PM_VAMPIRE || + u.umonnum == PM_VAMPIRE_LORD)); + boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF || + u.umonnum == PM_WINTER_WOLF || + u.umonnum == PM_WINTER_WOLF_CUB)); + const char *racenoun = (flags.female && urace.individual.f) ? + urace.individual.f : (urace.individual.m) ? + urace.individual.m : urace.noun; + + if (mtmp->mtame) { + if (kindred) { + Sprintf(verbuf, "Good %s to you Master%s", + isnight ? "evening" : "day", + isnight ? "!" : ". Why do we not rest?"); + verbl_msg = verbuf; + } else { + Sprintf(verbuf,"%s%s", + nightchild ? "Child of the night, " : "", + midnight() ? + "I can stand this craving no longer!" : + isnight ? + "I beg you, help me satisfy this growing craving!" : + "I find myself growing a little weary."); + verbl_msg = verbuf; + } + } else if (mtmp->mpeaceful) { + if (kindred && isnight) { + Sprintf(verbuf, "Good feeding %s!", + flags.female ? "sister" : "brother"); + verbl_msg = verbuf; + } else if (nightchild && isnight) { + Sprintf(verbuf, + "How nice to hear you, child of the night!"); + verbl_msg = verbuf; + } else + verbl_msg = "I only drink... potions."; + } else { + int vampindex; + static const char *vampmsg[] = { + /* These first two (0 and 1) are specially handled below */ + "I vant to suck your %s!", + "I vill come after %s without regret!", + /* other famous vampire quotes can follow here if desired */ + }; + if (kindred) + verbl_msg = "This is my hunting ground that you dare to prowl!"; + else if (youmonst.data == &mons[PM_SILVER_DRAGON] || + youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) { + /* Silver dragons are silver in color, not made of silver */ + Sprintf(verbuf, "%s! Your silver sheen does not frighten me!", + youmonst.data == &mons[PM_SILVER_DRAGON] ? + "Fool" : "Young Fool"); + verbl_msg = verbuf; + } else { + vampindex = rn2(SIZE(vampmsg)); + if (vampindex == 0) { + Sprintf(verbuf, vampmsg[vampindex], body_part(BLOOD)); + verbl_msg = verbuf; + } else if (vampindex == 1) { + Sprintf(verbuf, vampmsg[vampindex], + Upolyd ? an(mons[u.umonnum].mname) : an(racenoun)); + verbl_msg = verbuf; + } else + verbl_msg = vampmsg[vampindex]; + } + } + } + break; + case MS_WERE: + if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) { + pline("%s throws back %s head and lets out a blood curdling %s!", + Monnam(mtmp), mhis(mtmp), + ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl"); + wake_nearto(mtmp->mx, mtmp->my, 11*11); + } else + pline_msg = + "whispers inaudibly. All you can make out is \"moon\"."; + break; + case MS_BARK: + if (flags.moonphase == FULL_MOON && night()) { + pline_msg = "howls."; + } else if (mtmp->mpeaceful) { + if (mtmp->mtame && + (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || + moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) + pline_msg = "whines."; + else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000) + pline_msg = "yips."; + else { + if (mtmp->data != &mons[PM_DINGO]) /* dingos do not actually bark */ + pline_msg = "barks."; + } + } else { + pline_msg = "growls."; + } + break; + case MS_MEW: + if (mtmp->mtame) { + if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || + mtmp->mtame < 5) + pline_msg = "yowls."; + else if (moves > EDOG(mtmp)->hungrytime) + pline_msg = "miaos."; + else if (EDOG(mtmp)->hungrytime > moves + 1000) + pline_msg = "purrs."; + else + pline_msg = "mews."; + break; + } /* else FALLTHRU */ + case MS_GROWL: + pline_msg = mtmp->mpeaceful ? "snarls." : "growls!"; + break; + case MS_ROAR: + pline_msg = mtmp->mpeaceful ? "snarls." : "roars!"; + break; + case MS_SQEEK: + pline_msg = "squeaks."; + break; + case MS_SQAWK: + if (mtmp->data == &mons[PM_RAVEN] && !mtmp->mpeaceful) + verbl_msg = "Nevermore!"; + else + pline_msg = "squawks."; + break; + case MS_HISS: + if (!mtmp->mpeaceful) + pline_msg = "hisses!"; + else return 0; /* no sound */ + break; + case MS_BUZZ: + pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily."; + break; + case MS_GRUNT: + pline_msg = "grunts."; + break; + case MS_NEIGH: + if (mtmp->mtame < 5) + pline_msg = "neighs."; + else if (moves > EDOG(mtmp)->hungrytime) + pline_msg = "whinnies."; + else + pline_msg = "whickers."; + break; + case MS_WAIL: + pline_msg = "wails mournfully."; + break; + case MS_GURGLE: + pline_msg = "gurgles."; + break; + case MS_BURBLE: + pline_msg = "burbles."; + break; + case MS_SHRIEK: + pline_msg = "shrieks."; + aggravate(); + break; + case MS_IMITATE: + pline_msg = "imitates you."; + break; + case MS_BONES: + pline("%s rattles noisily.", Monnam(mtmp)); + You("freeze for a moment."); + nomul(-2); + break; + case MS_LAUGH: + { + static const char *laugh_msg[4] = { + "giggles.", "chuckles.", "snickers.", "laughs.", + }; + pline_msg = laugh_msg[rn2(4)]; + } + break; + case MS_MUMBLE: + pline_msg = "mumbles incomprehensibly."; + break; + case MS_DJINNI: + if (mtmp->mtame) { + verbl_msg = "Sorry, I'm all out of wishes."; + } else if (mtmp->mpeaceful) { + if (ptr == &mons[PM_WATER_DEMON]) + pline_msg = "gurgles."; + else + verbl_msg = "I'm free!"; + } else verbl_msg = "This will teach you not to disturb me!"; + break; + case MS_BOAST: /* giants */ + if (!mtmp->mpeaceful) { + switch (rn2(4)) { + case 0: pline("%s boasts about %s gem collection.", + Monnam(mtmp), mhis(mtmp)); + break; + case 1: pline_msg = "complains about a diet of mutton."; + break; + default: pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws."; + wake_nearto(mtmp->mx, mtmp->my, 7*7); + break; + } + break; + } + /* else FALLTHRU */ + case MS_HUMANOID: + if (!mtmp->mpeaceful) { + if (In_endgame(&u.uz) && is_mplayer(ptr)) { + mplayer_talk(mtmp); + break; + } else return 0; /* no sound */ + } + /* Generic peaceful humanoid behaviour. */ + if (mtmp->mflee) + pline_msg = "wants nothing to do with you."; + else if (mtmp->mhp < mtmp->mhpmax/4) + pline_msg = "moans."; + else if (mtmp->mconf || mtmp->mstun) + verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?"; + else if (!mtmp->mcansee) + verbl_msg = "I can't see!"; + else if (mtmp->mtrapped) { + struct trap *t = t_at(mtmp->mx, mtmp->my); + + if (t) t->tseen = 1; + verbl_msg = "I'm trapped!"; + } else if (mtmp->mhp < mtmp->mhpmax/2) + pline_msg = "asks for a potion of healing."; + else if (mtmp->mtame && !mtmp->isminion && + moves > EDOG(mtmp)->hungrytime) + verbl_msg = "I'm hungry."; + /* Specific monsters' interests */ + else if (is_elf(ptr)) + pline_msg = "curses orcs."; + else if (is_dwarf(ptr)) + pline_msg = "talks about mining."; + else if (likes_magic(ptr)) + pline_msg = "talks about spellcraft."; + else if (ptr->mlet == S_CENTAUR) + pline_msg = "discusses hunting."; + else switch (monsndx(ptr)) { + case PM_HOBBIT: + pline_msg = (mtmp->mhpmax - mtmp->mhp >= 10) ? + "complains about unpleasant dungeon conditions." + : "asks you about the One Ring."; + break; + case PM_ARCHEOLOGIST: + pline_msg = "describes a recent article in \"Spelunker Today\" magazine."; + break; +#ifdef TOURIST + case PM_TOURIST: + verbl_msg = "Aloha."; + break; +#endif + default: + pline_msg = "discusses dungeon exploration."; + break; + } + break; + case MS_SEDUCE: +#ifdef SEDUCE + if (ptr->mlet != S_NYMPH && + could_seduce(mtmp, &youmonst, (struct attack *)0) == 1) { + (void) doseduce(mtmp); + break; + } + switch ((poly_gender() != (int) mtmp->female) ? rn2(3) : 0) +#else + switch ((poly_gender() == 0) ? rn2(3) : 0) +#endif + { + case 2: + verbl_msg = "Hello, sailor."; + break; + case 1: + pline_msg = "comes on to you."; + break; + default: + pline_msg = "cajoles you."; + } + break; +#ifdef KOPS + case MS_ARREST: + if (mtmp->mpeaceful) + verbalize("Just the facts, %s.", + flags.female ? "Ma'am" : "Sir"); + else { + static const char *arrest_msg[3] = { + "Anything you say can be used against you.", + "You're under arrest!", + "Stop in the name of the Law!", + }; + verbl_msg = arrest_msg[rn2(3)]; + } + break; +#endif + case MS_BRIBE: + if (mtmp->mpeaceful && !mtmp->mtame) { + (void) demon_talk(mtmp); + break; + } + /* fall through */ + case MS_CUSS: + if (!mtmp->mpeaceful) + cuss(mtmp); + break; + case MS_SPELL: + /* deliberately vague, since it's not actually casting any spell */ + pline_msg = "seems to mutter a cantrip."; + break; + case MS_NURSE: + if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) + verbl_msg = "Put that weapon away before you hurt someone!"; + else if (uarmc || uarm || uarmh || uarms || uarmg || uarmf) + verbl_msg = Role_if(PM_HEALER) ? + "Doc, I can't help you unless you cooperate." : + "Please undress so I can examine you."; +#ifdef TOURIST + else if (uarmu) + verbl_msg = "Take off your shirt, please."; +#endif + else verbl_msg = "Relax, this won't hurt a bit."; + break; + case MS_GUARD: +#ifndef GOLDOBJ + if (u.ugold) +#else + if (money_cnt(invent)) +#endif + verbl_msg = "Please drop that gold and follow me."; + else + verbl_msg = "Please follow me."; + break; + case MS_SOLDIER: + { + static const char *soldier_foe_msg[3] = { + "Resistance is useless!", + "You're dog meat!", + "Surrender!", + }, *soldier_pax_msg[3] = { + "What lousy pay we're getting here!", + "The food's not fit for Orcs!", + "My feet hurt, I've been on them all day!", + }; + verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)] + : soldier_foe_msg[rn2(3)]; + } + break; + case MS_RIDER: + if (ptr == &mons[PM_DEATH] && !rn2(10)) + pline_msg = "is busy reading a copy of Sandman #8."; + else verbl_msg = "Who do you think you are, War?"; + break; + } + + if (pline_msg) pline("%s %s", Monnam(mtmp), pline_msg); + else if (verbl_msg) verbalize(verbl_msg); + return(1); +} + + +int +dotalk() +{ + int result; + boolean save_soundok = flags.soundok; + flags.soundok = 1; /* always allow sounds while chatting */ + result = dochat(); + flags.soundok = save_soundok; + return result; +} + +static int +dochat() +{ + register struct monst *mtmp; + register int tx,ty; + struct obj *otmp; + + if (is_silent(youmonst.data)) { + pline("As %s, you cannot speak.", an(youmonst.data->mname)); + return(0); + } + if (Strangled) { + You_cant("speak. You're choking!"); + return(0); + } + if (u.uswallow) { + pline("They won't hear you out there."); + return(0); + } + if (Underwater) { + Your("speech is unintelligible underwater."); + return(0); + } + + if (!Blind && (otmp = shop_object(u.ux, u.uy)) != (struct obj *)0) { + /* standing on something in a shop and chatting causes the shopkeeper + to describe the price(s). This can inhibit other chatting inside + a shop, but that shouldn't matter much. shop_object() returns an + object iff inside a shop and the shopkeeper is present and willing + (not angry) and able (not asleep) to speak and the position contains + any objects other than just gold. + */ + price_quote(otmp); + return(1); + } + + (void) getdir("Talk to whom? (in what direction)"); + +#ifdef STEED + if (u.usteed && u.dz > 0) + return (domonnoise(u.usteed)); +#endif + if (u.dz) { + pline("They won't hear you %s there.", u.dz < 0 ? "up" : "down"); + return(0); + } + + if (u.dx == 0 && u.dy == 0) { +/* + * Let's not include this. It raises all sorts of questions: can you wear + * 2 helmets, 2 amulets, 3 pairs of gloves or 6 rings as a marilith, + * etc... --KAA + if (u.umonnum == PM_ETTIN) { + You("discover that your other head makes boring conversation."); + return(1); + } +*/ + pline("Talking to yourself is a bad habit for a dungeoneer."); + return(0); + } + + tx = u.ux+u.dx; ty = u.uy+u.dy; + mtmp = m_at(tx, ty); + + if (!mtmp || mtmp->mundetected || + mtmp->m_ap_type == M_AP_FURNITURE || + mtmp->m_ap_type == M_AP_OBJECT) + return(0); + + /* sleeping monsters won't talk, except priests (who wake up) */ + if ((!mtmp->mcanmove || mtmp->msleeping) && !mtmp->ispriest) { + /* If it is unseen, the player can't tell the difference between + not noticing him and just not existing, so skip the message. */ + if (canspotmon(mtmp)) + pline("%s seems not to notice you.", Monnam(mtmp)); + return(0); + } + + if (mtmp->mtame && mtmp->meating) { + if (!canspotmon(mtmp)) + map_invisible(mtmp->mx, mtmp->my); + pline("%s is eating noisily.", Monnam(mtmp)); + return (0); + } + + return domonnoise(mtmp); +} + +#ifdef USER_SOUNDS + +extern void FDECL(play_usersound, (const char*, int)); + +typedef struct audio_mapping_rec { + struct re_pattern_buffer regex; + char* filename; + int volume; + struct audio_mapping_rec* next; +} audio_mapping; + +static audio_mapping* soundmap=0; + +char* sounddir="."; + +int +add_sound_mapping(mapping) +const char* mapping; +{ + char text[256]; + char filename[256]; + char filespec[256]; + int volume; + + if (sscanf(mapping, "MESG \"%[^\"]\"%*[\t ]\"%[^\"]\" %d", + text, filename, &volume)==3) + { + const char* err; + audio_mapping* new_map; + + sprintf(filespec,"%s/%s",sounddir,filename); + + if (access(filespec, R_OK)==0) { + new_map=(audio_mapping*)alloc(sizeof(audio_mapping)); + new_map->regex.translate=0; + new_map->regex.fastmap=0; + new_map->regex.buffer=0; + new_map->regex.allocated=0; + new_map->regex.regs_allocated=REGS_FIXED; + new_map->filename=strdup(filespec); + new_map->volume=volume; + new_map->next=soundmap; + + err=re_compile_pattern(text, strlen(text), &new_map->regex); + + if (err) { + sprintf(text, "%s\n", err); + raw_print(text); + free(new_map->filename); + free(new_map); + return 0; + } else { + soundmap=new_map; + } + } else { + sprintf(text, "%s not readable.\n", filespec); + raw_print(text); + return 0; + } + } else { + sprintf(text, "syntax error in SOUND\n"); + raw_print(text); + return 0; + } + + return 1; +} + +void +play_sound_for_message(msg) +const char* msg; +{ + audio_mapping* cursor=soundmap; + + while (cursor) { + if (re_search(&cursor->regex, msg, strlen(msg), 0, 9999, 0)>=0) { + play_usersound(cursor->filename, cursor->volume); + } + cursor=cursor->next; + } +} + +#endif /* USER_SOUNDS */ + +#endif /* OVLB */ + +/*sounds.c*/