From 5ed547995d68bac551e9535e56c72b595167ceaf Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Sun, 23 Nov 2003 06:43:17 +0000 Subject: [PATCH] status display - core modules (trunk only) Introduction of a new set of window port status display routines. The new routines are conditional on STATUS_VIA_WINDOWPORT being defined in config.h. See the experimental section, where the #define resides for the time being. --- doc/window.doc | 84 +++++-- include/config.h | 5 +- include/decl.h | 5 +- include/extern.h | 8 + include/winprocs.h | 15 ++ include/wintype.h | 5 +- src/allmain.c | 6 + src/botl.c | 534 ++++++++++++++++++++++++++++++++++++++++++++- src/decl.c | 5 +- src/end.c | 9 +- src/options.c | 71 +++--- src/save.c | 4 +- 12 files changed, 697 insertions(+), 54 deletions(-) diff --git a/doc/window.doc b/doc/window.doc index 126c58e2c..871f3ef40 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -20,16 +20,19 @@ Contents: I. Window Types and Terminology -There are 5 basic window types, used to call create_nhwindow(): +There are 4 basic window types, used to call create_nhwindow(): NHW_MESSAGE (top line) - NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) The tty window-port also uses NHW_BASE (the base display) internally. +(The genl_status_* routines use NHW_STATUS for backward compatibility + when displaying status information on the bottom lines. New code + should not use NHW_STATUS. NHW_STATUS will be phased out over time.) + NHW_MENU windows can be used for either menu or text display. Their basic feature is that for the tty-port, if the window is small enough, it appears in the corner of the tty display instead of overwriting @@ -53,12 +56,16 @@ integer, but doesn't necessarily have to be done that way. There are a few fixed window names that are known throughout the code: WIN_MESSAGE (top line) - WIN_STATUS (bottom lines) WIN_MAP (main dungeon) WIN_INVEN (inventory) Other windows are created and destroyed as needed. +(The genl_status_* routines use WIN_STATUS for backward compatibility + when displaying status information on the bottom lines. New code + should not use WIN_STATUS, or assume its presence. NHW_STATUS will + be phased out over time.) + "Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS TOS, etc.) "window-port" refers to the windowing platform. This is orthogonal (e.g. UNIX might use either a tty window-port or an X11 @@ -85,12 +92,12 @@ curs(window, x, y) displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. - -- For variable sized windows, like the status window, the + -- For variable sized windows, like the old status window, the behavior when curs() is called outside the window's limits is unspecified. The mac port wraps to 0, with the status window being 2 lines high and 80 columns wide. - -- Still used by curs_on_u(), status updates, screen locating - (identify, teleport). + -- Still used by curs_on_u(), obsolete status updates, + screen locating (identify, teleport). -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not currently support curs in the tty window-port. putstr(window, attr, str) @@ -331,7 +338,51 @@ char message_menu(char let, int how, const char *mesg) windows typically won't need this functionality, so can substitute genl_message_menu (windows.c) instead. -D. Misc. Routines +D. Status Display Routines + +status_init() -- core calls this to notify the window port that a status + display is required. The window port should perform + the necessary initialization in here, allocate memory, etc. +status_enablefield(int fldindex, char fldname, char fieldfmt, boolean enable) + -- notifies the window port which fields it is authorized to + display. + -- This may be called at any time, and is used + to disable as well as enable fields, depending on the + value of the final argument (TRUE = enable). + -- fldindex could be one of the following from botl.h: + BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, + BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, + BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, + BL_LEVELDESC, BL_EXP, BL_CONDITION + -- There are MAXBLSTATS status fields (from botl.h) +status_update(int fldindex, genericptr_t ptr, int chg, int percentage) + -- update the value of a status field + -- the fldindex identifies which field is changing and + is an integer index value from botl.h + -- fldindex could be any one of the following from botl.h: + BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, + BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, + BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, BL_HPMAX, + BL_LEVELDESC, BL_EXP, BL_CONDITION, + -- fldindex could also be BL_FLUSH (-1), which is not really + a field index, but is a special trigger to tell the + windowport that it should redisplay all its status fields, + even if no changes have been presented to it. + -- ptr is usually a "char *", unless fldindex is BL_CONDITION. + If fldindex is BL_CONDITION, then ptr is a long value with + any or none of the following bits set (from botl.h): + BL_MASK_BLIND 0x00000001L + BL_MASK_CONF 0x00000002L + BL_MASK_FOODPOIS 0x00000004L + BL_MASK_ILL 0x00000008L + BL_MASK_HALLU 0x00000010L + BL_MASK_STUNNED 0x00000020L + BL_MASK_SLIMED 0x00000040L +status_finish() -- called when it is time for the window port to tear down + the status display and free allocated memory, etc. + + +E. Misc. Routines make_sound(???) -- To be determined later. THIS IS CURRENTLY UN-IMPLEMENTED. nhbell() -- Beep at user. [This will exist at least until sounds are @@ -414,8 +465,11 @@ the window interface to the rest of NetHack. char toplines[BUFSZ] Contains the last message printed to the WIN_MESSAGE window, used by Norep(). -winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN - The four standard windows. +winid WIN_MESSAGE, WIN_MAP, WIN_INVEN + The three standard windows. + There is also a window called WIN_STATUS that is used + only for backward compatibility in the genl_status_* + set of generic status display functions. char *AE, *AS; Checked in options.c to see if we should switch to DEC_GRAPHICS. It is #ifdefed VMS and UNIX. int LI, CO; Set in sys/unix/ioctl.c. @@ -560,7 +614,7 @@ to support: +--------------------+--------------------+--------------------+--------+ align_message -- where to place message window (top, bottom, left, right) -align_status -- where to place status window (top, bottom, left, right). +align_status -- where to place status display (top, bottom, left, right). ascii_map -- port should display an ascii map if it can. color -- port should display color if it can. eight_bit_tty -- port should allow eight bit input. @@ -571,9 +625,9 @@ font_size_map -- port should use this size font for the map window. font_size_menu -- port should use this size font for menu windows. font_size_message -- port should use this size font for the message window. -font_size_status-- port should use this size font for the status window. +font_size_status-- port should use this size font for the status display. font_size_text -- port should use this size font for text windows. -font_status -- port should use a font by this name for status window. +font_status -- port should use a font by this name for status display. font_text -- port should use a font by this name for text windows. fullscreen -- port should try to use the whole screen. hilite_pet -- port should mark pets in some special way on the map. @@ -718,9 +772,9 @@ to initialize the function pointer table to _something_ so that calls to raw_print() will not fail. Choose_windows() should be called almost immediately upon entering main(). Look at unixmain.c for an example. -Display_gamewindows() is a common routine that displays the three standard -game windows (WIN_MESSAGE, WIN_MAP, and WIN_STATUS). It is normally called -just before the "Hello, welcome" message. +Display_gamewindows() is a common routine that displays the two standard +game windows (WIN_MESSAGE, WIN_MAP), and the status display. It is normally +called just before the "Hello, welcome" message. Process_options() is currently still unique to each port. There may be need in the future to make it possible to replace this on a per window-port basis. diff --git a/include/config.h b/include/config.h index ab0a15455..5873a2a40 100644 --- a/include/config.h +++ b/include/config.h @@ -1,4 +1,4 @@ -/* SCCS Id: @(#)config.h 3.4 2003/02/19 */ +/* SCCS Id: @(#)config.h 3.4 2003/11/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -353,7 +353,8 @@ typedef unsigned char uchar; */ /*#define GOLDOBJ */ /* Gold is kept on obj chains - Helge Hafting */ -#define AUTOPICKUP_EXCEPTIONS /* exceptions to autopickup - M. Allison */ +#define AUTOPICKUP_EXCEPTIONS /* exceptions to autopickup */ +#define STATUS_VIA_WINDOWPORT /* re-work of the status line updating process */ /* End of Section 5 */ diff --git a/include/decl.h b/include/decl.h index 12452c731..734e8ec02 100644 --- a/include/decl.h +++ b/include/decl.h @@ -320,7 +320,10 @@ E NEARDATA boolean vision_full_recalc; /* TRUE if need vision recalc */ E NEARDATA char **viz_array; /* could see/in sight row pointers */ /* Window system stuff */ -E NEARDATA winid WIN_MESSAGE, WIN_STATUS; +E NEARDATA winid WIN_MESSAGE; +#ifndef STATUS_VIA_WINDOWPORT +E NEARDATA winid WIN_STATUS; +#endif E NEARDATA winid WIN_MAP, WIN_INVEN; E char toplines[]; #ifndef TCAP_H diff --git a/include/extern.h b/include/extern.h index 05f459f2a..6a59bb761 100644 --- a/include/extern.h +++ b/include/extern.h @@ -131,6 +131,14 @@ E long NDECL(botl_score); E int FDECL(describe_level, (char *)); E const char *FDECL(rank_of, (int,SHORT_P,BOOLEAN_P)); E void NDECL(bot); +#ifdef STATUS_VIA_WINDOWPORT +E void FDECL(status_initialize, (BOOLEAN_P)); +E void NDECL(status_finish); +E void NDECL(genl_status_init); +E void NDECL(genl_status_finish); +E void FDECL(genl_status_update, (int, genericptr_t, int, int)); +E void FDECL(genl_status_enablefield, (int, const char *, const char *,BOOLEAN_P)); +#endif /* ### cmd.c ### */ diff --git a/include/winprocs.h b/include/winprocs.h index c1a7eca79..a9b9106c7 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -5,6 +5,8 @@ #ifndef WINPROCS_H #define WINPROCS_H +#include "botl.h" + struct window_procs { const char *name; unsigned long wincap; /* window port capability options supported */ @@ -67,6 +69,12 @@ struct window_procs { void FDECL((*win_preference_update), (const char *)); char * FDECL((*win_getmsghistory), (BOOLEAN_P)); void FDECL((*win_putmsghistory), (const char *)); +#ifdef STATUS_VIA_WINDOWPORT + void NDECL((*win_status_init)); + void NDECL((*win_status_finish)); + void FDECL((*win_status_enablefield), (int,const char *,const char *,BOOLEAN_P)); + void FDECL((*win_status_update), (int,genericptr_t,int,int)); +#endif }; extern NEARDATA struct window_procs windowprocs; @@ -138,6 +146,13 @@ extern NEARDATA struct window_procs windowprocs; #define preference_update (*windowprocs.win_preference_update) #define getmsghistory (*windowprocs.win_getmsghistory) #define putmsghistory (*windowprocs.win_putmsghistory) +#ifdef STATUS_VIA_WINDOWPORT +/* there is a status_initialize() in botl.c, + * which calls win_status_init() directly; same with status_finish. + */ +#define status_enablefield (*windowprocs.win_status_enablefield) +#define status_update (*windowprocs.win_status_update) +#endif /* * WINCAP diff --git a/include/wintype.h b/include/wintype.h index b7a4aa12b..c53371508 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -14,6 +14,10 @@ typedef union any { int a_int; char a_char; schar a_schar; + unsigned int a_uint; + int *a_iptr; + long *a_lptr; + unsigned *a_uptr; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ @@ -67,5 +71,4 @@ typedef struct mi { #define MENU_INVERT_PAGE '~' #define MENU_SEARCH ':' - #endif /* WINTYPE_H */ diff --git a/src/allmain.c b/src/allmain.c index 91ec6a234..9ea7220ef 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -447,7 +447,11 @@ void display_gamewindows() { WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); +#ifdef STATUS_VIA_WINDOWPORT + status_initialize(FALSE); +#else WIN_STATUS = create_nhwindow(NHW_STATUS); +#endif WIN_MAP = create_nhwindow(NHW_MAP); WIN_INVEN = create_nhwindow(NHW_MENU); @@ -466,7 +470,9 @@ display_gamewindows() * The mac port is not DEPENDENT on the order of these * displays, but it looks a lot better this way... */ +#ifndef STATUS_VIA_WINDOWPORT display_nhwindow(WIN_STATUS, FALSE); +#endif display_nhwindow(WIN_MESSAGE, FALSE); clear_glyph_buffer(); display_nhwindow(WIN_MAP, FALSE); diff --git a/src/botl.c b/src/botl.c index e838ba296..b20180de4 100644 --- a/src/botl.c +++ b/src/botl.c @@ -15,8 +15,12 @@ const char * const enc_stat[] = { "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 @@ -150,13 +154,13 @@ botl_score() } #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; @@ -203,6 +207,7 @@ bot1() curs(WIN_STATUS, 1, 0); putstr(WIN_STATUS, 0, newbot1); } +#endif /* provide the name of the current level for display by various ports */ int @@ -227,6 +232,7 @@ char *buf; return ret; } +#ifndef STATUS_VIA_WINDOWPORT STATIC_OVL void bot2() { @@ -289,4 +295,530 @@ bot() 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 required 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, 6, 0}, /* 1 BL_STR */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 2 BL_DX */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 3 BL_CO */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 4 BL_IN */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 5 BL_WI */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 6 BL_CH */ + { 0L, P_STR, (genericptr_t)0, (char *)0, 8, 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, 8, 0}, /* 10 BL_GOLD */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, BL_ENEMAX}, /* 11 BL_ENE */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 12 BL_ENEMAX */ + { 0L, P_LNG, (genericptr_t)0, (char *)0, 6, 0}, /* 13 BL_XP */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 14 BL_AC */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 6, 0}, /* 15 BL_HD */ + { 0L, P_INT, (genericptr_t)0, (char *)0, 10, 0}, /* 16 BL_TIME */ + { 0L, P_UINT,(genericptr_t)0, (char *)0, 20, 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 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)(); + } + for (i = 0; i < MAXBLSTATS; ++i) { + if ((i == BL_SCORE && !flags.showscore) || + (i == BL_EXP && !flags.showexp) || + (i == BL_TIME && !flags.time)) + 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(blstats[0][i].ptr.a_void); + free(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]; + + idx = (++idx % 2); + idx_p = ((idx+1) % 2); + + /* 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 */ + + Sprintf(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 + 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)) + 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) + free((genericptr_t)vals[i]); +} + +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; + 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_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: + (void) Sprintf(vals[idx], + fieldfmt[idx] ? fieldfmt[idx] : "%s", + (char *)ptr, MAXCO); + 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*/ + + diff --git a/src/decl.c b/src/decl.c index 0de6fee8d..9247fd961 100644 --- a/src/decl.c +++ b/src/decl.c @@ -255,7 +255,10 @@ NEARDATA boolean vision_full_recalc = 0; NEARDATA char **viz_array = 0;/* used in cansee() and couldsee() macros */ /* Global windowing data, defined here for multi-window-system support */ -NEARDATA winid WIN_MESSAGE = WIN_ERR, WIN_STATUS = WIN_ERR; +NEARDATA winid WIN_MESSAGE = WIN_ERR; +#ifndef STATUS_VIA_WINDOWPORT +NEARDATA WIN_STATUS = WIN_ERR; +#endif NEARDATA winid WIN_MAP = WIN_ERR, WIN_INVEN = WIN_ERR; char toplines[TBUFSZ]; /* Windowing stuff that's really tty oriented, but present for all ports */ diff --git a/src/end.c b/src/end.c index cf33ef4b7..70858f626 100644 --- a/src/end.c +++ b/src/end.c @@ -768,10 +768,17 @@ die: wait_synch(); display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP); +#ifdef STATUS_VIA_WINDOWPORT + status_finish(); +#else destroy_nhwindow(WIN_STATUS); +#endif destroy_nhwindow(WIN_MESSAGE); +#ifdef STATUS_VIA_WINDOWPORT + WIN_MESSAGE = WIN_MAP = WIN_ERR; +#else WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR; - +#endif if(!done_stopprint || flags.tombstone) endwin = create_nhwindow(NHW_TEXT); diff --git a/src/options.c b/src/options.c index 2df48da52..a0d51c899 100644 --- a/src/options.c +++ b/src/options.c @@ -26,6 +26,12 @@ NEARDATA struct instance_flags iflags; /* provide linkage */ #define PREFER_TILED FALSE #endif +#define MESSAGE_OPTION 1 +#define STATUS_OPTION 2 +#define MAP_OPTION 3 +#define MENU_OPTION 4 +#define TEXT_OPTION 5 + /* * NOTE: If you add (or delete) an option, please update the short * options help (option_help()), the long options help (dat/opthelp), @@ -1188,55 +1194,55 @@ boolean tinitial, tfrom_file; fullname = "font"; if (!strncmpi(opts, fullname, 4)) { - int wintype = -1; + int opttype = -1; char *fontopts = opts + 4; if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4)) - wintype = NHW_MAP; + opttype = MAP_OPTION; else if (!strncmpi(fontopts, "message", 7) || !strncmpi(fontopts, "_message", 8)) - wintype = NHW_MESSAGE; + opttype = MESSAGE_OPTION; else if (!strncmpi(fontopts, "text", 4) || !strncmpi(fontopts, "_text", 5)) - wintype = NHW_TEXT; + opttype = TEXT_OPTION; else if (!strncmpi(fontopts, "menu", 4) || !strncmpi(fontopts, "_menu", 5)) - wintype = NHW_MENU; + opttype = MENU_OPTION; else if (!strncmpi(fontopts, "status", 6) || !strncmpi(fontopts, "_status", 7)) - wintype = NHW_STATUS; + opttype = STATUS_OPTION; else if (!strncmpi(fontopts, "_size", 5)) { if (!strncmpi(fontopts, "_size_map", 8)) - wintype = NHW_MAP; + opttype = MAP_OPTION; else if (!strncmpi(fontopts, "_size_message", 12)) - wintype = NHW_MESSAGE; + opttype = MESSAGE_OPTION; else if (!strncmpi(fontopts, "_size_text", 9)) - wintype = NHW_TEXT; + opttype = TEXT_OPTION; else if (!strncmpi(fontopts, "_size_menu", 9)) - wintype = NHW_MENU; + opttype = MENU_OPTION; else if (!strncmpi(fontopts, "_size_status", 11)) - wintype = NHW_STATUS; + opttype = STATUS_OPTION; else { badoption(opts); return; } - if (wintype > 0 && !negated && + if (opttype > 0 && !negated && (op = string_for_opt(opts, FALSE)) != 0) { - switch(wintype) { - case NHW_MAP: + switch(opttype) { + case MAP_OPTION: iflags.wc_fontsiz_map = atoi(op); break; - case NHW_MESSAGE: + case MESSAGE_OPTION: iflags.wc_fontsiz_message = atoi(op); break; - case NHW_TEXT: + case TEXT_OPTION: iflags.wc_fontsiz_text = atoi(op); break; - case NHW_MENU: + case MENU_OPTION: iflags.wc_fontsiz_menu = atoi(op); break; - case NHW_STATUS: + case STATUS_OPTION: iflags.wc_fontsiz_status = atoi(op); break; } @@ -1245,11 +1251,11 @@ boolean tinitial, tfrom_file; } else { badoption(opts); } - if (wintype > 0 && + if (opttype > 0 && (op = string_for_opt(opts, FALSE)) != 0) { - wc_set_font_name(wintype, op); + wc_set_font_name(opttype, op); #ifdef MAC - set_font_name (wintype, op); + set_font_name (opttype, op); #endif return; } else if (negated) bad_negation(fullname, TRUE); @@ -2204,9 +2210,12 @@ goodfruit: #ifdef SCORE_ON_BOTL || (boolopt[i].addr) == &flags.showscore #endif - ) + ) { +#ifdef STATUS_VIA_WINDOWPORT + status_initialize(TRUE); /* TRUE = reassess only */ +#endif context.botl = TRUE; - + } else if ((boolopt[i].addr) == &flags.invlet_constant) { if (flags.invlet_constant) reassign(); } @@ -3745,26 +3754,26 @@ const char *optnam; STATIC_OVL void -wc_set_font_name(wtype, fontname) -int wtype; +wc_set_font_name(opttype, fontname) +int opttype; char *fontname; { char **fn = (char **)0; if (!fontname) return; - switch(wtype) { - case NHW_MAP: + switch(opttype) { + case MAP_OPTION: fn = &iflags.wc_font_map; break; - case NHW_MESSAGE: + case MESSAGE_OPTION: fn = &iflags.wc_font_message; break; - case NHW_TEXT: + case TEXT_OPTION: fn = &iflags.wc_font_text; break; - case NHW_MENU: + case MENU_OPTION: fn = &iflags.wc_font_menu; break; - case NHW_STATUS: + case STATUS_OPTION: fn = &iflags.wc_font_status; break; default: diff --git a/src/save.c b/src/save.c index 890f14385..2710777ce 100644 --- a/src/save.c +++ b/src/save.c @@ -1112,8 +1112,10 @@ freedynamicdata() #ifdef AUTOPICKUP_EXCEPTIONS free_autopickup_exceptions(); #endif - #endif /* FREE_ALL_MEMORY */ +#ifdef STATUS_VIA_WINDOWPORT + status_finish(); +#endif return; }