/* NetHack 3.6	priest.c	$NHDT-Date: 1545131519 2018/12/18 11:11:59 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.45 $ */
/* Copyright (c) Izchak Miller, Steve Linhart, 1989.              */
/* NetHack may be freely redistributed.  See license for details. */

/* JNetHack Copyright */
/* (c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-2000  */
/* For 3.4-, Copyright (c) SHIRAKATA Kentaro, 2002-2023            */
/* JNetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include "mfndpos.h"

/* these match the categorizations shown by enlightenment */
#define ALGN_SINNED (-4) /* worse than strayed (-1..-3) */
#define ALGN_PIOUS 14    /* better than fervent (9..13) */

STATIC_DCL boolean FDECL(histemple_at, (struct monst *, XCHAR_P, XCHAR_P));
STATIC_DCL boolean FDECL(has_shrine, (struct monst *));

void
newepri(mtmp)
struct monst *mtmp;
{
    if (!mtmp->mextra)
        mtmp->mextra = newmextra();
    if (!EPRI(mtmp)) {
        EPRI(mtmp) = (struct epri *) alloc(sizeof(struct epri));
        (void) memset((genericptr_t) EPRI(mtmp), 0, sizeof(struct epri));
    }
}

void
free_epri(mtmp)
struct monst *mtmp;
{
    if (mtmp->mextra && EPRI(mtmp)) {
        free((genericptr_t) EPRI(mtmp));
        EPRI(mtmp) = (struct epri *) 0;
    }
    mtmp->ispriest = 0;
}

/*
 * Move for priests and shopkeepers.  Called from shk_move() and pri_move().
 * Valid returns are  1: moved  0: didn't  -1: let m_move do it  -2: died.
 */
int
move_special(mtmp, in_his_shop, appr, uondoor, avoid, omx, omy, gx, gy)
register struct monst *mtmp;
boolean in_his_shop;
schar appr;
boolean uondoor, avoid;
register xchar omx, omy, gx, gy;
{
    register xchar nx, ny, nix, niy;
    register schar i;
    schar chcnt, cnt;
    coord poss[9];
    long info[9];
    long allowflags;
#if 0 /* dead code; see below */
    struct obj *ib = (struct obj *) 0;
#endif

    if (omx == gx && omy == gy)
        return 0;
    if (mtmp->mconf) {
        avoid = FALSE;
        appr = 0;
    }

    nix = omx;
    niy = omy;
    if (mtmp->isshk)
        allowflags = ALLOW_SSM;
    else
        allowflags = ALLOW_SSM | ALLOW_SANCT;
    if (passes_walls(mtmp->data))
        allowflags |= (ALLOW_ROCK | ALLOW_WALL);
    if (throws_rocks(mtmp->data))
        allowflags |= ALLOW_ROCK;
    if (tunnels(mtmp->data))
        allowflags |= ALLOW_DIG;
    if (!nohands(mtmp->data) && !verysmall(mtmp->data)) {
        allowflags |= OPENDOOR;
        if (monhaskey(mtmp, TRUE))
            allowflags |= UNLOCKDOOR;
    }
    if (is_giant(mtmp->data))
        allowflags |= BUSTDOOR;
    cnt = mfndpos(mtmp, poss, info, allowflags);

    if (mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */
        for (i = 0; i < cnt; i++)
            if (!(info[i] & NOTONL))
                goto pick_move;
        avoid = FALSE;
    }

#define GDIST(x, y) (dist2(x, y, gx, gy))
pick_move:
    chcnt = 0;
    for (i = 0; i < cnt; i++) {
        nx = poss[i].x;
        ny = poss[i].y;
        if (IS_ROOM(levl[nx][ny].typ)
            || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) {
            if (avoid && (info[i] & NOTONL))
                continue;
            if ((!appr && !rn2(++chcnt))
                || (appr && GDIST(nx, ny) < GDIST(nix, niy))) {
                nix = nx;
                niy = ny;
            }
        }
    }
    if (mtmp->ispriest && avoid && nix == omx && niy == omy
        && onlineu(omx, omy)) {
        /* might as well move closer as long it's going to stay
         * lined up */
        avoid = FALSE;
        goto pick_move;
    }

    if (nix != omx || niy != omy) {
        if (MON_AT(nix, niy))
            return 0;
        remove_monster(omx, omy);
        place_monster(mtmp, nix, niy);
        newsym(nix, niy);
        if (mtmp->isshk && !in_his_shop && inhishop(mtmp))
            check_special_room(FALSE);
#if 0 /* dead code; maybe someday someone will track down why... */
        if (ib) {
            if (cansee(mtmp->mx, mtmp->my))
#if 0 /*JP:T*/
                pline("%s picks up %s.", Monnam(mtmp),
                      distant_name(ib, doname));
#else
                pline("%sは%sを拾った．", Monnam(mtmp),
                      distant_name(ib, doname));
#endif
            obj_extract_self(ib);
            (void) mpickobj(mtmp, ib);
        }
#endif
        return 1;
    }
    return 0;
}

char
temple_occupied(array)
register char *array;
{
    register char *ptr;

    for (ptr = array; *ptr; ptr++)
        if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE)
            return *ptr;
    return '\0';
}

STATIC_OVL boolean
histemple_at(priest, x, y)
register struct monst *priest;
register xchar x, y;
{
    return (boolean) (priest && priest->ispriest
                      && (EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE))
                      && on_level(&(EPRI(priest)->shrlevel), &u.uz));
}

boolean
inhistemple(priest)
struct monst *priest;
{
    /* make sure we have a priest */
    if (!priest || !priest->ispriest)
        return FALSE;
    /* priest must be on right level and in right room */
    if (!histemple_at(priest, priest->mx, priest->my))
        return FALSE;
    /* temple room must still contain properly aligned altar */
    return has_shrine(priest);
}

