Пример #1
0
/*
 * creature (usually player) tries to touch (pick up or wield) an artifact obj.
 * Returns 0 if the object refuses to be touched.
 * This routine does not change any object chains.
 * Ignores such things as gauntlets, assuming the artifact is not
 * fooled by such trappings.
 */
int touch_artifact(struct obj *obj, struct monst *mon)
{
    const struct artifact *oart = get_artifact(obj);
    boolean badclass, badalign, self_willed, yours;

    if (!oart) return 1;

    yours = (mon == &youmonst);
    /* all quest artifacts are self-willed; it this ever changes, `badclass'
       will have to be extended to explicitly include quest artifacts */
    self_willed = ((oart->spfx & SPFX_INTEL) != 0);
    if (yours) {
	badclass = self_willed &&
		   ((oart->role != NON_PM && !Role_if (oart->role)) ||
		    (oart->race != NON_PM && !Race_if (oart->race)));
	badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
		   (oart->alignment != u.ualign.type || u.ualign.record < 0);
    } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) {
	badclass = self_willed &&
		   oart->role != NON_PM && oart != &artilist[ART_EXCALIBUR];
	badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE &&
		   (oart->alignment != sgn(mon->data->maligntyp));
    } else {    /* an M3_WANTSxxx monster or a fake player */
	/* special monsters trying to take the Amulet, invocation tools or
	   quest item can touch anything except for `spec_applies' artifacts */
	badclass = badalign = FALSE;
    }
    /* weapons which attack specific categories of monsters are
       bad for them even if their alignments happen to match */
    if (!badalign && (oart->spfx & SPFX_DBONUS) != 0) {
	struct artifact tmp;

	tmp = *oart;
	tmp.spfx &= SPFX_DBONUS;
	badalign = !!spec_applies(&tmp, mon);
    }

    if (((badclass || badalign) && self_willed) ||
       (badalign && (!yours || !rn2(4))))  {
	int dmg;
	char buf[BUFSZ];

	if (!yours) return 0;
	pline("You are blasted by %s power!", s_suffix(the(xname(obj))));
	dmg = dice((Antimagic ? 2 : 4), (self_willed ? 10 : 4));
	sprintf(buf, "touching %s", oart->name);
	losehp(dmg, buf, KILLED_BY);
	exercise(A_WIS, FALSE);
    }

    /* can pick it up unless you're totally non-synch'd with the artifact */
    if (badclass && badalign && self_willed) {
	if (yours) pline("%s your grasp!", Tobjnam(obj, "evade"));
	return 0;
    }

    return 1;
}
Пример #2
0
/* return a randomly chosen developer name */
STATIC_OVL const char *
dev_name()
{
	register int i, m = 0, n = SIZE(developers);
	register struct monst *mtmp;
	register boolean match;

	do {
	    match = FALSE;
	    i = rn2(n);
	    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
		if(!is_mplayer(mtmp->data)) continue;
		if(!strncmp(developers[i], NAME(mtmp),
			               strlen(developers[i]))) {
		    match = TRUE;
		    break;
	        }
	    }
	    m++;
	} while (match && m < 100); /* m for insurance */

	if (match) return (const char *)0;
	return(developers[i]);
}
Пример #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;
}
Пример #4
0
/* Bug: if the monster is a priest or shopkeeper, not every one of these
 * options works, since those are special cases.
 */
