/*	SCCS Id: @(#)invent.c	3.2	96/07/06	*/
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

/*
**	Japanese version Copyright
**	(c) Issei Numata, Naoki Hamada, Shigehiro Miyashita, 1994-1999
**	changing point is marked `JP' (94/6/7)
**	JNetHack may be freely redistributed.  See license for details. 
*/

#include "hack.h"
#include "artifact.h"

#define NOINVSYM	'#'
#define CONTAINED_SYM	'>'	/* designator for inside a container */

#ifdef OVL1
static void NDECL(reorder_invent);
static boolean FDECL(mergable,(struct obj *,struct obj *));
static void FDECL(invdisp_nothing, (const char *,const char *));
static boolean FDECL(worn_wield_only, (struct obj *));
static boolean FDECL(only_here, (struct obj *));
#endif /* OVL1 */
STATIC_DCL void FDECL(compactify,(char *));
STATIC_PTR int FDECL(ckunpaid,(struct obj *));
#ifdef OVLB
static boolean FDECL(this_type_only, (struct obj *));
static void NDECL(dounpaid);
static struct obj *FDECL(find_unpaid,(struct obj *,struct obj **));
static void FDECL(fully_identify_obj, (struct obj *));
static void FDECL(menu_identify, (int));
#endif /* OVLB */
STATIC_DCL char FDECL(obj_to_let,(struct obj *));


#ifdef OVLB

static int lastinvnr = 51;	/* 0 ... 51 (never saved&restored) */

#ifdef WIZARD
/* wizards can wish for venom, which will become an invisible inventory
 * item without this.  putting it in inv_order would mean venom would
 * suddenly become a choice for all the inventory-class commands, which
 * would probably cause mass confusion.  the test for inventory venom
 * is only WIZARD and not wizard because the wizard can leave venom lying
 * around on a bones level for normal players to find.
 */
static char venom_inv[] = { VENOM_CLASS, 0 };	/* (constant) */
#endif

void
assigninvlet(otmp)
register struct obj *otmp;
{
	boolean inuse[52];
	register int i;
	register struct obj *obj;

	for(i = 0; i < 52; i++) inuse[i] = FALSE;
	for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) {
		i = obj->invlet;
		if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else
		if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE;
		if(i == otmp->invlet) otmp->invlet = 0;
	}
	if((i = otmp->invlet) &&
	    (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z')))
		return;
	for(i = lastinvnr+1; i != lastinvnr; i++) {
		if(i == 52) { i = -1; continue; }
		if(!inuse[i]) break;
	}
	otmp->invlet = (inuse[i] ? NOINVSYM :
			(i < 26) ? ('a'+i) : ('A'+i-26));
	lastinvnr = i;
}

#endif /* OVLB */
#ifdef OVL1

/* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */
#define inv_rank(o) ((o)->invlet ^ 040)

/* sort the inventory; used by addinv() and doorganize() */
static void
reorder_invent()
{
	struct obj *otmp, *prev, *next;
	boolean need_more_sorting;

	do {
	    /*
	     * We expect at most one item to be out of order, so this
	     * isn't nearly as inefficient as it may first appear.
	     */
	    need_more_sorting = FALSE;
	    for (otmp = invent, prev = 0; otmp; ) {
		next = otmp->nobj;
		if (next && inv_rank(next) < inv_rank(otmp)) {
		    need_more_sorting = TRUE;
		    if (prev) prev->nobj = next;
		    else      invent = next;
		    otmp->nobj = next->nobj;
		    next->nobj = otmp;
		    prev = next;
		} else {
		    prev = otmp;
		    otmp = next;
		}
	    }
	} while (need_more_sorting);
}

#undef inv_rank

/* scan a list of objects to see whether another object will merge with
   one of them; used in pickup.c when all 52 inventory slots are in use,
   to figure out whether another object could still be picked up */
struct obj *
merge_choice(objlist, obj)
struct obj *objlist, *obj;
{
	struct monst *shkp;
	int save_nocharge;

	if (obj->otyp == SCR_SCARE_MONSTER)	/* punt on these */
	    return (struct obj *)0;
	/* if this is an item on the shop floor, the attributes it will
	   have when carried are different from what they are now; prevent
	   that from eliciting an incorrect result from mergable() */
	save_nocharge = obj->no_charge;
	if (objlist == invent && obj->where == OBJ_FLOOR &&
		(shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) {
	    if (obj->no_charge) obj->no_charge = 0;
	    /* A billable object won't have its `unpaid' bit set, so would
	       erroneously seem to be a candidate to merge with a similar
	       ordinary object.  That's no good, because once it's really
	       picked up, it won't merge after all.  It might merge with
	       another unpaid object, but we can't check that here (depends
	       too much upon shk's bill) and if it doesn't merge it would
	       end up in the '#' overflow inventory slot, so reject it now. */
	    else if (inhishop(shkp)) return (struct obj *)0;
	}
	while (objlist) {
	    if (mergable(objlist, obj)) break;
	    objlist = objlist->nobj;
	}
	obj->no_charge = save_nocharge;
	return objlist;
}

/* merge obj with otmp and delete obj if types agree */
int
merged(potmp, pobj)
struct obj **potmp, **pobj;
{
	register struct obj *otmp = *potmp, *obj = *pobj;

	if(mergable(otmp, obj)) {
		/* Approximate age: we do it this way because if we were to
		 * do it "accurately" (merge only when ages are identical)
		 * we'd wind up never merging any corpses.
		 * otmp->age = otmp->age*(1-proportion) + obj->age*proportion;
		 *
		 * Don't do the age manipulation if lit.  We would need
		 * to stop the burn on both items, then merge the age,
		 * then restart the burn.
		 */
		if (!obj->lamplit)
		    otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan))
			    / (otmp->quan + obj->quan);

		otmp->quan += obj->quan;
		otmp->owt += obj->owt;
		if(!otmp->onamelth && obj->onamelth)
			otmp = *potmp = oname(otmp, ONAME(obj));
		obj_extract_self(obj);

		/* really should merge the timeouts */
		if (obj->lamplit) end_burn(obj, TRUE);
		if (obj->timed) obj_stop_timers(obj);	/* follows end_burn */

		/* fixup for `#adjust' merging wielded darts, daggers, &c */
		if (obj->owornmask) {
			otmp->owornmask |= obj->owornmask;
			/* (it isn't necessary to "unwear" `obj' first) */
			if (otmp->where == OBJ_INVENT)
			    setworn(otmp, otmp->owornmask);
#if 0
			/* (this should never be necessary, since items
			    already in a monster's inventory don't ever get
			    merged into other objects [only vice versa]) */
			else if (otmp->where == OBJ_MINVENT) {
			    if (obj == MON_WEP(otmp->ocarry))
				MON_WEP(otmp->ocarry) = otmp;
			}
#endif
		}
		obfree(obj,otmp);	/* free(obj), bill->otmp */
		return(1);
	}
	return 0;
}

struct obj *
addinv(obj)
struct obj *obj;
{
	struct obj *otmp, *prev;

	if (obj->where != OBJ_FREE)
		panic("addinv: obj not free");

	if (obj->oclass == GOLD_CLASS) {
		u.ugold += obj->quan;
		flags.botl = 1;
		return obj;
	} else if (obj->otyp == AMULET_OF_YENDOR) {
		if (u.uhave.amulet) impossible("already have amulet?");
		u.uhave.amulet = 1;
	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
		if (u.uhave.menorah) impossible("already have candelabrum?");
		u.uhave.menorah = 1;
	} else if (obj->otyp == BELL_OF_OPENING) {
		if (u.uhave.bell) impossible("already have silver bell?");
		u.uhave.bell = 1;
	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
		if (u.uhave.book) impossible("already have the book?");
		u.uhave.book = 1;
	} else if (obj->oartifact) {
		if (is_quest_artifact(obj)) {
		    if (u.uhave.questart)
			impossible("already have quest artifact?");
		    u.uhave.questart = 1;
		    artitouch();
		}
		set_artifact_intrinsic(obj, 1, W_ART);
	}
	/* merge if possible; find end of chain in the process */
	for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj)
	    if (merged(&otmp, &obj)) {
		obj = otmp;
		goto added;
	    }
	/* didn't merge, so insert into chain */
	if (flags.invlet_constant || !prev) {
	    if (flags.invlet_constant) assigninvlet(obj);
	    obj->nobj = invent;		/* insert at beginning */
	    invent = obj;
	    if (flags.invlet_constant) reorder_invent();
	} else {
	    prev->nobj = obj;		/* insert at end */
	    obj->nobj = 0;
	}
	obj->where = OBJ_INVENT;

added:
	if (obj->otyp == LUCKSTONE ||
	    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
		/* new luckstone must be in inventory by this point
		 * for correct calculation */
		set_moreluck();
	}
	update_inventory();
	return(obj);
}

#endif /* OVL1 */
#ifdef OVLB

/* Add an item to the inventory unless we're fumbling, and give a message.
 * If there aren't any free inventory slots, we'll drop it instead.
 * If both success and failure messages are NULL, then we're just doing the
 * fumbling/slot-limit checking for a silent grab.
 */
struct obj *
hold_another_object(obj, drop_fmt, drop_arg, hold_msg)
struct obj *obj;
const char *drop_fmt, *drop_arg, *hold_msg;
{
	if (!Blind) obj->dknown = 1;	/* maximize mergibility */
	if (Fumbling) {
		if (drop_fmt) pline(drop_fmt, drop_arg);
		dropy(obj);
	} else {
		long oquan = obj->quan;
		int prev_encumbr = near_capacity();	/* before addinv() */
		/* encumbrance only matters if it would now become worse
		   than max( current_value, stressed ) */
		if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER;
		obj = addinv(obj);
		if (inv_cnt() > 52
		    || ((obj->otyp != LOADSTONE || !obj->cursed)
			&& near_capacity() > prev_encumbr)) {
			if (drop_fmt) pline(drop_fmt, drop_arg);
			/* undo any merge which took place */
			if (obj->quan > oquan) {
			    struct obj *otmp = splitobj(obj, oquan);
			    /* might have merged with weapon */
			    if (obj->owornmask)
				setworn(otmp, obj->owornmask);
			}
			dropx(obj);
		} else {
			if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan);
		}
	}
	return obj;
}