/*
 * pri_move: return 1: moved  0: didn't  -1: let m_move do it  -2: died
 */
int
pri_move(priest)
register struct monst *priest;
{
    register xchar gx, gy, omx, omy;
    schar temple;
    boolean avoid = TRUE;

    omx = priest->mx;
    omy = priest->my;

    if (!histemple_at(priest, omx, omy))
        return -1;

    temple = EPRI(priest)->shroom;

    gx = EPRI(priest)->shrpos.x;
    gy = EPRI(priest)->shrpos.y;

    gx += rn1(3, -1); /* mill around the altar */
    gy += rn1(3, -1);

    if (!priest->mpeaceful
        || (Conflict && !resist(priest, RING_CLASS, 0, 0))) {
        if (monnear(priest, u.ux, u.uy)) {
            if (Displaced)
/*JP
                Your("displaced image doesn't fool %s!", mon_nam(priest));
*/
                Your("幻影は%sをだませなかった！", mon_nam(priest));
            (void) mattacku(priest);
            return 0;
        } else if (index(u.urooms, temple)) {
            /* chase player if inside temple & can see him */
            if (priest->mcansee && m_canseeu(priest)) {
                gx = u.ux;
                gy = u.uy;
            }
            avoid = FALSE;
        }
    } else if (Invis)
        avoid = FALSE;

    return move_special(priest, FALSE, TRUE, FALSE, avoid, omx, omy, gx, gy);
}

/* exclusively for mktemple() */
void
priestini(lvl, sroom, sx, sy, sanctum)
d_level *lvl;
struct mkroom *sroom;
int sx, sy;
boolean sanctum; /* is it the seat of the high priest? */
{
    struct monst *priest;
    struct obj *otmp;
    int cnt;

    if (MON_AT(sx + 1, sy))
        (void) rloc(m_at(sx + 1, sy), FALSE); /* insurance */

    priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST],
                     sx + 1, sy, MM_EPRI);
    if (priest) {
        EPRI(priest)->shroom = (schar) ((sroom - rooms) + ROOMOFFSET);
        EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask);
        EPRI(priest)->shrpos.x = sx;
        EPRI(priest)->shrpos.y = sy;
        assign_level(&(EPRI(priest)->shrlevel), lvl);
        priest->mtrapseen = ~0; /* traps are known */
        priest->mpeaceful = 1;
        priest->ispriest = 1;
        priest->isminion = 0;
        priest->msleeping = 0;
        set_malign(priest); /* mpeaceful may have changed */

        /* now his/her goodies... */
        if (sanctum && EPRI(priest)->shralign == A_NONE
            && on_level(&sanctum_level, &u.uz)) {
            (void) mongets(priest, AMULET_OF_YENDOR);
        }
        /* 2 to 4 spellbooks */
        for (cnt = rn1(3, 2); cnt > 0; --cnt) {
            (void) mpickobj(priest, mkobj(SPBOOK_CLASS, FALSE));
        }
        /* robe [via makemon()] */
        if (rn2(2) && (otmp = which_armor(priest, W_ARMC)) != 0) {
            if (p_coaligned(priest))
                uncurse(otmp);
            else
                curse(otmp);
        }
    }
}

/* get a monster's alignment type without caller needing EPRI & EMIN */
aligntyp
mon_aligntyp(mon)
struct monst *mon;
{
    aligntyp algn = mon->ispriest ? EPRI(mon)->shralign
                                  : mon->isminion ? EMIN(mon)->min_align
                                                  : mon->data->maligntyp;

    if (algn == A_NONE)
        return A_NONE; /* negative but differs from chaotic */
    return (algn > 0) ? A_LAWFUL : (algn < 0) ? A_CHAOTIC : A_NEUTRAL;
}

/*
 * Specially aligned monsters are named specially.
 *      - aligned priests with ispriest and high priests have shrines
 *              they retain ispriest and epri when polymorphed
 *      - aligned priests without ispriest are roamers
 *              they have isminion set and use emin rather than epri
 *      - minions do not have ispriest but have isminion and emin
 *      - caller needs to inhibit Hallucination if it wants to force
 *              the true name even when under that influence
 */
char *
priestname(mon, pname)
register struct monst *mon;
char *pname; /* caller-supplied output buffer */
{
    boolean do_hallu = Hallucination,
            aligned_priest = mon->data == &mons[PM_ALIGNED_PRIEST],
            high_priest = mon->data == &mons[PM_HIGH_PRIEST];
    char whatcode = '\0';
    const char *what = do_hallu ? rndmonnam(&whatcode) : mon->data->mname;

    if (!mon->ispriest && !mon->isminion) /* should never happen...  */
        return strcpy(pname, what);       /* caller must be confused */

    *pname = '\0';
#if 0 /*JP*//*日本語では不要*/
    if (!do_hallu || !bogon_is_pname(whatcode))
        Strcat(pname, "the ");
#endif
    if (mon->minvis)
/*JP
        Strcat(pname, "invisible ");
*/
        Strcat(pname, "透明な");
    if (mon->isminion && EMIN(mon)->renegade)
/*JP
        Strcat(pname, "renegade ");
*/
        Strcat(pname, "裏切り者の");

#if 1 /*JP*//*属性はここで付ける*/
    if (do_hallu || !high_priest || !Is_astralevel(&u.uz)
        || distu(mon->mx, mon->my) <= 2 || program_state.gameover) {
        Strcat(pname, halu_gname(mon_aligntyp(mon)));
        Strcat(pname, "の");
    }
#endif
    if (mon->ispriest || aligned_priest) { /* high_priest implies ispriest */
        if (!aligned_priest && !high_priest) {
            ; /* polymorphed priest; use ``what'' as is */
        } else {
            if (high_priest)
#if 0 /*JP*/
                Strcat(pname, "high ");
#else
                {
                    if (Hallucination)
                        what = "無能高級官僚";
                    else
                        what = "法王";
                }
            else /* 上記で完成させて、以下のコードは通らなくする */
#endif
            if (Hallucination)
/*JP
                what = "poohbah";
*/
                what = "無能官僚";
            else if (mon->female)
/*JP
                what = "priestess";
*/
                what = "尼僧";
            else
/*JP
                what = "priest";
*/
                what = "僧侶";
        }
    } else {
/*JP
        if (mon->mtame && !strcmpi(what, "Angel"))
*/
        if (mon->mtame && !strcmpi(what, "天使"))
/*JP
            Strcat(pname, "guardian ");
*/
            Strcat(pname, "警護");
    }

    Strcat(pname, what);
#if 0 /*JP*//*属性はすでに付けている*/
    /* same as distant_monnam(), more or less... */
    if (do_hallu || !high_priest || !Is_astralevel(&u.uz)
        || distu(mon->mx, mon->my) <= 2 || program_state.gameover) {
        Strcat(pname, " of ");
        Strcat(pname, halu_gname(mon_aligntyp(mon)));
    }
#endif
    return pname;
}

