The one `anything any' that was triggering a warning was shadowing another `anything any' in the same function; no need to rename it, just remove the unnecessary declaration. Also, mark the couple of arrays with initializers that I'd noticed as static instead of letting them default to auto. The abil_to_spfx()::abil2spfx[] one might need to be redone in code as a switch if some compilers/linkers have trouble initializing it.
1464 lines
39 KiB
C
1464 lines
39 KiB
C
/* SCCS Id: @(#)botl.c 3.5 2008/02/19 */
|
|
/* 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;
|
|
|
|
#ifndef GOLDOBJ
|
|
utotal = u.ugold + hidden_gold();
|
|
if ((utotal -= u.ugold0) < 0L) utotal = 0L;
|
|
#else
|
|
utotal = money_cnt(invent) + hidden_gold();
|
|
if ((utotal -= u.umoney0) < 0L) utotal = 0L;
|
|
#endif
|
|
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)),
|
|
#ifndef GOLDOBJ
|
|
u.ugold,
|
|
#else
|
|
money_cnt(invent),
|
|
#endif
|
|
hp, hpmax, u.uen, u.uenmax, u.uac);
|
|
|
|
if (Upolyd)
|
|
Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel);
|
|
#ifdef EXP_ON_BOTL
|
|
else if(flags.showexp)
|
|
Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp);
|
|
#endif
|
|
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++;
|
|
}
|
|
Sprintf(nb = eos(nb), mbot);
|
|
} else
|
|
Sprintf(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 =
|
|
#ifndef GOLDOBJ
|
|
u.ugold;
|
|
#else
|
|
money_cnt(invent);
|
|
#endif
|
|
/*
|
|
* 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] = FALSE;
|
|
}
|
|
/* 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*/
|
|
|
|
|