diff --git a/include/botl.h b/include/botl.h index 9e4e36595..f7cbce08f 100644 --- a/include/botl.h +++ b/include/botl.h @@ -35,14 +35,15 @@ enum statusfields { BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, /* 1..6 */ BL_ALIGN, BL_SCORE, BL_CAP, BL_GOLD, BL_ENE, BL_ENEMAX, /* 7..12 */ BL_XP, BL_AC, BL_HD, BL_TIME, BL_HUNGER, BL_HP, /* 13..18 */ - BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION /* 19..22 */ + BL_HPMAX, BL_LEVELDESC, BL_EXP, BL_CONDITION, /* 19..22 */ + BL_COUNT }; enum relationships { NO_LTEQGT = -1, EQ_VALUE, LT_VALUE, LE_VALUE, GE_VALUE, GT_VALUE, TXT_VALUE }; -#define MAXBLSTATS (BL_CONDITION + 1) +#define MAXBLSTATS (BL_COUNT) #define BEFORE 0 #define NOW 1 @@ -63,6 +64,7 @@ enum relationships { NO_LTEQGT = -1, #define BL_MASK_LEV 0x00000400L #define BL_MASK_FLY 0x00000800L #define BL_MASK_RIDE 0x00001000L +#define BL_MASK_BITS 13 /* number of mask bits that can be set */ /* clang-format on */ #define REASSESS_ONLY TRUE diff --git a/win/win32/mhmsg.h b/win/win32/mhmsg.h index 090068d82..7eb65d0c0 100644 --- a/win/win32/mhmsg.h +++ b/win/win32/mhmsg.h @@ -69,11 +69,7 @@ typedef struct mswin_nhmsg_get_text { } MSNHMsgGetText, *PMSNHMsgGetText; typedef struct mswin_nhmsg_update_status { - int n_fields; - const char **vals; - boolean *activefields; - int *percents; - int *colors; + struct mswin_status_lines * status_lines; } MSNHMsgUpdateStatus, *PMSNHMsgUpdateStatus; #endif diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 074762816..57c70b436 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -9,7 +9,6 @@ #include "mhmsg.h" #include "mhfont.h" -#define NHSW_LINES 2 #define MAXWINDOWTEXT BUFSZ extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ @@ -60,24 +59,14 @@ void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int hei back_buffer_size(back_buffer, width, height); } + typedef struct mswin_nethack_status_window { int index; char window_text[NHSW_LINES][MAXWINDOWTEXT + 1]; - int n_fields; - const char **vals; - boolean *activefields; - int *percents; - int *colors; + mswin_status_lines * status_lines; back_buffer_t back_buffer; } NHStatusWindow, *PNHStatusWindow; -static int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, - BL_WI, BL_CH, BL_ALIGN, BL_SCORE, -1 }; -static 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 }; -static int *fieldorders[] = { fieldorder1, fieldorder2, NULL }; static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass"); LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM); @@ -195,22 +184,19 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case MSNH_MSG_GETTEXT: { PMSNHMsgGetText msg_data = (PMSNHMsgGetText) lParam; #ifdef STATUS_HILITES - int **fop; - int *f; - msg_data->buffer[0] = '\0'; - if (data->n_fields > 0) { - for (fop = fieldorders; *fop; fop++) { - for (f = *fop; *f != -1; f++) { - if (data->activefields[*f]) - strncat(msg_data->buffer, data->vals[*f], - msg_data->max_size - - strlen(msg_data->buffer)); - } - strncat(msg_data->buffer, "\r\n", - msg_data->max_size - strlen(msg_data->buffer)); + + for (int line = 0; line < NHSW_LINES; line++) { + mswin_status_line *status_line = data->status_lines[line].lines; + for (int i = 0; i < status_line->status_strings.count; i++) { + mswin_status_string * status_string = status_line->status_strings.status_strings[i]; + strncat(msg_data->buffer, status_string->str, + msg_data->max_size - strlen(msg_data->buffer)); } + strncat(msg_data->buffer, "\r\n", + msg_data->max_size - strlen(msg_data->buffer)); } + #else strncpy(msg_data->buffer, data->window_text[0], msg_data->max_size); @@ -223,11 +209,7 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case MSNH_MSG_UPDATE_STATUS: { PMSNHMsgUpdateStatus msg_data = (PMSNHMsgUpdateStatus) lParam; - data->n_fields = msg_data->n_fields; - data->vals = msg_data->vals; - data->activefields = msg_data->activefields; - data->percents = msg_data->percents; - data->colors = msg_data->colors; + data->status_lines = msg_data->status_lines; InvalidateRect(hWnd, NULL, TRUE); } break; } /* end switch( wParam ) { */ @@ -273,10 +255,6 @@ StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) static LRESULT onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) { - int hpbar_percent = 100; - int hpbar_color = NO_COLOR; - int *f; - int **fop; SIZE sz; HGDIOBJ normalFont, boldFont; WCHAR wbuf[BUFSZ]; @@ -308,12 +286,6 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) SetBkColor(hdc, status_bg_color); SetTextColor(hdc, status_fg_color); - if (iflags.wc2_hitpointbar && BL_HP < data->n_fields - && data->activefields[BL_HP]) { - hpbar_percent = data->percents[BL_HP]; - hpbar_color = data->colors[BL_HP] & 0x00ff; - } - clear_rect.left = 0; clear_rect.top = 0; clear_rect.right = width; @@ -321,23 +293,38 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) FillRect(hdc, &clear_rect, status_bg_brush); - for (fop = fieldorders; *fop; fop++) { + // TODO: Put it around for loop instead -- temporary to get a better diff + if (data->status_lines == NULL) { + BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); + + EndPaint(hWnd, &ps); + return 0; + } + + for (int line = 0; line < NHSW_LINES; line++) { LONG left = rt.left; LONG cy = 0; int vlen; - for (f = *fop; *f != BL_FLUSH; f++) { + + mswin_status_line * status_line = &data->status_lines->lines[line]; + + for (int i = 0; i < status_line->status_strings.count; i++) { + mswin_status_string * status_string = status_line->status_strings.status_strings[i]; int clr, atr; int fntatr = ATR_NONE; HGDIOBJ fnt; COLORREF nFg, nBg; - if (((*f) >= data->n_fields) || (!data->activefields[*f])) + if (status_string->str == NULL || status_string->str[0] == '\0') continue; - clr = data->colors[*f] & 0x00ff; - atr = (data->colors[*f] & 0xff00) >> 8; - vlen = strlen(data->vals[*f]); - const char *str = data->vals[*f]; + + clr = status_string->color & 0x00ff; + atr = (status_string->color & 0xff00) >> 8; + + const char *str = status_string->str; + + vlen = strlen(str); if (atr & HL_BOLD) fntatr = ATR_BOLD; @@ -362,8 +349,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) nBg = status_bg_color; sz.cy = -1; - if (*f == BL_TITLE && iflags.wc2_hitpointbar) { - HBRUSH back_brush = CreateSolidBrush(nhcolor_to_RGB(hpbar_color)); + + if (status_string->draw_bar && iflags.wc2_hitpointbar) { + + /* when we are drawing bar we need to look at the hp status + * field to get the correct percentage and color */ + COLORREF bar_color = nhcolor_to_RGB(status_string->bar_color); + HBRUSH back_brush = CreateSolidBrush(bar_color); RECT barrect; /* prepare for drawing */ @@ -371,7 +363,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) SetBkMode(hdc, OPAQUE); SetBkColor(hdc, status_bg_color); /* SetTextColor(hdc, nhcolor_to_RGB(hpbar_color)); */ - SetTextColor(hdc, status_fg_color); + SetTextColor(hdc, status_fg_color); if (useUnicode) { /* get bounding rectangle */ @@ -379,21 +371,22 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) /* first draw title normally */ DrawTextW(hdc, wbuf, vlen, &rt, DT_LEFT); - } else { + } + else { /* get bounding rectangle */ GetTextExtentPoint32A(hdc, str, vlen, &sz); /* first draw title normally */ DrawTextA(hdc, str, vlen, &rt, DT_LEFT); } - - if (hpbar_percent > 0) { + int bar_percent = status_string->bar_percent; + if (bar_percent > 0) { /* calc bar length */ barrect.left = rt.left; barrect.top = rt.top; barrect.bottom = sz.cy; - if (hpbar_percent > 0) - barrect.right = (int)((hpbar_percent * sz.cx) / 100); + if (bar_percent > 0) + barrect.right = (int)((bar_percent * sz.cx) / 100); /* else barrect.right = sz.cx; */ diff --git a/win/win32/mhstatus.h b/win/win32/mhstatus.h index 2349a29f3..1f0d75d26 100644 --- a/win/win32/mhstatus.h +++ b/win/win32/mhstatus.h @@ -9,6 +9,75 @@ #include "config.h" #include "global.h" +#define NHSW_LINES 2 + +static const int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, + BL_WI, BL_CH, BL_ALIGN, BL_SCORE, -1 }; +static const 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 }; +static const int *fieldorders[] = { fieldorder1, fieldorder2, NULL }; +static const int fieldcounts[NHSW_LINES] = { SIZE(fieldorder1) - 1, SIZE(fieldorder2) - 1}; + +#define MSWIN_MAX_LINE1_STRINGS (SIZE(fieldorder1) - 1) +#define MSWIN_MAX_LINE2_STRINGS (SIZE(fieldorder2) - 1 + BL_MASK_BITS) +#define MSWIN_MAX_LINE_STRINGS (MSWIN_MAX_LINE1_STRINGS > MSWIN_MAX_LINE2_STRINGS ? \ + MSWIN_MAX_LINE1_STRINGS : MSWIN_MAX_LINE2_STRINGS) + +#define MSWIN_LINE1_FIELDS (SIZE(fieldorder1) - 1) +#define MSWIN_LINE2_FIELDS (SIZE(fieldorder2) - 1) +#define MSWIN_MAX_LINE_FIELDS (MSWIN_LINE1_FIELDS > MSWIN_LINE2_FIELDS ? \ + MSWIN_LINE1_FIELDS : MSWIN_LINE2_FIELDS) + +/* when status hilites are enabled, we use an array of mswin_status_strings + * to represent what needs to be rendered. */ +typedef struct mswin_status_string { + const char * str; /* ascii string to be displayed */ + int color; /* string text color */ + boolean draw_bar; + int bar_percent; /* a percentage to indicate; 100 will draw no percentage bar */ + int bar_color; /* color index of percentage bar */ +} mswin_status_string; + +typedef struct mswin_status_strings +{ + int count; + mswin_status_string * status_strings[MSWIN_MAX_LINE_STRINGS]; +} mswin_status_strings; + +typedef struct mswin_status_field { + int field_index; // field index + boolean enabled; // whether the field is enabled + const char * name; // name of status field + const char * format; // format of field + + int percent; + int color; + char string[BUFSZ]; + +} mswin_status_field; + +typedef struct mswin_condition_field { + int mask; + const char * name; + int bit_position; +} mswin_condition_field; + +typedef struct mswin_status_fields { + int count; + mswin_status_field * status_fields[MSWIN_MAX_LINE_FIELDS]; +} mswin_status_fields; + +typedef struct mswin_status_line { + mswin_status_strings status_strings; + mswin_status_fields status_fields; +} mswin_status_line; + +typedef struct mswin_status_lines { + mswin_status_line lines[NHSW_LINES]; /* number of strings to be rendered on each line */ +} mswin_status_lines; + HWND mswin_init_status_window(void); void mswin_status_window_size(HWND hWnd, LPSIZE sz); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index c6714bc15..74a4cd3c6 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2766,12 +2766,28 @@ NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) return MessageBox(hWnd, text, title, type); } -static const char *_status_fieldnm[MAXBLSTATS]; -static const char *_status_fieldfmt[MAXBLSTATS]; -static char *_status_vals[MAXBLSTATS]; -static int _status_colors[MAXBLSTATS]; -static int _status_percents[MAXBLSTATS]; -static boolean _status_activefields[MAXBLSTATS]; +static mswin_status_lines _status_lines; +static mswin_status_string _status_strings[MAXBLSTATS]; +static mswin_status_string _condition_strings[BL_MASK_BITS]; +static mswin_status_field _status_fields[MAXBLSTATS]; + +static mswin_condition_field _condition_fields[BL_MASK_BITS] = { + { BL_MASK_STONE, " Stone" }, + { BL_MASK_SLIME, " Slime" }, + { BL_MASK_STRNGL, " Strngl" }, + { BL_MASK_FOODPOIS, " FoodPois" }, + { BL_MASK_TERMILL, " TermIll" }, + { BL_MASK_BLIND, " Blind" }, + { BL_MASK_DEAF, " Deaf" }, + { BL_MASK_STUN, " Stun" }, + { BL_MASK_CONF, " Conf" }, + { BL_MASK_HALLU, " Hallu" }, + { BL_MASK_LEV, " Lev" }, + { BL_MASK_FLY, " Fly" }, + { BL_MASK_RIDE, " Ride" } +}; + + extern winid WIN_STATUS; #ifdef STATUS_HILITES @@ -2792,15 +2808,62 @@ status_init() -- core calls this to notify the window port that a status void mswin_status_init(void) { - int i; logDebug("mswin_status_init()\n"); - for (i = 0; i < MAXBLSTATS; ++i) { - _status_vals[i] = (char *) alloc(BUFSZ); - *_status_vals[i] = '\0'; - _status_activefields[i] = FALSE; - _status_fieldfmt[i] = (const char *) 0; - _status_colors[i] = CLR_MAX; /* no color */ - _status_percents[i] = 0; + + for (int i = 0; i < SIZE(_status_fields); i++) { + mswin_status_field * status_field = &_status_fields[i]; + status_field->field_index = i; + status_field->enabled = FALSE; + } + + for (int i = 0; i < SIZE(_condition_fields); i++) { + mswin_condition_field * condition_field = &_condition_fields[i]; + nhassert(condition_field->mask == (1 << i)); + condition_field->bit_position = i; + } + + for (int i = 0; i < SIZE(_status_strings); i++) { + mswin_status_string * status_string = &_status_strings[i]; + status_string->str = NULL; + } + + for (int i = 0; i < SIZE(_condition_strings); i++) { + mswin_status_string * status_string = &_condition_strings[i]; + status_string->str = NULL; + } + + for (int lineIndex = 0; lineIndex < SIZE(_status_lines.lines); lineIndex++) { + mswin_status_line * line = &_status_lines.lines[lineIndex]; + + mswin_status_fields * status_fields = &line->status_fields; + status_fields->count = 0; + + mswin_status_strings * status_strings = &line->status_strings; + status_strings->count = 0; + + for (int i = 0; i < fieldcounts[lineIndex]; i++) { + int field_index = fieldorders[lineIndex][i]; + nhassert(field_index <= SIZE(_status_fields)); + + nhassert(status_fields->count <= SIZE(status_fields->status_fields)); + status_fields->status_fields[status_fields->count++] = &_status_fields[field_index]; + + nhassert(status_strings->count <= SIZE(status_strings->status_strings)); + status_strings->status_strings[status_strings->count++] = + &_status_strings[field_index]; + + if (field_index == BL_CONDITION) { + for (int j = 0; j < BL_MASK_BITS; j++) { + nhassert(status_strings->count <= SIZE(status_strings->status_strings)); + status_strings->status_strings[status_strings->count++] = + &_condition_strings[j]; + } + } + } + } + + + for (int i = 0; i < MAXBLSTATS; ++i) { #ifdef STATUS_HILITES _status_hilites[i].thresholdtype = 0; _status_hilites[i].behavior = BL_TH_NONE; @@ -2820,17 +2883,7 @@ status_finish() -- called when it is time for the window port to tear down void mswin_status_finish(void) { - /* tear down routine */ - int i; - logDebug("mswin_status_finish()\n"); - - /* free alloc'd memory here */ - for (i = 0; i < MAXBLSTATS; ++i) { - if (_status_vals[i]) - free((genericptr_t) _status_vals[i]); - _status_vals[i] = (char *) 0; - } } /* @@ -2853,9 +2906,41 @@ mswin_status_enablefield(int fieldidx, const char *nm, const char *fmt, { logDebug("mswin_status_enablefield(%d, %s, %s, %d)\n", fieldidx, nm, fmt, (int) enable); - _status_fieldfmt[fieldidx] = fmt; - _status_fieldnm[fieldidx] = nm; - _status_activefields[fieldidx] = enable; + + nhassert(fieldidx <= SIZE(_status_fields)); + mswin_status_field * field = &_status_fields[fieldidx]; + + nhassert(fieldidx <= SIZE(_status_strings)); + mswin_status_string * string = &_status_strings[fieldidx]; + + if (field != NULL) { + field->format = fmt; + field->name = nm; + field->enabled = enable; + + string->str = (field->enabled ? field->string : NULL); + + if (field->field_index == BL_CONDITION) + string->str = NULL; + + string->draw_bar = (field->enabled && field->field_index == BL_TITLE); + } +} + +/* TODO: turn this into a commmon helper; multiple identical implementations */ +static int +mswin_condcolor(bm, bmarray) +long bm; +unsigned long *bmarray; +{ + int i; + + if (bm && bmarray) + for (i = 0; i < CLR_MAX; ++i) { + if ((bm & bmarray[i]) != 0) + return i; + } + return NO_COLOR; } /* @@ -2910,11 +2995,10 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, MSNHMsgUpdateStatus update_cmd_data; int ocolor, ochar; unsigned ospecial; - long value = -1; - boolean reset_state = FALSE; logDebug("mswin_status_update(%d, %p, %d, %d, %x, %p)\n", idx, ptr, chg, percent, color, colormasks); +#if 0 // TODO: this code was dead ... do we need to respond to these updates? switch (idx) { case BL_RESET: reset_state = TRUE; @@ -2924,42 +3008,44 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, default: break; } +#endif if (idx >= 0) { - if (!_status_activefields[idx]) + + nhassert(idx <= SIZE(_status_fields)); + mswin_status_field * status_field = &_status_fields[idx]; + nhassert(status_field->field_index == idx); + + nhassert(idx <= SIZE(_status_strings)); + mswin_status_string * status_string = &_status_strings[idx]; + + if (!status_field->enabled) { + nhassert(status_string->str == NULL); return; - _status_percents[idx] = percent; + } + + // TODO: is color actualy color and attribute OR not? + status_field->color = color & 0xff; + status_string->color = color & 0xff; + switch (idx) { case BL_CONDITION: { + mswin_condition_field * condition_field = _condition_fields; + + nhassert(status_string->str == NULL); + cond = *condptr; - *_status_vals[idx] = '\0'; - if (cond & BL_MASK_STONE) - Strcat(_status_vals[idx], " Stone"); - if (cond & BL_MASK_SLIME) - Strcat(_status_vals[idx], " Slime"); - if (cond & BL_MASK_STRNGL) - Strcat(_status_vals[idx], " Strngl"); - if (cond & BL_MASK_FOODPOIS) - Strcat(_status_vals[idx], " FoodPois"); - if (cond & BL_MASK_TERMILL) - Strcat(_status_vals[idx], " TermIll"); - if (cond & BL_MASK_BLIND) - Strcat(_status_vals[idx], " Blind"); - if (cond & BL_MASK_DEAF) - Strcat(_status_vals[idx], " Deaf"); - if (cond & BL_MASK_STUN) - Strcat(_status_vals[idx], " Stun"); - if (cond & BL_MASK_CONF) - Strcat(_status_vals[idx], " Conf"); - if (cond & BL_MASK_HALLU) - Strcat(_status_vals[idx], " Hallu"); - if (cond & BL_MASK_LEV) - Strcat(_status_vals[idx], " Lev"); - if (cond & BL_MASK_FLY) - Strcat(_status_vals[idx], " Fly"); - if (cond & BL_MASK_RIDE) - Strcat(_status_vals[idx], " Ride"); - value = cond; + + for (int i = 0; i < BL_MASK_BITS; i++, condition_field++) { + status_string = &_condition_strings[i]; + + if (condition_field->mask & cond) { + status_string->str = condition_field->name; + status_string->color = mswin_condcolor(condition_field->mask, colormasks); + } + else + status_string->str = NULL; + } } break; case BL_GOLD: { char buf[BUFSZ]; @@ -2971,33 +3057,34 @@ mswin_status_update(int idx, genericptr_t ptr, int chg, int percent, int color, p = strchr(text, ':'); if (p) { strncpy(buf + 1, p, sizeof(buf) - 2); - value = atol(p + 1); } else { buf[1] = ':'; strncpy(buf + 2, text, sizeof(buf) - 2); - value = atol(text); } - Sprintf(_status_vals[idx], - _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s", - buf); + + Sprintf(status_field->string, status_field->format ? status_field->format : "%s", buf); + nhassert(status_string->str == status_field->string); } break; default: { - value = atol(text); - Sprintf(_status_vals[idx], - _status_fieldfmt[idx] ? _status_fieldfmt[idx] : "%s", + Sprintf(status_field->string, status_field->format ? status_field->format : "%s", text); + nhassert(status_string->str == status_field->string); } break; } - _status_colors[idx] = color; + /* if we received an update for the hp field, we must update the + * bar percent and bar color for the title string */ + if (idx == BL_HP) { + mswin_status_string * title_string = &_status_strings[BL_TITLE]; + + title_string->bar_color = color; + title_string->bar_percent = percent; + + } /* send command to status window */ ZeroMemory(&update_cmd_data, sizeof(update_cmd_data)); - update_cmd_data.n_fields = MAXBLSTATS; - update_cmd_data.vals = _status_vals; - update_cmd_data.activefields = _status_activefields; - update_cmd_data.percents = _status_percents; - update_cmd_data.colors = _status_colors; + update_cmd_data.status_lines = &_status_lines; SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND, (WPARAM) MSNH_MSG_UPDATE_STATUS, (LPARAM) &update_cmd_data); }