void
useup(obj)
register struct obj *obj;
{
	/*  Note:  This works correctly for containers because they */
	/*	   (containers) don't merge.			    */
	if(obj->quan > 1L){
#ifndef NO_SIGNAL
		obj->in_use = FALSE;	/* no longer in use */
#endif
		obj->quan--;
		obj->owt = weight(obj);
		update_inventory();
	} else {
		setnotworn(obj);
		freeinv(obj);
		obfree(obj, (struct obj *) 0);	/* deletes contents also */
	}
}

#endif /* OVLB */
#ifdef OVL3

void
freeinv(obj)
register struct obj *obj;
{
	extract_nobj(obj, &invent);

	if (obj->oclass == GOLD_CLASS) {
		u.ugold -= obj->quan;
		flags.botl = 1;
		return;
	} else if (obj->otyp == AMULET_OF_YENDOR) {
		if (!u.uhave.amulet) impossible("don't have amulet?");
		u.uhave.amulet = 0;
	} else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
		if (!u.uhave.menorah) impossible("don't have candelabrum?");
		u.uhave.menorah = 0;
	} else if (obj->otyp == BELL_OF_OPENING) {
		if (!u.uhave.bell) impossible("don't have silver bell?");
		u.uhave.bell = 0;
	} else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
		if (!u.uhave.book) impossible("don't have the book?");
		u.uhave.book = 0;
	} else if (obj->oartifact) {
		if (is_quest_artifact(obj)) {
		    if (!u.uhave.questart)
			impossible("don't have quest artifact?");
		    u.uhave.questart = 0;
		}
		set_artifact_intrinsic(obj, 0, W_ART);
	}

	if (obj->otyp == LOADSTONE) {
		curse(obj);
	} else if (obj->otyp == LUCKSTONE ||
		    (obj->oartifact && spec_ability(obj, SPFX_LUCK))) {
		set_moreluck();
		flags.botl = 1;
	}
	update_inventory();
}

void
delallobj(x, y)
int x, y;
{
	struct obj *otmp, *otmp2;

	for (otmp = level.objects[x][y]; otmp; otmp = otmp2) {
		if (otmp == uball)
			unpunish();
		/* after unpunish(), or might get deallocated chain */
		otmp2 = otmp->nexthere;
		if (otmp == uchain)
			continue;
		delobj(otmp);
	}
}

#endif /* OVL3 */
#ifdef OVL2

/* destroy object in fobj chain (if unpaid, it remains on the bill) */
void
delobj(obj)
register struct obj *obj;
{
	boolean update_map;

	if (obj->otyp == AMULET_OF_YENDOR ||
			obj->otyp == CANDELABRUM_OF_INVOCATION ||
			obj->otyp == BELL_OF_OPENING ||
			obj->otyp == SPE_BOOK_OF_THE_DEAD) {
		/* player might be doing something stupid, but we
		 * can't guarantee that.  assume special artifacts
		 * are indestructible via drawbridges, and exploding
		 * chests, and golem creation, and ...
		 */
		return;
	}
	update_map = (obj->where == OBJ_FLOOR);
	obj_extract_self(obj);
	if (update_map) newsym(obj->ox, obj->oy);
	obfree(obj, (struct obj *) 0);	/* frees contents also */
}

#endif /* OVL2 */
#ifdef OVL0

struct obj *
sobj_at(n,x,y)
register int n, x, y;
{
	register struct obj *otmp;

	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
		if(otmp->otyp == n)
		    return(otmp);
	return((struct obj *)0);
}

#endif /* OVL0 */
#ifdef OVLB

struct obj *
carrying(type)
register int type;
{
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->otyp == type)
			return(otmp);
	return((struct obj *) 0);
}

boolean
have_lizard()
{
	register struct obj *otmp;

	for(otmp = invent; otmp; otmp = otmp->nobj)
		if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD)
			return(TRUE);
	return(FALSE);
}

struct obj *
o_on(id, objchn)
unsigned int id;
register struct obj *objchn;
{
	struct obj *temp;

	while(objchn) {
		if(objchn->o_id == id) return(objchn);
		if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj)))
			return temp;
		objchn = objchn->nobj;
	}
	return((struct obj *) 0);
}

boolean
obj_here(obj, x, y)
register struct obj *obj;
int x, y;
{
	register struct obj *otmp;

	for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere)
		if(obj == otmp) return(TRUE);
	return(FALSE);
}

#endif /* OVLB */
#ifdef OVL2

struct obj *
g_at(x,y)
register int x, y;
{
	register struct obj *obj = level.objects[x][y];
	while(obj) {
	    if (obj->oclass == GOLD_CLASS) return obj;
	    obj = obj->nexthere;
	}
	return((struct obj *)0);
}

#endif /* OVL2 */
#ifdef OVLB

/* Make a gold object from the hero's gold. */
struct obj *
mkgoldobj(q)
register long q;
{
	register struct obj *otmp;

	otmp = mksobj(GOLD_PIECE, FALSE, FALSE);
	u.ugold -= q;
	otmp->quan = q;
	otmp->owt = weight(otmp);
	flags.botl = 1;
	return(otmp);
}

#endif /* OVLB */
#ifdef OVL1

STATIC_OVL void
compactify(buf)
register char *buf;
/* compact a string of inventory letters by dashing runs of letters */
{
	register int i1 = 1, i2 = 1;
	register char ilet, ilet1, ilet2;

	ilet2 = buf[0];
	ilet1 = buf[1];
	buf[++i2] = buf[++i1];
	ilet = buf[i1];
	while(ilet) {
		if(ilet == ilet1+1) {
			if(ilet1 == ilet2+1)
				buf[i2 - 1] = ilet1 = '-';
			else if(ilet2 == '-') {
				buf[i2 - 1] = ++ilet1;
				buf[i2] = buf[++i1];
				ilet = buf[i1];
				continue;
			}
		}
		ilet2 = ilet1;
		ilet1 = ilet;
		buf[++i2] = buf[++i1];
		ilet = buf[i1];
	}
}

/*
 * getobj returns:
 *	struct obj *xxx:	object to do something with.
 *	(struct obj *) 0	error return: no object.
 *	&zeroobj		explicitly no object (as in w-).
 */
/*JP
** word には動詞が入る．
**
** 日本語では，「どれを書きますか」より「どれに書きますか」の方が自然なので，
** 最初の一文字に「に」や「の」を指定した場合は助詞を変更する．
**
*/
struct obj *
getobj(let,word)
register const char *let,*word;
{
	register struct obj *otmp;
	register char ilet;
	char buf[BUFSZ], qbuf[QBUFSZ];
	char lets[BUFSZ];
	register int foo = 0;
	register char *bp = buf;
	xchar allowcnt = 0;	/* 0, 1 or 2 */
	boolean allowgold = FALSE, usegold = FALSE;
		/* Two possibilities: they can't use gold because it's illegal,
		 * or they can't use gold because they don't have any.
		 */
	boolean allowall = FALSE;
	boolean allownone = FALSE;
	xchar foox = 0;
	long cnt;
	boolean prezero = FALSE;

/*JP*/
	const char *joshi = "を";
	const char *what = "どれ";

	if(!strncmp(word, "に", 2)){
	  word += 2;
	  joshi = "に";
	}
	else if(!strncmp(word, "の", 2)){
	  word += 2;
	  joshi = "の";
	  what = "ど";
	}

	if(*let == ALLOW_COUNT) let++, allowcnt = 1;
	if(*let == GOLD_CLASS) let++,
		usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE);

	/* Equivalent of an "ugly check" for gold */
/*JP	if (usegold && !strcmp(word, "eat") && !metallivorous(uasmon))*/
	if (usegold && (!strcmp(word, "eat")||!strcmp(word,"食べる")) && !metallivorous(uasmon))
		usegold = allowgold = FALSE;

	if(*let == ALL_CLASSES) let++, allowall = TRUE;
	if(*let == ALLOW_NONE) let++, allownone = TRUE;
	/* "ugly check" for reading fortune cookies, part 1 */
	/* The normal 'ugly check' keeps the object on the inventory list.
	 * We don't want to do that for shirts/cookies, so the check for
	 * them is handled a bit differently (and also requires that we set
	 * allowall in the caller)
	 */
/*JP	if(allowall && !strcmp(word, "read")) allowall = FALSE;*/
	if(allowall && (!strcmp(word, "read")||!strcmp(word,"読む")))
	  allowall = FALSE;

	if(allownone) *bp++ = '-';
	if(allowgold) *bp++ = def_oc_syms[GOLD_CLASS];
	if(bp > buf && bp[-1] == '-') *bp++ = ' ';

	ilet = 'a';
	for (otmp = invent; otmp; otmp = otmp->nobj) {
	    if (!flags.invlet_constant) otmp->invlet = ilet;	/* reassign() */
	    if (!*let || index(let, otmp->oclass)) {
		register int otyp = otmp->otyp;
		bp[foo++] = otmp->invlet;

		/* ugly check: remove inappropriate things */
/*JP		if((!strcmp(word, "take off") &&*/
		if(((!strcmp(word, "take off")||!strcmp(word,"脱ぐ")||!strcmp(word,"はずす")||!strcmp(word,"装備を解く")) &&
		    (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))
		     || (otmp==uarm && uarmc)
#ifdef TOURIST
		     || (otmp==uarmu && (uarm || uarmc))
#endif
		    ))
/*JP		|| (!strcmp(word, "wear") &&*/
		|| ((!strcmp(word, "wear")||!strcmp(word,"着る")||!strcmp(word,"身につける")) &&
		     (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)))
							/* already worn */
/*JP		|| (!strcmp(word, "wield") &&*/
		|| ((!strcmp(word, "wield")||!strcmp(word,"装備する")) &&
		    (otmp->owornmask & W_WEP))
		    ) {
			foo--;
			foox++;
		}

		/* Second ugly check; unlike the first it won't trigger an
		 * "else" in "you don't have anything else to ___".
		 */