boolean
p_coaligned(priest)
struct monst *priest;
{
    return (boolean) (u.ualign.type == mon_aligntyp(priest));
}

STATIC_OVL boolean
has_shrine(pri)
struct monst *pri;
{
    struct rm *lev;
    struct epri *epri_p;

    if (!pri || !pri->ispriest)
        return FALSE;
    epri_p = EPRI(pri);
    lev = &levl[epri_p->shrpos.x][epri_p->shrpos.y];
    if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE))
        return FALSE;
    return (boolean) (epri_p->shralign
                      == (Amask2align(lev->altarmask & ~AM_SHRINE)));
}

struct monst *
findpriest(roomno)
char roomno;
{
    register struct monst *mtmp;

    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
        if (DEADMONSTER(mtmp))
            continue;
        if (mtmp->ispriest && (EPRI(mtmp)->shroom == roomno)
            && histemple_at(mtmp, mtmp->mx, mtmp->my))
            return mtmp;
    }
    return (struct monst *) 0;
}

/* called from check_special_room() when the player enters the temple room */
void
intemple(roomno)
int roomno;
{
    struct monst *priest, *mtmp;
    struct epri *epri_p;
    boolean shrined, sanctum, can_speak;
    long *this_time, *other_time;
    const char *msg1, *msg2;
    char buf[BUFSZ];

    /* don't do anything if hero is already in the room */
    if (temple_occupied(u.urooms0))
        return;

    if ((priest = findpriest((char) roomno)) != 0) {
        /* tended */

        epri_p = EPRI(priest);
        shrined = has_shrine(priest);
        sanctum = (priest->data == &mons[PM_HIGH_PRIEST]
                   && (Is_sanctum(&u.uz) || In_endgame(&u.uz)));
        can_speak = (priest->mcanmove && !priest->msleeping);
        if (can_speak && !Deaf && moves >= epri_p->intone_time) {
            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;
#if 0 /*JP:T*/
            pline("%s intones:",
                  canseemon(priest) ? Monnam(priest) : "A nearby voice");
#else
            pline("%sが詠唱した：",
                  canseemon(priest) ? Monnam(priest) : "近くで誰か");
#endif
            priest->ispriest = save_priest;
            epri_p->intone_time = moves + (long) d(10, 500); /* ~2505 */
            /* make sure that we don't suppress entry message when
               we've just given its "priest intones" introduction */
            epri_p->enter_time = 0L;
        }
        msg1 = msg2 = 0;
        if (sanctum && Is_sanctum(&u.uz)) {
            if (priest->mpeaceful) {
                /* first time inside */
/*JP
                msg1 = "Infidel, you have entered Moloch's Sanctum!";
*/
                msg1 = "異端者よ！ここは，モーロックの聖域だ！";
/*JP
                msg2 = "Be gone!";
*/
                msg2 = "立ちされ！";
                priest->mpeaceful = 0;
                /* became angry voluntarily; no penalty for attacking him */
                set_malign(priest);
            } else {
                /* repeat visit, or attacked priest before entering */
/*JP
                msg1 = "You desecrate this place by your presence!";
*/
                msg1 = "おまえはこの神聖な場所を汚している！";
            }
        } else if (moves >= epri_p->enter_time) {
#if 0 /*JP:T*/
            Sprintf(buf, "Pilgrim, you enter a %s place!",
                    !shrined ? "desecrated" : "sacred");
#else
            Sprintf(buf, "巡礼者よ，おまえは%s地にいる！",
                    !shrined ? "不浄の" : "神聖なる");
#endif
            msg1 = buf;
        }
        if (msg1 && can_speak && !Deaf) {
            verbalize1(msg1);
            if (msg2)
                verbalize1(msg2);
            epri_p->enter_time = moves + (long) d(10, 100); /* ~505 */
        }
        if (!sanctum) {
            if (!shrined || !p_coaligned(priest)
                || u.ualign.record <= ALGN_SINNED) {
/*JP
                msg1 = "have a%s forbidding feeling...";
*/
                msg1 = "%s近づきがたい気持がした．．．";
/*JP
                msg2 = (!shrined || !p_coaligned(priest)) ? "" : " strange";
*/
                msg2 = (!shrined || !p_coaligned(priest)) ? "" : "奇妙な";
                this_time = &epri_p->hostile_time;
                other_time = &epri_p->peaceful_time;
            } else {
/*JP
                msg1 = "experience %s sense of peace.";
*/
                msg1 = "%s満ち足りた気持ちになった．";
/*JP
                msg2 = (u.ualign.record >= ALGN_PIOUS) ? "a" : "an unusual";
*/
                msg2 = (u.ualign.record >= ALGN_PIOUS) ? "" : "いつになく";
                this_time = &epri_p->peaceful_time;
                other_time = &epri_p->hostile_time;
            }
            /* give message if we haven't seen it recently or
               if alignment update has caused it to switch from
               forbidding to sense-of-peace or vice versa */
            if (moves >= *this_time || *other_time >= *this_time) {
                You(msg1, msg2);
                *this_time = moves + (long) d(10, 20); /* ~55 */
                /* avoid being tricked by the RNG:  switch might have just
                   happened and previous random threshold could be larger */
                if (*this_time <= *other_time)
                    *other_time = *this_time - 1L;
            }
        }
        /* recognize the Valley of the Dead and Moloch's Sanctum
           once hero has encountered the temple priest on those levels */
        mapseen_temple(priest);
    } else {
        /* untended */

        switch (rn2(4)) {
        case 0:
/*JP
            You("have an eerie feeling...");
*/
            You("ぞっとした．．．");
            break;
        case 1:
/*JP
            You_feel("like you are being watched.");
*/
            You("見つめられているような気がした．");
            break;
        case 2:
/*JP
            pline("A shiver runs down your %s.", body_part(SPINE));
*/
            pline("あなたの%sを震えが走った．", body_part(SPINE));
            break;
        default:
            break; /* no message; unfortunately there's no
                      EPRI(priest)->eerie_time available to
                      make sure we give one the first time */
        }
        if (!rn2(5)
            && (mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS))
                   != 0) {
            int ngen = mvitals[PM_GHOST].born;
            if (canspotmon(mtmp))
#if 0 /*JP:T*/
                pline("A%s ghost appears next to you%c",
                      ngen < 5 ? "n enormous" : "",
                      ngen < 10 ? '!' : '.');
#else
                pline("%s幽霊があなたのすぐそばに現われた%s",
                      ngen < 5 ? "巨大な" : "",
                      ngen < 10 ? "！" : "．");
#endif
            else
/*JP
                You("sense a presence close by!");
*/
                You("すぐそばに何かがいるのを感じた！");
            mtmp->mpeaceful = 0;
            set_malign(mtmp);
            if (flags.verbose)
/*JP
                You("are frightened to death, and unable to move.");
*/
                You("まっさおになって驚き，動けなくなった．");
            nomul(-3);
/*JP
            multi_reason = "being terrified of a ghost";
*/
            multi_reason = "幽霊に恐怖している時に";
/*JP
            nomovemsg = "You regain your composure.";
*/
            nomovemsg = "あなたは平静を取り戻した．";
        }
    }
}

