/* NetHack 3.5	botl.c	$NHDT-Date: 1425083082 2015/02/28 00:24:42 $  $NHDT-Branch: (no branch, rebasing scshunt-unconditionals) $:$NHDT-Revision: 1.38 $ */
/* NetHack 3.5	botl.c	$Date: 2012/01/10 17:47:19 $  $Revision: 1.36 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"
#include <limits.h>

extern const char *hu_stat[];	/* defined in eat.c */

const char * const enc_stat[] = {
	"",
	"Burdened",
	"Stressed",
	"Strained",
	"Overtaxed",
	"Overloaded"
};

#ifdef STATUS_VIA_WINDOWPORT
struct istat_s {
	long time;
	unsigned anytype;
	anything a;
	char *val;
	int valwidth;
	int idxmax;
};

STATIC_DCL void NDECL(init_blstats);
STATIC_DCL char *FDECL(anything_to_s, (char *, anything *, int));
STATIC_DCL void FDECL(s_to_anything, (anything *, char *, int));
STATIC_OVL int FDECL(percentage, (struct istat_s *, struct istat_s *));
STATIC_OVL int FDECL(compare_blstats, (struct istat_s *, struct istat_s *));
# ifdef STATUS_HILITES
STATIC_DCL boolean FDECL(assign_hilite, (char *, char *, char *, char *));
STATIC_DCL const char *FDECL(clridx_to_s, (char *, int));
# endif
#else
STATIC_DCL void NDECL(bot1);
STATIC_DCL void NDECL(bot2);
#endif

/* MAXCO must hold longest uncompressed status line, and must be larger
 * than COLNO
 *
 * longest practical second status line at the moment is
 *	Astral Plane $:12345 HP:700(700) Pw:111(111) AC:-127 Xp:30/123456789
 *	T:123456 Satiated Conf FoodPois Ill Blind Stun Hallu Overloaded
 * -- or somewhat over 130 characters
 */
#if COLNO <= 140
#define MAXCO 160
#else
#define MAXCO (COLNO+20)
#endif

STATIC_OVL NEARDATA int mrank_sz = 0; /* loaded by max_rank_sz (from u_init) */
STATIC_DCL const char *NDECL(rank);

/* convert experience level (1..30) to rank index (0..8) */
int
xlev_to_rank(xlev)
int xlev;
{
	return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8;
}

#if 0	/* not currently needed */
/* convert rank index (0..8) to experience level (1..30) */
int
rank_to_xlev(rank)
int rank;
{
	return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30;
}
#endif

const char *
rank_of(lev, monnum, female)
	int lev;
	short monnum;
	boolean female;
{
	register const struct Role *role;
	register int i;


	/* Find the role */
	for (role = roles; role->name.m; role++)
	    if (monnum == role->malenum || monnum == role->femalenum)
	    	break;
	if (!role->name.m)
	    role = &urole;

	/* Find the rank */
	for (i = xlev_to_rank((int)lev); i >= 0; i--) {
	    if (female && role->rank[i].f) return (role->rank[i].f);
	    if (role->rank[i].m) return (role->rank[i].m);
	}

	/* Try the role name, instead */
	if (female && role->name.f) return (role->name.f);
	else if (role->name.m) return (role->name.m);
	return ("Player");
}


STATIC_OVL const char *
rank()
{
	return(rank_of(u.ulevel, Role_switch, flags.female));
}

int
title_to_mon(str, rank_indx, title_length)
const char *str;
int *rank_indx, *title_length;
{
	register int i, j;


	/* Loop through each of the roles */
	for (i = 0; roles[i].name.m; i++)
	    for (j = 0; j < 9; j++) {
	    	if (roles[i].rank[j].m && !strncmpi(str,
	    			roles[i].rank[j].m, strlen(roles[i].rank[j].m))) {
	    	    if (rank_indx) *rank_indx = j;
	    	    if (title_length) *title_length = strlen(roles[i].rank[j].m);
	    	    return roles[i].malenum;
	    	}
	    	if (roles[i].rank[j].f && !strncmpi(str,
	    			roles[i].rank[j].f, strlen(roles[i].rank[j].f))) {
	    	    if (rank_indx) *rank_indx = j;
	    	    if (title_length) *title_length = strlen(roles[i].rank[j].f);
	    	    return ((roles[i].femalenum != NON_PM) ?
	    	    		roles[i].femalenum : roles[i].malenum);
	    	}
	    }
	return NON_PM;
}

void
max_rank_sz()
{
	register int i, r, maxr = 0;
	for (i = 0; i < 9; i++) {
	    if (urole.rank[i].m && (r = strlen(urole.rank[i].m)) > maxr) maxr = r;
	    if (urole.rank[i].f && (r = strlen(urole.rank[i].f)) > maxr) maxr = r;
	}
	mrank_sz = maxr;
	return;
}

#ifdef SCORE_ON_BOTL
long
botl_score()
{
    long deepest = deepest_lev_reached(FALSE);
    long utotal;

    utotal = money_cnt(invent) + hidden_gold();
    if ((utotal -= u.umoney0) < 0L) utotal = 0L;
    utotal += u.urexp + (50 * (deepest - 1)) +
	      (deepest > 30 ? 10000 : deepest > 20 ? 1000*(deepest - 20) : 0);
    if (utotal < u.urexp) utotal = LONG_MAX; /* wrap around */
    return utotal;
}
#endif

#ifndef STATUS_VIA_WINDOWPORT
STATIC_OVL void
bot1()
{
	char newbot1[MAXCO];
	register char *nb;
	register int i,j;
	Strcpy(newbot1, plname);
	if('a' <= newbot1[0] && newbot1[0] <= 'z') newbot1[0] += 'A'-'a';
	newbot1[10] = 0;
	Sprintf(nb = eos(newbot1)," the ");

	if (Upolyd) {
		char mbot[BUFSZ];
		int k = 0;

		Strcpy(mbot, mons[u.umonnum].mname);
		while(mbot[k] != 0) {
		    if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) &&
					'a' <= mbot[k] && mbot[k] <= 'z')
			mbot[k] += 'A' - 'a';
		    k++;
		}
		Sprintf(nb = eos(nb), mbot);
	} else
		Sprintf(nb = eos(nb), rank());

	Sprintf(nb = eos(nb),"  ");
	i = mrank_sz + 15;
	j = (nb + 2) - newbot1; /* aka strlen(newbot1) but less computation */
	if((i - j) > 0)
		Sprintf(nb = eos(nb),"%*s", i-j, " ");	/* pad with spaces */
	if (ACURR(A_STR) > 18) {
		if (ACURR(A_STR) > STR18(100))
		    Sprintf(nb = eos(nb),"St:%2d ",ACURR(A_STR)-100);
		else if (ACURR(A_STR) < STR18(100))
		    Sprintf(nb = eos(nb), "St:18/%02d ",ACURR(A_STR)-18);
		else
		    Sprintf(nb = eos(nb),"St:18/** ");
	} else
		Sprintf(nb = eos(nb), "St:%-1d ",ACURR(A_STR));
	Sprintf(nb = eos(nb),
		"Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d",
		ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA));
	Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? "  Chaotic" :
			(u.ualign.type == A_NEUTRAL) ? "  Neutral" : "  Lawful");