char *x_monnam(const struct monst *mtmp,
	       int article, /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious
	                     * ARTICLE_YOUR: "your" on pets, "the" on everything
			     * else
			     * If the monster would be referred to as "it" or if the monster has a name
			     * _and_ there is no adjective, "invisible", "saddled", etc., override this
			     * and always use no article.
			     */
	       const char *adjective,
	       int suppress, /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE.
	                      * EXACT_NAME: combination of all the above
			      */
	       boolean called)
{
	static char buf[BUFSZ];

	const struct permonst *mdat = mtmp->data;
	boolean do_hallu, do_invis, do_it, do_saddle;
	boolean name_at_start, has_adjectives;
	char *bp;

	if (program_state.gameover)
	    suppress |= SUPPRESS_HALLUCINATION;
	if (article == ARTICLE_YOUR && !mtmp->mtame)
	    article = ARTICLE_THE;

	do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION);
	do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE);
	do_it = !canspotmon(mtmp) && 
	    article != ARTICLE_YOUR &&
	    !program_state.gameover &&
	    mtmp != u.usteed &&
	    !(u.uswallow && mtmp == u.ustuck) &&
	    !(suppress & SUPPRESS_IT);
	do_saddle = !(suppress & SUPPRESS_SADDLE);

	buf[0] = 0;

	/* unseen monsters, etc.  Use "it" */
	if (do_it) {
	    strcpy(buf, "it");
	    return buf;
	}

	/* priests and minions: don't even use this function */
	if (mtmp->ispriest || mtmp->isminion) {
	    struct monst *priestmon = newmonst(mtmp->mxtyp, mtmp->mnamelth);
	    char priestnambuf[BUFSZ];
	    char *name;
	    long save_prop = EHalluc_resistance;
	    memcpy(priestmon, mtmp, sizeof(struct monst) + mtmp->mxlth + mtmp->mnamelth);

	    /* when true name is wanted, explicitly block Hallucination */
	    if (!do_hallu) EHalluc_resistance = 1L;
	    if (!do_invis) priestmon->minvis = 0;
	    name = priestname(priestmon, priestnambuf);
	    EHalluc_resistance = save_prop;
	    if (article == ARTICLE_NONE && !strncmp(name, "the ", 4))
		name += 4;
	    strcpy(buf, name);
	    free(priestmon);
	    return buf;
	}

	/* Shopkeepers: use shopkeeper name.  For normal shopkeepers, just
	 * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible
	 * shopkeeper" or "Asidonhopo the blue dragon".  If hallucinating,
	 * none of this applies.
	 */
	if (mtmp->isshk && !do_hallu) {
	    if (adjective && article == ARTICLE_THE) {
		/* pathological case: "the angry Asidonhopo the blue dragon"
		   sounds silly */
		strcpy(buf, "the ");
		strcat(strcat(buf, adjective), " ");
		strcat(buf, shkname(mtmp));
		return buf;
	    }
	    strcat(buf, shkname(mtmp));
	    if (mdat == &mons[PM_SHOPKEEPER] && !do_invis)
		return buf;
	    strcat(buf, " the ");
	    if (do_invis)
		strcat(buf, "invisible ");
	    strcat(buf, mdat->mname);
	    return buf;
	}

	/* Put the adjectives in the buffer */
	if (adjective)
	    strcat(strcat(buf, adjective), " ");
	if (do_invis)
	    strcat(buf, "invisible ");

	if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) &&
	    !Blind && !Hallucination)
	    strcat(buf, "saddled ");

	if (buf[0] != 0)
	    has_adjectives = TRUE;
	else
	    has_adjectives = FALSE;

	/* Put the actual monster name or type into the buffer now */
	/* Be sure to remember whether the buffer starts with a name */
	if (do_hallu) {
	    strcat(buf, rndmonnam());
	    name_at_start = FALSE;
	} else if (mtmp->mnamelth) {
	    char *name = NAME(mtmp);

	    if (mdat == &mons[PM_GHOST]) {
		sprintf(eos(buf), "%s ghost", s_suffix(name));
		name_at_start = TRUE;
	    } else if (called) {
		sprintf(eos(buf), "%s called %s", mdat->mname, name);
		name_at_start = (boolean)type_is_pname(mdat);
	    } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) {
		/* <name> the <adjective> <invisible> <saddled> <rank> */
		char pbuf[BUFSZ];

		strcpy(pbuf, name);
		pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */
		if (has_adjectives)
		    strcat(pbuf, buf);
		strcat(pbuf, bp + 5);	/* append the rest of the name */
		strcpy(buf, pbuf);
		article = ARTICLE_NONE;
		name_at_start = TRUE;
	    } else {
		strcat(buf, name);
		name_at_start = TRUE;
	    }
	} else if (is_mplayer(mdat) && !In_endgame(&u.uz)) {
	    char pbuf[BUFSZ];
	    strcpy(pbuf, rank_of((int)mtmp->m_lev,
				 monsndx(mdat), (boolean)mtmp->female));
	    strcat(buf, lcase(pbuf));
	    name_at_start = FALSE;
	} else {
	    strcat(buf, mdat->mname);
	    name_at_start = (boolean)type_is_pname(mdat);
	}

	if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) {
	    if (mdat == &mons[PM_WIZARD_OF_YENDOR])
		article = ARTICLE_THE;
	    else
		article = ARTICLE_NONE;
	} else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) {
	    article = ARTICLE_THE;
	}

	{
	    char buf2[BUFSZ];

	    switch(article) {
		case ARTICLE_YOUR:
		    strcpy(buf2, "your ");
		    strcat(buf2, buf);
		    strcpy(buf, buf2);
		    return buf;
		case ARTICLE_THE:
		    strcpy(buf2, "the ");
		    strcat(buf2, buf);
		    strcpy(buf, buf2);
		    return buf;
		case ARTICLE_A:
		    return an(buf);
		case ARTICLE_NONE:
		default:
		    return buf;
	    }
	}
}