/* reset the move counters used to limit temple entry feedback;
   leaving the level and then returning yields a fresh start */
void
forget_temple_entry(priest)
struct monst *priest;
{
    struct epri *epri_p = priest->ispriest ? EPRI(priest) : 0;

    if (!epri_p) {
        impossible("attempting to manipulate shrine data for non-priest?");
        return;
    }
    epri_p->intone_time = epri_p->enter_time = epri_p->peaceful_time =
        epri_p->hostile_time = 0L;
}

void
priest_talk(priest)
register struct monst *priest;
{
    boolean coaligned = p_coaligned(priest);
    boolean strayed = (u.ualign.record < 0);

    /* KMH, conduct */
    u.uconduct.gnostic++;

    if (priest->mflee || (!priest->ispriest && coaligned && strayed)) {
/*JP
        pline("%s doesn't want anything to do with you!", Monnam(priest));
*/
        pline("%sはあなたに構いたくないようだ！", Monnam(priest));
        priest->mpeaceful = 0;
        return;
    }

    /* priests don't chat unless peaceful and in their own temple */
    if (!inhistemple(priest) || !priest->mpeaceful
        || !priest->mcanmove || priest->msleeping) {
        static const char *cranky_msg[3] = {
/*JP
            "Thou wouldst have words, eh?  I'll give thee a word or two!",
*/
            "汝言葉を望むのか？",
/*JP
            "Talk?  Here is what I have to say!",
*/
            "話す？何を言えばよいのだ！",
/*JP
            "Pilgrim, I would speak no longer with thee."
*/
            "巡礼者よ，汝に語ることなどない．"
        };

        if (!priest->mcanmove || priest->msleeping) {
#if 0 /*JP:T*/
            pline("%s breaks out of %s reverie!", Monnam(priest),
                  mhis(priest));
#else
            pline("%sは瞑想を中断した！", Monnam(priest));
#endif
            priest->mfrozen = priest->msleeping = 0;
            priest->mcanmove = 1;
        }
        priest->mpeaceful = 0;
        verbalize1(cranky_msg[rn2(3)]);
        return;
    }

    /* you desecrated the temple and now you want to chat? */
    if (priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE)
        && !has_shrine(priest)) {
        verbalize(
/*JP
              "Begone!  Thou desecratest this holy place with thy presence.");
*/
              "立ち去れ！汝はこの神聖なる場所を汚している．");
        priest->mpeaceful = 0;
        return;
    }
    if (!money_cnt(invent)) {
        if (coaligned && !strayed) {
            long pmoney = money_cnt(priest->minvent);
            if (pmoney > 0L) {
                /* Note: two bits is actually 25 cents.  Hmm. */
#if 0 /*JP:T*/
                pline("%s gives you %s for an ale.", Monnam(priest),
                      (pmoney == 1L) ? "one bit" : "two bits");
#else
                pline("%sはあなたがエール酒を飲めるように，%sを与えた．", Monnam(priest),
                      (pmoney == 1L) ? "金貨1枚" : "金貨2枚");
#endif
                money2u(priest, pmoney > 1L ? 2 : 1);
            } else
/*JP
                pline("%s preaches the virtues of poverty.", Monnam(priest));
*/
                pline("%sは清貧の美徳について説教した．", Monnam(priest));
            exercise(A_WIS, TRUE);
        } else
/*JP
            pline("%s is not interested.", Monnam(priest));
*/
            pline("%sは興味を示さない．", Monnam(priest));
        return;
    } else {
        long offer;

/*JP
        pline("%s asks you for a contribution for the temple.",
*/
        pline("%sはあなたに寺院への寄贈を求めた．",
              Monnam(priest));
        if ((offer = bribe(priest)) == 0) {
/*JP
            verbalize("Thou shalt regret thine action!");
*/
            verbalize("汝の行為は神を冒涜するものなり！");
            if (coaligned)
                adjalign(-1);
        } else if (offer < (u.ulevel * 200)) {
            if (money_cnt(invent) > (offer * 2L)) {
/*JP
                verbalize("Cheapskate.");
*/
                verbalize("ケチめ．");
            } else {
/*JP
                verbalize("I thank thee for thy contribution.");
*/
                verbalize("汝の寄贈に報いようぞ．");
                /* give player some token */
                exercise(A_WIS, TRUE);
            }
        } else if (offer < (u.ulevel * 400)) {
/*JP
            verbalize("Thou art indeed a pious individual.");
*/
            verbalize("汝，まさに敬虔なり．");
            if (money_cnt(invent) < (offer * 2L)) {
                if (coaligned && u.ualign.record <= ALGN_SINNED)
                    adjalign(1);
/*JP
                verbalize("I bestow upon thee a blessing.");
*/
                verbalize("汝に祝福を．");
                incr_itimeout(&HClairvoyant, rn1(500, 500));
            }
        } else if (offer < (u.ulevel * 600)
                   /* u.ublessed is only active when Protection is
                      enabled via something other than worn gear
                      (theft by gremlin clears the intrinsic but not
                      its former magnitude, making it recoverable) */
                   && (!(HProtection & INTRINSIC)
                       || (u.ublessed < 20
                           && (u.ublessed < 9 || !rn2(u.ublessed))))) {
/*JP
            verbalize("Thou hast been rewarded for thy devotion.");
*/
            verbalize("汝が献身に報わん．");
            if (!(HProtection & INTRINSIC)) {
                HProtection |= FROMOUTSIDE;
                if (!u.ublessed)
                    u.ublessed = rn1(3, 2);
            } else
                u.ublessed++;
        } else {
/*JP
            verbalize("Thy selfless generosity is deeply appreciated.");
*/
            verbalize("汝自身の真価は大いに認められた．");
            if (money_cnt(invent) < (offer * 2L) && coaligned) {
                if (strayed && (moves - u.ucleansed) > 5000L) {
                    u.ualign.record = 0; /* cleanse thee */
                    u.ucleansed = moves;
                } else {
                    adjalign(2);
                }
            }
        }
    }
}