#ifdef SCORE_ON_BOTL
	if (flags.showscore)
	    Sprintf(nb = eos(nb), " S:%ld", botl_score());
#endif
	curs(WIN_STATUS, 1, 0);
	putstr(WIN_STATUS, 0, newbot1);
}
#endif

/* provide the name of the current level for display by various ports */
int
describe_level(buf)
char *buf;
{
	int ret = 1;

	/* TODO:	Add in dungeon name */
	if (Is_knox(&u.uz))
		Sprintf(buf, "%s ", dungeons[u.uz.dnum].dname);
	else if (In_quest(&u.uz))
		Sprintf(buf, "Home %d ", dunlev(&u.uz));
	else if (In_endgame(&u.uz))
		Sprintf(buf,
			Is_astralevel(&u.uz) ? "Astral Plane " : "End Game ");
	else {
		/* ports with more room may expand this one */
		Sprintf(buf, "Dlvl:%-2d ", depth(&u.uz));
		ret = 0;
	}
	return ret;
}

#ifndef STATUS_VIA_WINDOWPORT
STATIC_OVL void
bot2()
{
	char  newbot2[MAXCO];
	register char *nb;
	int hp, hpmax;
	int cap = near_capacity();

	hp = Upolyd ? u.mh : u.uhp;
	hpmax = Upolyd ? u.mhmax : u.uhpmax;

	if(hp < 0) hp = 0;
	(void) describe_level(newbot2);
	Sprintf(nb = eos(newbot2),
		"%s:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d",
		encglyph(objnum_to_glyph(GOLD_PIECE)),
		money_cnt(invent),
		hp, hpmax, u.uen, u.uenmax, u.uac);

	if (Upolyd)
		Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel);
	else if(flags.showexp)
		Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp);
	else
		Sprintf(nb = eos(nb), " Exp:%u", u.ulevel);

	if(flags.time)
	    Sprintf(nb = eos(nb), " T:%ld", moves);
	if(strcmp(hu_stat[u.uhs], "        ")) {
		Sprintf(nb = eos(nb), " ");
		Strcat(newbot2, hu_stat[u.uhs]);
	}
	if(Confusion)	   Sprintf(nb = eos(nb), " Conf");
	if(Sick) {
		if (u.usick_type & SICK_VOMITABLE)
			   Sprintf(nb = eos(nb), " FoodPois");
		if (u.usick_type & SICK_NONVOMITABLE)
			   Sprintf(nb = eos(nb), " Ill");
	}
	if(Blind)	   Sprintf(nb = eos(nb), " Blind");
	if(Stunned)	   Sprintf(nb = eos(nb), " Stun");
	if(Hallucination)  Sprintf(nb = eos(nb), " Hallu");
	if(Slimed)         Sprintf(nb = eos(nb), " Slime");
	if(cap > UNENCUMBERED)
		Sprintf(nb = eos(nb), " %s", enc_stat[cap]);
	curs(WIN_STATUS, 1, 1);
	putmixed(WIN_STATUS, 0, newbot2);
}

void
bot()
{
	if (youmonst.data) {
		bot1();
		bot2();
	}
	context.botl = context.botlx = 0;
}

#else	/* STATUS_VIA_WINDOWPORT */

/* If entries are added to this, botl.h will require updating too */
struct istat_s blstats[2][MAXBLSTATS] = {
    {
    { 0L, ANY_STR,  {(genericptr_t)0L}, (char *)0, 80, 0 },	/*  0 BL_TITLE */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  1 BL_STR */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  2 BL_DX */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  3 BL_CO */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  4 BL_IN */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  5 BL_WI */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/*  6 BL_CH */
    { 0L, ANY_STR,  {(genericptr_t)0L}, (char *)0, 40,  0},	/*  7 BL_ALIGN */
    { 0L, ANY_LONG, {(genericptr_t)0L}, (char *)0, 20,  0},	/*  8 BL_SCORE */
    { 0L, ANY_LONG, {(genericptr_t)0L}, (char *)0, 20,  0},	/*  9 BL_CAP */
    { 0L, ANY_LONG, {(genericptr_t)0L}, (char *)0, 30,  0},	/* 10 BL_GOLD */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10, BL_ENEMAX}, /* 11 BL_ENE */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/* 12 BL_ENEMAX */
    { 0L, ANY_LONG, {(genericptr_t)0L}, (char *)0, 10,  0},	/* 13 BL_XP */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/* 14 BL_AC */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/* 15 BL_HD */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 20,  0},	/* 16 BL_TIME */
    { 0L, ANY_UINT, {(genericptr_t)0L}, (char *)0, 40,  0},	/* 17 BL_HUNGER */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10, BL_HPMAX},  /* 18 BL_HP */
    { 0L, ANY_INT,  {(genericptr_t)0L}, (char *)0, 10,  0},	/* 19 BL_HPMAX */
    { 0L, ANY_STR,  {(genericptr_t)0L}, (char *)0, 80,  0},	/* 20 BL_LEVELDESC */
    { 0L, ANY_LONG, {(genericptr_t)0L}, (char *)0, 20,  0},	/* 21 BL_EXP */
    { 0L, ANY_MASK32,{(genericptr_t)0L},(char *)0,  0,  0}	/* 22 BL_CONDITION */
    }
};

static boolean blinit = FALSE, update_all = FALSE;
const char *status_fieldnames[] = {
		"title", "strength", "dexterity", "constitution", "intelligence",
		"wisdom", "charisma", "alignment", "score", "carrying-capacity",
		"gold", "power", "power-max", "experience-level", "armor-class",
		"HD", "time", "hunger", "hitpoints", "hitpoints-max",
		"dungeon-level", "experience", "condition"
		};