/*JP		else if ((!strcmp(word, "wear") &&*/
		else if (((!strcmp(word, "wear")||!strcmp(word,"身につける")) &&
		    (otmp->oclass == TOOL_CLASS &&
		     otyp != BLINDFOLD && otyp != TOWEL))
/*JP		|| (!strcmp(word, "wield") &&*/
		|| ((!strcmp(word, "wield")||!strcmp(word,"装備する")) &&
		    (otmp->oclass == TOOL_CLASS && !is_weptool(otmp)))
/*JP		|| (!strcmp(word, "eat") && !is_edible(otmp))*/
		|| ((!strcmp(word, "eat")||!strcmp(word,"食べる")) && !is_edible(otmp))
/*JP		|| (!strcmp(word, "sacrifice") &&*/
		|| ((!strcmp(word, "sacrifice")||!strcmp(word,"捧げる")) &&
		    (otyp != CORPSE &&
		     otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR))
/*JP		|| (!strcmp(word, "write with") &&*/
		|| ((!strcmp(word, "write with")||!strcmp(word,"使って書く")) &&
		    (otmp->oclass == TOOL_CLASS &&
		     otyp != MAGIC_MARKER && otyp != TOWEL))
/*JP		|| (!strcmp(word, "tin") &&*/
		|| ((!strcmp(word, "tin")||!strcmp(word,"かん詰めにする")) &&
		    (otyp != CORPSE || !tinnable(otmp)))
/*JP		|| (!strcmp(word, "rub") &&*/
		|| ((!strcmp(word, "rub")||!strcmp(word,"こする")) &&
		    (otmp->oclass == TOOL_CLASS &&
		     otyp != OIL_LAMP && otyp != MAGIC_LAMP &&
		     otyp != BRASS_LANTERN))
/*JP		|| ((!strcmp(word, "use or apply") ||
			!strcmp(word, "untrap with")) &&*/
		|| ((!strcmp(word, "use or apply") || !strcmp(word, "使う") ||
			!strcmp(word, "untrap with") || !strcmp(word, "使って罠をはずす")) &&
		     /* only applicable weapon is BULLWHIP */
		    ((otmp->oclass == WEAPON_CLASS && otyp != BULLWHIP)
		|| (otmp->oclass == POTION_CLASS &&
		     /* only applicable potion is oil, and it will only
			be offered as a choice when already discovered */
		     (otyp != POT_OIL || !otmp->dknown ||
		      !objects[POT_OIL].oc_name_known))))
/*JP		|| (!strcmp(word, "invoke") &&*/
		|| ((!strcmp(word, "invoke") || !strcmp(word, "魔力を使う")) &&
		    (!otmp->oartifact && !objects[otyp].oc_unique &&
		     (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) &&
		     otyp != CRYSTAL_BALL &&	/* #invoke synonym for apply */
		   /* note: presenting the possibility of invoking non-artifact
		      mirrors and/or lamps is a simply a cruel deception... */
		     otyp != MIRROR && otyp != MAGIC_LAMP &&
		     (otyp != OIL_LAMP ||	/* don't list known oil lamp */
		      (otmp->dknown && objects[OIL_LAMP].oc_name_known))))
/*JP		|| (!strcmp(word, "untrap with") &&*/
		|| ((!strcmp(word, "untrap with") || !strcmp(word, "使って罠をはずす")) &&
		    (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE))
/*JP		|| (!strcmp(word, "charge") && !is_chargeable(otmp))*/
		|| ((!strcmp(word, "charge") || !strcmp(word, "充填する")) && !is_chargeable(otmp))
		    )
			foo--;
	    } else {

		/* "ugly check" for reading fortune cookies, part 2 */
/*JP		if ((!strcmp(word, "read") &&*/
		if (((!strcmp(word, "read")||!strcmp(word, "読む")) &&
		    (otmp->otyp == FORTUNE_COOKIE
#ifdef TOURIST
			|| otmp->otyp == T_SHIRT
		    )))
			allowall = TRUE;
	    }
#endif

	    if(ilet == 'z') ilet = 'A'; else ilet++;
	}
	bp[foo] = 0;
	if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0;
	Strcpy(lets, bp);	/* necessary since we destroy buf */
	if(foo > 5)			/* compactify string */
		compactify(bp);

	if(!foo && !allowall && !allowgold && !allownone) {
/*JP		You("don't have anything %sto %s.",
			foox ? "else " : "", word);*/
		You("%s%sものを持っていない．",
			foox ? "他に" : "", jconj(word, "れる"));
		return((struct obj *)0);
	}
	for(;;) {
		cnt = 0;
		if (allowcnt == 2) allowcnt = 1;  /* abort previous count */
		if(!buf[0]) {
/*JP			Sprintf(qbuf, "What do you want to %s? [*]", word);*/
			Sprintf(qbuf, "%s%s%sか？[*]", what, joshi, jconj(word,"ます"));
		} else {
/*JP			Sprintf(qbuf, "What do you want to %s? [%s or ?*]",*/
			Sprintf(qbuf, "%s%s%sか？[%s or ?*]", what, joshi,
				jconj(word,"ます"), buf);
		}
#ifdef REDO
		if (in_doagain)
		    ilet = readchar();
		else
#endif
		    ilet = yn_function(qbuf, (char *)0, '\0');
		if(ilet == '0') prezero = TRUE;
		while(digit(ilet) && allowcnt) {
#ifdef REDO
			if (ilet != '?' && ilet != '*')	savech(ilet);
#endif
			cnt = 10*cnt + (ilet - '0');
			allowcnt = 2;	/* signal presence of cnt */
			ilet = readchar();
		}
		if(digit(ilet)) {
/*JP			pline("No count allowed with this command.");*/
			pline("このコマンドに数字はつかえない．");
			continue;
		}
		if(index(quitchars,ilet)) {
		    if(flags.verbose)
/*JP			pline("Never mind.");*/
			pline("え？");
		    return((struct obj *)0);
		}
		if(ilet == '-') {
			return(allownone ? &zeroobj : (struct obj *) 0);
		}
		if(ilet == def_oc_syms[GOLD_CLASS]) {
			if(!usegold){
/*JP				You("cannot %s gold.", word);*/
				You("金貨%s%sことはできない．", joshi,word);
				return(struct obj *)0;
			} else if (!allowgold) {
/*JP				You("are not carrying any gold.");*/
				You("一銭も持ってない．");
				return(struct obj *)0;
			}
			if(cnt == 0 && prezero) return((struct obj *)0);
			/* Historic note: early Nethack had a bug which was
			 * first reported for Larn, where trying to drop 2^32-n
			 * gold pieces was allowed, and did interesting things
			 * to your money supply.  The LRS is the tax bureau
			 * from Larn.
			 */
			if(cnt < 0) {
/*JP	pline_The("LRS would be very interested to know you have that much.");*/
	pline("その技はとあるゲームのカジノで使えたけど，もはや使えないよ．");
				return(struct obj *)0;
			}

			if(!(allowcnt == 2 && cnt < u.ugold))
				cnt = u.ugold;
			return(mkgoldobj(cnt));
		}
/*JP		if(allowcnt == 2 && !strcmp(word,"throw")) {*/
		if(allowcnt == 2 && (!strcmp(word,"throw")||!strcmp(word,"投げる"))) {
			/* permit counts for throwing gold, but don't accept
			 * counts for other things since the throw code will
			 * split off a single item anyway */
			allowcnt = 1;
			if(cnt == 0 && prezero) return((struct obj *)0);
			if(cnt > 1) {
/*JP			    You("can only throw one item at a time.");*/
			    You("同時にたくさんのものを投げられない．");
			    continue;
			}
		}
		if(ilet == '?' || ilet == '*') {
		    ilet = display_inventory(ilet=='?' ? lets:(char *)0, TRUE);
		    if(!ilet) continue;
		    if(ilet == '\033') {
			if(flags.verbose)
/*JP			    pline("Never mind.");*/
			    pline("え？");
			return((struct obj *)0);
		    }
		    /* they typed a letter (not a space) at the prompt */
		}
#ifdef REDO
		savech(ilet);
#endif
		for (otmp = invent; otmp; otmp = otmp->nobj)
			if (otmp->invlet == ilet) break;
		if(!otmp) {
/*JP			You("don't have that object.");*/
			You("そんなものを持ってない．");
#ifdef REDO
			if (in_doagain) return((struct obj *) 0);
#endif
			continue;
		} else if (cnt < 0 || otmp->quan < cnt) {
/*JP			You("don't have that many!  You have only %ld.",*/
			You("そんなに持てない！せいぜい%ldってこだ．",
			    otmp->quan);
#ifdef REDO
			if (in_doagain) return((struct obj *) 0);
#endif
			continue;
		}
		break;
	}
	if(!allowall && let && !index(let,otmp->oclass)) {
		pline(silly_thing_to, word);
		return((struct obj *)0);
	}
	if(allowcnt == 2) {	/* cnt given */
		if(cnt == 0) return (struct obj *)0;
		if(cnt != otmp->quan) {
			register struct obj *obj = splitobj(otmp, cnt);
		/* Very ugly kludge necessary to prevent someone from trying
		 * to drop one of several loadstones and having the loadstone
		 * now be separate.
		 */
/*JP			if (!strcmp(word, "drop") &&*/
			if ((!strcmp(word, "drop")||(!strcmp(word,"置く"))) &&
			    obj->otyp == LOADSTONE && obj->cursed)
				otmp->corpsenm = obj->invlet;
			if(otmp == uwep) setuwep(obj);
		}
	}
	return(otmp);
}

#endif /* OVL1 */
#ifdef OVLB

STATIC_PTR int
ckunpaid(otmp)
register struct obj *otmp;
{
	return((int)(otmp->unpaid));
}

boolean
wearing_armor()
{
	return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms
#ifdef TOURIST
		|| uarmu
#endif
		));
}

boolean
is_worn(otmp)
register struct obj *otmp;
{
    return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP))));
}

static NEARDATA const char removeables[] =
	{ ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 };