struct monst *
mk_roamer(ptr, alignment, x, y, peaceful)
register struct permonst *ptr;
aligntyp alignment;
xchar x, y;
boolean peaceful;
{
    register struct monst *roamer;
    register boolean coaligned = (u.ualign.type == alignment);

#if 0 /* this was due to permonst's pxlth field which is now gone */
    if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL])
        return (struct monst *) 0;
#endif

    if (MON_AT(x, y))
        (void) rloc(m_at(x, y), FALSE); /* insurance */

    if (!(roamer = makemon(ptr, x, y, MM_ADJACENTOK | MM_EMIN)))
        return (struct monst *) 0;

    EMIN(roamer)->min_align = alignment;
    EMIN(roamer)->renegade = (coaligned && !peaceful);
    roamer->ispriest = 0;
    roamer->isminion = 1;
    roamer->mtrapseen = ~0; /* traps are known */
    roamer->mpeaceful = peaceful;
    roamer->msleeping = 0;
    set_malign(roamer); /* peaceful may have changed */

    /* MORE TO COME */
    return roamer;
}

void
reset_hostility(roamer)
register struct monst *roamer;
{
    if (!roamer->isminion)
        return;
    if (roamer->data != &mons[PM_ALIGNED_PRIEST]
        && roamer->data != &mons[PM_ANGEL])
        return;

    if (EMIN(roamer)->min_align != u.ualign.type) {
        roamer->mpeaceful = roamer->mtame = 0;
        set_malign(roamer);
    }
    newsym(roamer->mx, roamer->my);
}

boolean
in_your_sanctuary(mon, x, y)
struct monst *mon; /* if non-null, <mx,my> overrides <x,y> */
xchar x, y;
{
    register char roomno;
    register struct monst *priest;

    if (mon) {
        if (is_minion(mon->data) || is_rider(mon->data))
            return FALSE;
        x = mon->mx, y = mon->my;
    }
    if (u.ualign.record <= ALGN_SINNED) /* sinned or worse */
        return FALSE;
    if ((roomno = temple_occupied(u.urooms)) == 0
        || roomno != *in_rooms(x, y, TEMPLE))
        return FALSE;
    if ((priest = findpriest(roomno)) == 0)
        return FALSE;
    return (boolean) (has_shrine(priest) && p_coaligned(priest)
                      && priest->mpeaceful);
}

/* when attacking "priest" in his temple */
void
ghod_hitsu(priest)
struct monst *priest;
{
    int x, y, ax, ay, roomno = (int) temple_occupied(u.urooms);
    struct mkroom *troom;

