/* pet makes "I'm hungry" noises */ void beg(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) domonnoise(mtmp); else if (mtmp->data->msound >= MS_HUMANOID) { if (!canspotmon(level, mtmp)) map_invisible(mtmp->mx, mtmp->my); verbalize("I'm hungry."); } }
int dotalk(const struct nh_cmd_arg *arg) { struct monst *mtmp; int tx, ty; struct obj *otmp; schar dx; schar dy; schar dz; if (!getargdir(arg, NULL, &dx, &dy, &dz)) { /* decided not to chat */ return 0; } if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(youmonst.data->mname)); return 0; } if (Strangled) { pline("You can't speak. You're choking!"); return 0; } if (Engulfed) { pline("They won't hear you out there."); return 0; } if (Underwater) { pline("Your speech is unintelligible underwater."); return 0; } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != NULL) { /* 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; } if (u.usteed && dz > 0) { if (!u.usteed->mcanmove || u.usteed->msleeping) { pline("Your steed remains silent..."); return 0; } return domonnoise(u.usteed); } if (dz) { pline("They won't hear you %s there.", dz < 0 ? "up" : "down"); return 0; } if (dx == 0 && dy == 0) { if (u.umonnum == PM_ETTIN) { pline("You discover that your other head makes boring conversation."); return 0; } pline("Talking to yourself is a bad habit for a dungeoneer."); return 0; } tx = u.ux + dx; ty = u.uy + dy; if (!isok(tx, ty)) { pline("You call out into the abyss, but nobody hears you."); return 0; } mtmp = m_at(level, tx, ty); /* Do we try to close a door on the square? We do if a) the square is known by the player to be a doorway, b) there's no invisible-I marker there, c) there's no monster in a chattable state there. */ if (!mtmp || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { int membg = level->locations[tx][ty].mem_bg; if (membg == S_vodoor || membg == S_vcdoor || membg == S_ndoor || membg == S_hodoor || membg == S_hcdoor) { if (!level->locations[tx][ty].mem_invis) { struct nh_cmd_arg newarg; arg_from_delta(dx, dy, dz, &newarg); return doclose(&newarg); } } pline("You start talking, but nobody seems to hear you."); 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)); else pline("You start talking, but nobody seems to hear you."); return 0; } /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; 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); }
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; }
static int dochat(void) { struct monst *mtmp; int tx, ty; struct obj *otmp; schar dx, dy, dz; int mdx, mdy, mon_count; if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(mons_mname(youmonst.data))); return 0; } if (Strangled) { pline("You can't speak. You're choking!"); return 0; } if (u.uswallow) { pline("They won't hear you out there."); return 0; } if (Underwater) { pline("Your speech is unintelligible underwater."); return 0; } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != NULL) { /* 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; } /* count the monsters around the player */ mon_count = 0; for (mdx = -1; mdx <= 1; mdx++) { for (mdy = -1; mdy <= 1; mdy++) { if (mdx == 0 && mdy == 0) { /* account for steed */ if (u.usteed) { mon_count++; dx = 0; dy = 0; dz = 1; } continue; } mtmp = m_at(level, u.ux + mdx, u.uy + mdy); if (mtmp && canspotmon(level, mtmp)) { mon_count++; dx = mdx; dy = mdy; dz = 0; } } } /* don't ask for a direction if there's only one monster around */ if ((mon_count != 1 || iflags.paranoid_chat) && !getdir("Talk to whom? (in what direction)", &dx, &dy, &dz)) { /* decided not to chat */ return 0; } if (u.usteed && dz > 0) { if (!u.usteed->mcanmove || u.usteed->msleeping) { pline("Your steed remains silent..."); return 0; } return domonnoise(u.usteed); } if (dz) { pline("They won't hear you %s there.", dz < 0 ? "up" : "down"); return 0; } if (dx == 0 && 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) { pline("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 + dx; ty = u.uy + dy; mtmp = m_at(level, 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(level, mtmp)) pline("%s seems not to notice you.", Monnam(mtmp)); return 0; } /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (mtmp->mtame && mtmp->meating) { if (!canspotmon(level, mtmp)) map_invisible(mtmp->mx, mtmp->my); pline("%s is eating noisily.", Monnam(mtmp)); return 0; } if (Role_if(PM_CONVICT) && is_rat(mtmp->data) && !mtmp->mpeaceful && !mtmp->mtame) { int soothe_roll = rnl(10); pline("You attempt to soothe the %s with chittering sounds.", l_monnam(mtmp)); if (soothe_roll < 2) { tamedog(mtmp, NULL); } else if (soothe_roll > 8) { pline("%s unfortunately ignores your overtures.", Monnam(mtmp)); } else { mtmp->mpeaceful = 1; set_malign(mtmp); } return 1; } return domonnoise(mtmp); }
/* called when someone is being hit by Magicbane */ static boolean magicbane_hit( struct monst *magr, /* attacker */ struct monst *mdef, /* defender */ struct obj *mb, /* Magicbane */ int *dmgptr, /* extra damage target will suffer */ int dieroll, /* d20 that has already scored a hit */ boolean vis, /* whether the action can be seen */ char *hittee /* target's name: "you" or mon_nam(mdef) */ ) { const struct permonst *old_uasmon; const char *verb; boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst), resisted = FALSE, do_stun, do_confuse, result; int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2; result = FALSE; /* no message given yet */ /* the most severe effects are less likely at higher enchantment */ if (mb->spe >= 3) scare_dieroll /= (1 << (mb->spe / 3)); /* if target successfully resisted the artifact damage bonus, reduce overall likelihood of the assorted special effects */ if (!spec_dbon_applies) dieroll += 1; /* might stun even when attempting a more severe effect, but in that case it will only happen if the other effect fails; extra damage will apply regardless; 3.4.1: sometimes might just probe even when it hasn't been enchanted */ do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7)); /* the special effects also boost physical damage; increments are generally cumulative, but since the stun effect is based on a different criterium its damage might not be included; the base damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending on target's resistance check against AD_STUN (handled by caller) [note that a successful save against AD_STUN doesn't actually prevent the target from ending up stunned] */ attack_indx = MB_INDEX_PROBE; *dmgptr += rnd(4); /* (2..3)d4 */ if (do_stun) { attack_indx = MB_INDEX_STUN; *dmgptr += rnd(4); /* (3..4)d4 */ } if (dieroll <= scare_dieroll) { attack_indx = MB_INDEX_SCARE; *dmgptr += rnd(4); /* (3..5)d4 */ } if (dieroll <= (scare_dieroll / 2)) { attack_indx = MB_INDEX_CANCEL; *dmgptr += rnd(4); /* (4..6)d4 */ } /* give the hit message prior to inflicting the effects */ verb = mb_verb[!!Hallucination][attack_indx]; if (youattack || youdefend || vis) { result = TRUE; pline("The magic-absorbing blade %s %s!", vtense(NULL, verb), hittee); /* assume probing has some sort of noticeable feedback even if it is being done by one monster to another */ if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); } /* now perform special effects */ switch (attack_indx) { case MB_INDEX_CANCEL: old_uasmon = youmonst.data; /* No mdef->mcan check: even a cancelled monster can be polymorphed * into a golem, and the "cancel" effect acts as if some magical * energy remains in spellcasting defenders to be absorbed later. */ if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) { resisted = TRUE; } else { do_stun = FALSE; if (youdefend) { if (youmonst.data != old_uasmon) *dmgptr = 0; /* rehumanized, so no more damage */ if (u.uenmax > 0) { pline("You lose magical energy!"); u.uenmax--; if (u.uen > 0) u.uen--; iflags.botl = 1; } } else { if (mdef->data == &mons[PM_CLAY_GOLEM]) mdef->mhp = 1; /* cancelled clay golems will die */ if (youattack && attacktype(mdef->data, AT_MAGC)) { pline("You absorb magical energy!"); u.uenmax++; u.uen++; iflags.botl = 1; } } } break; case MB_INDEX_SCARE: if (youdefend) { if (Antimagic) { resisted = TRUE; } else { nomul(-3, "being scared stiff"); nomovemsg = ""; if (magr && magr == u.ustuck && sticks(youmonst.data)) { u.ustuck = NULL; pline("You release %s!", mon_nam(magr)); } } } else { if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL)) resisted = TRUE; else monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr)); } if (!resisted) do_stun = FALSE; break; case MB_INDEX_STUN: do_stun = TRUE; /* (this is redundant...) */ break; case MB_INDEX_PROBE: if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) { pline("The %s is insightful.", verb); /* pre-damage status */ probe_monster(mdef); } break; } /* stun if that was selected and a worse effect didn't occur */ if (do_stun) { if (youdefend) make_stunned((HStun + 3), FALSE); else mdef->mstun = 1; /* avoid extra stun message below if we used mb_verb["stun"] above */ if (attack_indx == MB_INDEX_STUN) do_stun = FALSE; } /* lastly, all this magic can be confusing... */ do_confuse = !rn2(12); if (do_confuse) { if (youdefend) make_confused(HConfusion + 4, FALSE); else mdef->mconf = 1; } if (youattack || youdefend || vis) { upstart(hittee); /* capitalize */ if (resisted) { pline("%s %s!", hittee, vtense(hittee, "resist")); shieldeff(youdefend ? u.ux : mdef->mx, youdefend ? u.uy : mdef->my); } if ((do_stun || do_confuse) && flags.verbose) { char buf[BUFSZ]; buf[0] = '\0'; if (do_stun) strcat(buf, "stunned"); if (do_stun && do_confuse) strcat(buf, " and "); if (do_confuse) strcat(buf, "confused"); pline("%s %s %s%c", hittee, vtense(hittee, "are"), buf, (do_stun && do_confuse) ? '!' : '.'); } } return result; }
static int dochat(int idx, int idy, int idz) { struct monst *mtmp; int tx, ty; struct obj *otmp; schar dx = idx; schar dy = idy; schar dz = idz; if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(youmonst.data->mname)); return 0; } if (Strangled) { pline("You can't speak. You're choking!"); return 0; } if (u.uswallow) { pline("They won't hear you out there."); return 0; } if (Underwater) { pline("Your speech is unintelligible underwater."); return 0; } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != NULL) { /* 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; } if (dx == -2 || dy == -2 || dz == -2) { if (!getdir(NULL, &dx, &dy, &dz)) { /* decided not to chat */ return 0; } } if (u.usteed && dz > 0) { if (!u.usteed->mcanmove || u.usteed->msleeping) { pline("Your steed remains silent..."); return 0; } return domonnoise(u.usteed); } if (dz) { pline("They won't hear you %s there.", dz < 0 ? "up" : "down"); return 0; } if (dx == 0 && 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) { pline("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 + dx; ty = u.uy + dy; mtmp = m_at(level, tx, ty); if (!mtmp || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { return doclose(dx, dy, 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 this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; 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); }