void
status_initialize(reassessment)
boolean reassessment;	/* TRUE = just reassess fields w/o other initialization*/
{
	int i;
	const char *fieldfmts[] = {
		"%s"," St:%s"," Dx:%s"," Co:%s"," In:%s"," Wi:%s"," Ch:%s",
		" %s"," S:%s"," %s"," %s"," Pw:%s", "(%s)"," Xp:%s", " AC:%s",
		" HD:%s"," T:%s"," %s"," HP:%s","(%s)","%s","/%s","%s"
		};
	if (!reassessment) {
		init_blstats();
		(*windowprocs.win_status_init)();
		blinit = TRUE;
	}
	for (i = 0; i < MAXBLSTATS; ++i) {
		if ((i == BL_SCORE && !flags.showscore)	||
		    (i == BL_EXP   && !flags.showexp)	||
		    (i == BL_TIME  && !flags.time)	||
		    (i == BL_HD    && !Upolyd)		||
		    ((i == BL_XP || i == BL_EXP) && Upolyd))
			status_enablefield(i, status_fieldnames[i],
						fieldfmts[i], FALSE);
		else
			status_enablefield(i, status_fieldnames[i],
						fieldfmts[i], TRUE);
	}
	update_all = TRUE;
}

void
status_finish()
{
	int i;

	/* call the window port cleanup routine first */
	(*windowprocs.win_status_finish)();

	/* free memory that we alloc'd now */
	for (i = 0; i < MAXBLSTATS; ++i) {
		if (blstats[0][i].val) free((genericptr_t)blstats[0][i].val);
		if (blstats[1][i].val) free((genericptr_t)blstats[1][i].val);
	}
}

STATIC_OVL void
init_blstats()
{
	int i;

	for (i = 0; i < MAXBLSTATS; ++i) {
		/* ensure initial field values set on blstats[1][i] too */
		blstats[1][i] = blstats[0][i];

		blstats[0][i].a = zeroany;
		blstats[1][i].a = zeroany;
		if (blstats[0][i].valwidth) {
		    blstats[0][i].val = (char *)alloc(blstats[0][i].valwidth);
		    blstats[1][i].val = (char *)alloc(blstats[0][i].valwidth);
		} else {
		    blstats[0][i].val = (char *)0;
		    blstats[1][i].val = (char *)0;
		}
	}
}

STATIC_OVL char *
anything_to_s(buf, a, anytype)
char *buf;
anything *a;
int anytype;
{
	if (!buf) return (char *)0;

	switch (anytype) {
	    case ANY_ULONG:	Sprintf(buf,"%lu", a->a_ulong); break;
	    case ANY_MASK32:	Sprintf(buf,"%lx", a->a_ulong); break;
	    case ANY_LONG:	Sprintf(buf,"%ld", a->a_long); break;
	    case ANY_INT:	Sprintf(buf,"%d",  a->a_int); break;
	    case ANY_UINT:	Sprintf(buf,"%u",  a->a_uint); break;
	    case ANY_IPTR:	Sprintf(buf,"%d",  *a->a_iptr); break;
	    case ANY_LPTR:	Sprintf(buf,"%ld", *a->a_lptr); break;
	    case ANY_ULPTR:	Sprintf(buf,"%lu", *a->a_ulptr); break;
	    case ANY_UPTR:	Sprintf(buf,"%u",  *a->a_uptr); break;
	    case ANY_STR: 	/* do nothing */; break;
	    default:
	    		buf[0] = '\0';
	}
	return buf;
}

STATIC_OVL void
s_to_anything(a, buf, anytype)
anything *a;
char *buf;
int anytype;
{
	if (!buf || !a) return;

	switch (anytype) {
	    case ANY_LONG:	a->a_long = atol(buf); break;
	    case ANY_INT:	a->a_int  = atoi(buf); break;
	    case ANY_UINT:	a->a_uint = (unsigned) atoi(buf); break;
	    case ANY_ULONG:	a->a_ulong = (unsigned long) atol(buf); break;
	    case ANY_IPTR:	if (a->a_iptr)
	    			    *a->a_iptr = atoi(buf); break;
	    case ANY_UPTR:	if (a->a_uptr)
				    *a->a_uptr = (unsigned) atoi(buf); break;
	    case ANY_LPTR:	if (a->a_lptr)
				    *a->a_lptr = atol(buf); break;
	    case ANY_ULPTR:	if (a->a_ulptr)
				    *a->a_ulptr = (unsigned long) atol(buf); break;
	    case ANY_MASK32:	a->a_ulong = (unsigned long) atol(buf); break;
	    default:		a->a_void = 0; break;
	}
	return;
}

STATIC_OVL int
compare_blstats(bl1, bl2)
struct istat_s *bl1, *bl2;
{
	int anytype, result = 0;

	if (!bl1 || !bl2) {
		panic("compare_blstat: bad istat pointer %s, %s",
		      fmt_ptr((genericptr_t)bl1),
		      fmt_ptr((genericptr_t)bl2));
	}

	anytype = bl1->anytype;
	if ((!bl1->a.a_void || !bl2->a.a_void) &&
	    (anytype == ANY_IPTR || anytype == ANY_UPTR ||
	     anytype == ANY_LPTR || anytype == ANY_ULPTR)) {
		panic("compare_blstat: invalid pointer %s, %s",
		      fmt_ptr((genericptr_t)bl1->a.a_void),
		      fmt_ptr((genericptr_t)bl2->a.a_void));
	}

	switch(anytype) {
	    case ANY_INT:
			result =(bl1->a.a_int < bl2->a.a_int) ?  1 :
	    			(bl1->a.a_int > bl2->a.a_int) ? -1 :
				0;
	    		break;
	    case ANY_IPTR:
			result =(*bl1->a.a_iptr < *bl2->a.a_iptr) ?  1 :
	    			(*bl1->a.a_iptr > *bl2->a.a_iptr) ? -1 :
				0;
	    		break;
	    case ANY_LONG:
			result =(bl1->a.a_long < bl2->a.a_long) ?  1 :
	    			(bl1->a.a_long > bl2->a.a_long) ? -1 :
				0;
	    		break;
	    case ANY_LPTR:
			result =(*bl1->a.a_lptr < *bl2->a.a_lptr) ?  1 :
	    			(*bl1->a.a_lptr > *bl2->a.a_lptr) ? -1 :
				0;
	    		break;
	    case ANY_UINT:
			result =(bl1->a.a_uint < bl2->a.a_uint) ?  1 :
	    			(bl1->a.a_uint > bl2->a.a_uint) ? -1 :
				0;
	    		break;
	    case ANY_UPTR:
			result =(*bl1->a.a_uptr < *bl2->a.a_uptr) ?  1 :
	    			(*bl1->a.a_uptr > *bl2->a.a_uptr) ? -1 :
				0;
	    		break;
	    case ANY_ULONG:
			result =(bl1->a.a_ulong < bl2->a.a_ulong) ?  1 :
	    			(bl1->a.a_ulong > bl2->a.a_ulong) ? -1 :
				0;
	    		break;
	    case ANY_ULPTR:
			result =(*bl1->a.a_ulptr < *bl2->a.a_ulptr) ?  1 :
	    			(*bl1->a.a_ulptr > *bl2->a.a_ulptr) ? -1 :
				0;
	    		break;
	    case ANY_STR:
			if (strcmp(bl1->val, bl2->val) == 0) result = 0;
			else result = 1;
			break;
	    case ANY_MASK32:
			if (bl1->a.a_ulong == bl2->a.a_ulong) result = 0;
			else result = 1;
			break;
	    default:
	    		result = 1;
	}
	return result;
}