    if (!roomno || !has_shrine(priest))
        return;

    ax = x = EPRI(priest)->shrpos.x;
    ay = y = EPRI(priest)->shrpos.y;
    troom = &rooms[roomno - ROOMOFFSET];

    if ((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y, 1)) {
        if (IS_DOOR(levl[u.ux][u.uy].typ)) {
            if (u.ux == troom->lx - 1) {
                x = troom->hx;
                y = u.uy;
            } else if (u.ux == troom->hx + 1) {
                x = troom->lx;
                y = u.uy;
            } else if (u.uy == troom->ly - 1) {
                x = u.ux;
                y = troom->hy;
            } else if (u.uy == troom->hy + 1) {
                x = u.ux;
                y = troom->ly;
            }
        } else {
            switch (rn2(4)) {
            case 0:
                x = u.ux;
                y = troom->ly;
                break;
            case 1:
                x = u.ux;
                y = troom->hy;
                break;
            case 2:
                x = troom->lx;
                y = u.uy;
                break;
            default:
                x = troom->hx;
                y = u.uy;
                break;
            }
        }
        if (!linedup(u.ux, u.uy, x, y, 1))
            return;
    }

    switch (rn2(3)) {
    case 0:
/*JP
        pline("%s roars in anger:  \"Thou shalt suffer!\"",
*/
        pline("%sは怒りの声をあげた：「汝，苦しむがよい！」",
              a_gname_at(ax, ay));
        break;
    case 1:
#if 0 /*JP:T*/
        pline("%s voice booms:  \"How darest thou harm my servant!\"",
              s_suffix(a_gname_at(ax, ay)));
#else
        pline("%sの声が響いた：「わが下僕に苦しむがよい！」",
              a_gname_at(ax, ay));
#endif
        break;
    default:
/*JP
        pline("%s roars:  \"Thou dost profane my shrine!\"",
*/
        pline("%sの声が聞こえる：「汝，我が聖堂を汚したり！」",
              a_gname_at(ax, ay));
        break;
    }

    buzz(-10 - (AD_ELEC - 1), 6, x, y, sgn(tbx),
         sgn(tby)); /* bolt of lightning */
    exercise(A_WIS, FALSE);
}

void
angry_priest()
{
    register struct monst *priest;
    struct rm *lev;

    if ((priest = findpriest(temple_occupied(u.urooms))) != 0) {
        struct epri *eprip = EPRI(priest);

        wakeup(priest, FALSE);
        setmangry(priest, FALSE);
        /*
         * If the altar has been destroyed or converted, let the
         * priest run loose.
         * (When it's just a conversion and there happens to be
         * a fresh corpse nearby, the priest ought to have an
         * opportunity to try converting it back; maybe someday...)
         */
        lev = &levl[eprip->shrpos.x][eprip->shrpos.y];
        if (!IS_ALTAR(lev->typ)
            || ((aligntyp) Amask2align(lev->altarmask & AM_MASK)
                != eprip->shralign)) {
            if (!EMIN(priest))
                newemin(priest);
            priest->ispriest = 0; /* now a roaming minion */
            priest->isminion = 1;
            EMIN(priest)->min_align = eprip->shralign;
            EMIN(priest)->renegade = FALSE;
            /* discard priest's memory of his former shrine;
               if we ever implement the re-conversion mentioned
               above, this will need to be removed */
            free_epri(priest);
        }
    }
}

/*
 * When saving bones, find priests that aren't on their shrine level,
 * and remove them.  This avoids big problems when restoring bones.
 * [Perhaps we should convert them into roamers instead?]
 */
void
clearpriests()
{
    struct monst *mtmp;

    for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) {
        if (DEADMONSTER(mtmp))
            continue;
        if (mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz))
            mongone(mtmp);
    }
}

/* munge priest-specific structure when restoring -dlc */
void
restpriest(mtmp, ghostly)
register struct monst *mtmp;
boolean ghostly;
{
    if (u.uz.dlevel) {
        if (ghostly)
            assign_level(&(EPRI(mtmp)->shrlevel), &u.uz);
    }
}

/*
 * align_str(), piousness(), mstatusline() and ustatusline() used to be
 * in pline.c, presumeably because the latter two generate one line of
 * output.  The USE_OLDARGS config gets warnings from 2016ish-vintage
 * gcc (for -Wint-to-pointer-cast, activated by -Wall or -W) when they
 * follow pline() itself.  Fixing up the variadic calls like is done for
 * lev_comp would be needlessly messy there.
 *
 * They don't belong here.  If/when enlightenment ever gets split off
 * from cmd.c (which definitely doesn't belong there), they should go
 * with it.
 */

const char *
align_str(alignment)
aligntyp alignment;
{
    switch ((int) alignment) {
    case A_CHAOTIC:
/*JP
        return "chaotic";
*/
        return "混沌";
    case A_NEUTRAL:
/*JP
        return "neutral";
*/
        return "中立";
    case A_LAWFUL:
/*JP
        return "lawful";
*/
        return "秩序";
    case A_NONE:
/*JP
        return "unaligned";
*/
        return "無心";
    }
/*JP
    return "unknown";
*/
    return "不明";
}