/* interactive version of getobj - used for Drop, Identify and */
/* Takeoff (A). Return the number of times fn was called successfully */
/* If combo is TRUE, we just use this to get a category list */
int
ggetobj(word, fn, mx, combo)
const char *word;
int FDECL((*fn),(OBJ_P)), mx;
boolean combo;		/* combination menu flag */
{
	int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0;
	boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0;
	boolean takeoff, ident, allflag, m_seen;
	int oletct, iletct, allowgold, unpaid, oc_of_sym;
	char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5];
	char buf[BUFSZ], qbuf[QBUFSZ];
/*JP*/
	const char *joshi = "を";

	if(!strncmp(word, "に", 2)){
	  word += 2;
	  joshi = "に";
	}
	else if(!strncmp(word, "の", 2)){
	  word += 2;
	  joshi = "の";
	}

/*JP	allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0;*/
	allowgold = (u.ugold && (!strcmp(word, "drop")||!strcmp(word, "置く"))) ? 1 : 0;
	takeoff = ident = allflag = m_seen = FALSE;
	if(!invent && !allowgold){
/*JP		You("have nothing to %s.", word);*/
		You("%sものは持っていない．", jcan(word));
		return(0);
	}
	if (combo) add_valid_menu_class(0);	/* reset */
/*JP	if (!strcmp(word, "take off")) {*/
	if (!strcmp(word, "take off")||!strcmp(word, "脱ぐ")||!strcmp(word, "はずす") || !strcmp(word, "装備を解く")) {
	    takeoff = TRUE;
	    filter = is_worn;
/*JP	} else if (!strcmp(word, "identify")) {*/
	} else if (!strcmp(word, "identify")|| !strcmp(word, "識別する")) {
	    ident = TRUE;
	    filter = not_fully_identified;
	}

	iletct = collect_obj_classes(ilets, invent,
				     FALSE, (allowgold != 0), filter);
	unpaid = count_unpaid(invent);

	if (ident && !iletct) {
	    return -1;		/* no further identifications */
	} else if (!takeoff && (unpaid || invent)) {
	    ilets[iletct++] = ' ';
	    if (unpaid) ilets[iletct++] = 'u';
	    if (invent) ilets[iletct++] = 'a';
	} else if (takeoff && invent) {
	    ilets[iletct++] = ' ';
	}
	ilets[iletct++] = 'i';
	if (!combo)
	    ilets[iletct++] = 'm';	/* allow menu presentation on request */
	ilets[iletct] = '\0';

	for (;;) {
/*JP	    Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]",*/
	    Sprintf(qbuf,"どの種類のもの%s%sか？[%s]",joshi,
		    jconj(word,"ます"), ilets);
	    getlin(qbuf, buf);
	    if (buf[0] == '\033') return(0);
	    if (index(buf, 'i')) {
		if (display_inventory((char *)0, TRUE) == '\033') return 0;
	    } else
		break;
	}

	ip = buf;
	olets[oletct = 0] = '\0';
	while ((sym = *ip++) != '\0') {
	    if (sym == ' ') continue;
	    oc_of_sym = def_char_to_objclass(sym);
	    if (takeoff && !(uwep && oc_of_sym == uwep->oclass) &&
		    (oc_of_sym != MAXOCLASSES)) {
		if (!index(removeables, oc_of_sym)) {
/*JP		    pline("Not applicable.");*/
		    pline("それはできない．");
		    return 0;
		} else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) {
/*JP		    You("are not wearing any armor.");*/
		    You("鎧を着ていない．");
		    return 0;
		} else if (oc_of_sym == WEAPON_CLASS && !uwep) {
/*JP		    You("are not wielding anything.");*/
		    You("何も装備していない．");
		    return 0;
		} else if (oc_of_sym == RING_CLASS && !uright && !uleft) {
/*JP		    You("are not wearing rings.");*/
		    You("指輪を身につけていない．");
		    return 0;
		} else if (oc_of_sym == AMULET_CLASS && !uamul) {
/*JP		    You("are not wearing an amulet.");*/
		    You("魔除けを身につけていない．");
		    return 0;
		} else if (oc_of_sym == TOOL_CLASS && !ublindf) {
/*JP		    You("are not wearing a blindfold.");*/
		    You("目隠しをしていない．");
		    return 0;
		}
	    }

	    if (oc_of_sym == GOLD_CLASS && !combo) {
		if (allowgold == 1)
		    (*fn)(mkgoldobj(u.ugold));
		else if (!u.ugold)
/*JP		    You("have no gold.");*/
		    You("一銭も持っていない．");
		allowgold = 2;
	    } else if (sym == 'a' || sym == 'A') {
		allflag = TRUE;
	    } else if (sym == 'u' || sym == 'U') {
		add_valid_menu_class('u');
		ckfn = ckunpaid;
	    } else if (sym == 'm') {
		m_seen = TRUE;
	    } else if (oc_of_sym == MAXOCLASSES) {
/*JP		You("don't have any %c's.", sym);*/
		You("%cに属する物を持っていない．", sym);
	    } else if (oc_of_sym != VENOM_CLASS) {	/* suppress venom */
		if (!index(olets, oc_of_sym)) {
		    add_valid_menu_class(oc_of_sym);
		    olets[oletct++] = oc_of_sym;
		    olets[oletct] = 0;
		}
	    }
	}

	if (m_seen)
	    return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3;
	else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag)
	    return 0;
	else if (allowgold == 2 && !oletct)
	    return 1;	/* you dropped gold (or at least tried to) */
	else
	    return askchain(&invent, olets, allflag, fn, ckfn, mx, word);
}

/*
 * Walk through the chain starting at objchn and ask for all objects
 * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull)
 * whether the action in question (i.e., fn) has to be performed.
 * If allflag then no questions are asked. Max gives the max nr of
 * objects to be treated. Return the number of objects treated.
 */
int
askchain(objchn, olets, allflag, fn, ckfn, mx, word)
struct obj **objchn;
register int allflag, mx;
register const char *olets, *word;	/* olets is an Obj Class char array */
register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P));
{
	register struct obj *otmp, *otmp2;
	register char sym, ilet;
	register int cnt = 0, dud = 0, tmp;
	boolean takeoff, nodot, ident, ininv;
	char qbuf[QBUFSZ];

/*JP	takeoff = !strcmp(word, "take off");
	ident = !strcmp(word, "identify");
	nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
		 ident || takeoff);*/
	takeoff = (!strcmp(word, "take off")||!strcmp(word,"脱ぐ")||!strcmp(word,"はずす")||!strcmp(word,"装備を解く"));
	ident = (!strcmp(word, "identify")||!strcmp(word,"識別する"));
	nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") ||
		 !strcmp(word, "置く") || ident || takeoff);
	ininv = (*objchn == invent);
	/* Changed so the askchain is interrogated in the order specified.
	 * For example, if a person specifies =/ then first all rings will be
	 * asked about followed by all wands -dgk
	 */
nextclass:
	ilet = 'a'-1;
	if (*objchn && (*objchn)->oclass == GOLD_CLASS)
		ilet--;		/* extra iteration */
	for (otmp = *objchn; otmp; otmp = otmp2) {
		if(ilet == 'z') ilet = 'A'; else ilet++;
		otmp2 = otmp->nobj;
		if (olets && *olets && otmp->oclass != *olets) continue;
		if (takeoff && !is_worn(otmp)) continue;
		if (ident && !not_fully_identified(otmp)) continue;
		if (ckfn && !(*ckfn)(otmp)) continue;
		if (!allflag) {
			Strcpy(qbuf, !ininv ? doname(otmp) :
				xprname(otmp, (char *)0, ilet, !nodot, 0L));
/*JP			Strcat(qbuf, "?");*/
			Strcat(qbuf, "？");
			sym = (takeoff || ident || otmp->quan < 2L) ?
				nyaq(qbuf) : nyNaq(qbuf);
		}
		else	sym = 'y';

		if (sym == '#') {
		 /* Number was entered; split the object unless it corresponds
		    to 'none' or 'all'.  2 special cases: cursed loadstones and
		    welded weapons (eg, multiple daggers) will remain as merged
		    unit; done to avoid splitting an object that won't be
		    droppable (even if we're picking up rather than dropping).
		  */
		    if (!yn_number)
			sym = 'n';
		    else {
			sym = 'y';
			if (yn_number < otmp->quan && !welded(otmp) &&
			    (!otmp->cursed || otmp->otyp != LOADSTONE)) {
			    struct obj *otmpx = splitobj(otmp, yn_number);
			    if (!otmpx || otmpx->nobj != otmp2)
				impossible("bad object split in askchain");
			    /* assume other worn items aren't mergable */
			    if (otmp == uwep) setuwep(otmpx);
			}
		    }
		}
		switch(sym){
		case 'a':
			allflag = 1;
		case 'y':
			tmp = (*fn)(otmp);
			if(tmp < 0) goto ret;
			cnt += tmp;
			if(--mx == 0) goto ret;
		case 'n':
			if(nodot) dud++;
		default:
			break;
		case 'q':
			/* special case for seffects() */
			if (ident) cnt = -1;
			goto ret;
		}
	}
	if (olets && *olets && *++olets)
		goto nextclass;
/*JP	if(!takeoff && (dud || cnt)) pline("That was all.");*/
	if(!takeoff && (dud || cnt)) pline("これで全部だ．");
/*JP	else if(!dud && !cnt) pline("No applicable objects.");*/
	else if(!dud && !cnt) pline("それはできない．");
ret:
	return(cnt);
}


/*
 *	Object identification routines:
 */

/* make an object actually be identified; no display updating */
static void
fully_identify_obj(otmp)
struct obj *otmp;
{
    makeknown(otmp->otyp);
    otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1;
    if (otmp->otyp == EGG && otmp->corpsenm != NON_PM)
	learn_egg_type(otmp->corpsenm);
}

/* ggetobj callback routine; identify an object and give immediate feedback */
int
identify(otmp)
struct obj *otmp;
{
    fully_identify_obj(otmp);
    prinv((char *)0, otmp, 0L);
    return 1;
}

/* menu of unidentified objects; select and identify up to id_limit of them */
static void
menu_identify(id_limit)
int id_limit;
{
    menu_item *pick_list;
    int n, i, first = 1;
    char buf[BUFSZ];
    /* assumptions:  id_limit > 0 and at least one unID'd item is present */

    while (id_limit) {
/*JP	Sprintf(buf, "What would you like to identify %s?",
		first ? "first" : "next");*/
	Sprintf(buf, "どれを%sに識別しますか？",
		first ? "最初" : "次");
	n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT,
		&pick_list, PICK_ANY, not_fully_identified);

	if (n > 0) {
	    if (n > id_limit) n = id_limit;
	    for (i = 0; i < n; i++, id_limit--)
		(void) identify(pick_list[i].item.a_obj);
	    free((genericptr_t) pick_list);
	    mark_synch(); /* Before we loop to pop open another menu */
	} else {
/*JP	    if (n < 0) pline("That was all.");*/
	    if (n < 0) pline("これで全部だ．");
	    id_limit = 0; /* Stop now */
	}
	first = 0;
    }
}

/* dialog with user to identify a given number of items; 0 means all */
void
identify_pack(id_limit)
int id_limit;
{
    struct obj *obj, *the_obj;
    int n, unid_cnt;

    unid_cnt = 0;
    the_obj = 0;		/* if unid_cnt ends up 1, this will be it */
    for (obj = invent; obj; obj = obj->nobj)
	if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj;

    if (!unid_cnt) {
/*JP	You("have already identified all of your possessions.");*/
	You("全ての所有物を識別してしまっている．");
    } else if (!id_limit) {
	/* identify everything */
	if (unid_cnt == 1) {
	    (void) identify(the_obj);
	} else {

	    /* TODO:  use fully_identify_obj and cornline/menu/whatever here */
	    for (obj = invent; obj; obj = obj->nobj)
		if (not_fully_identified(obj)) (void) identify(obj);

	}
    } else {
	/* identify up to `id_limit' items */
	n = 0;
	if (flags.menu_style == MENU_TRADITIONAL)
	    do {
/*JP		n = ggetobj("identify", identify, id_limit, FALSE);*/
		n = ggetobj("識別する", identify, id_limit, FALSE);
		if (n < 0) break; /* quit or no eligible items */
	    } while ((id_limit -= n) > 0);
	if (n == 0 || n < -1)
	    menu_identify(id_limit);
    }
    update_inventory();
}

#endif /* OVLB */
#ifdef OVL2

STATIC_OVL char
obj_to_let(obj)	/* should of course only be called for things in invent */
register struct obj *obj;
{
	if (obj->oclass == GOLD_CLASS)
		return GOLD_SYM;
	if (!flags.invlet_constant) {
		obj->invlet = NOINVSYM;
		reassign();
	}
	return obj->invlet;
}

/*
 * Print the indicated quantity of the given object.  If quan == 0L then use
 * the current quantity.
 */
void
prinv(prefix, obj, quan)
const char *prefix;
register struct obj *obj;
long quan;
{
	long savequan = obj->quan;
	if (quan) obj->quan = quan;
	if (!prefix) prefix = "";
/*JP	pline("%s%s%s",
	      prefix, *prefix ? " " : "",
	      xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L));*/
	pline("%s%s",
	      xprname(obj, (char *)0, obj_to_let(obj), *prefix ? FALSE : TRUE, 0L),
	      prefix);
	if (quan) obj->quan = savequan;
}

#endif /* OVL2 */
#ifdef OVL1

char *
xprname(obj, txt, let, dot, cost)
struct obj *obj;
const char *txt;	/* text to print instead of obj */
char let;		/* inventory letter */
boolean dot;		/* append period; (dot && cost => Iu) */
long cost;		/* cost (for inventory of unpaid or expended items) */
{
#ifdef LINT	/* handle static char li[BUFSZ]; */
	char li[BUFSZ];
#else
	static char li[BUFSZ];
#endif
	boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM;
    /*
     * If let is:
     *	*  Then obj == null and we are printing a total amount.
     *	>  Then the object is contained and doesn't have an inventory letter.
     */
    if (cost != 0 || let == '*') {
	/* if dot is true, we're doing Iu, otherwise Ix */
/*JP	Sprintf(li, "%c - %-45s %6ld zorkmid%s",
		(dot && use_invlet ? obj->invlet : let),
		(txt ? txt : doname(obj)), cost, plur(cost));*/
	Sprintf(li, "%c - %-45s %6ldゴールド",
		(dot && use_invlet ? obj->invlet : let),
		(txt ? txt : doname(obj)), cost);
    } else if (obj->oclass == GOLD_CLASS) {
/*JP	Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan),
		(dot ? "." : ""));*/
	Sprintf(li, "%ldゴールドの金塊%s", obj->quan,
		(dot ? "．" : ""));
    } else {
	/* ordinary inventory display or pickup message */
	Sprintf(li, "%c - %s%s",
		(use_invlet ? obj->invlet : let),
/*JP		(txt ? txt : doname(obj)), (dot ? "." : ""));*/
		(txt ? txt : doname(obj)), (dot ? "．" : ""));
    }
    return li;
}

#endif /* OVL1 */
#ifdef OVLB

int
ddoinv()
{
	(void) display_inventory((char *)0, FALSE);
	return 0;
}

/*
 * find_unpaid()
 *
 * Scan the given list of objects.  If last_found is NULL, return the first
 * unpaid object found.  If last_found is not NULL, then skip over unpaid
 * objects until last_found is reached, then set last_found to NULL so the
 * next unpaid object is returned.  This routine recursively follows
 * containers.
 */
static struct obj *
find_unpaid(list, last_found)
    struct obj *list, **last_found;
{
    struct obj *obj;

    while (list) {
	if (list->unpaid) {
	    if (*last_found) {
		/* still looking for previous unpaid object */
		if (list == *last_found)
		    *last_found = (struct obj *) 0;
	    } else
		return (*last_found = list);
	}
	if (Has_contents(list)) {
	    if ((obj = find_unpaid(list->cobj, last_found)) != 0)
		return obj;
	}
	list = list->nobj;
    }
    return (struct obj *) 0;
}

/*
 * If lets == NULL or "", list all objects in the inventory.  Otherwise,
 * list all objects with object classes that match the order in lets.
 *
 * Returns the letter identifier of a selected item, or 0 if nothing
 * was selected.
 */
char
display_inventory(lets, want_reply)
register const char *lets;
boolean want_reply;
{
	struct obj *otmp;
	char ilet, ret;
	char *invlet = flags.inv_order;
	int n, classcount;
	winid win;				/* windows being used */
	static winid local_win = WIN_ERR;	/* window for partial menus */
	anything any;
	menu_item *selected;

	/* overriden by global flag */
	if (flags.perm_invent) {
	    win = (lets && *lets) ? local_win : WIN_INVEN;
	    /* create the first time used */
	    if (win == WIN_ERR)
		win = local_win = create_nhwindow(NHW_MENU);
	} else
	    win = WIN_INVEN;

	if (!invent) {
/*JP	    pline("Not carrying anything%s.", u.ugold ? " except gold" : "");*/
	    pline("%s何も持っていない", u.ugold ? "お金以外" : "");
	    return 0;
	}
	if(!query_lang_mode())
	  set_trns_mode(0);

	/* oxymoron? temporarily assign permanent inventory letters */
	if (!flags.invlet_constant) reassign();

	if (lets && strlen(lets) == 1) {
	    /* when only one item of interest, use pline instead of menus;
	       we actually use a fake message-line menu in order to allow
	       the user to perform selection at the --More-- prompt for tty */
	    ret = '\0';
	    for (otmp = invent; otmp; otmp = otmp->nobj) {
		if (otmp->invlet == lets[0]) {
		    ret = message_menu(lets[0],
				  want_reply ? PICK_ONE : PICK_NONE,
				  xprname(otmp, (char *)0, lets[0], TRUE, 0L));
		    break;
		}
	    }
/*JP*/
	    set_trns_mode(1);
	    return ret;
	}

	start_menu(win);
nextclass:
	classcount = 0;
	any.a_void = 0;		/* set all bits to zero */
	for(otmp = invent; otmp; otmp = otmp->nobj) {
		ilet = otmp->invlet;
		if(!lets || !*lets || index(lets, ilet)) {
			if (!flags.sortpack || otmp->oclass == *invlet) {
			    if (flags.sortpack && !classcount) {
				any.a_void = 0;		/* zero */
				add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE,
				    let_to_name(*invlet, FALSE), MENU_UNSELECTED);
				classcount++;
			    }
			    any.a_char = ilet;
			    add_menu(win, obj_to_glyph(otmp),
					&any, ilet, 0, ATR_NONE, doname(otmp),
					MENU_UNSELECTED);
			}
		}
	}
	if (flags.sortpack) {
		if (*++invlet) goto nextclass;
#ifdef WIZARD
		if (--invlet != venom_inv) {
			invlet = venom_inv;
			goto nextclass;
		}
#endif
	}
	end_menu(win, (char *) 0);

	n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected);
	if (n > 0) {
	    ret = selected[0].item.a_char;
	    free((genericptr_t)selected);
	} else
	    ret = !n ? '\0' : '\033';	/* cancelled */

	set_trns_mode(1);
	return ret;
}

/*
 * Returns the number of unpaid items within the given list.  This includes
 * contained objects.
 */
int
count_unpaid(list)
    struct obj *list;
{
    int count = 0;

    while (list) {
	if (list->unpaid) count++;
	if (Has_contents(list))
	    count += count_unpaid(list->cobj);
	list = list->nobj;
    }
    return count;
}