STATIC_OVL int
percentage(bl, maxbl)
struct istat_s *bl, *maxbl;
{
	int result = 0;
	int anytype;

	if (!bl || !maxbl) {
		impossible("percentage: bad istat pointer %s, %s",
			   fmt_ptr((genericptr_t)bl),
			   fmt_ptr((genericptr_t)maxbl));
		return 0;
	}

	anytype = bl->anytype;
	if (maxbl->a.a_void) {
	    switch(anytype) {
		case ANY_INT:
			result = ((100 * bl->a.a_int) / maxbl->a.a_int);
			break;
		case ANY_LONG:
			result = (int) ((100L * bl->a.a_long) /
					maxbl->a.a_long);
			break;
		case ANY_UINT:
			result = (int) ((100U * bl->a.a_uint) /
					maxbl->a.a_uint);
			break;
		case ANY_ULONG:
			result = (int) ((100UL * bl->a.a_ulong) /
					maxbl->a.a_ulong);
		    	break;
		case ANY_IPTR:
			result = ((100 * (*bl->a.a_iptr)) /
					(*maxbl->a.a_iptr));
			break;
		case ANY_LPTR:
			result = (int) ((100L * (*bl->a.a_lptr)) /
					(*maxbl->a.a_lptr));
			break;
		case ANY_UPTR:
			result = (int) ((100U * (*bl->a.a_uptr)) /
					(*maxbl->a.a_uptr));
			break;
		case ANY_ULPTR:
			result = (int) ((100UL * (*bl->a.a_ulptr)) /
					(*maxbl->a.a_ulptr));
		    	break;
	    }
	}
	return result;
}

void
bot()
{
	char buf[BUFSZ];
	register char *nb;
	static int idx = 0, idx_p, idxmax;
	boolean updated = FALSE;
	unsigned anytype;
	int i, pc, chg, cap;
	struct istat_s *curr, *prev;
	boolean valset[MAXBLSTATS], chgval = FALSE;

	if (!blinit) panic("bot before init.");
	if (!youmonst.data) {
		context.botl = context.botlx = 0;
		update_all = FALSE;
		return;
	}

	cap = near_capacity();
	idx_p = idx;
	idx   = 1 - idx;	/* 0 -> 1, 1 -> 0 */

	/* clear the "value set" indicators */
	(void) memset((genericptr_t)valset, 0, MAXBLSTATS * sizeof(boolean));

	/*
	 *  Player name and title.
	 */
	buf[0] = '\0';
	Strcpy(buf, plname);
	if('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a';
	buf[10] = 0;
	Sprintf(nb = eos(buf)," the ");
	if (Upolyd) {
		char mbot[BUFSZ];
		int k = 0;

		Strcpy(mbot, mons[u.umonnum].mname);
		while(mbot[k] != 0) {
		    if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) &&
					'a' <= mbot[k] && mbot[k] <= 'z')
			mbot[k] += 'A' - 'a';
		    k++;
		}
		Sprintf1(nb = eos(nb), mbot);
	} else
		Sprintf1(nb = eos(nb), rank());
	Sprintf(blstats[idx][BL_TITLE].val, "%-29s", buf);
	valset[BL_TITLE] = TRUE;		/* indicate val already set */

	/* Strength */

	buf[0] = '\0';
	blstats[idx][BL_STR].a.a_int = ACURR(A_STR);
	if (ACURR(A_STR) > 18) {
		if (ACURR(A_STR) > STR18(100))
		    Sprintf(buf,"%2d",ACURR(A_STR)-100);
		else if (ACURR(A_STR) < STR18(100))
		    Sprintf(buf, "18/%02d",ACURR(A_STR)-18);
		else
		    Sprintf(buf,"18/**");
	} else
		Sprintf(buf, "%-1d",ACURR(A_STR));
	Strcpy(blstats[idx][BL_STR].val, buf);
	valset[BL_STR] = TRUE;		/* indicate val already set */


	/*  Dexterity, constitution, intelligence, wisdom, charisma. */
	 
	blstats[idx][BL_DX].a.a_int = ACURR(A_DEX);
	blstats[idx][BL_CO].a.a_int = ACURR(A_CON);
	blstats[idx][BL_IN].a.a_int = ACURR(A_INT);
	blstats[idx][BL_WI].a.a_int = ACURR(A_WIS);
	blstats[idx][BL_CH].a.a_int = ACURR(A_CHA);

	/* Alignment */

	Strcpy(blstats[idx][BL_ALIGN].val,
			(u.ualign.type == A_CHAOTIC) ? "Chaotic" :
			(u.ualign.type == A_NEUTRAL) ? "Neutral" : "Lawful");

	/* Score */

	blstats[idx][BL_SCORE].a.a_long =
#ifdef SCORE_ON_BOTL
		botl_score();
#else
		0;
