Exemplo n.º 1
0
/* 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.");
    }
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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);
}
Exemplo n.º 5
0
/* 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;
}
Exemplo n.º 6
0
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);
}