static void
dounpaid()
{
    winid win;
    struct obj *otmp, *marker;
    register char ilet;
    char *invlet = flags.inv_order;
    int classcount, count, num_so_far;
    int save_unpaid = 0;	/* lint init */
    long cost, totcost;

    count = count_unpaid(invent);

    if (count == 1) {
	marker = (struct obj *) 0;
	otmp = find_unpaid(invent, &marker);

	/* see if the unpaid item is in the top level inventory */
	for (marker = invent; marker; marker = marker->nobj)
	    if (marker == otmp) break;

	pline("%s", xprname(otmp, distant_name(otmp, doname),
			    marker ? otmp->invlet : CONTAINED_SYM,
			    TRUE, unpaid_cost(otmp)));
	return;
    }

    win = create_nhwindow(NHW_MENU);
    cost = totcost = 0;
    num_so_far = 0;	/* count of # printed so far */
    if (!flags.invlet_constant) reassign();

    do {
	classcount = 0;
	for (otmp = invent; otmp; otmp = otmp->nobj) {
	    ilet = otmp->invlet;
	    if (otmp->unpaid) {
		if (!flags.sortpack || otmp->oclass == *invlet) {
		    if (flags.sortpack && !classcount) {
			putstr(win, 0, let_to_name(*invlet, TRUE));
			classcount++;
		    }

		    totcost += cost = unpaid_cost(otmp);
		    /* suppress "(unpaid)" suffix */
		    save_unpaid = otmp->unpaid;
		    otmp->unpaid = 0;
		    putstr(win, 0, xprname(otmp, distant_name(otmp, doname),
					   ilet, TRUE, cost));
		    otmp->unpaid = save_unpaid;
		    num_so_far++;
		}
	    }
	}
    } while (flags.sortpack && (*++invlet));

    if (count > num_so_far) {
	/* something unpaid is contained */
	if (flags.sortpack)
	    putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE));
	/*
	 * Search through the container objects in the inventory for
	 * unpaid items.  The top level inventory items have already
	 * been listed.
	 */
	for (otmp = invent; otmp; otmp = otmp->nobj) {
	    if (Has_contents(otmp)) {
		marker = (struct obj *) 0;	/* haven't found any */
		while (find_unpaid(otmp->cobj, &marker)) {
		    totcost += cost = unpaid_cost(marker);
		    save_unpaid = marker->unpaid;
		    marker->unpaid = 0;    /* suppress "(unpaid)" suffix */
		    putstr(win, 0,
			   xprname(marker, distant_name(marker, doname),
				   CONTAINED_SYM, TRUE, cost));
		    marker->unpaid = save_unpaid;
		}
	    }
	}
    }

    putstr(win, 0, "");
/*JP    putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost));*/
    putstr(win, 0, xprname((struct obj *)0, "合計：", '*', FALSE, totcost));
    display_nhwindow(win, FALSE);
    destroy_nhwindow(win);
}


/* query objlist callback: return TRUE if obj type matches "this_type" */
static int this_type;

static boolean
this_type_only(obj)
    struct obj *obj;
{
    return (obj->oclass == this_type);
}

/* the 'I' command */
int
dotypeinv()
{
	char c = '\0';
	int n, i = 0;
	char *extra_types, types[BUFSZ];
	int class_count, oclass, unpaid_count;
	boolean billx = *u.ushops && doinvbill(0);
	menu_item *pick_list;
	boolean traditional = TRUE;
/*JP	const char *prompt = "What type of object do you want an inventory of?";*/
	const char *prompt = "どの種類の持ち物を見ますか？";

	if (!invent && !u.ugold && !billx) {
/*JP	    You("aren't carrying anything.");*/
	    You("その種類の物は何も持っていない．");
	    return 0;
	}
	unpaid_count = count_unpaid(invent);
	if (flags.menu_style != MENU_TRADITIONAL) {
	    if (flags.menu_style == MENU_FULL ||
				flags.menu_style == MENU_PARTIAL) {
		traditional = FALSE;
		i = UNPAID_TYPES;
		if (billx) i |= BILLED_TYPES;
		n = query_category(prompt, invent, i, &pick_list, PICK_ONE);
		if (!n) return 0;
		this_type = c = pick_list[0].item.a_int;
		free((genericptr_t) pick_list);
	    }
	}
	if (traditional) {
	    /* collect a list of classes of objects carried, for use as a prompt */
	    types[0] = 0;
	    class_count = collect_obj_classes(types, invent,
					      FALSE, (u.ugold != 0),
					      (boolean FDECL((*),(OBJ_P))) 0);
	    if (unpaid_count) {
		Strcat(types, "u");
		class_count++;
	    }
	    if (billx) {
		Strcat(types, "x");
		class_count++;
	    }
	    /* add everything not already included; user won't see these */
	    extra_types = eos(types);
	    *extra_types++ = '\033';
	    if (!unpaid_count) *extra_types++ = 'u';
	    if (!billx) *extra_types++ = 'x';
	    *extra_types = '\0';	/* for index() */
	    for (i = 0; i < MAXOCLASSES; i++)
		if (!index(types, def_oc_syms[i])) {
		    *extra_types++ = def_oc_syms[i];
		    *extra_types = '\0';
		}

	    if(class_count > 1) {
		c = yn_function(prompt, types, '\0');
#ifdef REDO
		savech(c);
#endif
		if(c == '\0') {
			clear_nhwindow(WIN_MESSAGE);
			return 0;
		}
	    } else {
		/* only one thing to itemize */
		if (unpaid_count)
		    c = 'u';
		else if (billx)
		    c = 'x';
		else
		    c = types[0];
	    }
	}
	if (c == 'x') {
	    if (billx)
		(void) doinvbill(1);
	    else
/*JP		pline("No used-up objects on your shopping bill.");*/
		pline("商店の請求書に使ってしまった物はない．");

	    return 0;
	}
	if (c == 'u') {
	    if (unpaid_count)
		dounpaid();
	    else
/*JP		You("are not carrying any unpaid objects.");*/
		You("未払いのアイテムを持っていない．");
	    return 0;
	}
	if (traditional) {
	    oclass = def_char_to_objclass(c); /* change to object class */
	    if (oclass == GOLD_CLASS) {
		return doprgold();
	    } else if (index(types, c) > index(types, '\033')) {
/*JP		You("have no such objects.");*/
	        You("何も持っていない．");
		return 0;
	    }
	    this_type = oclass;
	}
	if (query_objlist((char *) 0, invent,
		    (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT,
		    &pick_list, PICK_NONE, this_type_only) > 0)
	    free((genericptr_t)pick_list);
	return 0;
}

/* look at what is here */
int
dolook()
{
	register struct obj *otmp, *otmp0;
	struct trap *trap;
/*JP	const char *verb = Blind ? "feel" : "see";*/
	const char *verb = Blind ? "があるような気がした" : "をみつけた";
	const char *dfeature = (char*) 0;
	char fbuf[BUFSZ], fbuf2[BUFSZ];
	boolean no_article = FALSE;
	winid tmpwin;

	if(u.uswallow) {
/*JP		You("%s no objects here.", verb);*/
	        pline(Blind?"あなたは何もないような気がした．":"あなたは何もみつけられなかった．");
		return(!!Blind);
	}
	read_engr_at(u.ux, u.uy); /* Eric Backus */
	if ((trap = t_at(u.ux,u.uy)) && trap->tseen)
/*JP		pline("There is %s here.",*/
		pline("ここには%sがある．",
			jtrns_obj('^', (defsyms[trap_to_defsym(trap->ttyp)].explanation)));

	otmp0 = level.objects[u.ux][u.uy];

	if(IS_DOOR(levl[u.ux][u.uy].typ))  {
		switch(levl[u.ux][u.uy].doormask) {
		    case D_NODOOR:
/*JP			dfeature = "doorway"; break;*/
			dfeature = "出入口"; break;
		    case D_ISOPEN:
/*JP			dfeature = "open door"; break;*/
			dfeature = "開いている扉"; break;
		    case D_BROKEN:
/*JP			dfeature = "broken door"; break;*/
			dfeature = "壊れている扉"; break;
		    default:
/*JP			dfeature = "closed door";*/
			dfeature = "閉じている扉";
		}
		/* override door description for open drawbridge */
		if (is_drawbridge_wall(u.ux, u.uy) >= 0)
/*JP			dfeature = "open drawbridge portcullis";*/
			dfeature = "降りている跳ね橋";
	} else if(IS_FOUNTAIN(levl[u.ux][u.uy].typ))
		/* added by GAN 10/30/86 */
/*JP		dfeature = "fountain";*/
		dfeature = "泉";
	else if(IS_THRONE(levl[u.ux][u.uy].typ))
/*JP		dfeature = "opulent throne";*/
		dfeature = "華やかな玉座";
	else if(is_lava(u.ux,u.uy))
/*JP		dfeature = "molten lava",  no_article = TRUE;*/
		dfeature = "ドロドロの溶岩",  no_article = TRUE;
	else if(is_ice(u.ux,u.uy))
/*JP		dfeature = "ice",  no_article = TRUE;*/
		dfeature = "氷",  no_article = TRUE;
	else if(is_pool(u.ux,u.uy) && !Underwater)
/*JP		dfeature = "pool of water";*/
		dfeature = "水たまり";
#ifdef SINKS
	else if(IS_SINK(levl[u.ux][u.uy].typ))
/*JP		dfeature = "kitchen sink";*/
		dfeature = "流し台";
#endif
	else if(IS_ALTAR(levl[u.ux][u.uy].typ))  {
/*JP		Sprintf(fbuf2, "altar to %s (%s)",*/
		Sprintf(fbuf2, "%sの祭壇(%s)",
			a_gname(),
			align_str(Amask2align(levl[u.ux][u.uy].altarmask
							    & ~AM_SHRINE)));
		dfeature = fbuf2;
#ifdef NEWBIE
		if(!newbie.found_altar)
		     newbie.found_altar = moves;
#endif
	} else if(u.ux == xupstair && u.uy == yupstair)
/*JP		dfeature = "stairway up";*/
		dfeature = "上への階段";
	else if(u.ux == xdnstair && u.uy == ydnstair)
/*JP		dfeature = "stairway down";*/
		dfeature = "下への階段";
	else if(u.ux == sstairs.sx && u.uy == sstairs.sy) {
		if (sstairs.up)
/*JP			dfeature = "stairway up";*/
			dfeature = "上への階段";
		else
/*JP			dfeature = "stairway down";*/
			dfeature = "下への階段";
	} else if(u.ux == xupladder && u.uy == yupladder)
/*JP		dfeature = "ladder up";*/
		dfeature = "上へのはしご";
	else if(u.ux == xdnladder && u.uy == ydnladder)
/*JP		dfeature = "ladder down";*/
		dfeature = "下へのはしご";
	else if (levl[u.ux][u.uy].typ == DRAWBRIDGE_DOWN)
/*JP		dfeature = "lowered drawbridge";*/
		dfeature = "降りた跳ね橋";
	else if (levl[u.ux][u.uy].typ == DBWALL)
/*JP		dfeature = "raised drawbridge";*/
		dfeature = "上がっている跳ね橋";

	if (Blind) {
		boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz);
/*JP		You("try to feel what is %s%s.",
		    drift ? "floating here" : "lying here on the ",
		    drift ?	""	    : surface(u.ux, u.uy));*/
		You("何が%s%sのか調べようとした．",
		    drift ?	""	    : surface(u.ux, u.uy),
		    drift ? "浮いている" : "の上にある");
		if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy)))
			dfeature = 0;		/* ice already identifed */
		if (!can_reach_floor()) {
/*JP			pline("But you can't reach it!");*/
			pline("しかし届かない！");
			return(0);
		}
	}

	if (dfeature)