#endif
	/*  Hit points  */

	blstats[idx][BL_HP].a.a_int = Upolyd ? u.mh : u.uhp;
	blstats[idx][BL_HPMAX].a.a_int = Upolyd ? u.mhmax : u.uhpmax;
	if( blstats[idx][BL_HP].a.a_int < 0)
		blstats[idx][BL_HP].a.a_int = 0;

	/*  Dungeon level. */

	(void) describe_level(blstats[idx][BL_LEVELDESC].val);
	valset[BL_LEVELDESC] = TRUE;		/* indicate val already set */

	/* Gold */

	blstats[idx][BL_GOLD].a.a_long = money_cnt(invent);
	/*
	 * The tty port needs to display the current symbol for gold
	 * as a field header, so to accomodate that we pass gold with
	 * that already included. If a window port needs to use the text
	 * gold amount without the leading "$:" the port will have to
	 * add 2 to the value pointer it was passed in status_update()
	 * for the BL_GOLD case.
	 *
	 * Another quirk of BL_GOLD is that the field display may have
	 * changed if a new symbol set was loaded, or we entered or left
	 * the rogue level.
	 */

	Sprintf(blstats[idx][BL_GOLD].val,
			"%s:%ld",
			encglyph(objnum_to_glyph(GOLD_PIECE)),
			blstats[idx][BL_GOLD].a.a_long);
	valset[BL_GOLD] = TRUE;		/* indicate val already set */


	/* Power (magical energy) */

	blstats[idx][BL_ENE].a.a_int = u.uen;
	blstats[idx][BL_ENEMAX].a.a_int = u.uenmax;

	/* Armor class */

	blstats[idx][BL_AC].a.a_int = u.uac;

	/* Monster level (if Upolyd) */

	if (Upolyd)
		blstats[idx][BL_HD].a.a_int = mons[u.umonnum].mlevel;
	else
		blstats[idx][BL_HD].a.a_int = 0;

	/* Experience */

	blstats[idx][BL_XP].a.a_int = u.ulevel;
	blstats[idx][BL_EXP].a.a_int = u.uexp;

	/* Time (moves) */

	blstats[idx][BL_TIME].a.a_long  = moves;

	/* Hunger */

	blstats[idx][BL_HUNGER].a.a_uint = u.uhs;
	*(blstats[idx][BL_HUNGER].val) = '\0';
	if(strcmp(hu_stat[u.uhs], "        ") != 0)
		Strcpy(blstats[idx][BL_HUNGER].val, hu_stat[u.uhs]);
	valset[BL_HUNGER] = TRUE;

	/* Carrying capacity */

	*(blstats[idx][BL_CAP].val) = '\0';
	blstats[idx][BL_CAP].a.a_int = cap;
	if(cap > UNENCUMBERED)
		Strcpy(blstats[idx][BL_CAP].val, enc_stat[cap]);
	valset[BL_CAP] = TRUE;

	/* Conditions */

	if (Blind) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_BLIND;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_BLIND;
	
	if (Confusion) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_CONF;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_CONF;

	if (Sick && u.usick_type & SICK_VOMITABLE)
		blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_FOODPOIS;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_FOODPOIS;

	if (Sick && u.usick_type & SICK_NONVOMITABLE)
		blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_ILL;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_ILL;
				
	if (Hallucination) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_HALLU;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_HALLU;
	
	if (Stunned) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_STUNNED;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_STUNNED;

	if (Slimed) blstats[idx][BL_CONDITION].a.a_ulong |= BL_MASK_SLIMED;
	else blstats[idx][BL_CONDITION].a.a_ulong &= ~BL_MASK_SLIMED;
	
	/*
	 *  Now pass the changed values to window port.
	 */
	for (i = 0; i < MAXBLSTATS; i++) {
		if (((i == BL_SCORE) && !flags.showscore) ||
		    ((i == BL_EXP)   && !flags.showexp)   ||
		    ((i == BL_TIME)  && !flags.time)      ||
		    ((i == BL_HD)    && !Upolyd)	  ||
		    ((i == BL_XP || i == BL_EXP) && Upolyd))
			continue;
		anytype = blstats[idx][i].anytype;
		curr = &blstats[idx][i];
		prev = &blstats[idx_p][i];
		chg = 0;
		if (update_all || ((chg = compare_blstats(prev, curr)) != 0) ||
		    ((chgval = (valset[i] &&
		      strcmp(blstats[idx][i].val,blstats[idx_p][i].val))) != 0)) {
			idxmax = blstats[idx][i].idxmax;
			pc = (idxmax) ?
				percentage(curr, &blstats[idx][idxmax]) : 0;
			if (!valset[i]) (void) anything_to_s(curr->val,
							&curr->a, anytype);
			if (anytype != ANY_MASK32) {
				status_update(i, (genericptr_t)curr->val,
						valset[i] ? chgval : chg, pc);
			} else {
				status_update(i,
				    /* send pointer to mask */
				    (genericptr_t) &curr->a.a_ulong, chg, 0);
			}
			updated = TRUE;
		}
	}
	/*
	 * It is possible to get here, with nothing having been pushed
	 * to the window port, when none of the info has changed. In that
	 * case, we need to force a call to status_update() when
	 * context.botlx is set. The tty port in particular has a problem
	 * if that isn't done, since it sets context.botlx when a menu or
	 * text display obliterates the status line.
	 *
	 * To work around it, we call status_update() with ficticious
	 * index of BL_FLUSH (-1).
	 */
	if (context.botlx && !updated)
		status_update(BL_FLUSH,(genericptr_t)0,0,0);

	context.botl = context.botlx = 0;
	update_all = FALSE;
}

/*****************************************************************************/
/* Core status hiliting support                                              */
/*****************************************************************************/

#ifdef STATUS_HILITES

struct hilite_s {
	boolean set;
	anything threshold;
	int behavior;
	int coloridx[2];
};

struct hilite_s status_hilites[MAXBLSTATS];

/*
 * This is the parser for the hilite options
 * Example:
 *    OPTION=hilite_status: hitpoints/10%/red/normal
 *
 * set_hilite_status() separates each hilite entry into its 4 component
 * strings, then calls assign_hilite() to make the adjustments.
 */
boolean
set_status_hilites(op)
char *op;
{
	char hsbuf[4][QBUFSZ];
	boolean rslt, badopt = FALSE;
	int fldnum, num =0, ccount = 0;
	char c;

	num = fldnum = 0;
	hsbuf[0][0] = hsbuf[1][0] = hsbuf[2][0] = hsbuf[3][0] = '\0';
	while (*op && fldnum < 4 && ccount < (QBUFSZ - 2)) {
		c = lowc(*op);
		if (c == ' ') {
			if (fldnum >= 2) {
				rslt = assign_hilite(&hsbuf[0][0],
						     &hsbuf[1][0],
					             &hsbuf[2][0],
					             &hsbuf[3][0]);
				if (!rslt) {
					badopt = TRUE;
					break;
				}
			}
			hsbuf[0][0] = hsbuf[1][0] = '\0';
			hsbuf[2][0] = hsbuf[3][0] = '\0';
			fldnum = 0;
			ccount = 0;
		} else if (c == '/') {
			fldnum++;
			ccount = 0;
		} else {
			hsbuf[fldnum][ccount++] = c;
			hsbuf[fldnum][ccount] = '\0';
		}
		op++;
	}
	if (fldnum >= 2 && !badopt) {
		rslt = assign_hilite(&hsbuf[0][0],
				     &hsbuf[1][0],
			             &hsbuf[2][0],
			             &hsbuf[3][0]);
		if (!rslt) badopt = TRUE;
	}
	if (badopt) return FALSE;
	return TRUE;
}

