/* the sounds of distressed pets */ void whimper(struct monst *mtmp) { const char *whimper_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound || !canhear()) return; /* presumably nearness 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 %s.", Monnam(mtmp), vtense(NULL, whimper_verb)); action_interrupted(); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6); } }
/* * Close the drawbridge located at x,y */ void close_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; loc1 = &level->locations[x][y]; if (loc1->typ != DRAWBRIDGE_DOWN) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); if (cansee(x, y) || cansee(x2, y2)) pline("You see a drawbridge %s up!", (((u.ux == x || u.uy == y) && !Underwater) || distu(x2, y2) < distu(x, y)) ? "coming" : "going"); else if (canhear()) pline("You hear chains rattling and gears turning."); loc1->typ = DRAWBRIDGE_UP; loc2 = &level->locations[x2][y2]; loc2->typ = DBWALL; switch (loc1->drawbridgemask & DB_DIR) { case DB_NORTH: case DB_SOUTH: loc2->horizontal = TRUE; break; case DB_WEST: case DB_EAST: loc2->horizontal = FALSE; break; } loc2->wall_info = W_NONDIGGABLE; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* Do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */ do_entity(&(occupants[1])); if (OBJ_AT(x, y)) You_hear("smashing and crushing."); revive_nasty(x, y, NULL); revive_nasty(x2, y2, NULL); delallobj(x, y); delallobj(x2, y2); if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); del_engr_at(level, x, y); del_engr_at(level, x2, y2); newsym(x, y); newsym(x2, y2); block_point(x2, y2); /* vision */ }
/*VARARGS1*/ void verbalize(const char *line, ...) { va_list the_args; if (!canhear()) return; va_start(the_args, line); vpline(FALSE, FALSE, msgcat_many("\"", line, "\"", NULL), the_args); va_end(the_args); }
/*VARARGS1*/ void You_hear(const char *line, ...) { /* You can't hear while unconscious. */ if (!canhear()) return; va_list the_args; va_start(the_args, line); vpline(FALSE, FALSE, msgcat_many("You ", Underwater ? "barely " : "", "hear ", line, NULL), the_args); va_end(the_args); }
int breamq(struct monst *mtmp, int xdef, int ydef, const struct attack *mattk) { /* if new breath types are added, change AD_ACID to max type */ int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp; boolean youdef = u.ux == xdef && u.uy == ydef; if (!youdef && distmin(mtmp->mx, mtmp->my, xdef, ydef) < 3) return 0; boolean linedup = qlined_up(mtmp, xdef, ydef, TRUE, FALSE); if (linedup) { if (mtmp->mcan) { if (canhear()) { if (mon_visible(mtmp)) pline("%s coughs.", Monnam(mtmp)); else You_hear("a cough."); } return 0; } if (!mtmp->mspec_used && rn2(3)) { if ((typ >= AD_MAGM) && (typ <= AD_ACID)) { if (mon_visible(mtmp)) { pline("%s breathes %s!", Monnam(mtmp), breathwep[typ - 1]); action_interrupted(); } buzz((int)(-20 - (typ - 1)), (int)mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), 0); /* breath runs out sometimes. Also, give monster some cunning; don't breath if the target fell asleep. */ if (!rn2(3)) mtmp->mspec_used = 10 + rn2(20); boolean sleeping = youdef ? u_helpless(hm_asleep) : MON_AT(level, xdef, ydef) ? m_at(level, xdef, ydef)->msleeping : FALSE; if (typ == AD_SLEE && sleeping) mtmp->mspec_used += rnd(20); } else impossible("Breath weapon %d used", typ - 1); } } return 1; }
/* the sounds of a seriously abused pet, including player attacking it */ void growl(struct monst *mtmp) { const char *growl_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound || !canhear()) return; /* presumably nearness 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), vtense(NULL, growl_verb)); action_interrupted(); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); } }
/* * Open the drawbridge located at x,y */ void open_drawbridge(int x, int y) { struct rm *loc1, *loc2; struct trap *t; int x2, y2; loc1 = &level->locations[x][y]; if (loc1->typ != DRAWBRIDGE_UP) return; x2 = x; y2 = y; get_wall_for_db(&x2, &y2); if (cansee(x, y) || cansee(x2, y2)) pline("You see a drawbridge %s down!", (distu(x2, y2) < distu(x, y)) ? "going" : "coming"); else if (canhear()) pline("You hear chains rattling and gears turning."); loc1->typ = DRAWBRIDGE_DOWN; loc2 = &level->locations[x2][y2]; loc2->typ = DOOR; loc2->doormask = D_NODOOR; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */ do_entity(&(occupants[1])); revive_nasty(x, y, NULL); delallobj(x, y); if ((t = t_at(level, x, y)) != 0) deltrap(level, t); if ((t = t_at(level, x2, y2)) != 0) deltrap(level, t); del_engr_at(level, x, y); del_engr_at(level, x2, y2); newsym(x, y); newsym(x2, y2); unblock_point(x2, y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; }
int spitmq(struct monst *mtmp, int xdef, int ydef, const struct attack *mattk) { struct obj *otmp; if (mtmp->mcan) { if (canhear()) pline("A dry rattle comes from %s throat.", s_suffix(mon_nam(mtmp))); return 0; } boolean linedup = qlined_up(mtmp, xdef, ydef, FALSE, FALSE); if (linedup && ai_use_at_range( BOLT_LIM - distmin(mtmp->mx, mtmp->my, xdef, ydef))) { switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mktemp_sobj(level, BLINDING_VENOM); break; case AD_DRLI: otmp = mktemp_sobj(level, VAMPIRE_BLOOD); break; default: impossible("bad attack type in spitm"); /* fall through */ case AD_ACID: otmp = mktemp_sobj(level, ACID_VENOM); break; } if (mon_visible(mtmp)) { pline("%s spits venom!", Monnam(mtmp)); action_interrupted(); } m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), distmin(mtmp->mx, mtmp->my, xdef, ydef), otmp, FALSE); return 1; } return 0; }
/* the sounds of mistreated pets */ void yelp(struct monst *mtmp) { const char *yelp_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound || !canhear()) return; /* presumably nearness 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 %s!", Monnam(mtmp), vtense(NULL, yelp_verb)); action_interrupted(); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12); } }
static int domonnoise(struct monst *mtmp) { const char *pline_msg = 0, /* Monnam(mtmp) will be prepended */ *verbl_msg = 0; /* verbalize() */ const struct permonst *ptr = mtmp->data; /* presumably nearness checks have already been made */ if (!canhear()) return 0; if (is_silent(ptr)) return 0; /* Make sure its your role's quest quardian; adjust if not */ if (ptr->msound == MS_GUARDIAN && ptr != &pm_guardian) { int mndx = monsndx(ptr); ptr = &mons[genus(mndx, 1)]; } /* 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 = (u.ufemale && urace.individual.f) ? urace. individual.f : (urace.individual.m) ? urace.individual. m : urace.noun; if (mtmp->mtame) { if (kindred) verbl_msg = msgprintf("Good %s to you Master%s", isnight ? "evening" : "day", isnight ? "!" : ". Why do we not rest?"); else verbl_msg = msgcat( 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."); } else if (mtmp->mpeaceful) { if (kindred && isnight) verbl_msg = msgprintf("Good feeding %s!", u.ufemale ? "sister" : "brother"); else if (nightchild && isnight) verbl_msg = "How nice to hear you, child of the night!"; else verbl_msg = "I only drink... potions."; } else { int vampindex; static const char *const 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 */ verbl_msg = msgprintf( "%s! Your silver sheen does not frighten me!", youmonst.data == &mons[PM_SILVER_DRAGON] ? "Fool" : "Young Fool"); } else { vampindex = rn2(SIZE(vampmsg)); if (vampindex == 0) { verbl_msg = msgprintf( vampmsg[vampindex], body_part(BLOOD)); } else if (vampindex == 1) { verbl_msg = msgprintf( vampmsg[vampindex], Upolyd ? an(mons[u.umonnum].mname) : an(racenoun)); } 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_FOX]) pline_msg = whatthefoxsays(); else if (mtmp->data != &mons[PM_DINGO]) /* dingos do not actually bark */ pline_msg = "barks."; } } else { if (mtmp->data == &mons[PM_FOX]) pline_msg = whatthefoxsays(); 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 = "meows."; 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 (ptr == &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)); pline("You freeze for a moment."); helpless(2, hr_afraid, "scared by rattling", NULL); break; case MS_LAUGH: { static const char *const laugh_msg[4] = { "giggles.", "chuckles.", "snickers.", "laughs.", }; pline_msg = laugh_msg[rn2(4)]; } break; case MS_MUMBLE: pline_msg = "mumbles incomprehensibly."; break; case MS_WISHGIVER: 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(level, 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; case PM_TOURIST: verbl_msg = "Aloha."; break; case PM_PRISONER: verbl_msg = "Thank you for freeing me!"; break; default: pline_msg = "discusses dungeon exploration."; break; } break; case MS_SEDUCE: if (ptr->mlet != S_NYMPH && flags.seduce_enabled && could_seduce(mtmp, &youmonst, NULL) == 1) { doseduce(mtmp); break; } switch ((poly_gender() != (int)mtmp->female) ? rn2(3) : 0) { case 2: verbl_msg = "Hello, sailor."; break; case 1: pline_msg = "comes on to you."; break; default: pline_msg = "cajoles you."; } break; case MS_ARREST: if (mtmp->mpeaceful) verbalize("Just the facts, %s.", u.ufemale ? "Ma'am" : "Sir"); else { static const char *const 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; case MS_BRIBE: if (mtmp->mpeaceful && !mtmp->mtame) { 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 && !uskin()) || 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."; else if (uarmu) verbl_msg = "Take off your shirt, please."; else verbl_msg = "Relax, this won't hurt a bit."; break; case MS_GUARD: if (money_cnt(invent)) verbl_msg = "Please drop that gold and follow me."; else verbl_msg = "Please follow me."; break; case MS_SOLDIER: { static const char *const soldier_foe_msg[3] = { "Resistance is useless!", "You're dog meat!", "Surrender!", }, *const 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("%s", verbl_msg); return 1; }
void dosounds(void) { struct mkroom *sroom; int hallu, vx, vy; struct monst *mtmp; if (!canhear() || Engulfed || Underwater) return; hallu = Hallucination ? 1 : 0; if (has_terrain(level, FOUNTAIN) && !rn2(400)) { static const char *const fountain_msg[4] = { "bubbling water.", "water falling on coins.", "the splashing of a naiad.", "a soda fountain!", }; You_hear("%s", fountain_msg[rn2(3) + hallu]); } if (has_terrain(level, SINK) && !rn2(300)) { static const char *const sink_msg[3] = { "a slow drip.", "a gurgling noise.", "dishes being washed!", }; You_hear("%s", sink_msg[rn2(2) + hallu]); } if (search_special(level, 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 = level->monlist; 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("%s", throne_msg[which]); else pline(throne_msg[2], uhis()); return; } } } if (search_special(level, SWAMP) && !rn2(200)) { static const char *const swamp_msg[3] = { "You hear mosquitoes!", "You smell marsh gas!", /* so it's a smell... */ "You hear Donald Duck!", }; pline("%s", swamp_msg[rn2(2) + hallu]); return; } if ((sroom = search_special(level, VAULT)) && !rn2(200)) { 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 (gold_at(level, vx, vy)) gold_in_vault = TRUE; if (vault_occupied(u.urooms) != (ROOM_INDEX(sroom) + ROOMOFFSET)) { 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 (search_special(level, BEEHIVE) && !rn2(200)) { for (mtmp = level->monlist; 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 (search_special(level, MORGUE) && !rn2(200)) { for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_undead(mtmp->data) && mon_in_room(mtmp, MORGUE)) { switch (rn2(2) + hallu) { case 1: if (!strcmp(body_part(HAIR), "hair")) { pline("The %s on the back of your %s stands up.", body_part(HAIR), body_part(NECK)); break; } /* fall through */ case 2: if (!strcmp(body_part(HAIR), "hair")) { pline("The %s on your %s seems to stand up.", body_part(HAIR), body_part(HEAD)); break; } /* fall through */ case 0: pline("You suddenly realize it is unnaturally quiet."); break; } return; } } } if (search_special(level, BARRACKS) && !rn2(200)) { static const char *const barracks_msg[4] = { "blades being honed.", "loud snoring.", "dice being thrown.", "General MacArthur!", }; int count = 0; for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_mercenary(mtmp->data) && mon_in_room(mtmp, BARRACKS) && /* sleeping implies not-yet-disturbed (usually) */ (mtmp->msleeping || ++count > 5)) { You_hear("%s", barracks_msg[rn2(3) + hallu]); return; } } } if (search_special(level, 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 = level->monlist; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->msleeping || is_animal(mtmp->data)) && mon_in_room(mtmp, ZOO)) { You_hear("%s", zoo_msg[rn2(2) + hallu]); return; } } } if ((sroom = search_special(level, ANY_SHOP)) && !rn2(200)) { if (tended_shop(sroom) && !strchr(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) { static const char *const shop_msg[3] = { "someone cursing shoplifters.", "the chime of a cash register.", "Neiman and Marcus arguing!", }; You_hear("%s", shop_msg[rn2(2) + hallu]); } return; } if (search_special(level, DELPHI) && !rn2(400)) { /* make sure the Oracle is still here */ for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_POTTER]) break; /* and don't produce silly effects when he's clearly visible */ if (mtmp && (hallu || !canseemon(mtmp))) { static const char *const ora_msg[5] = { "political commentary.", "convulsive ravings about WLAN controllers.", "an Adirondack woodsman.", "someone ask you for your punchcards.", /* if(hallucinating) */ "loud praise for Netgear devices." /* if(hallucinating) */ }; You_hear("%s", ora_msg[rn2(3) + hallu * 2]); } return; } }
/* called from check_special_room() when the player enters the temple room */ void intemple(int roomno) { struct monst *priest = findpriest((char)roomno); boolean tended = (priest != NULL); boolean sanctum, can_speak; xchar shrined; const char *msg1, *msg2; if (In_mines(&u.uz) && !historysearch("entered the Minetown temple", TRUE)) historic_event(FALSE, TRUE, "entered the Minetown temple"); if (!temple_occupied(u.urooms0)) { if (tended) { shrined = has_shrine(priest); sanctum = (priest->data == &mons[PM_HIGH_PRIEST] && (shrined & AM_SANCTUM)); can_speak = (priest->mcanmove && !priest->msleeping && canhear()); if (can_speak) { unsigned save_priest = priest->ispriest; /* don't reveal the altar's owner upon temple entry in the endgame; for the Sanctum, the next message names Moloch so suppress the "of Moloch" for him here too */ if (sanctum && !Hallucination) priest->ispriest = 0; pline("%s intones:", canseemon(priest) ? Monnam(priest) : "A nearby voice"); priest->ispriest = save_priest; } msg2 = 0; if (sanctum && CONST_EPRI(priest)->shralign == A_NONE) { if (priest->mpeaceful) { msg1 = "Infidel, you have entered Moloch's Sanctum!"; msg2 = "Be gone!"; msethostility(priest, TRUE, TRUE); } else msg1 = "You desecrate this place by your presence!"; } else { msg1 = msgprintf("Pilgrim, you enter a %s place!", !shrined ? "desecrated" : "sacred"); } if (can_speak) { verbalize("%s", msg1); if (msg2) verbalize("%s", msg2); } if (!sanctum) { /* !tended -> !shrined */ if (!shrined || !p_coaligned(priest) || u.ualign.record <= ALGN_SINNED) pline("You have a%s forbidding feeling...", (!shrined) ? "" : " strange"); else pline("You experience a strange sense of peace."); } } else { switch (rn2(3)) { case 0: pline("You have an eerie feeling..."); break; case 1: pline("You feel like you are being watched."); break; default: pline("A shiver runs down your %s.", body_part(SPINE)); break; } if (!rn2(5)) { struct monst *mtmp; if (!((mtmp = makemon(&mons[PM_GHOST], level, u.ux, u.uy, NO_MM_FLAGS)))) return; if (!Blind || sensemon(mtmp)) pline("An enormous ghost appears next to you!"); else pline("You sense a presence close by!"); msethostility(mtmp, TRUE, TRUE); if (flags.verbose) pline("You are frightened to death, and unable to move."); helpless(3, hr_afraid, "frightened to death", "You regain your composure."); } } } }
/* So you want music... */ int do_play_instrument(struct obj *instr, const struct nh_cmd_arg *arg) { char c = 'y'; const char *buf; int x, y; boolean ok; if (Underwater) { pline(msgc_cancelled, "You can't play music underwater!"); return 0; } if (Upolyd && !can_blow_instrument(youmonst.data) && (instr->otyp == BUGLE || instr->otyp == WOODEN_FLUTE || instr->otyp == MAGIC_FLUTE || instr->otyp == TOOLED_HORN || instr->otyp == FIRE_HORN || instr->otyp == FROST_HORN)) { pline(msgc_cancelled, "You are incapable of playing %s in your current form!", the(xname(instr))); return 0; } if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) { c = yn("Improvise?"); } if (c == 'n') { if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') { buf = msg_from_string(gamestate.castle_tune); } else { /* Note: This is explicitly not getarglin(); we don't want command repeat to repeat the tune. */ buf = getlin("What tune are you playing? [5 notes, A-G]", FALSE); if (*buf == '\033') buf = ""; buf = msgmungspaces(buf); /* convert to uppercase and change any "H" to the expected "B" */ buf = msgcaseconv(buf, highc_htob, highc_htob, highc_htob); } pline(msgc_occstart, "You extract a strange sound from %s!", the(xname(instr))); /* Check if there was the Stronghold drawbridge near and if the tune conforms to what we're waiting for. */ if (Is_stronghold(&u.uz)) { exercise(A_WIS, TRUE); /* just for trying */ if (!strcmp(buf, gamestate.castle_tune)) { /* Search for the drawbridge */ for (y = youmonst.my - 1; y <= youmonst.my + 1; y++) for (x = youmonst.mx - 1; x <= youmonst.mx + 1; x++) if (isok(x, y)) if (find_drawbridge(&x, &y)) { /* tune now fully known */ u.uevent.uheard_tune = 2; if (level->locations[x][y].typ == DRAWBRIDGE_DOWN) close_drawbridge(x, y); else open_drawbridge(x, y); return 1; } } else if (canhear()) { if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1; /* Okay, it wasn't the right tune, but perhaps we can give the player some hints like in the Mastermind game */ ok = FALSE; for (y = youmonst.my - 1; y <= youmonst.my + 1 && !ok; y++) for (x = youmonst.mx - 1; x <= youmonst.mx + 1 && !ok; x++) if (isok(x, y)) if (IS_DRAWBRIDGE(level->locations[x][y].typ) || is_drawbridge_wall(x, y) >= 0) ok = TRUE; if (ok) { /* There is a drawbridge near */ int tumblers, gears; boolean matched[5]; tumblers = gears = 0; for (x = 0; x < 5; x++) matched[x] = FALSE; for (x = 0; x < (int)strlen(buf); x++) if (x < 5) { if (buf[x] == gamestate.castle_tune[x]) { gears++; matched[x] = TRUE; } else for (y = 0; y < 5; y++) if (!matched[y] && buf[x] == gamestate.castle_tune[y] && buf[y] != gamestate.castle_tune[y]) { tumblers++; matched[y] = TRUE; break; } } if (tumblers) if (gears) You_hear(msgc_hint, "%d tumbler%s click and %d gear%s turn.", tumblers, plur(tumblers), gears, plur(gears)); else You_hear(msgc_hint, "%d tumbler%s click.", tumblers, plur(tumblers)); else if (gears) { You_hear(msgc_hint, "%d gear%s turn.", gears, plur(gears)); /* could only get `gears == 5' by playing five correct notes followed by excess; otherwise, tune would have matched above */ if (gears == 5) u.uevent.uheard_tune = 2; } } } } return 1; } else return do_improvisation(instr, arg); }
void invault(void) { struct monst *guard; int trycount, vaultroom = (int)vault_occupied(u.urooms); boolean messages = TRUE; if (!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if (++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ int x, y, gx, gy; xchar rx, ry; long umoney; const char *buf; /* first find the goal for the guard */ if (!find_guard_dest(NULL, &rx, &ry)) return; gx = rx; gy = ry; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if (level->locations[x][y].typ != ROOM) { /* player dug a door and is in it */ if (level->locations[x + 1][y].typ == ROOM) x = x + 1; else if (level->locations[x][y + 1].typ == ROOM) y = y + 1; else if (level->locations[x - 1][y].typ == ROOM) x = x - 1; else if (level->locations[x][y - 1].typ == ROOM) y = y - 1; else if (level->locations[x + 1][y + 1].typ == ROOM) { x = x + 1; y = y + 1; } else if (level->locations[x - 1][y - 1].typ == ROOM) { x = x - 1; y = y - 1; } else if (level->locations[x + 1][y - 1].typ == ROOM) { x = x + 1; y = y - 1; } else if (level->locations[x - 1][y + 1].typ == ROOM) { x = x - 1; y = y + 1; } } while (level->locations[x][y].typ == ROOM) { int dx, dy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if (abs(gx - x) >= abs(gy - y)) x += dx; else y += dy; } if (x == u.ux && y == u.uy) { if (level->locations[x + 1][y].typ == HWALL || level->locations[x + 1][y].typ == DOOR) x = x + 1; else if (level->locations[x - 1][y].typ == HWALL || level->locations[x - 1][y].typ == DOOR) x = x - 1; else if (level->locations[x][y + 1].typ == VWALL || level->locations[x][y + 1].typ == DOOR) y = y + 1; else if (level->locations[x][y - 1].typ == VWALL || level->locations[x][y - 1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if (!(guard = makemon(&mons[PM_GUARD], level, x, y, NO_MM_FLAGS))) return; guard->isgd = 1; msethostility(guard, FALSE, TRUE); EGD(guard)->gddone = 0; EGD(guard)->ogx = x; EGD(guard)->ogy = y; assign_level(&(EGD(guard)->gdlevel), &u.uz); EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; /* We used to reset fainted status here, but that doesn't really make sense; instead, that's treated like normal helplessness */ if (canspotmon(guard)) pline("Suddenly one of the Vault's guards enters!"); else if (canhear()) You_hear("someone else enter the Vault."); else messages = FALSE; newsym(guard->mx, guard->my); if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected || u.uburied) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Engulfed) { if ((!u.ustuck->minvis || perceives(guard->data))) verbalize("How did that %s get in here?", m_monnam(u.ustuck)); if (messages) pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Strangled || is_silent(youmonst.data) || u_helpless(hm_all)) { /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } action_interrupted(); trycount = 5; do { buf = getlin("\"Hello stranger, who are you?\" -", FALSE); buf = msgmungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ strncmpi(buf, u.uplname, (int)strlen(u.uplname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") || !strcmpi(buf, "Creosote")) { if (!mvitals[PM_CROESUS].died) { verbalize("Oh, yes, of course. Sorry to have disturbed you."); mongone(guard); } else { setmangry(guard); verbalize("Back from the dead, are you? I'll remedy that!"); /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; mon_wield_item(guard); } } return; } verbalize("I don't know you."); umoney = money_cnt(invent); if (!umoney && !hidden_gold()) verbalize("Please follow me."); else { if (!umoney) verbalize("You have hidden money."); verbalize("Most likely all your money was stolen from this vault."); verbalize("Please drop that money and follow me."); } EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; if (IS_WALL(level->locations[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = level->locations[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = level->rooms[vlt].lx, hix = level->rooms[vlt].hx; xchar lowy = level->rooms[vlt].ly, hiy = level->rooms[vlt].hy; if (x == lowx - 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TLCORNER; else if (x == hix + 1 && y == lowy - 1) EGD(guard)->fakecorr[0].ftyp = TRCORNER; else if (x == lowx - 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BLCORNER; else if (x == hix + 1 && y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = BRCORNER; else if (y == lowy - 1 || y == hiy + 1) EGD(guard)->fakecorr[0].ftyp = HWALL; else if (x == lowx - 1 || x == hix + 1) EGD(guard)->fakecorr[0].ftyp = VWALL; } level->locations[x][y].typ = DOOR; level->locations[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } }