It was possible for status_finish to get called twice, therefore free() could end up called twice. Add a macro symbol for the argument to status_initialize(). Adjust some field widths so that there is a little bit of breathing space.
841 lines
23 KiB
C
841 lines
23 KiB
C
/* SCCS Id: @(#)botl.c 3.4 2003/11/22 */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
|
|
extern const char *hu_stat[]; /* defined in eat.c */
|
|
|
|
const char * const enc_stat[] = {
|
|
"",
|
|
"Burdened",
|
|
"Stressed",
|
|
"Strained",
|
|
"Overtaxed",
|
|
"Overloaded"
|
|
};
|
|
|
|
#ifdef STATUS_VIA_WINDOWPORT
|
|
STATIC_OVL void NDECL(init_blstats);
|
|
#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 struct Role *role;
|
|
register int i;
|
|
|
|
|
|
/* Find the role */
|
|
for (role = (struct 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()
|
|
{
|
|
int deepest = deepest_lev_reached(FALSE);
|
|
#ifndef GOLDOBJ
|
|
long ugold = u.ugold + hidden_gold();
|
|
|
|
if ((ugold -= u.ugold0) < 0L) ugold = 0L;
|
|
return ugold + u.urexp + (long)(50 * (deepest - 1))
|
|
#else
|
|
long umoney = money_cnt(invent) + hidden_gold();
|
|
|
|
if ((umoney -= u.umoney0) < 0L) umoney = 0L;
|
|
return umoney + u.urexp + (long)(50 * (deepest - 1))
|
|
#endif
|
|
+ (long)(deepest > 30 ? 10000 :
|
|
deepest > 20 ? 1000*(deepest - 20) : 0);
|
|
}
|
|
#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),
|
|
"%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS],
|
|
#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);
|
|
putstr(WIN_STATUS, 0, newbot2);
|
|
}
|
|
|
|
void
|
|
bot()
|
|
{
|
|
bot1();
|
|
bot2();
|
|
context.botl = context.botlx = 0;
|
|
}
|
|
|
|
#else /* STATUS_VIA_WINDOWPORT */
|
|
|
|
/* These are used within botl.c only */
|
|
#define P_MASK 1
|
|
#define P_STR 2
|
|
#define P_INT 3
|
|
#define P_LNG 4
|
|
#define P_UINT 5
|
|
|
|
struct istat_s {
|
|
long time;
|
|
unsigned ptype;
|
|
anything ptr;
|
|
char *val;
|
|
int valwidth;
|
|
int idxmax;
|
|
};
|
|
|
|
#define percentage(current, maximum) ((100 * current) / maximum)
|
|
#define percentagel(current, maximum) ((int)((100L * current) / maximum))
|
|
|
|
/* If entries are added to this, botl.h will require updating too */
|
|
struct istat_s blstats[2][MAXBLSTATS] = {
|
|
{
|
|
{ 0L, P_STR, (genericptr_t)0, (char *)0, 80, 0}, /* 0 BL_TITLE */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 1 BL_STR */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 2 BL_DX */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 3 BL_CO */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 4 BL_IN */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 5 BL_WI */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 6 BL_CH */
|
|
{ 0L, P_STR, (genericptr_t)0, (char *)0, 40, 0}, /* 7 BL_ALIGN */
|
|
{ 0L, P_LNG, (genericptr_t)0, (char *)0, 20, 0}, /* 8 BL_SCORE */
|
|
{ 0L, P_LNG, (genericptr_t)0, (char *)0, 20, 0}, /* 9 BL_CAP */
|
|
{ 0L, P_LNG, (genericptr_t)0, (char *)0, 10, 0}, /* 10 BL_GOLD */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, BL_ENEMAX}, /* 11 BL_ENE */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 12 BL_ENEMAX */
|
|
{ 0L, P_LNG, (genericptr_t)0, (char *)0, 10, 0}, /* 13 BL_XP */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 14 BL_AC */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 15 BL_HD */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 20, 0}, /* 16 BL_TIME */
|
|
{ 0L, P_UINT,(genericptr_t)0, (char *)0, 40, 0}, /* 17 BL_HUNGER */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10,BL_HPMAX}, /* 18 BL_HP */
|
|
{ 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 19 BL_HPMAX */
|
|
{ 0L, P_STR, (genericptr_t)0, (char *)0, 80, 0}, /* 20 BL_LEVELDESC */
|
|
{ 0L, P_LNG, (genericptr_t)0, (char *)0, 20, 0}, /* 21 BL_EXP */
|
|
{ 0L, P_MASK,(genericptr_t)0, (char *)0, 0, 0}, /* 22 BL_CONDITION */
|
|
}
|
|
};
|
|
|
|
static boolean blinit = FALSE, update_all = FALSE;
|
|
|
|
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"
|
|
};
|
|
const char *fieldnames[] = {
|
|
"title", "strength", "dexterity", "constitution", "intelligence",
|
|
"wisdom", "charisma", "alignment", "score", "capacity",
|
|
"gold", "power", "power-max", "experience-level", "armor-class",
|
|
"HD", "time", "hunger", "hitpoints", "hitpoints-max",
|
|
"dungeon-level", "experience", "condition"
|
|
};
|
|
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, fieldnames[i], fieldfmts[i], FALSE);
|
|
else
|
|
status_enablefield(i, 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) {
|
|
free((genericptr_t)blstats[0][i].ptr.a_void);
|
|
free((genericptr_t)blstats[1][i].ptr.a_void);
|
|
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) {
|
|
switch(blstats[0][i].ptype) {
|
|
case P_INT:
|
|
blstats[0][i].ptr.a_iptr = (int *)alloc(sizeof(int));
|
|
blstats[1][i].ptr.a_iptr = (int *)alloc(sizeof(int));
|
|
*(blstats[0][i].ptr.a_iptr) = 0;
|
|
*(blstats[1][i].ptr.a_iptr) = 0;
|
|
break;
|
|
case P_LNG:
|
|
case P_MASK:
|
|
blstats[0][i].ptr.a_lptr = (long *)alloc(sizeof(long));
|
|
blstats[1][i].ptr.a_lptr = (long *)alloc(sizeof(long));
|
|
*(blstats[0][i].ptr.a_lptr) = 0L;
|
|
*(blstats[1][i].ptr.a_lptr) = 0L;
|
|
break;
|
|
case P_UINT:
|
|
blstats[0][i].ptr.a_uptr = (unsigned *)alloc(sizeof(unsigned));
|
|
blstats[1][i].ptr.a_uptr = (unsigned *)alloc(sizeof(unsigned));
|
|
*(blstats[0][i].ptr.a_uptr) = 0;
|
|
*(blstats[1][i].ptr.a_uptr) = 0;
|
|
break;
|
|
}
|
|
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;
|
|
}
|
|
blstats[1][i].ptype = blstats[0][i].ptype;
|
|
}
|
|
}
|
|
|
|
void
|
|
bot()
|
|
{
|
|
char buf[BUFSZ];
|
|
register char *nb;
|
|
static boolean init = FALSE;
|
|
static int idx = 0, idx_p, idxmax;
|
|
boolean updated = FALSE;
|
|
unsigned ptype;
|
|
int i, pc, cap = near_capacity();
|
|
anything curr, prev;
|
|
boolean valset[MAXBLSTATS];
|
|
|
|
if (!blinit) panic("bot before init.");
|
|
|
|
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);
|
|
|
|
/* Strength */
|
|
|
|
buf[0] = '\0';
|
|
*(blstats[idx][BL_STR].ptr.a_iptr) = 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].ptr.a_iptr) = ACURR(A_DEX);
|
|
*(blstats[idx][BL_CO].ptr.a_iptr) = ACURR(A_CON);
|
|
*(blstats[idx][BL_IN].ptr.a_iptr) = ACURR(A_INT);
|
|
*(blstats[idx][BL_WI].ptr.a_iptr) = ACURR(A_WIS);
|
|
*(blstats[idx][BL_CH].ptr.a_iptr) = 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].ptr.a_lptr) =
|
|
#ifdef SCORE_ON_BOTL
|
|
botl_score();
|
|
#else
|
|
0;
|
|
#endif
|
|
/* Hit points */
|
|
|
|
*(blstats[idx][BL_HP].ptr.a_iptr) = Upolyd ? u.mh : u.uhp;
|
|
*(blstats[idx][BL_HPMAX].ptr.a_iptr) = Upolyd ? u.mhmax : u.uhpmax;
|
|
if( *(blstats[idx][BL_HP].ptr.a_iptr) < 0)
|
|
*(blstats[idx][BL_HP].ptr.a_iptr) = 0;
|
|
|
|
/* Dungeon level. */
|
|
|
|
(void) describe_level(blstats[idx][BL_LEVELDESC].val);
|
|
|
|
/* Gold */
|
|
|
|
*(blstats[idx][BL_GOLD].ptr.a_lptr) =
|
|
#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.
|
|
*/
|
|
Sprintf(blstats[idx][BL_GOLD].val, "%c:%ld",
|
|
oc_syms[COIN_CLASS], *(blstats[idx][BL_GOLD].ptr.a_lptr));
|
|
valset[BL_GOLD] = TRUE; /* indicate val already set */
|
|
|
|
/* Power (magical energy) */
|
|
|
|
*(blstats[idx][BL_ENE].ptr.a_iptr) = u.uen;
|
|
*(blstats[idx][BL_ENEMAX].ptr.a_iptr) = u.uenmax;
|
|
|
|
/* Armor class */
|
|
|
|
*(blstats[idx][BL_AC].ptr.a_iptr) = u.uac;
|
|
|
|
/* Monster level (if Upolyd) */
|
|
|
|
if (Upolyd)
|
|
*(blstats[idx][BL_HD].ptr.a_iptr) = mons[u.umonnum].mlevel;
|
|
else
|
|
*(blstats[idx][BL_HD].ptr.a_iptr) = 0;
|
|
|
|
/* Experience */
|
|
|
|
*(blstats[idx][BL_XP].ptr.a_iptr) = u.ulevel;
|
|
*(blstats[idx][BL_EXP].ptr.a_lptr) = u.uexp;
|
|
|
|
/* Time (moves) */
|
|
|
|
*(blstats[idx][BL_TIME].ptr.a_lptr) = moves;
|
|
|
|
/* Hunger */
|
|
|
|
*(blstats[idx][BL_HUNGER].ptr.a_uptr) = 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].ptr.a_iptr) = cap;
|
|
if(cap > UNENCUMBERED)
|
|
Strcpy(blstats[idx][BL_CAP].val, enc_stat[cap]);
|
|
valset[BL_CAP] = TRUE;
|
|
|
|
/* Conditions */
|
|
|
|
if (Blind) *(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_BLIND;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_BLIND;
|
|
|
|
if (Confusion) *(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_CONF;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_CONF;
|
|
|
|
if (Sick && u.usick_type & SICK_VOMITABLE)
|
|
*(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_FOODPOIS;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_FOODPOIS;
|
|
|
|
if (Sick && u.usick_type & SICK_NONVOMITABLE)
|
|
*(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_ILL;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_ILL;
|
|
|
|
if (Hallucination) *(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_HALLU;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_HALLU;
|
|
|
|
if (Stunned) *(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_STUNNED;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_STUNNED;
|
|
|
|
if (Slimed) *(blstats[idx][BL_CONDITION].ptr.a_lptr) |= BL_MASK_SLIMED;
|
|
else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~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;
|
|
ptype = blstats[idx][i].ptype;
|
|
switch (ptype) {
|
|
case P_INT:
|
|
curr.a_iptr = blstats[idx][i].ptr.a_iptr;
|
|
prev.a_iptr = blstats[idx_p][i].ptr.a_iptr;
|
|
if (update_all || (*curr.a_iptr != *prev.a_iptr)) {
|
|
idxmax = blstats[idx][i].idxmax;
|
|
pc = (idxmax) ? percentage(*curr.a_iptr,
|
|
*(blstats[idx][idxmax].ptr.a_iptr)) : 0;
|
|
if (!valset[i])
|
|
Sprintf(blstats[idx][i].val,
|
|
"%d", *curr.a_iptr);
|
|
status_update(i,
|
|
(genericptr_t)blstats[idx][i].val,
|
|
(update_all || *curr.a_iptr > *prev.a_iptr) ?
|
|
1 : -1, pc);
|
|
updated = TRUE;
|
|
}
|
|
break;
|
|
case P_LNG:
|
|
curr.a_lptr = blstats[idx][i].ptr.a_lptr;
|
|
prev.a_lptr = blstats[idx_p][i].ptr.a_lptr;
|
|
if (update_all || (*curr.a_lptr != *prev.a_lptr)) {
|
|
idxmax = blstats[idx][i].idxmax;
|
|
pc = (idxmax) ? percentagel(*curr.a_lptr,
|
|
*(blstats[idx][idxmax].ptr.a_lptr)) : 0;
|
|
if (!valset[i])
|
|
Sprintf(blstats[idx][i].val,
|
|
"%-1ld", *curr.a_lptr);
|
|
status_update(i,
|
|
(genericptr_t)blstats[idx][i].val,
|
|
(update_all || *curr.a_lptr > *prev.a_lptr) ?
|
|
1 : -1, pc);
|
|
updated = TRUE;
|
|
}
|
|
break;
|
|
case P_UINT:
|
|
curr.a_uptr = blstats[idx][i].ptr.a_uptr;
|
|
prev.a_uptr = blstats[idx_p][i].ptr.a_uptr;
|
|
if (update_all || (*curr.a_uptr != *prev.a_uptr)) {
|
|
/*
|
|
* idxmax = blstats[idx][i].idxmax);
|
|
* pc = (idxmax) ? percentage(*curr.a_uptr,
|
|
* *(blstats[idx][idxmax].ptr.a_uptr)) : 0;
|
|
* status_via_win(i, val,
|
|
* (*curr.a_uptr > *prev.a_uptr) ? 1 : -1, pc);
|
|
*/
|
|
if (!valset[i])
|
|
Sprintf(blstats[idx][i].val,
|
|
"%u", *curr.a_uptr);
|
|
status_update(i,
|
|
(genericptr_t)blstats[idx][i].val,
|
|
(update_all || *curr.a_uptr > *prev.a_uptr) ?
|
|
1 : -1, 0);
|
|
updated = TRUE;
|
|
}
|
|
break;
|
|
case P_STR:
|
|
if (update_all ||
|
|
strcmp(blstats[idx][i].val, blstats[idx_p][i].val)) {
|
|
status_update(i,
|
|
(genericptr_t) blstats[idx][i].val,0,0);
|
|
updated = TRUE;
|
|
}
|
|
break;
|
|
case P_MASK:
|
|
curr.a_lptr = blstats[idx][i].ptr.a_lptr;
|
|
prev.a_lptr = blstats[idx_p][i].ptr.a_lptr;
|
|
if (update_all || (*curr.a_lptr != *prev.a_lptr)) {
|
|
status_update(i,
|
|
/* send the actual mask, not a pointer to it */
|
|
(genericptr_t)*curr.a_lptr,0,0);
|
|
updated = TRUE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* 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;
|
|
}
|
|
|
|
void
|
|
genl_status_update(idx, ptr, chg, percent)
|
|
int idx, chg, percent;
|
|
genericptr_t ptr;
|
|
{
|
|
char newbot1[MAXCO], newbot2[MAXCO];
|
|
static int init = FALSE;
|
|
long cond;
|
|
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 = (long)ptr;
|
|
*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], " Hallu");
|
|
if (cond & BL_MASK_HALLU) Strcat(vals[idx], " Stun");
|
|
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, evertime */
|
|
newbot1[0] = '\0';
|
|
for (i = 0; fieldorder1[i] >= 0; ++i) {
|
|
int idx = fieldorder1[i];
|
|
if (activefields[idx])
|
|
Strcat(newbot1, vals[idx]);
|
|
}
|
|
newbot2[0] = '\0';
|
|
for (i = 0; fieldorder2[i] >= 0; ++i) {
|
|
int idx = fieldorder2[i];
|
|
if (activefields[idx])
|
|
Strcat(newbot2, vals[idx]);
|
|
}
|
|
curs(WIN_STATUS, 1, 0);
|
|
putstr(WIN_STATUS, 0, newbot1);
|
|
curs(WIN_STATUS, 1, 1);
|
|
putstr(WIN_STATUS, 0, newbot2);
|
|
}
|
|
#endif /*STATUS_VIA_WINDOWPORT*/
|
|
|
|
/*botl.c*/
|
|
|
|
|