void
clear_status_hilites()
{
	int i;
	anything it;
	it.a_void = 0;
	for (i = 0; i < MAXBLSTATS; ++i) {
		(void) memset((genericptr_t)&status_hilites[i],
				0, sizeof(struct hilite_s));
		/* notify window port */
		status_threshold(i, blstats[0][i].anytype,it,0,0,0);
	}
}

STATIC_OVL boolean
assign_hilite(sa,sb,sc,sd)
char *sa, *sb, *sc, *sd;
{
	char *tmp, *how;
	int i, dt, idx = -1;
	int coloridx[2] = {-1, -1};
	boolean inverse[2] = {FALSE, FALSE};
	boolean bold[2]	   = {FALSE, FALSE};
	boolean normal[2]  = {0,0};
	boolean percent = FALSE, down_up = FALSE, changed = FALSE;
	anything threshold;

	threshold.a_void = 0;

	/* Example:
	 * 	hilite_status: hitpoints/10%/red/normal
	 */

	/* field name to idx */
	for (i = 0; sa && i < MAXBLSTATS; ++i) {
		if (strcmpi(sa,status_fieldnames[i]) == 0) {
			idx = i;
			break;
		}
	}
	if (idx == -1) return FALSE;
	status_hilites[idx].set = FALSE;	/* mark it "unset" */

	/* threshold */
	if (!sb) return FALSE;
	if ((strcmpi(sb, "updown") == 0) || (strcmpi(sb, "downup") == 0) ||
	    (strcmpi(sb, "up") == 0)     || (strcmpi(sb, "down") == 0)) {
	    	down_up = TRUE;
	} else if ((strcmpi(sb, "changed") == 0) &&
		 (idx == BL_TITLE     || idx == BL_ALIGN ||
		  idx == BL_LEVELDESC || idx == BL_CONDITION)) {
		changed = TRUE;		/* changed is only thing allowed */
	} else {
		tmp = sb;
		while (*tmp) {
			if (*tmp == '%') {
				*tmp = '\0';
				percent = TRUE;
				break;
			} else if (!index("0123456789", *tmp))
				return FALSE;
			tmp++;
		}
		if (strlen(sb) > 0) {
			dt = blstats[0][idx].anytype;
			if (percent) dt = ANY_INT;
			(void) s_to_anything(&threshold, sb, dt);
		} else return FALSE;
		if (percent &&
			(threshold.a_int < 1 || threshold.a_int > 100))
				return FALSE;
		if (!threshold.a_void && (strcmp(sb, "0") != 0)) return FALSE;
	}

	/* actions */
	for (i = 0; i < 2; ++i) {
	    if (!i) how = sc;
	    else how = sd;
	    if (!how) {
	    	if (!i) return FALSE;
	    	else break;		/* sc is mandatory; sd is not */
	    }

	    if (strcmpi(how, "bold") == 0) {
	    	bold[i] = TRUE;
	    } else if (strcmpi(how, "inverse") == 0) {
	    	inverse[i] = TRUE;
	    } else if (strcmpi(how, "normal") == 0) {
	    	normal[i] = TRUE;
	    } else {
		int k;
		char colorname[BUFSZ];
		for (k = 0; k < CLR_MAX; ++k) {
			/* we have to make a copy to change space to dash */
			(void) strcpy(colorname, c_obj_colors[k]);
			for(tmp = index(colorname,' ');
			    tmp; tmp = index(colorname, ' '))
				*tmp = '-';
			if (strcmpi(how, colorname) == 0) {
				coloridx[i] = k;
				break;
			}
	        }
	        if (k >= CLR_MAX) return FALSE;
	    }
	}

	/* Assign the values */

	for (i = 0; i < 2; ++i) {
	    if (inverse[i]) status_hilites[idx].coloridx[i] = BL_HILITE_INVERSE;
	    else if (bold[i])   status_hilites[idx].coloridx[i] = BL_HILITE_BOLD;
	    else if (coloridx[i]) status_hilites[idx].coloridx[i] = coloridx[i];
	    else status_hilites[idx].coloridx[i] = BL_HILITE_NONE;
	}

	if (percent)
		status_hilites[idx].behavior = BL_TH_VAL_PERCENTAGE;
	else if (down_up)
		status_hilites[idx].behavior = BL_TH_UPDOWN;
	else if (threshold.a_void)
		status_hilites[idx].behavior = BL_TH_VAL_ABSOLUTE;
	else
		status_hilites[idx].behavior = BL_TH_NONE;

	if (status_hilites[idx].behavior != BL_TH_NONE) {
		status_hilites[idx].threshold = threshold;
		status_hilites[idx].set = TRUE;
	}

	/* Now finally, we notify the window port */
	status_threshold(idx, dt, threshold,
			status_hilites[idx].behavior,
			status_hilites[idx].coloridx[0],
			status_hilites[idx].coloridx[1]);
	return TRUE;
}
/*
 * get_status_hilites
 *
 * Returns a string containing all the status hilites in the
 * same format that is used to specify a status hilite preference
 * in the config file.  
 */
char *
get_status_hilites(buf, bufsiz)
char *buf;
int bufsiz;
{
	int i, j, k, coloridx;
	const char *text = (char *)0;
	char tmp[BUFSZ], colorname[BUFSZ];
	boolean val_percentage, val_absolute, up_down;
	boolean added_one = FALSE;

	if (!buf) return (char *)0;
	*buf = '\0';

	bufsiz--;	/* required trailing null */
	for (i = 0; i < MAXBLSTATS; ++i) {
		val_percentage = val_absolute = up_down = FALSE;
		if (status_hilites[i].set) {
			if (!added_one)
				added_one = TRUE;
			else {
				Strcat(buf, " ");
				bufsiz--;
			}
			k = strlen(status_fieldnames[i]);
			if (k < bufsiz) {
				Strcat(buf,status_fieldnames[i]);
				bufsiz -= k;
			}
			if (bufsiz > 1) {
				Strcat(buf, "/");
				bufsiz--;
			}
			if (status_hilites[i].behavior == BL_TH_VAL_PERCENTAGE) {
				val_percentage = TRUE;
			} else if (status_hilites[i].behavior ==
							BL_TH_VAL_ABSOLUTE) {
				val_absolute = TRUE;
			} else if (status_hilites[i].behavior == BL_TH_UPDOWN) {
				up_down = TRUE;
				text = "updown";
			}

			anything_to_s(tmp, &status_hilites[i].threshold,
					blstats[0][i].anytype);
			text = tmp;
			k = strlen(text);
			if (k < (bufsiz - 1)) {
				Strcat(buf, text);
				if (val_percentage) Strcat(buf, "%"), k++;
				bufsiz -= k;
			}
			for (j = 0; j < 2; ++j) {
				if (bufsiz > 1) {
				    Strcat(buf, "/");
				    bufsiz--;
				}
				coloridx = status_hilites[i].coloridx[j];
				if (coloridx < 0) {
				    if (coloridx == BL_HILITE_BOLD)
						text = "bold";
				    else if (coloridx == BL_HILITE_INVERSE)
						text = "inverse";
				    else 
						text = "normal";
				} else {
				    char *blank;
				    (void) strcpy(colorname, c_obj_colors[coloridx]);
				    for(blank = index(colorname,' ');
			    			blank; blank = index(colorname, ' '))
					*blank = '-';
				    text = colorname;
				}
				k = strlen(text);
				if (k < bufsiz) {
					Strcat(buf, text); 
					bufsiz -= k;
				}
			}
		}
	}
	return buf;
}

STATIC_OVL const char *
clridx_to_s(buf, idx)
char *buf;
int idx;
{
	static const char *a[] = { "bold", "inverse", "normal" };

	if (buf) {
		buf[0] = '\0';
		if (idx < 0 && idx >= BL_HILITE_BOLD)
			Strcpy(buf, a[idx + 3]);
		else if (idx >= 0 && idx < CLR_MAX)
			Strcpy(buf, c_obj_colors[idx]);
	}
	return buf;
}

boolean
status_hilite_menu()
{
	int i, j, k, pick_cnt, pick_idx, opt_idx;
	menu_item *statfield_picks = (menu_item *)0;
	const char *fieldname;
	int field_picks[MAXBLSTATS], res;
	struct hilite_s hltemp[MAXBLSTATS];
	char buf[BUFSZ], thresholdbuf[BUFSZ], below[BUFSZ], above[BUFSZ];
	winid tmpwin;
	anything any;

        tmpwin = create_nhwindow(NHW_MENU);
	start_menu(tmpwin);
	for (i = 0; i < MAXBLSTATS; i++) {
		(void) memset(&hltemp[i], 0, sizeof(struct hilite_s));
		fieldname = status_fieldnames[i];
		any.a_int = i + 1;
		add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
			 ATR_NONE, fieldname, MENU_UNSELECTED);
		field_picks[i] = 0;
        }
	end_menu(tmpwin, "Change hilite on which status field(s):");
	if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &statfield_picks)) > 0) {
	    for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) {
		opt_idx = statfield_picks[pick_idx].item.a_int - 1;
		field_picks[opt_idx] = 1;
	    }
	    free((genericptr_t)statfield_picks);
	    statfield_picks = (menu_item *)0;
	}
	destroy_nhwindow(tmpwin);
	if (pick_cnt < 0) return FALSE;

	for (i = 0; i < MAXBLSTATS; i++) {
	    if (field_picks[i]) {
		menu_item *pick = (menu_item *)0;
		Sprintf(buf, "Threshold behavior options for %s:",
			status_fieldnames[i]);
	        tmpwin = create_nhwindow(NHW_MENU);
		start_menu(tmpwin);
		if (i == BL_CONDITION) {
			any = zeroany;
			any.a_int = BL_TH_CONDITION + 1;
			add_menu(tmpwin, NO_GLYPH, &any, 'c', 0,
				ATR_NONE, "Condition bitmask threshold.",
				MENU_UNSELECTED);
		}
		any = zeroany;
		any.a_int = BL_TH_NONE + 1;
		add_menu(tmpwin, NO_GLYPH, &any, 'n', 0,
			ATR_NONE,"None", MENU_UNSELECTED);
 	    	if (i != BL_CONDITION) {
			if (blstats[0][i].idxmax > 0) {
				any = zeroany;
				any.a_int = BL_TH_VAL_PERCENTAGE + 1;
				add_menu(tmpwin, NO_GLYPH, &any, 'p', 0,
					ATR_NONE, "Percentage threshold.",
					MENU_UNSELECTED);
			}
			any = zeroany;
			any.a_int = BL_TH_UPDOWN + 1;
			add_menu(tmpwin, NO_GLYPH, &any, 'u', 0,
				ATR_NONE, "UpDown threshold.",
				MENU_UNSELECTED);
			any = zeroany;
			any.a_int = BL_TH_VAL_ABSOLUTE + 1;
			add_menu(tmpwin, NO_GLYPH, &any, 'v', 0,
				ATR_NONE,"Value threshold.",
				MENU_UNSELECTED);
		}
		end_menu(tmpwin, buf);
		if ((res=select_menu(tmpwin, PICK_ONE, &pick)) > 0) {
			hltemp[i].behavior = pick->item.a_int - 1;
			free((genericptr_t)pick);
		}
		destroy_nhwindow(tmpwin);
		if (res < 0) return FALSE;

		if (hltemp[i].behavior == BL_TH_UPDOWN) {
			Sprintf(below, "%s decreases",
				status_fieldnames[i]);
			Sprintf(above, "%s increases",
				status_fieldnames[i]);
		} else if (hltemp[i].behavior) {
			/* Have them enter the threshold*/
			Sprintf(buf, "Set %s threshold to what%s?",
				status_fieldnames[i],
				(hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ?
				" percentage" :
				(hltemp[i].behavior == BL_TH_CONDITION) ?
				" mask" : "");
			getlin(buf, thresholdbuf);
			if (thresholdbuf[0] == '\033') return FALSE;
			(void) s_to_anything(&hltemp[i].threshold,
						thresholdbuf,
						blstats[0][i].anytype);
			if (!hltemp[i].threshold.a_void) return FALSE;

			Sprintf(below, "%s falls below %s%s",
				status_fieldnames[i],
				thresholdbuf,
				(hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ?
					"%" : "");
			Sprintf(above, "%s rises above %s%s",
				status_fieldnames[i],
				thresholdbuf,
				(hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ?
					"%" : "");
		}
		for (j = 0; j < 2 && (hltemp[i].behavior != BL_TH_NONE); ++j) {
		    char prompt[QBUFSZ];
		    /* j == 0 below, j == 1 above */
		    menu_item *pick2 = (menu_item *)0;
		    Sprintf(prompt, "Display how when %s?",
				j ? above : below);
	            tmpwin = create_nhwindow(NHW_MENU);
		    start_menu(tmpwin);
		    for (k = -3; k < CLR_MAX; ++k) {
/*		    	if (k == -1) continue; */
			any = zeroany;
			any.a_int = (k >= 0) ? k + 1 : k;
			if (k > 0) add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
						ATR_NONE, c_obj_colors[k],
						MENU_UNSELECTED);
			else if (k == -1) add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
						ATR_NONE,"normal",
						MENU_UNSELECTED);
			else if (k == -2) add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
						ATR_NONE,"inverse",
						MENU_UNSELECTED);
			else if (k == -3) add_menu(tmpwin, NO_GLYPH, &any, 0, 0,
						ATR_NONE,"bold",
						MENU_UNSELECTED);
		    }
		    end_menu(tmpwin, prompt);
		    if ((res = select_menu(tmpwin, PICK_ONE, &pick2)) > 0) {
			hltemp[i].coloridx[j] = (pick2->item.a_char > 0) ?
						pick2->item.a_int - 1 :
						pick2->item.a_int;
			free((genericptr_t)pick2);
		    }
		    destroy_nhwindow(tmpwin);
		    if (res < 0) return FALSE;
		}
	    }
	}
	buf[0] = '\0';
	for (i = 0; i < MAXBLSTATS; i++) {
	    if (field_picks[i]) {
	    	Sprintf(eos(buf), "%s/%s%s/",
	    		status_fieldnames[i],
			(hltemp[i].behavior == BL_TH_UPDOWN) ?  "updown" :
			anything_to_s(thresholdbuf,
					&hltemp[i].threshold,
					blstats[0][i].anytype),
			(hltemp[i].behavior == BL_TH_VAL_PERCENTAGE) ? "%" : "");
		/* borrow thresholdbuf for use with these last two */
	    	Sprintf(eos(buf), "%s/",
			clridx_to_s(thresholdbuf, hltemp[i].coloridx[0]));
	    	Sprintf(eos(buf), "%s ",
			clridx_to_s(thresholdbuf, hltemp[i].coloridx[1]));
	    }
	}
	return set_status_hilites(buf);
}
#endif /*STATUS_HILITES*/