/*JP		Sprintf(fbuf, "There is %s%s here.",
			no_article ? "" :
				index(vowels,dfeature[0]) ? "an " : "a ",*/
		Sprintf(fbuf, "ここには%sがある．",
			dfeature);

	if(!otmp0 || (is_pool(u.ux,u.uy) && !Underwater)) {
		if (dfeature) pline(fbuf);
/*JP		if (Blind || !dfeature) You("%s no objects here.", verb);*/
				        pline(Blind ?
					      "なにもないような気がする．" :
					      "なにもみつけられなかった．");
		return(!!Blind);
	}
	/* we know there is something here */

	if (!otmp0->nexthere) {
	    /* only one object */
	    if (dfeature) pline(fbuf);
/*JP
	    You("%s here %s.", verb, doname(otmp0));
*/
#ifdef NEWBIE
	    if(Is_container(otmp0))
		 newbie.found_chest = moves;
#endif
	    pline("%s%s．",doname(otmp0),verb);
	    feel_cockatrice(otmp0, FALSE);
	} else {
	    display_nhwindow(WIN_MESSAGE, FALSE);
	    tmpwin = create_nhwindow(NHW_MENU);
	    if(dfeature) {
		putstr(tmpwin, 0, fbuf);
		putstr(tmpwin, 0, "");
	    }
/*JP	    putstr(tmpwin, 0, "Things that are here:");*/
	    putstr(tmpwin, 0, "ここにはあるものは．．．");
	    for(otmp = otmp0; otmp; otmp = otmp->nexthere) {
		putstr(tmpwin, 0, doname(otmp));
		feel_cockatrice(otmp, FALSE);
	    }
	    display_nhwindow(tmpwin, TRUE);
	    destroy_nhwindow(tmpwin);
	}
	return(!!Blind);
}

void
feel_cockatrice(otmp, force_touch)
struct obj *otmp;
boolean force_touch;
{
	if ((Blind || force_touch) &&
		!uarmg && !resists_ston(&youmonst) &&
		(otmp->otyp == CORPSE && otmp->corpsenm == PM_COCKATRICE)) {
	    if(poly_when_stoned(uasmon))
/*JP		You("touched the cockatrice corpse with your bare %s.",*/
		You("コカトリスの死体に素%sで触った．",
			makeplural(body_part(HAND)));
	    else
/*JP		pline("Touching the cockatrice corpse is a fatal mistake...");*/
		pline("コカトリスの死体に触れるのは致命的な間違いだ．．．");
/*JP	    instapetrify("cockatrice corpse");*/
	    instapetrify("コカトリスの死体で");
	}
}

#endif /* OVLB */
#ifdef OVL1

void
stackobj(obj)
struct obj *obj;
{
	struct obj *otmp;

	for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere)
		if(otmp != obj && merged(&obj,&otmp))
			break;
	return;
}

static boolean
mergable(otmp, obj)	/* returns TRUE if obj  & otmp can be merged */
	register struct obj *otmp, *obj;
{
	if (obj->otyp != otmp->otyp || obj->unpaid != otmp->unpaid ||
	    obj->spe != otmp->spe || obj->dknown != otmp->dknown ||
	    (obj->bknown != otmp->bknown && !Role_is('P')) ||
	    obj->cursed != otmp->cursed || obj->blessed != otmp->blessed ||
	    obj->no_charge != otmp->no_charge ||
	    obj->obroken != otmp->obroken ||
	    obj->otrapped != otmp->otrapped ||
	    obj->lamplit != otmp->lamplit ||
	    obj->oeroded != otmp->oeroded)
	    return(FALSE);

	if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) &&
	    (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown))
	    return FALSE;

	if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten ||
					  obj->orotten != otmp->orotten))
	    return(FALSE);

	if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) {
		if (obj->corpsenm != otmp->corpsenm)
				return FALSE;
	}

	/* hatching eggs don't merge; ditto for revivable corpses */
	if ((obj->otyp == EGG && (obj->timed || otmp->timed)) ||
	    (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM &&
		mons[otmp->corpsenm].mlet == S_TROLL))
	    return FALSE;

	/* allow candle merging only if their ages are close */
	/* see begin_burn() for a reference for the magic "25" */
	if (Is_candle(obj) && obj->age/25 != otmp->age/25)
	    return(FALSE);

	/* burning potions of oil never merge */
	if (obj->otyp == POT_OIL && obj->lamplit)
	    return FALSE;

	/* don't merge surcharged item with base-cost item */
	if (obj->unpaid && !same_price(obj, otmp))
	    return FALSE;

	/* if they have names, make sure they're the same */
	if ( (obj->onamelth != otmp->onamelth &&
		((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE)
	     ) ||
	    (obj->onamelth && otmp->onamelth &&
		    strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth)))
		return FALSE;

	/* for the moment, any additional information is incompatible */
	if (obj->oxlth || otmp->oxlth) return FALSE;

	if(obj->oartifact != otmp->oartifact) return FALSE;

	if(obj->known == otmp->known ||
		!objects[otmp->otyp].oc_uses_known) {
		return((boolean)(objects[obj->otyp].oc_merge));
	} else return(FALSE);
}

int
doprgold()
{
	/* the messages used to refer to "carrying gold", but that didn't
	   take containers into account */
	if(!u.ugold)
/*JP	    Your("wallet is empty.");*/
	    Your("財布は空っぽだ．");
	else
/*JP	    Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold));*/
	    Your("財布には%ldゴールド入っている．", u.ugold);
	shopper_financial_report();
	return 0;
}

#endif /* OVL1 */
#ifdef OVLB

int
doprwep()
{
/*JP	if(!uwep) You("are empty %s.", body_part(HANDED));*/
	if(!uwep) You("%sに武器をもっていない．", body_part(HAND));
	else prinv((char *)0, uwep, 0L);
	return 0;
}

int
doprarm()
{
	if(!wearing_armor())
/*JP		You("are not wearing any armor.");*/
		You("鎧を着ていない．");
	else {
#ifdef TOURIST
		char lets[8];
#else
		char lets[7];
#endif
		register int ct = 0;

#ifdef TOURIST
		if(uarmu) lets[ct++] = obj_to_let(uarmu);
#endif
		if(uarm) lets[ct++] = obj_to_let(uarm);
		if(uarmc) lets[ct++] = obj_to_let(uarmc);
		if(uarmh) lets[ct++] = obj_to_let(uarmh);
		if(uarms) lets[ct++] = obj_to_let(uarms);
		if(uarmg) lets[ct++] = obj_to_let(uarmg);
		if(uarmf) lets[ct++] = obj_to_let(uarmf);
		lets[ct] = 0;
		(void) display_inventory(lets, FALSE);
	}
	return 0;
}

int
doprring()
{
	if(!uleft && !uright)
/*JP		You("are not wearing any rings.");*/
		You("指輪を身につけていない．");
	else {
		char lets[3];
		register int ct = 0;

		if(uleft) lets[ct++] = obj_to_let(uleft);
		if(uright) lets[ct++] = obj_to_let(uright);
		lets[ct] = 0;
		(void) display_inventory(lets, FALSE);
	}
	return 0;
}

int
dopramulet()
{
	if (!uamul)
/*JP		You("are not wearing an amulet.");*/
		You("魔除けを身につけていない．");
	else
		prinv((char *)0, uamul, 0L);
	return 0;
}

int
doprtool()
{
	register struct obj *otmp;
	register int ct=0;
	char lets[52+1];

	for(otmp = invent; otmp; otmp = otmp->nobj) {
		if ((otmp->owornmask & W_TOOL) ||
		    (otmp->oclass == TOOL_CLASS &&
			(otmp == uwep || otmp->lamplit)) ||
		    (otmp->otyp == LEASH && otmp->leashmon))
			lets[ct++] = obj_to_let(otmp);
	}
	lets[ct] = 0;
/*JP	if (!ct) You("are not using any tools.");*/
	if (!ct) You("道具を使っていない．");
	else (void) display_inventory(lets, FALSE);
	return 0;
}

/*
 * uses up an object that's on the floor, charging for it as necessary
 */
void
useupf(obj)
register struct obj *obj;
{
	register struct obj *otmp;

	/* burn_floor_paper() keeps an object pointer that it tries to
	 * useupf() multiple times, so obj must survive if plural */
	if(obj->quan > 1L)
		otmp = splitobj(obj, obj->quan - 1L);
	else
		otmp = obj;
	if(costly_spot(otmp->ox, otmp->oy)) {
	    if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0)))
	        addtobill(otmp, FALSE, FALSE, FALSE);
	    else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE);
	}
	delobj(otmp);
}

#endif /* OVLB */


#ifdef OVL1

/*
 * Conversion from a class to a string for printing.
 * This must match the object class order.
 */
STATIC_VAR NEARDATA const char *names[] = { 0,
#if 0 /*JP*/
	"Illegal objects", "Weapons", "Armor", "Rings", "Amulets",
	"Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks",
	"Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls",
	"Chains", "Venoms"
#endif
	"妙な物体", "武器", "鎧", "指輪", "魔除け",
	"道具", "食料", "薬", "巻物", "魔法書",
        "杖", "金貨", "宝石", "岩または彫像", "鉄球",
        "鎖", "毒"
};

static NEARDATA const char oth_symbols[] = {
	CONTAINED_SYM,
	'\0'
};

