From 10480f4397c84000ed7acdd6ca3619a6e307e93b Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Sun, 30 Nov 2003 05:51:53 +0000 Subject: [PATCH] core support for status field highlighting (trunk only) This provides the core support needed for status field highlighting. This patch doesn't actually perform status field highlighting for any port, but provides the core hooks for doing so. The syntax is: OPTIONS=hilite_status:{fieldname}/{threshold}/{below}/{above} where {fieldname} is the name of a status field. {threshold} is the value used as the threshold to trigger a display change. It can also be set to "updown" to trigger a display change whenever it rises or whenever it falls. If you end the threshold value with %, then it signifies that you want to trigger the display change based on the percentage of maximum. {below}, {above} are the color or display attribute that you want to use when the field value is underneath the threshold. Supported display fields are: normal, inverse, bold, black, red, green, brown, blue, magenta, cyan, gray, orange, bright-green, yellow, bright-blue, bright-magenta, bright-cyan, or white. Valid field names are: alignment, armor-class, carrying-capacity, charisma, condition, constitution, dexterity, dungeon-level, experience-level, experience, gold, HD, hitpoints-max, hitpoints, hunger, intelligence, power-max, power, score, strength, time, title, wisdom Refer to window.doc for details. Guidebook updates to come later. --- doc/window.doc | 37 ++ include/botl.h | 18 + include/config.h | 1 + include/decl.h | 4 + include/extern.h | 7 + include/flag.h | 1 - include/winprocs.h | 11 +- include/wintype.h | 21 + src/botl.c | 986 ++++++++++++++++++++++++++++++++++++-------- src/files.c | 16 +- src/options.c | 48 ++- src/pline.c | 4 + sys/amiga/winami.c | 6 + sys/mac/macwin.c | 11 +- sys/wince/mswproc.c | 3 + win/Qt/qt_win.cpp | 3 + win/X11/winX.c | 3 + win/gem/wingem.c | 3 + win/gnome/gnbind.c | 3 + win/tty/wintty.c | 3 + win/win32/mswproc.c | 3 + 21 files changed, 997 insertions(+), 195 deletions(-) diff --git a/doc/window.doc b/doc/window.doc index 3596debe2..7f8106cf3 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -386,6 +386,43 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage) status_finish() -- called when it is time for the window port to tear down the status display and free allocated memory, etc. +status_threshold(int fldidx, int threshholdtype, anything threshold, + int behavior, int under, int over) + -- called when a hiliting preference is added, changed, or + removed. + -- the fldindex identifies which field is having its hiliting + preference set. It 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 + -- datatype is P_INT, P_UINT, P_LONG, or P_MASK. + -- threshold is an "anything" union which can contain the + datatype value. + -- behavior is used to define how threshold is used and can + be BL_TH_NONE, BL_TH_VAL_PERCENTAGE, BL_TH_VAL_ABSOLUTE, + or BL_TH_UPDOWN. BL_TH_NONE means don't do anything above + or below the threshold. BL_TH_VAL_PERCENTAGE treats the + threshold value as a precentage of the maximum possible + value. BL_TH_VAL_ABSOLUTE means that the threshold is an + actual value. BL_TH_UPDOWN means that threshold is not + used, and the two below/above hilite values indicate how + to display something going down (under) or rising (over). + -- under is the hilite attribute used if value is below the + threshold. The attribute can be BL_HILITE_NONE, + BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one + of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, + CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, + CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, + CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). + -- over is the hilite attribute used if value is at or above + the threshold. The attribute can be BL_HILITE_NONE, + BL_HILITE_INVERSE, BL_HILITE_BOLD (-1, -2, or -3), or one + of the color indexes of CLR_BLACK, CLR_RED, CLR_GREEN, + CLR_BROWN, CLR_BLUE, CLR_MAGENTA, CLR_CYAN, CLR_GRAY, + CLR_ORANGE, CLR_BRIGHT_GREEN, CLR_YELLOW, CLR_BRIGHT_BLUE, + CLR_BRIGHT_MAGENTA, CLR_BRIGHT_CYAN, or CLR_WHITE (0 - 15). E. Misc. Routines diff --git a/include/botl.h b/include/botl.h index fa8631e86..8922c6359 100644 --- a/include/botl.h +++ b/include/botl.h @@ -5,6 +5,8 @@ #ifndef BOTL_H #define BOTL_H +#ifdef STATUS_VIA_WINDOWPORT + #define BL_FLUSH -1 #define BL_TITLE 0 #define BL_STR 1 @@ -43,4 +45,20 @@ #define REASSESS_ONLY TRUE +#ifdef STATUS_HILITES +/* hilite status field behavior - coloridx values */ +#define BL_HILITE_NONE -1 /* no hilite of this field */ +#define BL_HILITE_INVERSE -2 /* inverse hilite */ +#define BL_HILITE_BOLD -3 /* bold hilite */ + /* or any CLR_ index (0 - 15) */ +#define BL_TH_NONE 0 +#define BL_TH_VAL_PERCENTAGE 100 /* threshold is percentage */ +#define BL_TH_VAL_ABSOLUTE 101 /* threshold is particular value */ +#define BL_TH_UPDOWN 102 /* threshold is up or down change */ +#define BL_TH_CONDITION 103 /* threshold is bitmask of conditions */ +#endif + +extern const char *status_fieldnames[]; /* in botl.c */ +#endif + #endif /* BOTL_H */ diff --git a/include/config.h b/include/config.h index 5873a2a40..8f3bf03e6 100644 --- a/include/config.h +++ b/include/config.h @@ -355,6 +355,7 @@ typedef unsigned char uchar; /*#define GOLDOBJ */ /* Gold is kept on obj chains - Helge Hafting */ #define AUTOPICKUP_EXCEPTIONS /* exceptions to autopickup */ #define STATUS_VIA_WINDOWPORT /* re-work of the status line updating process */ +#define STATUS_HILITES /* support hilites of status fields */ /* End of Section 5 */ diff --git a/include/decl.h b/include/decl.h index 734e8ec02..dac11660e 100644 --- a/include/decl.h +++ b/include/decl.h @@ -152,6 +152,10 @@ E NEARDATA struct sinfo { int panicking; /* `panic' is in progress */ #if defined(VMS) || defined(WIN32) int exiting; /* an exit handler is executing */ +#endif + int in_impossible; +#ifdef PANICLOG + int in_paniclog; #endif } program_state; diff --git a/include/extern.h b/include/extern.h index 7397abfa8..3df221569 100644 --- a/include/extern.h +++ b/include/extern.h @@ -140,6 +140,13 @@ 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)); +# ifdef STATUS_HILITES +E void FDECL(genl_status_threshold, (int,int,anything,int,int,int)); +E boolean FDECL(set_status_hilites, (char *op)); +E void NDECL(clear_status_hilites); +E char *FDECL(get_status_hilites, (char *, int)); +E boolean NDECL(status_hilite_menu); +# endif #endif /* ### cmd.c ### */ diff --git a/include/flag.h b/include/flag.h index 7963d1ba0..cbfd0c618 100644 --- a/include/flag.h +++ b/include/flag.h @@ -259,7 +259,6 @@ struct instance_flags { boolean wc2_fullscreen; /* run fullscreen */ boolean wc2_softkeyboard; /* use software keyboard */ boolean wc2_wraptext; /* wrap text */ - boolean cmdassist; /* provide detailed assistance for some commands */ boolean clicklook; /* allow right-clicking for look */ boolean obsolete; /* obsolete options can point at this, it isn't used */ diff --git a/include/winprocs.h b/include/winprocs.h index a9b9106c7..1240dd0ee 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -74,6 +74,9 @@ struct window_procs { 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)); +# ifdef STATUS_HILITES + void FDECL((*win_status_threshold), (int,int,anything,int,int,int)); +# endif #endif }; @@ -152,6 +155,9 @@ extern NEARDATA struct window_procs windowprocs; */ #define status_enablefield (*windowprocs.win_status_enablefield) #define status_update (*windowprocs.win_status_update) +#ifdef STATUS_HILITES +#define status_threshold (*windowprocs.win_status_threshold) +#endif #endif /* @@ -195,8 +201,9 @@ extern NEARDATA struct window_procs windowprocs; #define WC2_FULLSCREEN 0x01L /* 01 display full screen */ #define WC2_SOFTKEYBOARD 0x02L /* 02 software keyboard */ -#define WC2_WRAPTEXT 0x04L /* 04 wrap long lines of text */ - /* 29 free bits */ +#define WC2_WRAPTEXT 0x04L /* 03 wrap long lines of text */ +#define WC2_HILITE_STATUS 0x08L /* 04 hilite fields in status */ + /* 28 free bits */ #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 diff --git a/include/wintype.h b/include/wintype.h index c53371508..eca261195 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -15,14 +15,35 @@ typedef union any { char a_char; schar a_schar; unsigned int a_uint; + long a_long; + unsigned long a_ulong; int *a_iptr; long *a_lptr; + unsigned long *a_ulptr; unsigned *a_uptr; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ /* (buggy old Ultrix compiler) */ +/* symbolic names for the data types housed in anything */ +#define ANY_VOID 1 +#define ANY_OBJ 2 /* struct obj */ +#define ANY_MONST 3 /* struct monst (not used) */ +#define ANY_INT 4 /* int */ +#define ANY_CHAR 5 /* char */ +#define ANY_UCHAR 6 /* unsigned char */ +#define ANY_SCHAR 7 /* signed char */ +#define ANY_UINT 8 /* unsigned int */ +#define ANY_LONG 9 /* long */ +#define ANY_ULONG 10 /* unsigned long */ +#define ANY_IPTR 11 /* pointer to int */ +#define ANY_UPTR 12 /* pointer to unsigned int */ +#define ANY_LPTR 13 /* pointer to long */ +#define ANY_ULPTR 14 /* pointer to unsigned long */ +#define ANY_STR 15 /* pointer to null-terminated char string */ +#define ANY_MASK32 16 /* mask of 32 bits (stored as unsigned long) */ + /* menu return list */ typedef struct mi { anything item; /* identifier */ diff --git a/src/botl.c b/src/botl.c index 0f9744d0f..e753b8f11 100644 --- a/src/botl.c +++ b/src/botl.c @@ -16,7 +16,16 @@ const char * const enc_stat[] = { }; #ifdef STATUS_VIA_WINDOWPORT -STATIC_OVL void NDECL(init_blstats); +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 *)); +STATIC_OVL int FDECL(de_pointer_type, (int)); +# ifdef STATUS_HILITES +STATIC_DCL boolean FDECL(assign_hilite, (char *, char *, char *, char *)); +STATIC_DCL char *FDECL(clridx_to_s, (char *, int)); +# endif #else STATIC_DCL void NDECL(bot1); STATIC_DCL void NDECL(bot2); @@ -297,55 +306,53 @@ bot() #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; + unsigned anytype; + anything a; 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 */ + { 0L, ANY_STR, {(genericptr_t)0}, (char *)0, 80, 0 }, /* 0 BL_TITLE */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 1 BL_STR */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 2 BL_DX */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 3 BL_CO */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 4 BL_IN */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 5 BL_WI */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 6 BL_CH */ + { 0L, ANY_STR, {(genericptr_t)0}, (char *)0, 40, 0}, /* 7 BL_ALIGN */ + { 0L, ANY_LONG, {(genericptr_t)0}, (char *)0, 20, 0}, /* 8 BL_SCORE */ + { 0L, ANY_LONG, {(genericptr_t)0}, (char *)0, 20, 0}, /* 9 BL_CAP */ + { 0L, ANY_LONG, {(genericptr_t)0}, (char *)0, 10, 0}, /* 10 BL_GOLD */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, BL_ENEMAX}, /* 11 BL_ENE */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 12 BL_ENEMAX */ + { 0L, ANY_LONG, {(genericptr_t)0}, (char *)0, 10, 0}, /* 13 BL_XP */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 14 BL_AC */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 15 BL_HD */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 20, 0}, /* 16 BL_TIME */ + { 0L, ANY_UINT, {(genericptr_t)0}, (char *)0, 40, 0}, /* 17 BL_HUNGER */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10,BL_HPMAX}, /* 18 BL_HP */ + { 0L, ANY_INT, {(genericptr_t)0}, (char *)0, 10, 0}, /* 19 BL_HPMAX */ + { 0L, ANY_STR, {(genericptr_t)0}, (char *)0, 80, 0}, /* 20 BL_LEVELDESC */ + { 0L, ANY_LONG, {(genericptr_t)0}, (char *)0, 20, 0}, /* 21 BL_EXP */ + { 0L, ANY_MASK32,{(genericptr_t)0}, (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) @@ -357,13 +364,6 @@ boolean reassessment; /* TRUE = just reassess fields w/o other initialization*/ " %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)(); @@ -375,9 +375,11 @@ boolean reassessment; /* TRUE = just reassess fields w/o other initialization*/ (i == BL_TIME && !flags.time) || (i == BL_HD && !Upolyd) || ((i == BL_XP || i == BL_EXP) && Upolyd)) - status_enablefield(i, fieldnames[i], fieldfmts[i], FALSE); + status_enablefield(i, status_fieldnames[i], + fieldfmts[i], FALSE); else - status_enablefield(i, fieldnames[i], fieldfmts[i], TRUE); + status_enablefield(i, status_fieldnames[i], + fieldfmts[i], TRUE); } update_all = TRUE; } @@ -392,8 +394,6 @@ 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); } @@ -405,25 +405,26 @@ 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; + /* ensure initial field values set on blstats[1][i] too */ + blstats[1][i] = blstats[0][i]; + + switch(blstats[0][i].anytype) { + case ANY_INT: + blstats[0][i].a.a_int = 0; + blstats[1][i].a.a_int = 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; + case ANY_ULONG: + case ANY_MASK32: + blstats[0][i].a.a_ulong = 0UL; + blstats[1][i].a.a_ulong = 0UL; 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; + case ANY_LONG: + blstats[0][i].a.a_long = 0L; + blstats[1][i].a.a_long = 0L; + break; + case ANY_UINT: + blstats[0][i].a.a_uint = 0U; + blstats[1][i].a.a_uint = 0U; break; } if (blstats[0][i].valwidth) { @@ -433,10 +434,185 @@ init_blstats() blstats[0][i].val = (char *)0; blstats[1][i].val = (char *)0; } - blstats[1][i].ptype = blstats[0][i].ptype; } } +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 %ld, %ld", + (long)bl1, (long)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 %ls, %ld", + (long)bl1->a.a_void, (long)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 %ld, %ld", + (long)bl, (long)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() { @@ -444,9 +620,9 @@ bot() register char *nb; static int idx = 0, idx_p, idxmax; boolean updated = FALSE; - unsigned ptype; - int i, pc, cap = near_capacity(); - anything curr, prev; + unsigned anytype; + int i, pc, chg, cap = near_capacity(); + struct istat_s *curr, *prev; boolean valset[MAXBLSTATS]; if (!blinit) panic("bot before init."); @@ -480,11 +656,12 @@ bot() } 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].ptr.a_iptr) = ACURR(A_STR); + 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); @@ -500,11 +677,11 @@ bot() /* 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); + 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 */ @@ -514,7 +691,7 @@ bot() /* Score */ - *(blstats[idx][BL_SCORE].ptr.a_lptr) = + blstats[idx][BL_SCORE].a.a_long = #ifdef SCORE_ON_BOTL botl_score(); #else @@ -522,18 +699,19 @@ bot() #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; + 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].ptr.a_lptr) = + blstats[idx][BL_GOLD].a.a_long = #ifndef GOLDOBJ u.ugold; #else @@ -548,37 +726,37 @@ bot() * for the BL_GOLD case. */ Sprintf(blstats[idx][BL_GOLD].val, "%c:%ld", - oc_syms[COIN_CLASS], *(blstats[idx][BL_GOLD].ptr.a_lptr)); + oc_syms[COIN_CLASS], blstats[idx][BL_GOLD].a.a_long); 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; + blstats[idx][BL_ENE].a.a_int = u.uen; + blstats[idx][BL_ENEMAX].a.a_int = u.uenmax; /* Armor class */ - *(blstats[idx][BL_AC].ptr.a_iptr) = u.uac; + blstats[idx][BL_AC].a.a_int = u.uac; /* Monster level (if Upolyd) */ if (Upolyd) - *(blstats[idx][BL_HD].ptr.a_iptr) = mons[u.umonnum].mlevel; + blstats[idx][BL_HD].a.a_int = mons[u.umonnum].mlevel; else - *(blstats[idx][BL_HD].ptr.a_iptr) = 0; + blstats[idx][BL_HD].a.a_int = 0; /* Experience */ - *(blstats[idx][BL_XP].ptr.a_iptr) = u.ulevel; - *(blstats[idx][BL_EXP].ptr.a_lptr) = u.uexp; + blstats[idx][BL_XP].a.a_int = u.ulevel; + blstats[idx][BL_EXP].a.a_int = u.uexp; /* Time (moves) */ - *(blstats[idx][BL_TIME].ptr.a_lptr) = moves; + blstats[idx][BL_TIME].a.a_long = moves; /* Hunger */ - *(blstats[idx][BL_HUNGER].ptr.a_uptr) = u.uhs; + 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]); @@ -587,35 +765,35 @@ bot() /* Carrying capacity */ *(blstats[idx][BL_CAP].val) = '\0'; - *(blstats[idx][BL_CAP].ptr.a_iptr) = cap; + 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].ptr.a_lptr) |= BL_MASK_BLIND; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_BLIND; + 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].ptr.a_lptr) |= BL_MASK_CONF; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_CONF; + 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].ptr.a_lptr) |= BL_MASK_FOODPOIS; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_FOODPOIS; + 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].ptr.a_lptr) |= BL_MASK_ILL; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_ILL; + 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].ptr.a_lptr) |= BL_MASK_HALLU; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_HALLU; + 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].ptr.a_lptr) |= BL_MASK_STUNNED; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_STUNNED; + 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].ptr.a_lptr) |= BL_MASK_SLIMED; - else *(blstats[idx][BL_CONDITION].ptr.a_lptr) &= ~BL_MASK_SLIMED; + 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. @@ -627,81 +805,24 @@ bot() ((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); + 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) { + 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, chg, pc); + } else { 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; + /* send actual mask, not a pointer to it */ + (genericptr_t) curr->a.a_ulong, chg, 0); + } + updated = TRUE; } } /* @@ -722,6 +843,502 @@ bot() 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(a,b,c,d) +char *a, *b, *c, *d; +{ + 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 percentage = 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; a && i < MAXBLSTATS; ++i) { + if (strcmpi(a,status_fieldnames[i]) == 0) { + idx = i; + break; + } + } + if (idx == -1) return FALSE; + status_hilites[idx].set = FALSE; /* mark it "unset" */ + + /* threshold */ + if (!b) return FALSE; + if ((strcmpi(b, "updown") == 0) || (strcmpi(b, "downup") == 0) || + (strcmpi(b, "up") == 0) || (strcmpi(b, "down") == 0)) { + down_up = TRUE; + } else if ((strcmpi(b, "changed") == 0) && + (idx == BL_TITLE || idx == BL_ALIGN || + idx == BL_LEVELDESC || idx == BL_CONDITION)) { + changed = TRUE; /* changed is only thing allowed */ + } else { + tmp = b; + while (*tmp) { + if (*tmp == '%') { + *tmp = '\0'; + percentage = TRUE; + break; + } else if (!index("0123456789", *tmp)) + return FALSE; + tmp++; + } + if (strlen(b) > 0) { + dt = blstats[0][idx].anytype; + if (percentage) dt = ANY_INT; + (void) s_to_anything(&threshold, b, dt); + } else return FALSE; + if (percentage && + (threshold.a_int < 1 || threshold.a_int > 100)) + return FALSE; + if (!threshold.a_void && (strcmp(b, "0") != 0)) return FALSE; + } + + /* actions */ + for (i = 0; i < 2; ++i) { + if (!i) how = c; + else how = d; + if (!how) { + if (!i) return FALSE; + else break; /* c is mandatory; d 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 (percentage) + 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 char * +clridx_to_s(buf, idx) +char *buf; +int idx; +{ + 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; +} + +STATIC_OVL int +de_pointer_type(anytype) +int anytype; +{ + int dt = anytype; + if (anytype == ANY_IPTR) dt = ANY_INT; + else if (anytype == ANY_LPTR) dt = ANY_LONG; + else if (anytype == ANY_UPTR) dt = ANY_UINT; + else if (anytype == ANY_ULPTR) dt = ANY_ULONG; + return dt; +} + +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.a_void = 0; + any.a_int = BL_TH_CONDITION + 1; + add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, + ATR_NONE, "Condition bitmask threshold.", + MENU_UNSELECTED); + } + any.a_void = 0; + 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.a_void = 0; + any.a_int = BL_TH_VAL_PERCENTAGE + 1; + add_menu(tmpwin, NO_GLYPH, &any, 'p', 0, + ATR_NONE, "Percentage threshold.", + MENU_UNSELECTED); + } + any.a_void = 0; + any.a_int = BL_TH_UPDOWN + 1; + add_menu(tmpwin, NO_GLYPH, &any, 'u', 0, + ATR_NONE, "UpDown threshold.", + MENU_UNSELECTED); + any.a_void = 0; + 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 *pick = (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.a_void = 0; + 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, &pick)) > 0) { + hltemp[i].coloridx[j] = (pick->item.a_char > 0) ? + pick->item.a_int - 1 : + pick->item.a_int; + free((genericptr_t)pick); + } + 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 */ /*****************************************************************************/ @@ -730,6 +1347,7 @@ const char *fieldnm[MAXBLSTATS]; const char *fieldfmt[MAXBLSTATS]; char *vals[MAXBLSTATS]; boolean activefields[MAXBLSTATS]; +struct hilite_s hilites[MAXBLSTATS]; NEARDATA winid WIN_STATUS; void @@ -772,6 +1390,15 @@ boolean enable; activefields[fieldidx] = enable; } +void +genl_status_threshold(fldidx, thresholdtype, threshold, behavior, under, over) +int fldidx,thresholdtype; +int behavior, under, over; +anything threshold; +{ + +} + void genl_status_update(idx, ptr, chg, percent) int idx, chg, percent; @@ -831,6 +1458,7 @@ genericptr_t ptr; curs(WIN_STATUS, 1, 1); putstr(WIN_STATUS, 0, newbot2); } + #endif /*STATUS_VIA_WINDOWPORT*/ /*botl.c*/ diff --git a/src/files.c b/src/files.c index 1cca1ca06..d2e3086dc 100644 --- a/src/files.c +++ b/src/files.c @@ -2275,12 +2275,16 @@ const char *reason; /* explanation */ FILE *lfile; char buf[BUFSZ]; - lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); - if (lfile) { - (void) fprintf(lfile, "%s %08ld: %s %s\n", - version_string(buf), yyyymmdd((time_t)0L), - type, reason); - (void) fclose(lfile); + if (!program_state.in_paniclog) { + program_state.in_paniclog = 1; + lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); + if (lfile) { + (void) fprintf(lfile, "%s %08ld: %s %s\n", + version_string(buf), yyyymmdd((time_t)0L), + type, reason); + (void) fclose(lfile); + } + program_state.in_paniclog = 0; } #endif /* PANICLOG */ return; diff --git a/src/options.c b/src/options.c index 22775af91..8214fcd1b 100644 --- a/src/options.c +++ b/src/options.c @@ -2138,7 +2138,23 @@ goodfruit: return; } } - +#if defined(STATUS_VIA_WINDOWPORT) && defined(STATUS_HILITES) + /* hilite fields in status prompt */ + if (match_optname(opts, "hilite_status", 13, TRUE)) { + op = string_for_opt(opts, TRUE); + if (op && negated) { + clear_status_hilites(); + return; + } else if (!op) { + /* a value is mandatory */ + badoption(opts); + return; + } + if (!set_status_hilites(op)) + badoption(opts); + return; + } +#endif /* OK, if we still haven't recognized the option, check the boolean * options list */ @@ -2474,12 +2490,23 @@ doset() doset_add_menu(tmpwin, compopt[i].name, (pass == DISP_IN_GAME) ? 0 : indexoffset); } +#ifdef STATUS_VIA_WINDOWPORT +# ifdef STATUS_HILITES + any.a_int = -2; + get_status_hilites(buf2, 60); + if (!iflags.menu_tab_sep) + Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", + "status_hilites", buf2); + else + Sprintf(buf, fmtstr_doset_add_menu_tab, "status_hilites", buf2); + add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); +# endif +#endif #ifdef AUTOPICKUP_EXCEPTIONS any.a_int = -1; Sprintf(buf, "autopickup exceptions (%d currently set)", count_ape_maps((int *)0, (int *)0)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); - #endif /* AUTOPICKUP_EXCEPTIONS */ #ifdef PREFIXES_IN_USE any.a_void = 0; @@ -2501,10 +2528,22 @@ doset() for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_indx = pick_list[pick_idx].item.a_int - 1; #ifdef AUTOPICKUP_EXCEPTIONS - if (opt_indx == -2) { + if (opt_indx == -2) { /* -3 due to -1 offset for select_menu() */ special_handling("autopickup_exception", setinitial, fromfile); } else +#endif +#ifdef STATUS_VIA_WINDOWPORT +# ifdef STATUS_HILITES + if (opt_indx == -3) { /* -3 due to -1 offset for select_menu() */ + if (!status_hilite_menu()) + pline("Bad status hilite(s) specified."); + else { + if (wc2_supported("status_hilites")) + preference_update("status_hilites"); + } + } else +# endif #endif if (opt_indx < boolcount) { /* boolean option */ @@ -3605,6 +3644,9 @@ struct wc_Opt wc2_options[] = { {"fullscreen", WC2_FULLSCREEN}, {"softkeyboard", WC2_SOFTKEYBOARD}, {"wraptext", WC2_WRAPTEXT}, +#ifdef STATUS_VIA_WINDOWPORT + {"hilite_status", WC2_HILITE_STATUS}, +#endif {(char *)0, 0L} }; diff --git a/src/pline.c b/src/pline.c index 2febc95f0..60218fe15 100644 --- a/src/pline.c +++ b/src/pline.c @@ -252,6 +252,9 @@ void impossible VA_DECL(const char *, s) VA_START(s); VA_INIT(s, const char *); + if (program_state.in_impossible) + panic("impossible called impossible"); + program_state.in_impossible = 1; { char pbuf[BUFSZ]; Vsprintf(pbuf,s,VA_ARGS); @@ -259,6 +262,7 @@ impossible VA_DECL(const char *, s) } vpline(s,VA_ARGS); pline("Program in disorder - perhaps you'd better #quit."); + program_state.in_impossible = 0; VA_END(); } diff --git a/sys/amiga/winami.c b/sys/amiga/winami.c index d3a771527..c29187d29 100644 --- a/sys/amiga/winami.c +++ b/sys/amiga/winami.c @@ -87,6 +87,9 @@ struct window_procs amii_procs = genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; @@ -154,6 +157,9 @@ struct window_procs amiv_procs = genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/sys/mac/macwin.c b/sys/mac/macwin.c index c41e2e96b..27845db68 100644 --- a/sys/mac/macwin.c +++ b/sys/mac/macwin.c @@ -2648,10 +2648,13 @@ struct window_procs mac_procs = { genl_getmsghistory, genl_putmsghistory, #ifdef STATUS_VIA_WINDOWPORT - genl_status_init, - genl_status_finish, - genl_status_enablefield, - genl_status_update, + genl_status_init, + genl_status_finish, + genl_status_enablefield, + genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/sys/wince/mswproc.c b/sys/wince/mswproc.c index 6c4a7cb9a..379f8df4c 100644 --- a/sys/wince/mswproc.c +++ b/sys/wince/mswproc.c @@ -102,6 +102,9 @@ struct window_procs mswin_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index 8f7fb0ac2..02bce25eb 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -5286,6 +5286,9 @@ struct window_procs Qt_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/X11/winX.c b/win/X11/winX.c index 80d4cf720..2d2c68c90 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -167,6 +167,9 @@ struct window_procs X11_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/gem/wingem.c b/win/gem/wingem.c index d987d681b..f2b834035 100644 --- a/win/gem/wingem.c +++ b/win/gem/wingem.c @@ -105,6 +105,9 @@ struct window_procs Gem_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c index 5b70362e3..727d35563 100644 --- a/win/gnome/gnbind.c +++ b/win/gnome/gnbind.c @@ -84,6 +84,9 @@ struct window_procs Gnome_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 7770003c7..25c9f1512 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -119,6 +119,9 @@ struct window_procs tty_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif }; diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 93edd9146..c17e35c72 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -128,6 +128,9 @@ struct window_procs mswin_procs = { genl_status_finish, genl_status_enablefield, genl_status_update, +# ifdef STATUS_HILITES + genl_status_threshold, +# endif #endif };