/* used for self-probing */
char *
piousness(showneg, suffix)
boolean showneg;
const char *suffix;
{
    static char buf[32]; /* bigger than "insufficiently neutral" */
    const char *pio;

    /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */
    if (u.ualign.record >= 20)
/*JP
        pio = "piously";
*/
        pio = "敬虔な";
    else if (u.ualign.record > 13)
/*JP
        pio = "devoutly";
*/
        pio = "信心深い";
    else if (u.ualign.record > 8)
/*JP
        pio = "fervently";
*/
        pio = "熱心な";
    else if (u.ualign.record > 3)
/*JP
        pio = "stridently";
*/
        pio = "大げさな";
    else if (u.ualign.record == 3)
        pio = "";
    else if (u.ualign.record > 0)
/*JP
        pio = "haltingly";
*/
        pio = "不完全な";
    else if (u.ualign.record == 0)
/*JP
        pio = "nominally";
*/
        pio = "形だけの";
    else if (!showneg)
/*JP
        pio = "insufficiently";
*/
        pio = "不十分な";
    else if (u.ualign.record >= -3)
/*JP
        pio = "strayed";
*/
        pio = "迷いを持った";
    else if (u.ualign.record >= -8)
/*JP
        pio = "sinned";
*/
        pio = "罪を負った";
    else
/*JP
        pio = "transgressed";
*/
        pio = "逸脱した";

    Sprintf(buf, "%s", pio);
    if (suffix && (!showneg || u.ualign.record >= 0)) {
#if 0 /*JP*/
        if (u.ualign.record != 3)
            Strcat(buf, " ");
#endif
        Strcat(buf, suffix);
    }
    return buf;
}

/* stethoscope or probing applied to monster -- one-line feedback */
void
mstatusline(mtmp)
struct monst *mtmp;
{
    aligntyp alignment = mon_aligntyp(mtmp);
    char info[BUFSZ], monnambuf[BUFSZ];

    info[0] = 0;
    if (mtmp->mtame) {
/*JP
        Strcat(info, ", tame");
*/
        Strcat(info, ", 飼いならされている");
        if (wizard) {
            Sprintf(eos(info), " (%d", mtmp->mtame);
            if (!mtmp->isminion)
                Sprintf(eos(info), "; hungry %ld; apport %d",
                        EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport);
            Strcat(info, ")");
        }
    } else if (mtmp->mpeaceful)
/*JP
        Strcat(info, ", peaceful");
*/
        Strcat(info, ", 友好的");

    if (mtmp->data == &mons[PM_LONG_WORM]) {
        int segndx, nsegs = count_wsegs(mtmp);

        /* the worm code internals don't consider the head of be one of
           the worm's segments, but we count it as such when presenting
           worm feedback to the player */
        if (!nsegs) {
/*JP
            Strcat(info, ", single segment");
*/
            Strcat(info, ", 全体");
        } else {
            ++nsegs; /* include head in the segment count */
            segndx = wseg_at(mtmp, bhitpos.x, bhitpos.y);
#if 0 /*JP:T*/
            Sprintf(eos(info), ", %d%s of %d segments",
                    segndx, ordin(segndx), nsegs);
#else
            Sprintf(eos(info), ", %d節のうち%d番目",
                    nsegs, segndx);
#endif
        }
    }
    if (mtmp->cham >= LOW_PM && mtmp->data != &mons[mtmp->cham])
        /* don't reveal the innate form (chameleon, vampire, &c),
           just expose the fact that this current form isn't it */
/*JP
        Strcat(info, ", shapechanger");
*/
        Strcat(info, ", 変化");
    /* pets eating mimic corpses mimic while eating, so this comes first */
    if (mtmp->meating)
/*JP
        Strcat(info, ", eating");
*/
        Strcat(info, ", 食事中");
    /* a stethoscope exposes mimic before getting here so this
       won't be relevant for it, but wand of probing doesn't */
    if (mtmp->mundetected || mtmp->m_ap_type)
        mhidden_description(mtmp, TRUE, eos(info));
    if (mtmp->mcan)
/*JP
        Strcat(info, ", cancelled");
*/
        Strcat(info, ", 無力");
    if (mtmp->mconf)
/*JP
        Strcat(info, ", confused");
*/
        Strcat(info, ", 混乱状態");
    if (mtmp->mblinded || !mtmp->mcansee)
/*JP
        Strcat(info, ", blind");
*/
        Strcat(info, ", 盲目");
    if (mtmp->mstun)
/*JP
        Strcat(info, ", stunned");
*/
        Strcat(info, ", くらくら状態");
    if (mtmp->msleeping)
/*JP
        Strcat(info, ", asleep");
*/
        Strcat(info, ", 睡眠状態");
#if 0 /* unfortunately mfrozen covers temporary sleep and being busy \
         (donning armor, for instance) as well as paralysis */
    else if (mtmp->mfrozen)
        Strcat(info, ", paralyzed");
#else
    else if (mtmp->mfrozen || !mtmp->mcanmove)
/*JP
        Strcat(info, ", can't move");
*/
        Strcat(info, ", 動けない");
#endif
    /* [arbitrary reason why it isn't moving] */
    else if (mtmp->mstrategy & STRAT_WAITMASK)
/*JP
        Strcat(info, ", meditating");
*/
        Strcat(info, ", 冥想中");
    if (mtmp->mflee)
/*JP
        Strcat(info, ", scared");
*/
        Strcat(info, ", 怯えている");
    if (mtmp->mtrapped)
/*JP
        Strcat(info, ", trapped");
*/
        Strcat(info, ", 罠にかかっている");
    if (mtmp->mspeed)
#if 0 /*JP:T*/
        Strcat(info, (mtmp->mspeed == MFAST) ? ", fast"
                      : (mtmp->mspeed == MSLOW) ? ", slow"
                         : ", [? speed]");
#else
        Strcat(info, (mtmp->mspeed == MFAST) ? ", 素早い"
                      : (mtmp->mspeed == MSLOW) ? ", 遅い"
                         : ", 速度不明");
#endif
    if (mtmp->minvis)
/*JP
        Strcat(info, ", invisible");
*/
        Strcat(info, ", 不可視");
    if (mtmp == u.ustuck)
#if 0 /*JP:T*/
        Strcat(info, sticks(youmonst.data) ? ", held by you"
                      : !u.uswallow ? ", holding you"
                         : attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST)
                            ? ", digesting you"
                            : is_animal(u.ustuck->data) ? ", swallowing you"
                               : ", engulfing you");