/*****************************************************************************/
/* genl backward compat stuff - probably doesn't belong in botl.c any longer */
/*****************************************************************************/

const char *fieldnm[MAXBLSTATS];
const char *fieldfmt[MAXBLSTATS];
char *vals[MAXBLSTATS];
boolean activefields[MAXBLSTATS];
NEARDATA winid WIN_STATUS;

void
genl_status_init()
{
	int i;
	for (i = 0; i < MAXBLSTATS; ++i) {
		vals[i] = (char *)alloc(MAXCO);
		*vals[i] = '\0';
		activefields[i] = FALSE;
		fieldfmt[i] = (const char *)0;
	}
	/* Use a window for the genl version; backward port compatibility */
	WIN_STATUS = create_nhwindow(NHW_STATUS);
	display_nhwindow(WIN_STATUS, FALSE);
}

void
genl_status_finish()
{
	/* tear down routine */
	int i;

	/* free alloc'd memory here */
	for (i = 0; i < MAXBLSTATS; ++i) {
		if (vals[i]) free((genericptr_t)vals[i]);
		vals[i] = (char *)0;
	}
}

void
genl_status_enablefield(fieldidx, nm, fmt, enable)
int fieldidx;
const char *nm;
const char *fmt;
boolean enable;
{
	fieldfmt[fieldidx] = fmt;
	fieldnm[fieldidx] = nm;
	activefields[fieldidx] = enable;
}

# ifdef STATUS_HILITES
void
genl_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over)
int fldidx,thresholdtype;
int behavior, under, over;
anything threshold;
{
	return;
}
# endif /* STATUS_HILITES */

void
genl_status_update(idx, ptr, chg, percent)
int idx, chg, percent;
genericptr_t ptr;
{
	char newbot1[MAXCO], newbot2[MAXCO];
	long cond, *condptr = (long *)ptr;
	register int i;
	char *text = (char *)ptr;
	int fieldorder1[] = {
		 BL_TITLE, BL_STR, BL_DX,BL_CO, BL_IN,
		 BL_WI, BL_CH,BL_ALIGN, BL_SCORE, -1
		};
	int fieldorder2[] = {
		 BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX,
		 BL_ENE, BL_ENEMAX, BL_AC, BL_XP, BL_EXP, BL_HD,
		 BL_TIME, BL_HUNGER,BL_CAP, BL_CONDITION, -1
		};

	if (idx != BL_FLUSH) {
	    if (!activefields[idx]) return;
	    switch(idx) {
		case BL_CONDITION:
	    		cond = *condptr;
	    		*vals[idx] = '\0';
	    		if (cond & BL_MASK_BLIND) Strcat(vals[idx], " Blind");
	    		if (cond & BL_MASK_CONF) Strcat(vals[idx], " Conf");
	    		if (cond & BL_MASK_FOODPOIS)
					Strcat(vals[idx], " FoodPois");
	    		if (cond & BL_MASK_ILL) Strcat(vals[idx], " Ill");
	    		if (cond & BL_MASK_STUNNED) Strcat(vals[idx], " Stun");
	    		if (cond & BL_MASK_HALLU) Strcat(vals[idx], " Hallu");
	    		if (cond & BL_MASK_SLIMED) Strcat(vals[idx], " Slime");
	    		break;
		default:
	    		Sprintf(vals[idx],
				fieldfmt[idx] ? fieldfmt[idx] : "%s", text);
	    		break;
	    }
	}

	/* This genl version updates everything on the display, everytime */
	newbot1[0] = '\0';
	for (i = 0; fieldorder1[i] >= 0; ++i) {
	    int idx1 = fieldorder1[i];
	    if (activefields[idx1])
	    	Strcat(newbot1, vals[idx1]);
	}
	newbot2[0] = '\0';
	for (i = 0; fieldorder2[i] >= 0; ++i) {
	    int idx2 = fieldorder2[i];
	    if (activefields[idx2])
	    	Strcat(newbot2, vals[idx2]);
	}
	curs(WIN_STATUS, 1, 0);
	putstr(WIN_STATUS, 0, newbot1);
	curs(WIN_STATUS, 1, 1);
	putmixed(WIN_STATUS, 0, newbot2);   /* putmixed() due to GOLD glyph */
}

#endif /*STATUS_VIA_WINDOWPORT*/

/*botl.c*/


