1573 lines
47 KiB
C
1573 lines
47 KiB
C
/* NetHack 3.6 botl.c $NHDT-Date: 1432512764 2015/05/25 00:12:44 $ $NHDT-Branch: master $:$NHDT-Revision: 1.50 $ */
|
|
/* 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++;
|
|
}
|
|
Strcpy(nb = eos(nb), mbot);
|
|
} else
|
|
Strcpy(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 = -1, dt = -1, 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*/
|