#else
        Strcat(info, sticks(youmonst.data) ? ", あなたが掴まえている"
                      : !u.uswallow ? ", 掴まえている"
                         : attacktype_fordmg(u.ustuck->data, AT_ENGL, AD_DGST)
                            ? ", 消化している"
                            : is_animal(u.ustuck->data) ? ", 飲み込んでいる"
                               : ", 巻き込んでいる");
#endif
    if (mtmp == u.usteed)
/*JP
        Strcat(info, ", carrying you");
*/
        Strcat(info, ", あなたを乗せている");

    /* avoid "Status of the invisible newt ..., invisible" */
    /* and unlike a normal mon_nam, use "saddled" even if it has a name */
    Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *) 0,
                               (SUPPRESS_IT | SUPPRESS_INVISIBLE), FALSE));

/*JP
    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", monnambuf,
*/
    pline("%sの状態 (%s)： Level %d  HP %d(%d)  AC %d%s", monnambuf,
          align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax,
          find_mac(mtmp), info);
}

/* stethoscope or probing applied to hero -- one-line feedback */
void
ustatusline()
{
    char info[BUFSZ];

    info[0] = '\0';
    if (Sick) {
#if 0 /*JP*/
        Strcat(info, ", dying from");
        if (u.usick_type & SICK_VOMITABLE)
            Strcat(info, " food poisoning");
        if (u.usick_type & SICK_NONVOMITABLE) {
            if (u.usick_type & SICK_VOMITABLE)
                Strcat(info, " and");
            Strcat(info, " illness");
        }
#else
        Strcat(info, ", ");
        if (u.usick_type & SICK_VOMITABLE)
            Strcat(info, "食中毒");
        if (u.usick_type & SICK_NONVOMITABLE) {
            if (u.usick_type & SICK_VOMITABLE)
                Strcat(info, "と");
            Strcat(info, "病気");
        }
        Strcat(info, "で死につつある");
#endif
    }
    if (Stoned)
/*JP
        Strcat(info, ", solidifying");
*/
        Strcat(info, ", 石化しつつある");
    if (Slimed)
/*JP
        Strcat(info, ", becoming slimy");
*/
        Strcat(info, ", スライムになりつつある");
    if (Strangled)
/*JP
        Strcat(info, ", being strangled");
*/
        Strcat(info, ", 首を絞められている");
    if (Vomiting)
#if 0 /*JP:T*/
        Strcat(info, ", nauseated"); /* !"nauseous" */
#else
        Strcat(info, ", 吐き気がする");
#endif
    if (Confusion)
/*JP
        Strcat(info, ", confused");
*/
        Strcat(info, ", 混乱状態");
    if (Blind) {
#if 0 /*JP*/
        Strcat(info, ", blind");
        if (u.ucreamed) {
            if ((long) u.ucreamed < Blinded || Blindfolded
                || !haseyes(youmonst.data))
                Strcat(info, ", cover");
            Strcat(info, "ed by sticky goop");
        } /* note: "goop" == "glop"; variation is intentional */
#else
        Strcat(info, ", ");
        if (u.ucreamed) {
            Strcat(info, "ねばねばべとつくもので");
            if ((long)u.ucreamed < Blinded || Blindfolded
                || !haseyes(youmonst.data))
              Strcat(info, "覆われて");
        }
        Strcat(info, "盲目状態");
#endif
    }
    if (Stunned)
/*JP
        Strcat(info, ", stunned");
*/
        Strcat(info, ", くらくら状態");
    if (!u.usteed && Wounded_legs) {
        const char *what = body_part(LEG);
        if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES)
            what = makeplural(what);
/*JP
        Sprintf(eos(info), ", injured %s", what);
*/
        Sprintf(eos(info), ", %sにけがをしている", what);
    }
    if (Glib)
/*JP
        Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND)));
*/
        Sprintf(eos(info), ", %sがぬるぬる", makeplural(body_part(HAND)));
    if (u.utrap)
/*JP
        Strcat(info, ", trapped");
*/
        Strcat(info, ", 罠にかかっている");
    if (Fast)
/*JP
        Strcat(info, Very_fast ? ", very fast" : ", fast");
*/
        Strcat(info, Very_fast ? ", とても素早い" : ", 素早い");
    if (u.uundetected)
/*JP
        Strcat(info, ", concealed");
*/
        Strcat(info, ", 隠れている");
    if (Invis)
/*JP
        Strcat(info, ", invisible");
*/
        Strcat(info, ", 不可視");
    if (u.ustuck) {
#if 0 /*JP*/
        if (sticks(youmonst.data))
            Strcat(info, ", holding ");
        else
            Strcat(info, ", held by ");
        Strcat(info, mon_nam(u.ustuck));
#else
        Strcat(info, ", ");
        Strcat(info, mon_nam(u.ustuck));
        if (sticks(youmonst.data))
            Strcat(info, "を掴まえている");
        else
            Strcat(info, "に掴まえられている");
#endif
    }

/*JP
    pline("Status of %s (%s):  Level %d  HP %d(%d)  AC %d%s.", plname,
*/
    pline("%sの状態 (%s)： Level %d  HP %d(%d)  AC %d%s", plname,
          piousness(FALSE, align_str(u.ualign.type)),
          Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp,
          Upolyd ? u.mhmax : u.uhpmax, u.uac, info);
}

/*priest.c*/