static NEARDATA const char *oth_names[] = {
/*JP	"Bagged/Boxed items"*/
	"詰められた道具"
};

char *
let_to_name(let,unpaid)
char let;
boolean unpaid;
{
	const char *class_name;
	const char *pos;
	int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0;
	unsigned len;
	static NEARDATA char *buf = (char *)0;
	static NEARDATA unsigned bufsiz = 0;

	if (oclass)
	    class_name = names[oclass];
	else if ((pos = index(oth_symbols, let)) != 0)
	    class_name = oth_names[pos - oth_symbols];
	else
	    class_name = names[0];

/*JP	len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof "");*/
	len = strlen(class_name) + (unpaid ? sizeof "未払いの" : sizeof "");
	if (len > bufsiz) {
	    if (buf)  free((genericptr_t)buf),  buf = (char *)0;
	    bufsiz = len + 10; /* add slop to reduce incremental realloc */
	    buf = (char *) alloc(bufsiz);
	}
	if (unpaid)
/*JP	    Strcat(strcpy(buf, "Unpaid "), class_name);*/
	    Strcat(strcpy(buf, "未払いの"), class_name);
	else
	    Strcpy(buf, class_name);
	return (buf);
}

#endif /* OVL1 */
#ifdef OVLB

void
reassign()
{
	register int i;
	register struct obj *obj;

	for(obj = invent, i = 0; obj; obj = obj->nobj, i++)
		obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26);
	lastinvnr = i;
}

#endif /* OVLB */
#ifdef OVL1

int
doorganize()	/* inventory organizer by Del Lamb */
{
	struct obj *obj, *otmp;
	register int ix, cur;
	register char let;
	char alphabet[52+1], buf[52+1];
	char qbuf[QBUFSZ];
	char allowall[2];
	const char *adj_type;

	if (!flags.invlet_constant) reassign();
	/* get a pointer to the object the user wants to organize */
	allowall[0] = ALL_CLASSES; allowall[1] = '\0';
/*JP	if (!(obj = getobj(allowall,"adjust"))) return(0);*/
	if (!(obj = getobj(allowall,"調整する"))) return(0);

	/* initialize the list with all upper and lower case letters */
	for (let = 'a', ix = 0;  let <= 'z';) alphabet[ix++] = let++;
	for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++;
	alphabet[52] = 0;

	/* blank out all the letters currently in use in the inventory */
	/* except those that will be merged with the selected object   */
	for (otmp = invent; otmp; otmp = otmp->nobj)
	    if (otmp != obj && !mergable(otmp,obj)){
			if (otmp->invlet <= 'Z')
				alphabet[(otmp->invlet) - 'A' + 26] = ' ';
			else	alphabet[(otmp->invlet) - 'a']	    = ' ';
	    }

	/* compact the list by removing all the blanks */
	for (ix = cur = 0; ix <= 52; ix++)
		if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix];

	/* and by dashing runs of letters */
	if(cur > 5) compactify(buf);

	/* get new letter to use as inventory letter */
	for (;;) {
/*JP		Sprintf(qbuf, "Adjust letter to what [%s]?",buf);*/
		Sprintf(qbuf, "どの文字に調整しますか[%s]？",buf);
		let = yn_function(qbuf, (char *)0, '\0');
		if(index(quitchars,let)) {
/*JP			pline("Never mind.");*/
			pline("え？");
			return(0);
		}
		if (let == '@' || !letter(let))
/*JP			pline("Select an inventory slot letter.");*/
			pline("持ち物の文字を選んでください．");
		else
			break;
	}

	/* change the inventory and print the resulting item */
/*JP	adj_type = "Moving:";*/
	adj_type = "を移動した．";

	/*
	 * don't use freeinv/addinv to avoid double-touching artifacts,
	 * dousing lamps, losing luck, cursing loadstone, etc.
	 */
	extract_nobj(obj, &invent);

	for (otmp = invent; otmp;)
		if (merged(&otmp,&obj)) {
/*JP			adj_type = "Merging:";*/
			adj_type = "を合わせた．";
			obj = otmp;
			otmp = otmp->nobj;
			extract_nobj(obj, &invent);
		} else {
			if (otmp->invlet == let) {
/*JP				adj_type = "Swapping:";*/
				adj_type = "を交換した．";
				otmp->invlet = obj->invlet;
			}
			otmp = otmp->nobj;
		}

	/* inline addinv (assuming flags.invlet_constant and !merged) */
	obj->invlet = let;
	obj->nobj = invent; /* insert at beginning */
	obj->where = OBJ_INVENT;
	invent = obj;
	reorder_invent();

	prinv(adj_type, obj, 0L);
	update_inventory();
	return(0);
}

/* common to display_minventory and display_cinventory */
static void
invdisp_nothing(hdr, txt)
const char *hdr, *txt;
{
	winid win;
	anything any;
	menu_item *selected;

	any.a_void = 0;
	win = create_nhwindow(NHW_MENU);
	start_menu(win);
	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_INVERSE, hdr, MENU_UNSELECTED);
	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED);
	add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED);
	end_menu(win, (char *)0);
	if (select_menu(win, PICK_NONE, &selected) > 0)
	    free((genericptr_t)selected);
	destroy_nhwindow(win);
	return;
}

/* query_objlist callback: return things that could possibly be worn/wielded */
static boolean
worn_wield_only(obj)
struct obj *obj;
{
    return (obj->oclass == WEAPON_CLASS
		|| obj->oclass == ARMOR_CLASS
		|| obj->oclass == AMULET_CLASS
		|| obj->oclass == RING_CLASS
		|| obj->oclass == TOOL_CLASS);
}

/*
 * Display a monster's inventory.
 * Returns a pointer to the object from the monster's inventory selected
 * or NULL if nothing was selected.
 *
 * By default, only worn and wielded items are displayed.  The caller
 * can pick one.  Modifier flags are:
 *
 *	MINV_NOLET	- nothing selectable
 *	MINV_ALL	- display all inventory
 */
struct obj *
display_minventory(mon, dflags)
register struct monst *mon;
int dflags;
{
	struct obj *ret, m_gold;
	char tmp[QBUFSZ];
	int n;
	menu_item *selected = 0;
	int do_all = (dflags & MINV_ALL) != 0,
	    do_gold = (do_all && mon->mgold);

/*JP	Sprintf(tmp,"%s %s:", s_suffix(Monnam(mon)),
		do_all ? "possessions" : "armament");*/
	Sprintf(tmp,"%sの%s：", s_suffix(Monnam(mon)),
		do_all ? "持ち物" : "装備");

	if (do_all ? (mon->minvent || mon->mgold)
		   : (mon->misc_worn_check || MON_WEP(mon))) {
	    /* Fool the 'weapon in hand' routine into
	     * displaying 'weapon in claw', etc. properly.
	     */
	    char save_usym = u.usym;

	    u.usym = mon->data->mlet;
	    uasmon = mon->data;

	    if (do_gold) {
		/* make temporary gold object & insert at head of inventory */
		m_gold = zeroobj;
		m_gold.otyp = GOLD_PIECE;  m_gold.oclass = GOLD_CLASS;
		m_gold.quan = mon->mgold;  m_gold.dknown = 1;
		m_gold.where = OBJ_FREE;
		add_to_minv(mon, &m_gold);
	    }

	    n = query_objlist(tmp, mon->minvent, INVORDER_SORT, &selected,
			(dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE,
			do_all ? allow_all : worn_wield_only);

	    if (do_gold) obj_extract_self(&m_gold);

	    u.usym = save_usym;
	    set_uasmon();
	} else {
/*JP	    invdisp_nothing(tmp, "(none)");*/
	    invdisp_nothing(tmp, "(何もない)");
	    n = 0;
	}

	if (n > 0) {
	    ret = selected[0].item.a_obj;
	    free((genericptr_t)selected);
	    /*
	     * Unfortunately, we can't return a pointer to our temporary
	     * gold object.  We'll have to work out a scheme where this
	     * can happen.  Maybe even put gold in the inventory list...
	     */
	    if (ret == &m_gold) ret = (struct obj *) 0;
	} else
	    ret = (struct obj *) 0;
	return ret;
}

/*
 * Display the contents of a container in inventory style.
 * Currently, this is only used for statues, via wand of probing.
 */
struct obj *
display_cinventory(obj)
register struct obj *obj;
{
	struct obj *ret;
	char tmp[QBUFSZ];
	int n;
	menu_item *selected = 0;

/*JP	Sprintf(tmp,"Contents of %s:", doname(obj));*/
	Sprintf(tmp,"%sの中身：", doname(obj));

	if (obj->cobj) {
	    n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected,
			    PICK_NONE, allow_all);
	} else {
/*JP	    invdisp_nothing(tmp, "(empty)");*/
	    invdisp_nothing(tmp, "(空っぽ)");
	    n = 0;
	}
	if (n > 0) {
	    ret = selected[0].item.a_obj;
	    free((genericptr_t)selected);
	} else
	    ret = (struct obj *) 0;
	return ret;
}

/* query objlist callback: return TRUE if obj is at given location */
static coord only;

static boolean
only_here(obj)
    struct obj *obj;
{
    return (obj->ox == only.x && obj->oy == only.y);
}

/*
 * Display a list of buried items in inventory style.  Return a non-zero
 * value if there were items at that spot.
 *
 * Currently, this is only used with a wand of probing zapped downwards.
 */
int
display_binventory(x, y, as_if_seen)
int x, y;
boolean as_if_seen;
{
	struct obj *obj;
	menu_item *selected = 0;
	int n;

	/* count # of objects here */
	for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj)
	    if (obj->ox == x && obj->oy == y) {
		if (as_if_seen) obj->dknown = 1;
		n++;
	    }

	if (n) {
	    only.x = x;
	    only.y = y;
/*JP	    if (query_objlist("Things that are buried here:",*/
	    if (query_objlist("ここに埋められているもの：",
			      level.buriedobjlist, INVORDER_SORT,
			      &selected, PICK_NONE, only_here) > 0)
		free((genericptr_t)selected);
	    only.x = only.y = 0;
	}
	return n;
}

#endif /* OVL1 */

/*invent.c*/
