From 024e9e122576db664e37df0937cfb4c06c436e0c Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 8 Oct 2017 18:12:08 -0700 Subject: [PATCH 01/43] fix #6144 - strength loss from severe hunger It was possible to arbitrarily boost strength (up to its race-specific limit) by wearing a ring of sustain ability, becoming weak from hunger (but not actually losing strength due to Fixed_abil), removing the ring, eating enough to stop being Weak, then repeat as desired. I think you could substitute polymorph for wearing ring, and rehumanize for removing ring and get similar results, although that would be more tedious. My first attempt to fix this was a lot more complicated. This one puts the temporary strength loss in ATEMP(A_STR) where it carries over from normal form to polymophed form and back. Fixed_abil doesn't prevent the loss any more, nor its recovery. One side-effect of the change is that the possibility of dying when becoming weak from hunger (if Str gets down to 3, further attempts to lower it take away HP instead of Str) no longer exists. Using ATEMP() instead of directly manipulating ABASE() means that current strength is less but underlying base strength does not actually drop any more. --- doc/fixes36.1 | 1 + src/apply.c | 5 ++--- src/attrib.c | 19 +++++++++++++------ src/eat.c | 24 ++++++++++++++++++++---- src/potion.c | 4 ++-- src/pray.c | 2 +- 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e6f3e7c78..19c92f722 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -451,6 +451,7 @@ give feedback when released from a bear trap depending upon how the dynamically inserted pattern-match phrase fit #version output left out "pattern matching via " if the basic NetHack features entry was split across two lines +recovery of strength lost due to weakness from hunger was vulnerable to abuse Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/apply.c b/src/apply.c index e5df1b904..c477a4fb8 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1951,9 +1951,8 @@ struct obj *obj; if (ABASE(idx) >= AMAX(idx)) continue; val_limit = AMAX(idx); - /* don't recover strength lost from hunger */ - if (idx == A_STR && u.uhs >= WEAK) - val_limit--; + /* this used to adjust 'val_limit' for A_STR when u.uhs was + WEAK or worse, but that's handled via ATEMP(A_STR) now */ if (Fixed_abil) { /* potion/spell of restore ability override sustain ability intrinsic but unicorn horn usage doesn't */ diff --git a/src/attrib.c b/src/attrib.c index e0021632f..a3812d54b 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -366,20 +366,27 @@ set_moreluck() void restore_attrib() { - int i; + int i, equilibrium;; + + /* + * Note: this gets called on every turn but ATIME() is never set + * to non-zero anywhere, and ATEMP() is only used for strength loss + * from hunger, so it doesn't actually do anything. + */ for (i = 0; i < A_MAX; i++) { /* all temporary losses/gains */ - - if (ATEMP(i) && ATIME(i)) { + equilibrium = (i == A_STR && u.uhs >= WEAK) ? -1 : 0; + if (ATEMP(i) != equilibrium && ATIME(i) != 0) { if (!(--(ATIME(i)))) { /* countdown for change */ - ATEMP(i) += ATEMP(i) > 0 ? -1 : 1; - + ATEMP(i) += (ATEMP(i) > 0) ? -1 : 1; + context.botl = 1; if (ATEMP(i)) /* reset timer */ ATIME(i) = 100 / ACURR(A_CON); } } } - (void) encumber_msg(); + if (context.botl) + (void) encumber_msg(); } #define AVAL 50 /* tune value for exercise gains */ diff --git a/src/eat.c b/src/eat.c index 9bd6346b0..6bbc1836b 100644 --- a/src/eat.c +++ b/src/eat.c @@ -112,8 +112,11 @@ register struct obj *obj; void init_uhunger() { + context.botl = (u.uhs != NOT_HUNGRY || ATEMP(A_STR) < 0); u.uhunger = 900; u.uhs = NOT_HUNGRY; + if (ATEMP(A_STR) < 0) + ATEMP(A_STR) = 0; } /* tin types [SPINACH_TIN = -1, overrides corpsenm, nut==600] */ @@ -2961,10 +2964,23 @@ boolean incr; } if (newhs != u.uhs) { - if (newhs >= WEAK && u.uhs < WEAK) - losestr(1); /* this may kill you -- see below */ - else if (newhs < WEAK && u.uhs >= WEAK) - losestr(-1); + if (newhs >= WEAK && u.uhs < WEAK) { + /* this used to be losestr(1) which had the potential to + be fatal (still handled below) by reducing HP if it + tried to take base strength below minimum of 3 */ + ATEMP(A_STR) = -1; /* temporary loss overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } else if (newhs < WEAK && u.uhs >= WEAK) { + /* this used to be losestr(-1) which could be abused by + becoming weak while wearing ring of sustain ability, + removing ring, eating to 'restore' strength which boosted + strength by a point each time the cycle was performed; + substituting "while polymorphed" for sustain ability and + "rehumanize" for ring removal might have done that too */ + ATEMP(A_STR) = 0; /* repair of loss also overrides Fixed_abil */ + /* defer context.botl status update until after hunger message */ + } + switch (newhs) { case HUNGRY: if (Hallucination) { diff --git a/src/potion.c b/src/potion.c index f167bf710..4925b27b0 100644 --- a/src/potion.c +++ b/src/potion.c @@ -565,8 +565,8 @@ register struct obj *otmp; i = rn2(A_MAX); /* start at a random point */ for (ii = 0; ii < A_MAX; ii++) { lim = AMAX(i); - if (i == A_STR && u.uhs >= 3) - --lim; /* WEAK */ + /* this used to adjust 'lim' for A_STR when u.uhs was + WEAK or worse, but that's handled via ATEMP(A_STR) now */ if (ABASE(i) < lim) { ABASE(i) = lim; context.botl = 1; diff --git a/src/pray.c b/src/pray.c index f9fe72083..51dfbb5bb 100644 --- a/src/pray.c +++ b/src/pray.c @@ -343,7 +343,7 @@ int trouble; u.utrap = 0; break; case TROUBLE_STARVING: - losestr(-1); + /* temporarily lost strength recovery now handled by init_uhunger() */ /*FALLTHRU*/ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH)); From b1f7bd37910a0f8392eaf39d42814356af6d4b0f Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 8 Oct 2017 17:32:58 -0700 Subject: [PATCH 02/43] Win32GUI: Set main window background brush to black. Black is a better choice given that the map background will always be black. This also creates a better polished experience when all window backgrounds are set to black. --- win/win32/mhmain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 48c2ea3a6..f64ab7665 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -104,7 +104,7 @@ register_main_window_class() wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_NETHACKW); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); wcex.lpszMenuName = (TCHAR *) IDC_NETHACKW; wcex.lpszClassName = szMainWindowClass; From 7c24b420a9ba0b66760fb0e726c2da2ef27c7e41 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 8 Oct 2017 17:33:20 -0700 Subject: [PATCH 03/43] Win32GUI: Fix bug with specifying no color for status hilite. We were mapping NO_COLOR to white instead of the default foreground color. --- win/win32/mhstatus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index 5e522b7b1..fe1badb48 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -275,7 +275,8 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) else if (atr & HL_DIM) fntatr = ATR_DIM; fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); - nFg = (clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) : Fg; + nFg = (clr == NO_COLOR ? Fg : + ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) : Fg)); nBg = Bg; GetTextExtentPoint32(hdc, wbuf, vlen, &sz); From 1ec7bed5299d0896e5306ff72b8bd5d2f2063302 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 8 Oct 2017 21:13:33 -0700 Subject: [PATCH 04/43] Win32GUI: Use a back buffer for all status rendering This eliminates all flickering when status is updated. --- win/win32/mhstatus.c | 121 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 97 insertions(+), 24 deletions(-) diff --git a/win/win32/mhstatus.c b/win/win32/mhstatus.c index fe1badb48..a362c60bd 100644 --- a/win/win32/mhstatus.c +++ b/win/win32/mhstatus.c @@ -12,6 +12,52 @@ extern COLORREF nhcolor_to_RGB(int c); /* from mhmap */ +typedef struct back_buffer { + HWND hWnd; + HDC hdc; + HBITMAP bm; + HBITMAP orig_bm; + int width; + int height; +} back_buffer_t; + +void back_buffer_free(back_buffer_t * back_buffer) +{ + if (back_buffer->bm != NULL) { + SelectObject(back_buffer->hdc, back_buffer->orig_bm); + DeleteObject(back_buffer->bm); + back_buffer->bm = NULL; + } +} + +void back_buffer_allocate(back_buffer_t * back_buffer, int width, int height) +{ + HDC hdc = GetDC(back_buffer->hWnd); + back_buffer->bm = CreateCompatibleBitmap(hdc, width, height); + back_buffer->orig_bm = SelectObject(back_buffer->hdc, back_buffer->bm); + back_buffer->width = width; + back_buffer->height = height; + ReleaseDC(back_buffer->hWnd, hdc); +} + +void back_buffer_size(back_buffer_t * back_buffer, int width, int height) +{ + if (back_buffer->bm == NULL || back_buffer->width != width + || back_buffer->height != height) { + back_buffer_free(back_buffer); + back_buffer_allocate(back_buffer, width, height); + } +} + +void back_buffer_init(back_buffer_t * back_buffer, HWND hWnd, int width, int height) +{ + back_buffer->hWnd = hWnd; + back_buffer->hdc = CreateCompatibleDC(NULL); + back_buffer->bm = NULL; + + back_buffer_size(back_buffer, width, height); +} + typedef struct mswin_nethack_status_window { int index; char window_text[NHSW_LINES][MAXWINDOWTEXT + 1]; @@ -20,6 +66,7 @@ typedef struct mswin_nethack_status_window { boolean *activefields; int *percents; int *colors; + back_buffer_t back_buffer; } NHStatusWindow, *PNHStatusWindow; static int fieldorder1[] = { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, @@ -45,6 +92,7 @@ mswin_init_status_window() HWND ret; NHStatusWindow *data; RECT rt; + int width, height; if (!run_once) { register_status_window_class(); @@ -59,12 +107,14 @@ mswin_init_status_window() } /* create status window object */ + width = rt.right - rt.left; + height = rt.bottom - rt.top; ret = CreateWindow(szStatusWindowClass, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_SIZEBOX, - rt.left, /* horizontal position of window */ - rt.top, /* vertical position of window */ - rt.right - rt.left, /* window width */ - rt.bottom - rt.top, /* window height */ + rt.left, /* horizontal position of window */ + rt.top, /* vertical position of window */ + width, /* window width */ + height, /* window height */ GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL); if (!ret) panic("Cannot create status window"); @@ -80,8 +130,20 @@ mswin_init_status_window() ZeroMemory(data, sizeof(NHStatusWindow)); SetWindowLongPtr(ret, GWLP_USERDATA, (LONG_PTR) data); + back_buffer_init(&data->back_buffer, ret, width, height); + mswin_apply_window_style(ret); + if (status_bg_brush == NULL) { + status_bg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_STATUS); + status_bg_brush = CreateSolidBrush(status_bg_color); + } + + if (status_fg_brush == NULL) { + status_fg_color = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_STATUS); + status_fg_brush = CreateSolidBrush(status_fg_color); + } + return ret; } @@ -98,9 +160,7 @@ register_status_window_class() wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = status_bg_brush - ? status_bg_brush - : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_STATUS); + wcex.hbrBackground = NULL; wcex.lpszMenuName = NULL; wcex.lpszClassName = szStatusWindowClass; @@ -216,30 +276,35 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) int *f; int **fop; SIZE sz; - HGDIOBJ oldFont, normalFont, boldFont; + HGDIOBJ normalFont, boldFont; TCHAR wbuf[BUFSZ]; - COLORREF OldBg, OldFg, Bg, Fg; RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; + int width, height; + RECT clear_rect; + HDC front_buffer_hdc; data = (PNHStatusWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); - hdc = BeginPaint(hWnd, &ps); + front_buffer_hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); + width = rt.right - rt.left; + height = rt.bottom - rt.top; + + back_buffer_size(&data->back_buffer, width, height); + + hdc = data->back_buffer.hdc; + normalFont = mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE); boldFont = mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, FALSE); - oldFont = SelectObject(hdc, normalFont); - Bg = status_bg_brush ? status_bg_color - : (COLORREF) GetSysColor(DEFAULT_COLOR_BG_STATUS); - OldBg = SetBkColor(hdc, Bg); + SelectObject(hdc, normalFont); - Fg = status_fg_brush ? status_fg_color - : (COLORREF) GetSysColor(DEFAULT_COLOR_FG_STATUS); - OldFg = SetTextColor(hdc, Fg); + SetBkColor(hdc, status_bg_color); + SetTextColor(hdc, status_fg_color); if (iflags.wc2_hitpointbar && BL_HP < data->n_fields && data->activefields[BL_HP]) { @@ -247,6 +312,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) hpbar_color = data->colors[BL_HP] & 0x00ff; } + clear_rect.left = 0; + clear_rect.top = 0; + clear_rect.right = width; + clear_rect.bottom = height; + + FillRect(hdc, &clear_rect, status_bg_brush); + for (fop = fieldorders; *fop; fop++) { LONG left = rt.left; LONG cy = 0; @@ -275,9 +347,10 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) else if (atr & HL_DIM) fntatr = ATR_DIM; fnt = mswin_get_font(NHW_STATUS, fntatr, hdc, FALSE); - nFg = (clr == NO_COLOR ? Fg : - ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) : Fg)); - nBg = Bg; + nFg = (clr == NO_COLOR ? status_fg_color + : ((clr >= 0 && clr < CLR_MAX) ? nhcolor_to_RGB(clr) + : status_fg_color)); + nBg = status_bg_color; GetTextExtentPoint32(hdc, wbuf, vlen, &sz); if (*f == BL_TITLE && iflags.wc2_hitpointbar) { @@ -287,7 +360,7 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) /* first draw title normally */ SelectObject(hdc, fnt); SetBkMode(hdc, OPAQUE); - SetBkColor(hdc, Bg); + SetBkColor(hdc, status_bg_color); SetTextColor(hdc, nhcolor_to_RGB(hpbar_color)); DrawText(hdc, wbuf, vlen, &rt, DT_LEFT); @@ -323,13 +396,13 @@ onWMPaint(HWND hWnd, WPARAM wParam, LPARAM lParam) rt.left += sz.cx; cy = max(cy, sz.cy); } + rt.left = left; rt.top += cy; } - SelectObject(hdc, oldFont); - SetTextColor(hdc, OldFg); - SetBkColor(hdc, OldBg); + BitBlt(front_buffer_hdc, 0, 0, width, height, hdc, 0, 0, SRCCOPY); + EndPaint(hWnd, &ps); return 0; From c64ae2d28dd092a94d7981d7a56f32949ea23648 Mon Sep 17 00:00:00 2001 From: Bart House Date: Mon, 9 Oct 2017 12:45:22 -0700 Subject: [PATCH 05/43] Win32GUI: Clear selection counts for perm invent --- win/win32/mhmenu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index 59004e21f..6bdea0a2f 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -254,6 +254,8 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, && how != PICK_NONE) { data->menu.prompt[0] = '\0'; SetMenuListType(hWnd, PICK_NONE); + for (i = 0; i < data->menu.size; i++) + data->menu.items[i].count = 0; LayoutMenu(hWnd); } } From 9b3d35898960eb360e163c5e56601a7ecd5453d5 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 9 Oct 2017 15:27:24 -0700 Subject: [PATCH 06/43] fix #H6203 - jumping over water doesn't Accidentally caused by my grappling hook fix 2 months ago, attempting to jump over water made hero enter that water and drown (or crawl out). hurtle_step() was originally intended to be used for recoil while levitating, but it is used in other situations where not levitating and behavior for the two circumstances should be different. This doesn't fix things properly, just gets jumping working again. --- doc/fixes36.1 | 2 ++ include/extern.h | 4 ++-- include/youprop.h | 3 ++- src/apply.c | 8 ++++---- src/dothrow.c | 19 +++++++++++++++++++ 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 19c92f722..ab147170d 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -509,6 +509,8 @@ hero poly'd into vampire could drain monster down to 0 HP without killing it, "you observe a fog cloud where a vampire/bat was" if an unseen vampire on the far side of a closed door shifted shape to pass under that door fix mention_walls reporting secret doors as solid stone +jumping over water unintentionally moved hero through that water, causing + drowning if not able to water walk or fly Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index cc2bf44dc..31180fd66 100644 --- a/include/extern.h +++ b/include/extern.h @@ -536,11 +536,11 @@ E int FDECL(thitmonst, (struct monst *, struct obj *)); E int FDECL(hero_breaks, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E int FDECL(breaks, (struct obj *, XCHAR_P, XCHAR_P)); E void FDECL(release_camera_demon, (struct obj *, XCHAR_P, XCHAR_P)); -E void FDECL(breakobj, - (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P, BOOLEAN_P)); +E void FDECL(breakobj, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(breaktest, (struct obj *)); E boolean FDECL(walk_path, (coord *, coord *, boolean (*)(genericptr, int, int), genericptr_t)); +E boolean FDECL(hurtle_jump, (genericptr_t, int, int)); E boolean FDECL(hurtle_step, (genericptr_t, int, int)); /* ### drawing.c ### */ diff --git a/include/youprop.h b/include/youprop.h index 79fa70a78..d71ec8b5c 100644 --- a/include/youprop.h +++ b/include/youprop.h @@ -227,7 +227,8 @@ && !BFlying) /* May touch surface; does not override any others */ -#define Wwalking (u.uprops[WWALKING].extrinsic && !Is_waterlevel(&u.uz)) +#define EWwalking u.uprops[WWALKING].extrinsic +#define Wwalking (EWwalking && !Is_waterlevel(&u.uz)) /* Don't get wet, can't go under water; overrides others except levitation */ /* Wwalking is meaningless on water level */ diff --git a/src/apply.c b/src/apply.c index c477a4fb8..ca72cc466 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1769,10 +1769,10 @@ int magic; /* 0=Physical, otherwise skill level */ temp = -temp; if (range < temp) range = temp; - (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t) &range); - /* hurtle_step results in (u.ux, u.uy) == (cc.x, cc.y) and usually - * moves the ball if punished, but does not handle all the effects - * of landing on the final position. + (void) walk_path(&uc, &cc, hurtle_jump, (genericptr_t) &range); + /* hurtle_jump -> hurtle_step results in == + * and usually moves the ball if punished, but does not handle all + * the effects of landing on the final position. */ teleds(cc.x, cc.y, FALSE); sokoban_guilt(); diff --git a/src/dothrow.c b/src/dothrow.c index 6c9aeb315..9918e5e77 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -519,6 +519,25 @@ genericptr_t arg; return FALSE; } +/* hack for hurtle_step() -- it ought to be changed to take an argument + indicating lev/fly-to-dest vs lev/fly-to-dest-minus-one-land-on-dest + vs drag-to-dest; original callers use first mode, jumping wants second, + grappling hook backfire and thrown chained ball need third */ +boolean +hurtle_jump(arg, x, y) +genericptr_t arg; +int x, y; +{ + boolean res; + long save_EWwalking = EWwalking; + + /* prevent jumping over water from being placed in that water */ + EWwalking |= I_SPECIAL; + res = hurtle_step(arg, x, y); + EWwalking = save_EWwalking; + return res; +} + /* * Single step for the hero flying through the air from jumping, flying, * etc. Called from hurtle() and jump() via walk_path(). We expect the From 19663e157fb51c18ee286b5587b7b4803f279238 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 9 Oct 2017 17:34:02 -0700 Subject: [PATCH 07/43] hurtling into unseen monsters Expand "You bump into it." into something more comprehensive when encountering an unseen monster while hurtling. Tested with jumping but other forms of hurtling should behave the same. --- src/dothrow.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/dothrow.c b/src/dothrow.c index 9918e5e77..0b1539454 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -625,8 +625,8 @@ int x, y; } if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y) && bad_rock(youmonst.data, x, u.uy)) { - boolean too_much = - (invent && (inv_weight() + weight_cap() > 600)); + boolean too_much = (invent && (inv_weight() + weight_cap() > 600)); + /* Move at a diagonal. */ if (bigmonst(youmonst.data) || too_much) { You("%sget forcefully wedged into a crevice.", @@ -640,14 +640,43 @@ int x, y; } } - if ((mon = m_at(x, y)) != 0) { - You("bump into %s.", a_monnam(mon)); + if ((mon = m_at(x, y)) != 0 +#if 0 /* we can't include these two exceptions unless we know we're + * going to end up past the current spot rather than on it; + * for that, we need to know that the range is not exhausted + * and also that the next spot doesn't contain an obstacle */ + && !(mon->mundetected && hides_under(mon) && (Flying || Levitation)) + && !(mon->mundetected && mon->data->mlet == S_EEL + && (Flying || Levitation || Wwalking)) +#endif + ) { + const char *mnam, *pronoun; + int glyph = glyph_at(x, y); + + mon->mundetected = 0; /* wakeup() will handle mimic */ + mnam = a_monnam(mon); /* after unhiding */ + pronoun = mhim(mon); + if (!strcmp(mnam, "it")) { + /* mhim() uses pronoun_gender() which forces neuter if monster + can't be seen; we want him/her for humanoid sensed by touch */ + if (!strcmp(pronoun, "it") && humanoid(mon->data)) + pronoun = genders[mon->female].him; + mnam = !strcmp(pronoun, "it") ? "something" : "someone"; + } + if (!glyph_is_monster(glyph) && !glyph_is_invisible(glyph)) + You("find %s by bumping into %s.", mnam, pronoun); + else + You("bump into %s.", mnam); wakeup(mon, FALSE); + if (!canspotmon(mon)) + map_invisible(mon->mx, mon->my); setmangry(mon, FALSE); - wake_nearto(x,y, 10); + wake_nearto(x, y, 10); return FALSE; } - if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data, u.ux, y) + + if ((u.ux - x) && (u.uy - y) + && bad_rock(youmonst.data, u.ux, y) && bad_rock(youmonst.data, x, u.uy)) { /* Move at a diagonal. */ if (Sokoban) { From 99c6b7f4da951def294ab61b565f2933a30fd632 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 15:29:46 +0300 Subject: [PATCH 08/43] Add context menu for current location Add a new boolean option herecmd_menu. If this is on, and using a windowport that supports mouse, clicking on your character pops up a menu of actions doable in that location. Basically this is nothing new, as almost all of the same actions were done before on the mouse click. You can also pop up the context menu with the #herecmdmenu extended command --- doc/Guidebook.mn | 5 ++ doc/Guidebook.tex | 4 ++ doc/fixes36.1 | 2 + include/flag.h | 1 + src/cmd.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++ src/options.c | 1 + 6 files changed, 140 insertions(+) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 0d934b465..b7b2258cf 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -982,6 +982,8 @@ Force a lock. Autocompletes. Default key is 'M-f'. Show what type of thing a map symbol corresponds to. Default key is ';'. .lp #help Show the help menu. Default key is '?', and 'h' if number_pad is on. +.lp #herecmdmenu +Show a menu of possible actions in your current location. .lp #history Show long version and game history. Default key is 'V'. .lp #inventory @@ -2556,6 +2558,9 @@ with the `/' command, ask if you want to see it (default on). Turning help off makes just looking at things faster, since you aren't interrupted with the ``More info?'' prompt, but it also means that you might miss some interesting and/or important information. Persistent. +.lp herecmd_menu +When using a windowport that supports mouse and clicking on yourself, show +a menu of possible actions for this location. Same as herecmdmenu command. .lp hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 9119ac17d..66610799e 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3124,6 +3124,10 @@ Turning help off makes just looking at things faster, since you aren't interrupted with the ``{\tt More info?}'' prompt, but it also means that you might miss some interesting and/or important information. Persistent. %.lp +\item[\ib{herecmd\verb+_+menu}] +When using a windowport that supports mouse and clicking on yourself, show +a menu of possible actions for this location. Same as herecmdmenu command. +%.lp \item[\ib{hilite\verb+_+pet}] Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ab147170d..1a3d60848 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -687,6 +687,8 @@ Master Key of Thievery always finds door and chest traps if used to lock or blessed (for non-rogues); player is offered the opportunity to disarm "Elbereth" must now be the only engraved text on a square to function "Elbereth" now erodes based on attacks by the player, not monsters scared +option herecmd_menu to make a mouse click on your character pop up + a context menu, and extended command #herecmdmenu to do the same Platform- and/or Interface-Specific New Features diff --git a/include/flag.h b/include/flag.h index 415688a92..5b205e5b7 100644 --- a/include/flag.h +++ b/include/flag.h @@ -191,6 +191,7 @@ struct instance_flags { * behaviour of various NetHack functions and probably warrant * a structure of their own elsewhere some day. */ + boolean herecmd_menu; /* use menu when mouseclick on yourself */ boolean invis_goldsym; /* gold symbol is ' '? */ int parse_config_file_src; /* hack for parse_config_line() */ int in_lava_effects; /* hack for Boots_off() */ diff --git a/src/cmd.c b/src/cmd.c index add6ebd52..4c8372115 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -114,6 +114,7 @@ static int NDECL(dosuspend_core); /**/ static int NDECL((*timed_occ_fn)); +STATIC_PTR int NDECL(doherecmdmenu); STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); @@ -181,6 +182,8 @@ STATIC_DCL void FDECL(attributes_enlightenment, (int, int)); static const char *readchar_queue = ""; static coord clicklook_cc; +STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), const char *)); +STATIC_DCL char FDECL(here_cmd_menu, (BOOLEAN_P)); STATIC_DCL char *NDECL(parse); STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *)); @@ -2899,6 +2902,7 @@ struct ext_func_tab extcmdlist[] = { { ';', "glance", "show what type of thing a map symbol corresponds to", doquickwhatis, IFBURIED | GENERALCMD }, { '?', "help", "give a help message", dohelp, IFBURIED | GENERALCMD }, + { '\0', "herecmdmenu", "show menu of commands you can do here", doherecmdmenu, IFBURIED }, { 'V', "history", "show long version and game history", dohistory, IFBURIED | GENERALCMD }, { 'i', "inventory", "show your inventory", ddoinv, IFBURIED }, @@ -4658,6 +4662,124 @@ register int x, y; return x >= 1 && x <= COLNO - 1 && y >= 0 && y <= ROWNO - 1; } +STATIC_PTR int +doherecmdmenu(VOID_ARGS) +{ + char ch = here_cmd_menu(TRUE); + + if (ch) + return 1; + + return 0; +} + +STATIC_OVL void +add_herecmd_menuitem(win, func, text) +winid win; +int NDECL((*func)); +const char *text; +{ + char ch; + anything any; + + if ((ch = cmd_from_func(func)) != '\0') { + any.a_void = (genericptr_t)func; + add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, text, MENU_UNSELECTED); + } +} + +STATIC_OVL char +here_cmd_menu(doit) +boolean doit; +{ + winid win; + anything any; + char ch; + char buf[BUFSZ]; + schar typ = levl[u.ux][u.uy].typ; + int npick; + menu_item *picks = (menu_item *) 0; + + win = create_nhwindow(NHW_MENU); + start_menu(win); + + if (IS_FOUNTAIN(typ) || IS_SINK(typ)) { + Sprintf(buf, "Drink from the %s", + defsyms[IS_FOUNTAIN(typ) ? S_fountain : S_sink].explanation); + add_herecmd_menuitem(win, dodrink, buf); + } + + if (IS_FOUNTAIN(typ)) + add_herecmd_menuitem(win, dodip, + "Dip something into the fountain"); + + if (IS_THRONE(typ)) + add_herecmd_menuitem(win, dosit, + "Sit on the throne"); + + if ((u.ux == xupstair && u.uy == yupstair) + || (u.ux == sstairs.sx && u.uy == sstairs.sy + && sstairs.up) + || (u.ux == xupladder && u.uy == yupladder)) { + Sprintf(buf, "Go up the %s", + (u.ux == xupladder && u.uy == yupladder) + ? "ladder" : "stairs"); + add_herecmd_menuitem(win, doup, buf); + } + + if ((u.ux == xdnstair && u.uy == ydnstair) + || (u.ux == sstairs.sx && u.uy == sstairs.sy + && !sstairs.up) + || (u.ux == xdnladder && u.uy == ydnladder)) { + Sprintf(buf, "Go down the %s", + (u.ux == xupladder && u.uy == yupladder) + ? "ladder" : "stairs"); + add_herecmd_menuitem(win, dodown, buf); + } + + if (OBJ_AT(u.ux, u.uy)) { + struct obj *otmp = level.objects[u.ux][u.uy]; + Sprintf(buf, "Pick up %s", otmp->nexthere ? "items" : doname(otmp)); + add_herecmd_menuitem(win, dopickup, buf); + + if (Is_container(otmp)) { + Sprintf(buf, "Loot %s", doname(otmp)); + add_herecmd_menuitem(win, doloot, buf); + } + + if (otmp->oclass == FOOD_CLASS) { + Sprintf(buf, "Eat %s", doname(otmp)); + add_herecmd_menuitem(win, doeat, buf); + } + } + + if (invent) + add_herecmd_menuitem(win, dodrop, "Drop items"); + + add_herecmd_menuitem(win, donull, "Rest one turn"); + add_herecmd_menuitem(win, dosearch, "Search around you"); + add_herecmd_menuitem(win, dolook, "Look at what is here"); + + end_menu(win, "What do you want to do?"); + npick = select_menu(win, PICK_ONE, &picks); + destroy_nhwindow(win); + if (npick > 0) { + if (doit) { + int NDECL((*func)) = picks->item.a_void; + int ret = func(); + + free((genericptr_t)picks); + return (char)ret; + } else { + ch = cmd_from_func(picks->item.a_void); + free((genericptr_t)picks); + return ch; + } + } + return '\0'; +} + + static NEARDATA int last_multi; /* @@ -4692,6 +4814,11 @@ int x, y, mod; } if (x == 0 && y == 0) { + if (iflags.herecmd_menu) { + cmd[0] = here_cmd_menu(FALSE); + return cmd; + } + /* here */ if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { diff --git a/src/options.c b/src/options.c index 7086a7b5e..56db02537 100644 --- a/src/options.c +++ b/src/options.c @@ -129,6 +129,7 @@ static struct Bool_Opt { { "fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE }, { "goldX", &iflags.goldX, FALSE, SET_IN_GAME }, { "help", &flags.help, TRUE, SET_IN_GAME }, + { "herecmd_menu", &iflags.herecmd_menu, FALSE, SET_IN_GAME }, { "hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME }, /*WC*/ { "hilite_pile", &iflags.hilite_pile, FALSE, SET_IN_GAME }, { "hitpointbar", &iflags.wc2_hitpointbar, FALSE, SET_IN_GAME }, /*WC2*/ From 7f495a1ee3dd4fad7e9615e374f197ed43e20c1d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 16:49:07 +0300 Subject: [PATCH 09/43] Add context menu for the location next to you --- src/cmd.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/cmd.c b/src/cmd.c index 4c8372115..195f492a9 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -184,6 +184,7 @@ static coord clicklook_cc; STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), const char *)); STATIC_DCL char FDECL(here_cmd_menu, (BOOLEAN_P)); +STATIC_DCL char FDECL(there_cmd_menu, (int, int)); STATIC_DCL char *NDECL(parse); STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *)); @@ -4688,6 +4689,46 @@ const char *text; } } +STATIC_OVL char +there_cmd_menu(x, y) +int x, y; +{ + winid win; + anything any; + char ch; + char buf[BUFSZ]; + schar typ = levl[x][y].typ; + int npick; + menu_item *picks = (menu_item *) 0; + struct trap *ttmp; + + win = create_nhwindow(NHW_MENU); + start_menu(win); + + if (IS_DOOR(typ)) { + int dm = levl[x][y].doormask; + if ((dm & (D_CLOSED|D_LOCKED))) { + add_herecmd_menuitem(win, dokick, "Kick the door"); + add_herecmd_menuitem(win, doopen, "Open the door"); + } else if ((dm & D_ISOPEN)) { + add_herecmd_menuitem(win, doclose, "Close the door"); + } + } + + if (typ <= SCORR) + add_herecmd_menuitem(win, dosearch, "Search for secret doors"); + + end_menu(win, "What do you want to do?"); + npick = select_menu(win, PICK_ONE, &picks); + destroy_nhwindow(win); + if (npick > 0) { + ch = cmd_from_func(picks->item.a_void); + free((genericptr_t)picks); + return ch; + } + return '\0'; +} + STATIC_OVL char here_cmd_menu(doit) boolean doit; @@ -4857,6 +4898,13 @@ int x, y, mod; && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) { cmd[1] = Cmd.dirchars[dir]; cmd[2] = '\0'; + if (iflags.herecmd_menu) { + cmd[0] = there_cmd_menu(u.ux + x, u.uy + y); + if (cmd[0] == '\0') + cmd[1] = '\0'; + return cmd; + } + if (IS_DOOR(levl[u.ux + x][u.uy + y].typ)) { /* slight assistance to the player: choose kick/open for them */ From e2b367102a65fc9f9a4382a366ae2b7fd5d84e1f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 17:50:39 +0300 Subject: [PATCH 10/43] Complain if hints file does not exist --- sys/unix/setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sys/unix/setup.sh b/sys/unix/setup.sh index f3319adb7..5c210264c 100755 --- a/sys/unix/setup.sh +++ b/sys/unix/setup.sh @@ -26,6 +26,11 @@ x) hints=/dev/null ;; esac +if [ ! -f "$hints" ]; then + echo "Cannot find hints file $hfile" + exit 1 +fi + /bin/sh ./mkmkfile.sh Makefile.top TOP ../../Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.dat DAT ../../dat/Makefile $hints $hfile /bin/sh ./mkmkfile.sh Makefile.doc DOC ../../doc/Makefile $hints $hfile From 76d223c178986214bfe9567dd6028a9b6b4eaef0 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 18:20:29 +0300 Subject: [PATCH 11/43] Qt4: handle menu page selector keys Qt4 doesn't do menu paging, so handle the select page, invert page, and unselect page like selecting, inverting or unselecting all. --- win/Qt4/qt4menu.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp index 7d70a26e2..a6fc8c2f5 100644 --- a/win/Qt4/qt4menu.cpp +++ b/win/Qt4/qt4menu.cpp @@ -482,11 +482,11 @@ void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event) accept(); else if (key==MENU_SEARCH) Search(); - else if (key==MENU_SELECT_ALL) + else if (key==MENU_SELECT_ALL || key==MENU_SELECT_PAGE) All(); - else if (key==MENU_INVERT_ALL) + else if (key==MENU_INVERT_ALL || key==MENU_INVERT_PAGE) Invert(); - else if (key==MENU_UNSELECT_ALL) + else if (key==MENU_UNSELECT_ALL || key==MENU_UNSELECT_PAGE) ChooseNone(); else if (('0' <= key && key <= '9') || key == '\b') InputCount(key); From f06cf62a35ed88721ef37f8590f50d9f8abeb81c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 19:19:17 +0300 Subject: [PATCH 12/43] Qt4: Allow clicking anywhere in menus Instead of requiring clicking on the checkbox, allow clicking anywhere in a selectable line to select it. --- win/Qt4/qt4menu.cpp | 6 ++++++ win/Qt4/qt4menu.h | 1 + 2 files changed, 7 insertions(+) diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp index a6fc8c2f5..fe004e87c 100644 --- a/win/Qt4/qt4menu.cpp +++ b/win/Qt4/qt4menu.cpp @@ -132,6 +132,7 @@ NetHackQtMenuWindow::NetHackQtMenuWindow(QWidget *parent) : grid->setRowStretch(2, 1); setFocusPolicy(Qt::StrongFocus); table->setFocusPolicy(Qt::NoFocus); + connect(table, SIGNAL(cellClicked(int,int)), this, SLOT(cellToggleSelect(int,int))); setLayout(grid); } @@ -560,6 +561,11 @@ void NetHackQtMenuWindow::ToggleSelect(int i) } } +void NetHackQtMenuWindow::cellToggleSelect(int i, int j) +{ + ToggleSelect(i); +} + void NetHackQtMenuWindow::DoSelection(bool) { if (how == PICK_ONE) { diff --git a/win/Qt4/qt4menu.h b/win/Qt4/qt4menu.h index ad15841bc..5bc265920 100644 --- a/win/Qt4/qt4menu.h +++ b/win/Qt4/qt4menu.h @@ -66,6 +66,7 @@ public slots: void Search(); void ToggleSelect(int); + void cellToggleSelect(int, int); void DoSelection(bool); protected: From 4f95d19ab74de278be559677dc0dc582e95a69a4 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 19:28:03 +0300 Subject: [PATCH 13/43] Qt4: Prevent selecting all in pick-one menus --- win/Qt4/qt4menu.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp index fe004e87c..5bfefd3b5 100644 --- a/win/Qt4/qt4menu.cpp +++ b/win/Qt4/qt4menu.cpp @@ -502,6 +502,9 @@ void NetHackQtMenuWindow::keyPressEvent(QKeyEvent* event) void NetHackQtMenuWindow::All() { + if (how != PICK_ANY) + return; + for (int i=0; iitem(i, 0); if (count != NULL) count->setText(""); @@ -512,6 +515,9 @@ void NetHackQtMenuWindow::All() } void NetHackQtMenuWindow::ChooseNone() { + if (how != PICK_ANY) + return; + for (int i=0; iitem(i, 0); if (count != NULL) count->setText(""); @@ -522,6 +528,9 @@ void NetHackQtMenuWindow::ChooseNone() } void NetHackQtMenuWindow::Invert() { + if (how != PICK_ANY) + return; + for (int i=0; iitem(i, 0); if (count != NULL) count->setText(""); @@ -532,6 +541,9 @@ void NetHackQtMenuWindow::Invert() } void NetHackQtMenuWindow::Search() { + if (how != PICK_NONE) + return; + NetHackQtStringRequestor requestor(this, "Search for:"); char line[256]; if (requestor.Get(line)) { From 2fa61f9038483d65af561d34057ce49695638aa6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 19:56:51 +0300 Subject: [PATCH 14/43] Qt4: Use generic putmixed routine --- win/Qt4/qt4bind.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index feed0a656..ab4726a5f 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -683,7 +683,7 @@ struct window_procs Qt_procs = { nethack_qt4::NetHackQtBind::qt_destroy_nhwindow, nethack_qt4::NetHackQtBind::qt_curs, nethack_qt4::NetHackQtBind::qt_putstr, - nethack_qt4::NetHackQtBind::qt_putstr, /* FIXME: should be qt_putmixed() */ + genl_putmixed, nethack_qt4::NetHackQtBind::qt_display_file, nethack_qt4::NetHackQtBind::qt_start_menu, nethack_qt4::NetHackQtBind::qt_add_menu, From 257f17f8df7985cf282c63bf5ab024eefb8719d3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 20:18:04 +0300 Subject: [PATCH 15/43] Qt4: Don't segfault with QT_COMPACT --- sys/unix/hints/linux-qt4 | 2 +- win/Qt4/qt4main.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/sys/unix/hints/linux-qt4 b/sys/unix/hints/linux-qt4 index 51f6ad05b..ae3911939 100644 --- a/sys/unix/hints/linux-qt4 +++ b/sys/unix/hints/linux-qt4 @@ -20,7 +20,7 @@ VARDIR = $(HACKDIR) POSTINSTALL= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; chmod $(VARFILEPERM) $(INSTDIR)/sysconf; POSTINSTALL+= bdftopcf win/X11/nh10.bdf > $(INSTDIR)/nh10.pcf; (cd $(INSTDIR); mkfontdir); -CFLAGS=-O -I../include -DNOTPARMDECL +CFLAGS=-g -O -I../include -DNOTPARMDECL CFLAGS+=-DHACKDIR=\"$(HACKDIR)\" CFLAGS+=-DSYSCF -DSYSCF_FILE=\"$(HACKDIR)/sysconf\" CFLAGS+=-DCOMPRESS=\"/bin/gzip\" -DCOMPRESS_EXTENSION=\".gz\" diff --git a/win/Qt4/qt4main.cpp b/win/Qt4/qt4main.cpp index ec7e58324..f9a74e506 100644 --- a/win/Qt4/qt4main.cpp +++ b/win/Qt4/qt4main.cpp @@ -861,14 +861,17 @@ void NetHackQtMainWindow::doKeys(const QString& k) void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) { message=window; - hsplitter->insertWidget(0, message->Widget()); + if (!qt_compact_mode) + hsplitter->insertWidget(0, message->Widget()); ShowIfReady(); } void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) { + map=window; - vsplitter->insertWidget(1, map->Widget()); + if (!qt_compact_mode) + vsplitter->insertWidget(1, map->Widget()); ShowIfReady(); connect(map,SIGNAL(resized()),this,SLOT(layout())); } @@ -876,7 +879,8 @@ void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) { status=window; - hsplitter->insertWidget(2, status->Widget()); + if (!qt_compact_mode) + hsplitter->insertWidget(2, status->Widget()); ShowIfReady(); } From dbacc98a1dc6d25cf91aa3d63d08973437e4253d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 21:13:37 +0300 Subject: [PATCH 16/43] Qt4: Fix wrong condition in search blocking --- win/Qt4/qt4menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Qt4/qt4menu.cpp b/win/Qt4/qt4menu.cpp index 5bfefd3b5..5ab053891 100644 --- a/win/Qt4/qt4menu.cpp +++ b/win/Qt4/qt4menu.cpp @@ -541,7 +541,7 @@ void NetHackQtMenuWindow::Invert() } void NetHackQtMenuWindow::Search() { - if (how != PICK_NONE) + if (how == PICK_NONE) return; NetHackQtStringRequestor requestor(this, "Search for:"); From 4dff3a707ef8d989176b34331bd85b04d626a0fc Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 21:47:35 +0300 Subject: [PATCH 17/43] Qt4: Pile mark --- include/qt_xpms.h | 14 ++++++++++++ win/Qt4/qt4map.cpp | 54 +++++++++++++++++++++++++++------------------- win/Qt4/qt4map.h | 1 + 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/include/qt_xpms.h b/include/qt_xpms.h index a91ac5f11..5667c13c0 100644 --- a/include/qt_xpms.h +++ b/include/qt_xpms.h @@ -946,6 +946,20 @@ static const char *pet_mark_small_xpm[] = { "..X.." }; /* XPM */ +static const char *pile_mark_xpm[] = { +/* width height ncolors chars_per_pixel */ +"5 5 2 1", +/* colors */ +". c None", +"X c #00FF00", +/* pixels */ +"..X..", +"..X..", +"XXXXX", +"..X..", +"..X.." +}; +/* XPM */ static const char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", diff --git a/win/Qt4/qt4map.cpp b/win/Qt4/qt4map.cpp index 39c915ee5..f3425bab2 100644 --- a/win/Qt4/qt4map.cpp +++ b/win/Qt4/qt4map.cpp @@ -71,6 +71,7 @@ NetHackQtMapViewport::NetHackQtMapViewport(NetHackQtClickBuffer& click_sink) : change(10) { pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); + pile_annotation = QPixmap(pile_mark_xpm); Clear(); cursor.setX(0); @@ -157,29 +158,33 @@ void NetHackQtMapViewport::paintEvent(QPaintEvent* event) QString(QChar(ch)).left(1) ); } - if (glyph_is_pet(g) #ifdef TEXTCOLOR - && ::iflags.hilite_pet + if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); + } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + } #endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } - } - } + } + } painter.setFont(font()); } else { for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); + int color; + int ch; + unsigned special; + mapglyph(g, &ch, &color, &special, i, j); qt_settings->glyphs().drawCell(painter, g, i, j); - if (glyph_is_pet(g) #ifdef TEXTCOLOR - && ::iflags.hilite_pet + if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); + } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + } #endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } } } } @@ -649,6 +654,7 @@ NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : viewport.setPalette(palette); pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); + pile_annotation = QPixmap(pile_mark_xpm); cursor.setX(0); cursor.setY(0); @@ -835,13 +841,13 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event) Qt::AlignCenter, QString(QChar(ch)).left(1) ); - if (glyph_is_pet(g) #ifdef TEXTCOLOR - && ::iflags.hilite_pet + if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); + } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + } #endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } } } @@ -850,14 +856,18 @@ void NetHackQtMapWindow::paintEvent(QPaintEvent* event) for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); + int color; + int ch; + unsigned special; + mapglyph(g, &ch, &color, &special, i, j); qt_settings->glyphs().drawCell(painter, g, i, j); - if (glyph_is_pet(g) #ifdef TEXTCOLOR - && ::iflags.hilite_pet + if (((special & MG_PET) != 0) && ::iflags.hilite_pet) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); + } else if (((special & MG_OBJPILE) != 0) && ::iflags.hilite_pile) { + painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pile_annotation); + } #endif - ) { - painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); - } } } } diff --git a/win/Qt4/qt4map.h b/win/Qt4/qt4map.h index da2df88ad..337a726aa 100644 --- a/win/Qt4/qt4map.h +++ b/win/Qt4/qt4map.h @@ -33,6 +33,7 @@ private: unsigned short& Glyph(int x, int y) { return glyph[y][x]; } QPoint cursor; QPixmap pet_annotation; + QPixmap pile_annotation; NetHackQtClickBuffer& clicksink; Clusterizer change; From 2fcf1ad1396b3b866820aae9b155a9e5e29dc11c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Tue, 10 Oct 2017 22:55:30 +0300 Subject: [PATCH 18/43] Qt4: put and get message history --- win/Qt4/qt4bind.cpp | 27 ++++++++++++++++++++++++++- win/Qt4/qt4bind.h | 4 ++++ win/Qt4/qt4main.cpp | 5 +++++ win/Qt4/qt4main.h | 1 + win/Qt4/qt4msg.cpp | 15 +++++++++++++++ win/Qt4/qt4msg.h | 2 ++ 6 files changed, 53 insertions(+), 1 deletion(-) diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index ab4726a5f..75c5f821b 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -605,6 +605,30 @@ void NetHackQtBind::qt_outrip(winid wid, int how, time_t when) window->UseRIP(how, when); } +char * NetHackQtBind::qt_getmsghistory(BOOLEAN_P init) +{ + NetHackQtMessageWindow* window = main->GetMessageWindow(); + if (window) + return (char *)window->GetStr(init); + return NULL; +} + +void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) +{ + NetHackQtMessageWindow* window = main->GetMessageWindow(); + //raw_printf("msg='%s'", msg); + if (window && msg) + window->PutStr(ATR_NONE, QString::fromLatin1(msg)); +} + +void NetHackQtBind::qt_putmsghistory(const std::string& msg, BOOLEAN_P is_restoring) +{ + NetHackQtMessageWindow* window = main->GetMessageWindow(); + if (window) + window->PutStr(ATR_NONE, QString::fromLatin1(msg.c_str(), msg.size())); +} + + bool NetHackQtBind::notify(QObject *receiver, QEvent *event) { // Ignore Alt-key navigation to menubar, it's annoying when you @@ -728,7 +752,8 @@ struct window_procs Qt_procs = { #endif genl_preference_update, - genl_getmsghistory, genl_putmsghistory, + nethack_qt4::NetHackQtBind::qt_getmsghistory, + nethack_qt4::NetHackQtBind::qt_putmsghistory, genl_status_init, genl_status_finish, genl_status_enablefield, #ifdef STATUS_HILITES diff --git a/win/Qt4/qt4bind.h b/win/Qt4/qt4bind.h index 99a2c0d11..ad396b78c 100644 --- a/win/Qt4/qt4bind.h +++ b/win/Qt4/qt4bind.h @@ -78,6 +78,10 @@ public: static void qt_start_screen(); static void qt_end_screen(); + static char *qt_getmsghistory(BOOLEAN_P init); + static void qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring); + static void qt_putmsghistory(const std::string& msg, BOOLEAN_P is_restoring); + static void qt_outrip(winid wid, int how, time_t when); static int qt_kbhit(); diff --git a/win/Qt4/qt4main.cpp b/win/Qt4/qt4main.cpp index f9a74e506..4fd8d14da 100644 --- a/win/Qt4/qt4main.cpp +++ b/win/Qt4/qt4main.cpp @@ -866,6 +866,11 @@ void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) ShowIfReady(); } +NetHackQtMessageWindow * NetHackQtMainWindow::GetMessageWindow() +{ + return message; +} + void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow2* window) { diff --git a/win/Qt4/qt4main.h b/win/Qt4/qt4main.h index 33f5b2635..a3ec15ac2 100644 --- a/win/Qt4/qt4main.h +++ b/win/Qt4/qt4main.h @@ -41,6 +41,7 @@ public: NetHackQtMainWindow(NetHackQtKeyBuffer&); void AddMessageWindow(NetHackQtMessageWindow* window); + NetHackQtMessageWindow * GetMessageWindow(); void AddMapWindow(NetHackQtMapWindow2* window); void AddStatusWindow(NetHackQtStatusWindow* window); void RemoveWindow(NetHackQtWindow* window); diff --git a/win/Qt4/qt4msg.cpp b/win/Qt4/qt4msg.cpp index e1194795d..7c3ccd1df 100644 --- a/win/Qt4/qt4msg.cpp +++ b/win/Qt4/qt4msg.cpp @@ -35,6 +35,7 @@ NetHackQtMessageWindow::NetHackQtMessageWindow() : list->setFocusPolicy(Qt::NoFocus); ::iflags.window_inited = 1; map = 0; + currgetmsg = 0; connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); updateFont(); } @@ -80,6 +81,20 @@ void NetHackQtMessageWindow::Display(bool block) } } +const char * NetHackQtMessageWindow::GetStr(bool init) +{ + if (init) + currgetmsg = 0; + + QListWidgetItem *item = list->item(++currgetmsg); + if (item) { + QString str = item->text(); + //raw_printf("getstr[%i]='%s'", currgetmsg, str.toLatin1().constData()); + return str.toLatin1().constData(); + } + return NULL; +} + void NetHackQtMessageWindow::PutStr(int attr, const QString& text) { #ifdef USER_SOUNDS diff --git a/win/Qt4/qt4msg.h b/win/Qt4/qt4msg.h index 5c391cc4f..238ace478 100644 --- a/win/Qt4/qt4msg.h +++ b/win/Qt4/qt4msg.h @@ -22,6 +22,7 @@ public: virtual QWidget* Widget(); virtual void Clear(); virtual void Display(bool block); + virtual const char *GetStr(bool init); virtual void PutStr(int attr, const QString& text); void Scroll(int dx, int dy); @@ -31,6 +32,7 @@ public: private: QListWidget* list; bool changed; + int currgetmsg; NetHackQtMapWindow2* map; private slots: From c6f0058e3d74c24639114217174adf87824fcbbe Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 11 Oct 2017 00:32:39 +0300 Subject: [PATCH 19/43] Qt4: Handle saving/loading message history --- win/Qt4/qt4bind.cpp | 45 +++++++++++++++++++++++++++++++++++---------- win/Qt4/qt4bind.h | 5 ++++- win/Qt4/qt4msg.cpp | 8 +++++++- win/Qt4/qt4msg.h | 1 + 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index 75c5f821b..0adc02346 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -18,6 +18,7 @@ extern "C" { #undef max #include +#include #if QT_VERSION >= 0x050000 #include #include @@ -119,6 +120,9 @@ NetHackQtBind::NetHackQtBind(int& argc, char** argv) : main = new NetHackQtMainWindow(keybuffer); connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit())); qt_settings=new NetHackQtSettings(main->width(),main->height()); + msgs_strings = new QStringList(); + msgs_initd = false; + msgs_saved = false; } void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) @@ -616,19 +620,37 @@ char * NetHackQtBind::qt_getmsghistory(BOOLEAN_P init) void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) { NetHackQtMessageWindow* window = main->GetMessageWindow(); - //raw_printf("msg='%s'", msg); - if (window && msg) + if (!window) + return; + + if (is_restoring && !msgs_initd) { + /* we're restoring history from the previous session, but new + messages have already been issued this session */ + int i = 0; + const char *str; + + while ((str = window->GetStr((i == 0)))) { + msgs_strings->append(str); + i++; + } + msgs_initd = true; + msgs_saved = (i > 0); + window->ClearMessages(); + } + + if (msg) { + //raw_printf("msg='%s'", msg); window->PutStr(ATR_NONE, QString::fromLatin1(msg)); + } else if (msgs_saved) { + /* restore strings */ + int i; + for (i = 0; i < msgs_strings->size(); i++) + window->PutStr(ATR_NONE, msgs_strings->at((i))); + delete msgs_strings; + msgs_initd = false; + } } -void NetHackQtBind::qt_putmsghistory(const std::string& msg, BOOLEAN_P is_restoring) -{ - NetHackQtMessageWindow* window = main->GetMessageWindow(); - if (window) - window->PutStr(ATR_NONE, QString::fromLatin1(msg.c_str(), msg.size())); -} - - bool NetHackQtBind::notify(QObject *receiver, QEvent *event) { // Ignore Alt-key navigation to menubar, it's annoying when you @@ -682,6 +704,9 @@ NetHackQtKeyBuffer NetHackQtBind::keybuffer; NetHackQtClickBuffer NetHackQtBind::clickbuffer; NetHackQtMainWindow* NetHackQtBind::main=0; QFrame* NetHackQtBind::splash=0; +QStringList *NetHackQtBind::msgs_strings; +boolean NetHackQtBind::msgs_saved = false; +boolean NetHackQtBind::msgs_initd = false; static void Qt_positionbar(char *) {} diff --git a/win/Qt4/qt4bind.h b/win/Qt4/qt4bind.h index ad396b78c..820341cae 100644 --- a/win/Qt4/qt4bind.h +++ b/win/Qt4/qt4bind.h @@ -80,7 +80,6 @@ public: static char *qt_getmsghistory(BOOLEAN_P init); static void qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring); - static void qt_putmsghistory(const std::string& msg, BOOLEAN_P is_restoring); static void qt_outrip(winid wid, int how, time_t when); static int qt_kbhit(); @@ -89,6 +88,10 @@ public: private: virtual bool notify(QObject *receiver, QEvent *event); + + static QStringList *msgs_strings; + static boolean msgs_saved; + static boolean msgs_initd; }; } // namespace nethack_qt4 diff --git a/win/Qt4/qt4msg.cpp b/win/Qt4/qt4msg.cpp index 7c3ccd1df..d82e102fe 100644 --- a/win/Qt4/qt4msg.cpp +++ b/win/Qt4/qt4msg.cpp @@ -73,6 +73,12 @@ void NetHackQtMessageWindow::Clear() map->clearMessages(); } +void NetHackQtMessageWindow::ClearMessages() +{ + if (list) + list->clear(); +} + void NetHackQtMessageWindow::Display(bool block) { if (changed) { @@ -86,7 +92,7 @@ const char * NetHackQtMessageWindow::GetStr(bool init) if (init) currgetmsg = 0; - QListWidgetItem *item = list->item(++currgetmsg); + QListWidgetItem *item = list->item(currgetmsg++); if (item) { QString str = item->text(); //raw_printf("getstr[%i]='%s'", currgetmsg, str.toLatin1().constData()); diff --git a/win/Qt4/qt4msg.h b/win/Qt4/qt4msg.h index 238ace478..f4091ad18 100644 --- a/win/Qt4/qt4msg.h +++ b/win/Qt4/qt4msg.h @@ -26,6 +26,7 @@ public: virtual void PutStr(int attr, const QString& text); void Scroll(int dx, int dy); + void ClearMessages(); void setMap(NetHackQtMapWindow2*); From 76a47b5e3404ac64868e31fbb7aad2ec05d3ecb1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 11 Oct 2017 01:06:07 +0300 Subject: [PATCH 20/43] Qt4: Save message history to dumplog --- win/Qt4/qt4bind.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index 0adc02346..dee38e8c3 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -641,11 +641,18 @@ void NetHackQtBind::qt_putmsghistory(const char *msg, BOOLEAN_P is_restoring) if (msg) { //raw_printf("msg='%s'", msg); window->PutStr(ATR_NONE, QString::fromLatin1(msg)); +#ifdef DUMPLOG + dumplogmsg(msg); +#endif } else if (msgs_saved) { /* restore strings */ int i; - for (i = 0; i < msgs_strings->size(); i++) + for (i = 0; i < msgs_strings->size(); i++) { window->PutStr(ATR_NONE, msgs_strings->at((i))); +#ifdef DUMPLOG + dumplogmsg(msgs_strings->at(i).toLatin1().constData()); +#endif + } delete msgs_strings; msgs_initd = false; } From 5d1f77301a1cf7b2a257dc82444d172e6715be47 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 10 Oct 2017 15:56:18 -0700 Subject: [PATCH 21/43] context menu tweaks Fix several warnings about using 'void *' for a function pointer and a couple of unused variables. Add a_nfunc for 'int NDECL((*func))' alternative for union anything. Make the enum list of union anything types actually match the alternatives (field a_uchar was missing from enums, enum mask32 had no corresponding a_mask32 field). Add another command, #therecmdmenu, so that the context menu for an adjacent spot can be tested without mouse support. It revealed that you could get an empty menu if nothing applicable was at target spot. Add a few adjacent actions: lock/unlock door if carrying suitable implement, search door for traps, examine known trap (door/ceiling, not door), #untrap known trap, mount saddled critter, remove saddle. Make "kick door" be the last choice for closed door instead of first. Add one 'here' action: dismount. Both #herecmdmenu and #therecmdmenu interact strangely with ^A, but differently from each other. I didn't make any attempt to solve this. There's no documentation for #therecmdmenu. --- include/wintype.h | 4 ++ src/cmd.c | 178 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 140 insertions(+), 42 deletions(-) diff --git a/include/wintype.h b/include/wintype.h index 3dbcc0500..3bb82347d 100644 --- a/include/wintype.h +++ b/include/wintype.h @@ -15,6 +15,7 @@ typedef union any { int a_int; char a_char; schar a_schar; + uchar a_uchar; unsigned int a_uint; long a_long; unsigned long a_ulong; @@ -23,6 +24,8 @@ typedef union any { unsigned long *a_ulptr; unsigned *a_uptr; const char *a_string; + int NDECL((*a_nfunc)); + unsigned long a_mask32; /* used by status highlighting */ /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ @@ -45,6 +48,7 @@ enum any_types { ANY_LPTR, /* pointer to long */ ANY_ULPTR, /* pointer to unsigned long */ ANY_STR, /* pointer to null-terminated char string */ + ANY_NFUNC, /* pointer to function taking no args, returning int */ ANY_MASK32 /* 32-bit mask (stored as unsigned long) */ }; diff --git a/src/cmd.c b/src/cmd.c index 195f492a9..27e05f4d8 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -115,6 +115,7 @@ static int NDECL(dosuspend_core); /**/ static int NDECL((*timed_occ_fn)); STATIC_PTR int NDECL(doherecmdmenu); +STATIC_PTR int NDECL(dotherecmdmenu); STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); @@ -182,9 +183,10 @@ STATIC_DCL void FDECL(attributes_enlightenment, (int, int)); static const char *readchar_queue = ""; static coord clicklook_cc; -STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), const char *)); +STATIC_DCL void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), + const char *)); STATIC_DCL char FDECL(here_cmd_menu, (BOOLEAN_P)); -STATIC_DCL char FDECL(there_cmd_menu, (int, int)); +STATIC_DCL char FDECL(there_cmd_menu, (BOOLEAN_P, int, int)); STATIC_DCL char *NDECL(parse); STATIC_DCL void FDECL(show_direction_keys, (winid, CHAR_P, BOOLEAN_P)); STATIC_DCL boolean FDECL(help_dir, (CHAR_P, int, const char *)); @@ -2903,7 +2905,8 @@ struct ext_func_tab extcmdlist[] = { { ';', "glance", "show what type of thing a map symbol corresponds to", doquickwhatis, IFBURIED | GENERALCMD }, { '?', "help", "give a help message", dohelp, IFBURIED | GENERALCMD }, - { '\0', "herecmdmenu", "show menu of commands you can do here", doherecmdmenu, IFBURIED }, + { '\0', "herecmdmenu", "show menu of commands you can do here", + doherecmdmenu, IFBURIED }, { 'V', "history", "show long version and game history", dohistory, IFBURIED | GENERALCMD }, { 'i', "inventory", "show your inventory", ddoinv, IFBURIED }, @@ -3001,6 +3004,9 @@ struct ext_func_tab extcmdlist[] = { { C('t'), "teleport", "teleport around the level", dotele, IFBURIED }, { '\0', "terrain", "show map without obstructions", doterrain, IFBURIED | AUTOCOMPLETE }, + { '\0', "therecmdmenu", + "show menu of commands you can do from here to adjacent spot", + dotherecmdmenu }, { 't', "throw", "throw something", dothrow }, { '\0', "timeout", "look at timeout queue and hero's timed intrinsics", wiz_timeout_queue, IFBURIED | AUTOCOMPLETE | WIZMODECMD }, @@ -4663,15 +4669,30 @@ register int x, y; return x >= 1 && x <= COLNO - 1 && y >= 0 && y <= ROWNO - 1; } +/* #herecmdmenu command */ STATIC_PTR int doherecmdmenu(VOID_ARGS) { char ch = here_cmd_menu(TRUE); - if (ch) - return 1; + return ch ? 1 : 0; +} - return 0; +/* #therecmdmenu command, a way to test there_cmd_menu without mouse */ +STATIC_PTR int +dotherecmdmenu(VOID_ARGS) +{ + char ch; + + if (!getdir((const char *) 0) || !isok(u.ux + u.dx, u.uy + u.dy)) + return 0; + + if (u.dx || u.dy) + ch = there_cmd_menu(TRUE, u.ux + u.dx, u.uy + u.dy); + else + ch = here_cmd_menu(TRUE); + + return ch ? 1 : 0; } STATIC_OVL void @@ -4684,49 +4705,113 @@ const char *text; anything any; if ((ch = cmd_from_func(func)) != '\0') { - any.a_void = (genericptr_t)func; + any = zeroany; + any.a_nfunc = func; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, text, MENU_UNSELECTED); } } STATIC_OVL char -there_cmd_menu(x, y) +there_cmd_menu(doit, x, y) +boolean doit; int x, y; { winid win; - anything any; char ch; char buf[BUFSZ]; schar typ = levl[x][y].typ; - int npick; + int npick, K = 0; menu_item *picks = (menu_item *) 0; struct trap *ttmp; + struct monst *mtmp; win = create_nhwindow(NHW_MENU); start_menu(win); if (IS_DOOR(typ)) { + boolean key_or_pick, card; int dm = levl[x][y].doormask; - if ((dm & (D_CLOSED|D_LOCKED))) { - add_herecmd_menuitem(win, dokick, "Kick the door"); - add_herecmd_menuitem(win, doopen, "Open the door"); + + if ((dm & (D_CLOSED | D_LOCKED))) { + add_herecmd_menuitem(win, doopen, "Open the door"), ++K; + /* unfortunately there's no lknown flag for doors to + remember the locked/unlocked state */ + key_or_pick = (carrying(SKELETON_KEY) || carrying(LOCK_PICK)); + card = (carrying(CREDIT_CARD) != 0); + if (key_or_pick || card) { + Sprintf(buf, "%sunlock the door", + key_or_pick ? "lock or " : ""); + add_herecmd_menuitem(win, doapply, upstart(buf)), ++K; + } + /* unfortunately there's no tknown flag for doors (or chests) + to remember whether a trap had been found */ + add_herecmd_menuitem(win, dountrap, + "Search the door for a trap"), ++K; + /* [what about #force?] */ + add_herecmd_menuitem(win, dokick, "Kick the door"), ++K; } else if ((dm & D_ISOPEN)) { - add_herecmd_menuitem(win, doclose, "Close the door"); + add_herecmd_menuitem(win, doclose, "Close the door"), ++K; } } if (typ <= SCORR) - add_herecmd_menuitem(win, dosearch, "Search for secret doors"); + add_herecmd_menuitem(win, dosearch, "Search for secret doors"), ++K; - end_menu(win, "What do you want to do?"); - npick = select_menu(win, PICK_ONE, &picks); - destroy_nhwindow(win); - if (npick > 0) { - ch = cmd_from_func(picks->item.a_void); - free((genericptr_t)picks); - return ch; + if ((ttmp = t_at(x, y)) != 0 && ttmp->tseen) { + add_herecmd_menuitem(win, doidtrap, "Examine trap"), ++K; + if (ttmp->ttyp != VIBRATING_SQUARE) + add_herecmd_menuitem(win, dountrap, "Attempt to disarm trap"), ++K; } - return '\0'; + + mtmp = m_at(x, y); + if (mtmp && !canspotmon(mtmp)) + mtmp = 0; + if (mtmp && which_armor(mtmp, W_SADDLE)) { + char *mnam = x_monnam(mtmp, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE); + + if (!u.usteed) { + Sprintf(buf, "Ride %s", mnam); + add_herecmd_menuitem(win, doride, buf), ++K; + } + Sprintf(buf, "Remove saddle from %s", mnam); + add_herecmd_menuitem(win, doloot, buf), ++K; + } + if (mtmp && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE) + && carrying(SADDLE)) { + Sprintf(buf, "Put saddle on %s", mon_nam(mtmp)), ++K; + add_herecmd_menuitem(win, doapply, buf); + } +#if 0 + if (mtmp || glyph_is_invisible(glyph_at(x, y))) { + /* "Attack %s", mtmp ? mon_nam(mtmp) : "unseen creature" */ + } else { + /* "Move %s", direction */ + } +#endif + + if (K) { + end_menu(win, "What do you want to do?"); + npick = select_menu(win, PICK_ONE, &picks); + } else { + pline("No applicable actions."); + npick = 0; + } + destroy_nhwindow(win); + ch = '\0'; + if (npick > 0) { + int NDECL((*func)) = picks->item.a_nfunc; + free((genericptr_t) picks); + + if (doit) { + int ret = (*func)(); + + ch = (char) ret; + } else { + ch = cmd_from_func(func); + } + } + return ch; } STATIC_OVL char @@ -4734,7 +4819,6 @@ here_cmd_menu(doit) boolean doit; { winid win; - anything any; char ch; char buf[BUFSZ]; schar typ = levl[u.ux][u.uy].typ; @@ -4749,37 +4833,47 @@ boolean doit; defsyms[IS_FOUNTAIN(typ) ? S_fountain : S_sink].explanation); add_herecmd_menuitem(win, dodrink, buf); } - if (IS_FOUNTAIN(typ)) add_herecmd_menuitem(win, dodip, "Dip something into the fountain"); - if (IS_THRONE(typ)) add_herecmd_menuitem(win, dosit, "Sit on the throne"); if ((u.ux == xupstair && u.uy == yupstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy - && sstairs.up) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) || (u.ux == xupladder && u.uy == yupladder)) { Sprintf(buf, "Go up the %s", (u.ux == xupladder && u.uy == yupladder) ? "ladder" : "stairs"); add_herecmd_menuitem(win, doup, buf); } - if ((u.ux == xdnstair && u.uy == ydnstair) - || (u.ux == sstairs.sx && u.uy == sstairs.sy - && !sstairs.up) + || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) || (u.ux == xdnladder && u.uy == ydnladder)) { Sprintf(buf, "Go down the %s", (u.ux == xupladder && u.uy == yupladder) ? "ladder" : "stairs"); add_herecmd_menuitem(win, dodown, buf); } + if (u.usteed) { /* another movement choice */ + Sprintf(buf, "Dismount %s", + x_monnam(u.usteed, ARTICLE_THE, (char *) 0, + SUPPRESS_SADDLE, FALSE)); + add_herecmd_menuitem(win, doride, buf); + } + +#if 0 + if (Upolyd) { /* before objects */ + Sprintf(buf, "Use %s special ability", + s_suffix(mons[u.umonnum].mname)); + add_herecmd_menuitem(win, domonability, buf); + } +#endif if (OBJ_AT(u.ux, u.uy)) { struct obj *otmp = level.objects[u.ux][u.uy]; + Sprintf(buf, "Pick up %s", otmp->nexthere ? "items" : doname(otmp)); add_herecmd_menuitem(win, dopickup, buf); @@ -4787,7 +4881,6 @@ boolean doit; Sprintf(buf, "Loot %s", doname(otmp)); add_herecmd_menuitem(win, doloot, buf); } - if (otmp->oclass == FOOD_CLASS) { Sprintf(buf, "Eat %s", doname(otmp)); add_herecmd_menuitem(win, doeat, buf); @@ -4804,20 +4897,20 @@ boolean doit; end_menu(win, "What do you want to do?"); npick = select_menu(win, PICK_ONE, &picks); destroy_nhwindow(win); + ch = '\0'; if (npick > 0) { - if (doit) { - int NDECL((*func)) = picks->item.a_void; - int ret = func(); + int NDECL((*func)) = picks->item.a_nfunc; + free((genericptr_t) picks); - free((genericptr_t)picks); - return (char)ret; + if (doit) { + int ret = (*func)(); + + ch = (char) ret; } else { - ch = cmd_from_func(picks->item.a_void); - free((genericptr_t)picks); - return ch; + ch = cmd_from_func(func); } } - return '\0'; + return ch; } @@ -4899,7 +4992,7 @@ int x, y, mod; cmd[1] = Cmd.dirchars[dir]; cmd[2] = '\0'; if (iflags.herecmd_menu) { - cmd[0] = there_cmd_menu(u.ux + x, u.uy + y); + cmd[0] = there_cmd_menu(FALSE, u.ux + x, u.uy + y); if (cmd[0] == '\0') cmd[1] = '\0'; return cmd; @@ -5271,6 +5364,7 @@ wiz_port_debug() num_menu_selections = SIZE(menu_selections) - 1; if (num_menu_selections > 0) { menu_item *pick_list; + win = create_nhwindow(NHW_MENU); start_menu(win); for (k = 0; k < num_menu_selections; ++k) { From 46217bbda2f34b0610bdbc72a9c908a86d8c4f5f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 11 Oct 2017 09:50:18 +0300 Subject: [PATCH 22/43] Qt4: Put yn queries in message history When using OPTIONS=popup_dialog, or compiling with USE_POPUPS, the yes/no -questions weren't put into the message history. --- win/Qt4/qt4bind.cpp | 72 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index dee38e8c3..2fef131ce 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -497,51 +497,48 @@ int NetHackQtBind::qt_doprev_message() char NetHackQtBind::qt_yn_function(const char *question_, const char *choices, CHAR_P def) { QString question(QString::fromLatin1(question_)); + QString message; + char yn_esc_map='\033'; + + if (choices) { + // anything beyond is hidden> + QString choicebuf = choices; + size_t cb = choicebuf.indexOf('\033'); + choicebuf = choicebuf.mid(0U, cb); + message = QString("%1 [%2] ").arg(question, choicebuf); + if (def) message += QString("(%1) ").arg(QChar(def)); + // escape maps to 'q' or 'n' or default, in that order + yn_esc_map = (index(choices, 'q') ? 'q' : + (index(choices, 'n') ? 'n' : def)); + } else { + message = question; + } if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { // Similar to X11 windowport `slow' feature. - QString message; - char yn_esc_map='\033'; - - if (choices) { - // anything beyond is hidden> - QString choicebuf = choices; - size_t cb = choicebuf.indexOf('\033'); - choicebuf = choicebuf.mid(0U, cb); - message = QString("%1 [%2] ").arg(question, choicebuf); - if (def) message += QString("(%1) ").arg(QChar(def)); - // escape maps to 'q' or 'n' or default, in that order - yn_esc_map = (index(choices, 'q') ? 'q' : - (index(choices, 'n') ? 'n' : def)); - } else { - message = question; - } + int result = -1; #ifdef USE_POPUPS - // Improve some special-cases (DIRKS 08/02/23) - if (strcmp (choices,"ynq") == 0) { - switch (QMessageBox::information (NetHackQtBind::mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2)) - { - case 0: return 'y'; - case 1: return 'n'; - case 2: return 'q'; - } - } + if (choices) { + if (!strcmp(choices,"ynq")) + result = QMessageBox::information (NetHackQtBind::mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2); + else if (!strcmp(choices,"yn")) + result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Yes", "&No",0,1); + else if (!strcmp(choices, "rl")) + result = QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Right", "&Left",0,1); - if (strcmp (choices,"yn") == 0) { - switch (QMessageBox::information(NetHackQtBind::mainWidget(),"NetHack",question,"&Yes", "&No",0,1)) - { - case 0: return 'y'; - case 1: return 'n'; - } - } + if (result >= 0 && result < strlen(choices)) { + char yn_resp = choices[result]; + message += QString(" %1").arg(yn_resp); + result = yn_resp; + } + } #endif NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); - int result=-1; - while (result<0) { + while (result < 0) { char ch=NetHackQtBind::qt_nhgetch(); if (ch=='\033') { result=yn_esc_map; @@ -562,7 +559,12 @@ char NetHackQtBind::qt_yn_function(const char *question_, const char *choices, C return result; } else { NetHackQtYnDialog dialog(mainWidget(),question,choices,def); - return dialog.Exec(); + char ret = dialog.Exec(); + if (!(ret == '\0' || ret == '\033') && choices) + message += QString(" %1").arg(ret); + else if (def) + message += QString(" %1").arg(def); + NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); } } From ffeabfdf3bbd64eaa66c52f883d7842df995d8ec Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 11 Oct 2017 17:29:55 -0700 Subject: [PATCH 23/43] X11 default resources - macro expansion The X11 interface reads file NetHack.ad (after cd'ing to the playground directory, where 'make install' puts a copy) and feeds the contents to X Windows for use as default resources to override the compiled in defaults. When use of #define was introduced into NetHack.ad (back in September, 2016) this was severely hobbled and startup spit out a lot complaints to stderr about invalid resource values. This implements rudimentary macro expansion for '#define name value' within the data stream that's fed to X, getting back decent default values and eliminating the invalid value complaints. --- win/X11/winX.c | 115 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 12 deletions(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index 78e304b1f..c10fd620a 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -136,6 +136,7 @@ struct window_procs X11_procs = { static winid NDECL(find_free_window); static void FDECL(nhFreePixel, (XtAppContext, XrmValuePtr, XtPointer, XrmValuePtr, Cardinal *)); +static boolean FDECL(new_resource_macro, (String, unsigned)); static void NDECL(load_default_resources); static void NDECL(release_default_resources); #ifdef X11_HANGUP_SIGNAL @@ -480,7 +481,43 @@ Widget w; #endif } -static String *default_resource_data = 0; /* NULL-terminated array */ +static String *default_resource_data = 0, /* NULL-terminated arrays */ + *def_rsrc_macr = 0, /* macro names */ + *def_rsrc_valu = 0; /* macro values */ + +/* caller found "#define"; parse into macro name and its expansion value */ +static boolean +new_resource_macro(inbuf, numdefs) +String inbuf; /* points past '#define' rather than to start of buffer */ +unsigned numdefs; /* array slot to fill */ +{ + String p, q; + + /* we expect inbuf to be terminated by newline; get rid of it */ + q = eos(inbuf); + if (q > inbuf && q[-1] == '\n') + q[-1] = '\0'; + + /* figure out macro's name */ + for (p = inbuf; *p == ' ' || *p == '\t'; ++p) + continue; /* skip whitespace */ + for (q = p; *q && *q != ' ' && *q != '\t'; ++q) + continue; /* token consists of non-whitespace */ + Strcat(q, " "); /* guarantee something beyond '#define FOO' */ + *q++ = '\0'; /* p..(q-1) contains macro name */ + if (!*p) /* invalid definition: '#define' followed by nothing */ + return FALSE; + def_rsrc_macr[numdefs] = dupstr(p); + + /* figure out macro's value; empty value is supported but not expected */ + while (*q == ' ' || *q == '\t') + ++q; /* skip whitespace between name and value */ + for (p = eos(q); --p > q && (*p == ' ' || *p == '\t'); ) + continue; /* discard trailing whitespace */ + *++p = '\0'; /* q..p containes macro value */ + def_rsrc_valu[numdefs] = dupstr(q); + return TRUE; +} /* read the template NetHack.ad into default_resource_data[] to supply fallback resources to XtAppInitialize() */ @@ -489,8 +526,8 @@ load_default_resources() { FILE *fp; String inbuf; - unsigned insiz, linelen, longlen, numlines; - boolean comment = FALSE; /* lint suppression */ + unsigned insiz, linelen, longlen, numlines, numdefs, midx; + boolean comment, isdef; /* * Running nethack via the shell script adds $HACKDIR to the path used @@ -499,7 +536,11 @@ load_default_resources() * load its contents into memory so that the application startup call * in X11_init_nhwindows() can use them as fallback resources. * - * No attempt to support the 'include' directive has been made. + * No attempt to support the 'include' directive has been made, nor + * backslash+newline continuation lines. Macro expansion (at most + * one substitution per line) is supported. '#define' to introduce + * a macro must be at start of line (no whitespace before or after + * the '#' character). */ fp = fopen("./NetHack.ad", "r"); if (!fp) @@ -509,35 +550,84 @@ load_default_resources() insiz = BUFSIZ; /* stdio BUFSIZ, not nethack BUFSZ */ inbuf = (String) alloc(insiz); linelen = longlen = 0; - numlines = 0; + numlines = numdefs = 0; + comment = isdef = FALSE; /* lint suppression */ while (fgets(inbuf, insiz, fp)) { - if (!linelen) /* inbuf has start of record; treat empty as comment */ + if (!linelen) { + /* !linelen: inbuf has start of record; treat empty as comment */ comment = (*inbuf == '!' || *inbuf == '\n'); + isdef = !strncmp(inbuf, "#define", 7); + ++numdefs; + } linelen += strlen(inbuf); if (!index(inbuf, '\n')) continue; if (linelen > longlen) longlen = linelen; linelen = 0; - if (!comment) + if (!comment && !isdef) ++numlines; } - free((genericptr_t) inbuf); insiz = longlen + 1; - inbuf = (String) alloc(insiz); + if (numdefs) { /* don't alloc if 0; no need for any terminator */ + def_rsrc_macr = (String *) alloc(numdefs * sizeof (String)); + def_rsrc_valu = (String *) alloc(numdefs * sizeof (String)); + insiz += BUFSIZ; /* include room for macro expansion within buffer */ + } + if (insiz > BUFSIZ) { + free((genericptr_t) inbuf); + inbuf = (String) alloc(insiz); + } ++numlines; /* room for terminator */ default_resource_data = (String *) alloc(numlines * sizeof (String)); - /* now read the file into the array */ + /* now re-read the file, storing its contents into the allocated array + after performing macro substitutions */ (void) rewind(fp); - numlines = 0; + numlines = numdefs = 0; while (fgets(inbuf, insiz, fp)) { - if (*inbuf != '!' && *inbuf != '\n') + if (!strncmp(inbuf, "#define", 7)) { + if (new_resource_macro(&inbuf[7], numdefs)) + ++numdefs; + } else if (*inbuf != '!' && *inbuf != '\n') { + if (numdefs) { + /* + * Macro expansion: we assume at most one substitution + * per line. That's all that our sample NetHack.ad uses. + * + * If we ever need more, this will have to become a lot + * more sophisticated. It will need to find the first + * instance within inbuf[] rather than first macro which + * appears, and to avoid finding names within substituted + * expansion values. + * + * Any substitution which would exceed the buffer size is + * skipped. A sophisticated implementation would need to + * be prepared to allocate a bigger buffer when needed. + */ + linelen = strlen(inbuf); + for (midx = 0; midx < numdefs; ++midx) { + if ((linelen + strlen(def_rsrc_valu[midx]) + < insiz - strlen(def_rsrc_macr[midx])) + && strNsubst(inbuf, def_rsrc_macr[midx], + def_rsrc_valu[midx], 1)) + break; + } + } default_resource_data[numlines++] = dupstr(inbuf); + } } default_resource_data[numlines] = (String) 0; (void) fclose(fp); free((genericptr_t) inbuf); + if (def_rsrc_macr) { /* implies def_rsrc_valu is non-Null too */ + for (midx = 0; midx < numdefs; ++midx) { + free((genericptr_t) def_rsrc_macr[midx]); + free((genericptr_t) def_rsrc_valu[midx]); + } + free((genericptr_t) def_rsrc_macr), def_rsrc_macr = 0; + free((genericptr_t) def_rsrc_valu), def_rsrc_valu = 0; + } } static void @@ -550,6 +640,7 @@ release_default_resources() free((genericptr_t) default_resource_data[idx]); free((genericptr_t) default_resource_data), default_resource_data = 0; } + /* def_rsrc_macr[] and def_rsrc_valu[] have already been released */ } /* Global Functions ======================================================= */ From 55143cd66eceb8acc29355b1fde475ce55be3f6d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 12 Oct 2017 12:33:04 +0300 Subject: [PATCH 24/43] Qt4: Add NetHack version to player selection popup --- win/Qt4/qt4plsel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index 56b8849bd..ea792f8ab 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -6,6 +6,7 @@ extern "C" { #include "hack.h" +#include "date.h" } #undef Invisible #undef Warning @@ -37,7 +38,7 @@ namespace nethack_qt4 { void centerOnMain( QWidget* w ); // end temporary -static const char nh_attribution[] = "
NetHack" +static const char nh_attribution[] = "
NetHack " VERSION_STRING "" "
by the NetHack DevTeam
"; class NhPSListViewItem : public QTableWidgetItem { From b586d58dbbaccbeeb3b90c81a78918e93cf93633 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 12 Oct 2017 12:42:32 +0300 Subject: [PATCH 25/43] Qt4: Gender, not Sex. TOURIST is unconditional. --- win/Qt4/qt4inv.cpp | 5 ----- win/Qt4/qt4plsel.cpp | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/win/Qt4/qt4inv.cpp b/win/Qt4/qt4inv.cpp index 9165d58b3..f753ad097 100644 --- a/win/Qt4/qt4inv.cpp +++ b/win/Qt4/qt4inv.cpp @@ -73,13 +73,8 @@ void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) drawWorn(painter,uarms,0,1); // Shield drawWorn(painter,uarmg,0,2); // Gloves - repeated drawWorn(painter,uarmg,2,2); // Gloves - repeated -#ifdef TOURIST drawWorn(painter,uarmf,1,5); // Shoes (feet) drawWorn(painter,uarmu,1,4); // Undershirt -#else - drawWorn(painter,0 ,1,5,false); - drawWorn(painter,uarmf,1,4); // Shoes (feet) -#endif drawWorn(painter,uleft,0,3); // RingL drawWorn(painter,uright,2,3); // RingR diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index ea792f8ab..99bb15a5b 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -178,7 +178,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : connect(name, SIGNAL(textChanged(const QString&)), this, SLOT(selectName(const QString&)) ); name->setFocus(); - QGroupBox* genderbox = new QGroupBox("Sex",this); + QGroupBox* genderbox = new QGroupBox("Gender",this); QButtonGroup *gendergroup = new QButtonGroup(this); QGroupBox* alignbox = new QGroupBox("Alignment",this); QButtonGroup *aligngroup = new QButtonGroup(this); From 11e50e8ca23da60b919191657e1005b2eb576733 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 12 Oct 2017 13:37:52 +0300 Subject: [PATCH 26/43] Qt4: Add Random button to player selection --- win/Qt4/qt4plsel.cpp | 71 +++++++++++++++++++++++++++++++++----------- win/Qt4/qt4plsel.h | 3 ++ 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index 99bb15a5b..c49b6981f 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -159,8 +159,9 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : | | | | +--------------+ 3 | | | | ...stretch... | | | | - 4 | | | | [ Play ] - 5 | | | | [ Quit ] + 4 | | | | [ Random ] + 5 | | | | [ Play ] + 6 | | | | [ Quit ] +---------+ +---------+ */ @@ -192,23 +193,26 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : #ifdef QT_CHOOSE_RACE_FIRST race = new NhPSListView(this); role = new NhPSListView(this); - l->addWidget( race, 1,0,5,1 ); - l->addWidget( role, 1,1,5,1 ); + l->addWidget( race, 1,0,6,1 ); + l->addWidget( role, 1,1,6,1 ); #else role = new NhPSListView(this); race = new NhPSListView(this); - l->addWidget( role, 1,0,5,1 ); - l->addWidget( race, 1,1,5,1 ); + l->addWidget( role, 1,0,6,1 ); + l->addWidget( race, 1,1,6,1 ); #endif l->addWidget( genderbox, 1, 2 ); l->addWidget( alignbox, 2, 2 ); l->addWidget( logo, 3, 2, Qt::AlignCenter ); - l->setRowStretch( 3, 5 ); + l->setRowStretch( 3, 6 ); int i; int nrole; + chosen_gend = flags.initgend; + chosen_align = flags.initalign; + // XXX QListView unsorted goes in rev. for (nrole=0; roles[nrole].name.m; nrole++) ; @@ -255,15 +259,46 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : } connect( aligngroup, SIGNAL(buttonPressed(int)), this, SLOT(selectAlignment(int)) ); + QPushButton* rnd = new QPushButton("Random",this); + l->addWidget( rnd, 4, 2 ); + rnd->setDefault(false); + connect( rnd, SIGNAL(clicked()), this, SLOT(Randomize()) ); + QPushButton* ok = new QPushButton("Play",this); - l->addWidget( ok, 4, 2 ); + l->addWidget( ok, 5, 2 ); ok->setDefault(true); connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); QPushButton* cancel = new QPushButton("Quit",this); - l->addWidget( cancel, 5, 2 ); + l->addWidget( cancel, 6, 2 ); connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); + Randomize(); +} + +void NetHackQtPlayerSelector::Randomize() +{ + int nrole = role->rowCount(); + int nrace = race->rowCount(); + + boolean picksomething = (flags.initrole == ROLE_NONE + || flags.initrace == ROLE_NONE + || flags.initgend == ROLE_NONE + || flags.initalign == ROLE_NONE); + + if (flags.randomall && picksomething) { + if (flags.initrole == ROLE_NONE) + flags.initrole == ROLE_RANDOM; + if (flags.initrace == ROLE_NONE) + flags.initrace == ROLE_RANDOM; + if (flags.initgend == ROLE_NONE) + flags.initgend == ROLE_RANDOM; + if (flags.initalign == ROLE_NONE) + flags.initalign == ROLE_RANDOM; + } + + rigid_role_checks(); + // Randomize race and role, unless specified in config int ro = flags.initrole; if (ro == ROLE_NONE || ro == ROLE_RANDOM) { @@ -280,7 +315,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : } } - // make sure we have a valid combination, honoring + // make sure we have a valid combination, honoring // the users request if possible. bool choose_race_first; #ifdef QT_CHOOSE_RACE_FIRST @@ -333,12 +368,8 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : role->setCurrentCell(ro, 0); race->setCurrentCell(ra, 0); - - flags.initrace = race->currentRow(); - flags.initrole = role->currentRow(); } - void NetHackQtPlayerSelector::selectName(const QString& n) { str_copy(plname,n.toLatin1().constData(),SIZE(plname)); @@ -379,7 +410,7 @@ void NetHackQtPlayerSelector::selectRole(int crow, int ccol, int prow, int pcol) } #endif - flags.initrole = role->currentRow(); + //flags.initrole = role->currentRow(); setupOthers(); } @@ -417,7 +448,7 @@ void NetHackQtPlayerSelector::selectRace(int crow, int ccol, int prow, int pcol) } #endif - flags.initrace = race->currentRow(); + //flags.initrace = race->currentRow(); setupOthers(); } @@ -461,12 +492,12 @@ void NetHackQtPlayerSelector::setupOthers() void NetHackQtPlayerSelector::selectGender(int i) { - flags.initgend = i; + chosen_gend = i; } void NetHackQtPlayerSelector::selectAlignment(int i) { - flags.initalign = i; + chosen_align = i; } void NetHackQtPlayerSelector::Quit() @@ -494,6 +525,10 @@ bool NetHackQtPlayerSelector::Choose() } if ( exec() ) { + flags.initrace = race->currentRow(); + flags.initrole = role->currentRow(); + flags.initgend = chosen_gend; + flags.initalign = chosen_align; return true; } else { return false; diff --git a/win/Qt4/qt4plsel.h b/win/Qt4/qt4plsel.h index b82341270..de070d147 100644 --- a/win/Qt4/qt4plsel.h +++ b/win/Qt4/qt4plsel.h @@ -21,6 +21,7 @@ public: public slots: void Quit(); void Random(); + void Randomize(); void selectName(const QString& n); void selectRole(int current, int, int previous, int); @@ -38,6 +39,8 @@ private: QRadioButton **gender; QRadioButton **alignment; bool fully_specified_role; + int chosen_gend; + int chosen_align; }; } // namespace nethack_qt4 From b340e783f503fe23b6ff605aa5fd5d2688350257 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 12 Oct 2017 13:43:46 +0300 Subject: [PATCH 27/43] Qt4: Remove extra empty space from player selection --- win/Qt4/qt4plsel.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index c49b6981f..72859c423 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -184,9 +184,7 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QGroupBox* alignbox = new QGroupBox("Alignment",this); QButtonGroup *aligngroup = new QButtonGroup(this); QVBoxLayout* vbgb = new QVBoxLayout(genderbox); - vbgb->addSpacing(fontMetrics().height()*3/4); QVBoxLayout* vbab = new QVBoxLayout(alignbox); - vbab->addSpacing(fontMetrics().height()); QLabel* logo = new QLabel(nh_attribution, this); l->addWidget( namebox, 0,0,1,3 ); From 601bff5159b3b85ce976d2886da52fa330a01e59 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 12 Oct 2017 15:18:26 -0700 Subject: [PATCH 28/43] X11 WC_ flags Add a few windowing capability flags that were omitted for X11. There may be others which ought to be set too; I don't understand a bunch of them. --- win/X11/winX.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index c10fd620a..e04acfefe 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winX.c $NHDT-Date: 1457079197 2016/03/04 08:13:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.41 $ */ +/* NetHack 3.6 winX.c $NHDT-Date: 1507846693 2017/10/12 22:18:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -97,7 +97,11 @@ extern NEARDATA winid WIN_STATUS; /* Interface definition, for windows.c */ struct window_procs X11_procs = { - "X11", WC_COLOR | WC_HILITE_PET | WC_TILED_MAP, 0L, X11_init_nhwindows, + "X11", + (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP + | WC_PERM_INVENT | WC_MOUSE_SUPPORT), + 0L, /* WC2 flag mask */ + X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, X11_clear_nhwindow, X11_display_nhwindow, X11_destroy_nhwindow, X11_curs, From 20d8cb4238e26eeebf76786175e0328ebab1738b Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 12 Oct 2017 15:21:00 -0700 Subject: [PATCH 29/43] options: ascii_map vs tiled_map X11 supports both ascii map and tiled map and is able to switch back and forth during play. 'O' shows both of them as boolean options, but toggling ascii_map did nothing since tiled_map retained whatever value it had at the time. For core options handling, make toggling either ascii_map or tiled_map also set the other one to the opposite value, so ascii on forces tiled off and vice versa. --- src/options.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/options.c b/src/options.c index 56db02537..b281ba695 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1507164574 2017/10/05 00:49:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.311 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1507846854 2017/10/12 22:20:54 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.315 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3720,8 +3720,19 @@ boolean tinitial, tfrom_file; vision_full_recalc = 1; /* delayed recalc */ if (iflags.use_color) need_redraw = TRUE; /* darkroom refresh */ - } else if (boolopt[i].addr == &iflags.wc_tiled_map - || boolopt[i].addr == &flags.showrace + } else if (boolopt[i].addr == &iflags.wc_ascii_map) { + /* toggling ascii_map; set tiled_map to its opposite; + what does it mean to turn off ascii map if tiled map + isn't supported? -- right now, we do nothing */ + iflags.wc_tiled_map = negated; + need_redraw = TRUE; + } else if (boolopt[i].addr == &iflags.wc_tiled_map) { + /* toggling tiled_map; set ascii_map to its opposite; + as with ascii_map, what does it mean to turn off tiled + map if ascii map isn't supported? */ + iflags.wc_ascii_map = negated; + need_redraw = TRUE; + } else if (boolopt[i].addr == &flags.showrace || boolopt[i].addr == &iflags.use_inverse || boolopt[i].addr == &iflags.hilite_pile || boolopt[i].addr == &iflags.hilite_pet) { @@ -5524,7 +5535,8 @@ const char *mapping; ape = (struct autopickup_exception *) alloc(sizeof *ape); ape->regex = regex_init(); if (!regex_compile(text, ape->regex)) { - config_error_add("%s: %s", APE_regex_error, regex_error_desc(ape->regex)); + config_error_add("%s: %s", APE_regex_error, + regex_error_desc(ape->regex)); regex_free(ape->regex); free((genericptr_t) ape); return 0; @@ -6183,13 +6195,11 @@ STATIC_OVL boolean wc_supported(optnam) const char *optnam; { - int k = 0; + int k; - while (wc_options[k].wc_name) { - if (!strcmp(wc_options[k].wc_name, optnam) - && (windowprocs.wincap & wc_options[k].wc_bit)) - return TRUE; - k++; + for (k = 0; wc_options[k].wc_name; ++k) { + if (!strcmp(wc_options[k].wc_name, optnam)) + return (windowprocs.wincap & wc_options[k].wc_bit) ? TRUE : FALSE; } return FALSE; } @@ -6243,13 +6253,12 @@ STATIC_OVL boolean wc2_supported(optnam) const char *optnam; { - int k = 0; + int k; - while (wc2_options[k].wc_name) { - if (!strcmp(wc2_options[k].wc_name, optnam) - && (windowprocs.wincap2 & wc2_options[k].wc_bit)) - return TRUE; - k++; + for (k = 0; wc2_options[k].wc_name; ++k) { + if (!strcmp(wc2_options[k].wc_name, optnam)) + return (windowprocs.wincap2 & wc2_options[k].wc_bit) ? TRUE + : FALSE; } return FALSE; } From 7b156bf704c7174ac22aba6a0454272cfac737bc Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 13 Oct 2017 22:41:33 +0300 Subject: [PATCH 30/43] X11: add new player selection dialog The dialog shows the player's name, race, role, gender, and alignment in a single window, similar to the Qt4 dialog. Also allows randomizing the character selection. Use the dialog by setting OPTIONS=player_selection:dialog --- doc/fixes36.1 | 1 + include/extern.h | 1 + include/winX.h | 7 + sys/unix/unixmain.c | 14 + win/X11/NetHack.ad | 47 ++- win/X11/winX.c | 22 +- win/X11/winmisc.c | 893 +++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 980 insertions(+), 5 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 1a3d60848..c037bade6 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -708,6 +708,7 @@ X11: status display split into three columns to accomodate Stone/Deaf/Lev/&c; resources replaced by status_condition[1-3].* X11: more terminal-like default resources win32gui: save and load map colors from registry +X11: add new character selection dialog, and obey player_selection:dialog NetHack Community Patches (or Variation) Included diff --git a/include/extern.h b/include/extern.h index 31180fd66..fbbd8bd74 100644 --- a/include/extern.h +++ b/include/extern.h @@ -2484,6 +2484,7 @@ E void NDECL(port_help); E void FDECL(sethanguphandler, (void (*)(int))); E boolean NDECL(authorize_wizard_mode); E boolean FDECL(check_user_string, (char *)); +E char *NDECL(get_login_name); #endif /* UNIX */ /* ### unixtty.c ### */ diff --git a/include/winX.h b/include/winX.h index 796121405..6e87aa62b 100644 --- a/include/winX.h +++ b/include/winX.h @@ -242,6 +242,7 @@ E boolean exit_x_event; /* exit condition for event loop */ #define EXIT_ON_EXIT 2 #define EXIT_ON_SENT_EVENT 3 E int click_x, click_y, click_button, updated_inventory; +E boolean plsel_ask_name; typedef struct { Boolean slow; /* issue prompts between map and message wins */ @@ -334,6 +335,12 @@ E void FDECL(algn_key, E void FDECL(ec_delete, (Widget, XEvent *, String *, Cardinal *)); E void FDECL(ec_key, (Widget, XEvent *, String *, Cardinal *)); /* extended command action */ +E void FDECL(plsel_quit, (Widget, XEvent *, String *, + Cardinal *)); /* player selection dialog */ +E void FDECL(plsel_play, (Widget, XEvent *, String *, + Cardinal *)); /* player selection dialog */ +E void FDECL(plsel_randomize, (Widget, XEvent *, String *, + Cardinal *)); /* player selection dialog */ E void NDECL(release_extended_cmds); /* ### winstatus.c ### */ diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 2270ab262..2e8f41330 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -696,4 +696,18 @@ get_unix_pw() return pw; } +char * +get_login_name() +{ + static char buf[BUFSZ]; + struct passwd *pw = get_unix_pw(); + + buf[0] = '\0'; + + if (pw) + (void)strcpy(buf, pw->pw_name); + + return buf; +} + /*unixmain.c*/ diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 3e1eed6e7..25568da7b 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -4,7 +4,8 @@ #define NETHACK_CLR_FG grey #define NETHACK_CLR_BG black #define NETHACK_CLR_QUIT red -#define NETHACK_CLR_RANDOM green +#define NETHACK_CLR_RANDOM yellow +#define NETHACK_CLR_PLAY green #define NETHACK_CLR_HELP green #define NETHACK_BTN_SHAPE roundedRectangle #define NETHACK_BTN_ROUND 20 @@ -119,12 +120,54 @@ NetHack*showGrip: False ! text input prompt window NetHack*response*textSink*background: red +NetHack*textSink*background: red + NetHack*response*foreground: NETHACK_CLR_FG NetHack*response*background: NETHACK_CLR_BG NetHack*response*borderColor: NETHACK_CLR_FG NetHack*response*borderWidth: 1 -! role selection window +! player selection dialog (OPTIONS=player_selection:dialog) +!NetHack*player_selection_dialog.height: 420 +!NetHack*player_selection_dialog.width: 403 + +!NetHack*player_selection_dialog*foreground: black +!NetHack*player_selection_dialog*background: white +NetHack*player_selection_dialog*name_label.borderWidth: 0 +NetHack*player_selection_dialog*race_label.borderWidth: 0 +NetHack*player_selection_dialog*role_label.borderWidth: 0 +NetHack*player_selection_dialog*gender_label.borderWidth: 0 +NetHack*player_selection_dialog*align_label.borderWidth: 0 +NetHack*player_selection_dialog*button_vp.borderWidth: 0 + +NetHack*player_selection_dialog*name_input.borderWidth: 1 +NetHack*player_selection_dialog*name_input.borderColor: NETHACK_CLR_FG + +NetHack*player_selection_dialog*role_vp.borderColor: NETHACK_CLR_FG +NetHack*player_selection_dialog*race_vp.borderColor: NETHACK_CLR_FG +NetHack*player_selection_dialog*gender_vp.borderColor: NETHACK_CLR_FG +NetHack*player_selection_dialog*align_vp.borderColor: NETHACK_CLR_FG + +NetHack*player_selection_dialog*random.foreground: NETHACK_CLR_RANDOM +NetHack*player_selection_dialog*random.borderColor: NETHACK_CLR_RANDOM +NetHack*player_selection_dialog*random.borderWidth: 1 +NetHack*player_selection_dialog*random.shapeStyle: NETHACK_BTN_SHAPE +NetHack*player_selection_dialog*random.cornerRoundPercent: NETHACK_BTN_ROUND + +NetHack*player_selection_dialog*quit.foreground: NETHACK_CLR_QUIT +NetHack*player_selection_dialog*quit.borderColor: NETHACK_CLR_QUIT +NetHack*player_selection_dialog*quit.borderWidth: 1 +NetHack*player_selection_dialog*quit.shapeStyle: NETHACK_BTN_SHAPE +NetHack*player_selection_dialog*quit.cornerRoundPercent: NETHACK_BTN_ROUND + +NetHack*player_selection_dialog*play.foreground: NETHACK_CLR_PLAY +NetHack*player_selection_dialog*play.borderColor: NETHACK_CLR_PLAY +NetHack*player_selection_dialog*play.borderWidth: 1 +NetHack*player_selection_dialog*play.shapeStyle: NETHACK_BTN_SHAPE +NetHack*player_selection_dialog*play.cornerRoundPercent: NETHACK_BTN_ROUND + + +! role selection window (OPTIONS=player_selection:prompts) NetHack*player_selection*random.foreground: NETHACK_CLR_RANDOM NetHack*player_selection*random.background: black NetHack*player_selection*random.borderColor: NETHACK_CLR_RANDOM diff --git a/win/X11/winX.c b/win/X11/winX.c index e04acfefe..8d097a791 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -99,7 +99,7 @@ extern NEARDATA winid WIN_STATUS; struct window_procs X11_procs = { "X11", (WC_COLOR | WC_HILITE_PET | WC_ASCII_MAP | WC_TILED_MAP - | WC_PERM_INVENT | WC_MOUSE_SUPPORT), + | WC_PLAYER_SELECTION | WC_PERM_INVENT | WC_MOUSE_SUPPORT), 0L, /* WC2 flag mask */ X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, @@ -1126,6 +1126,9 @@ static XtActionsRec actions[] = { { nhStr("ec_key"), ec_key }, /* extended commands */ { nhStr("ec_delete"), ec_delete }, /* ext-com menu delete */ { nhStr("ps_key"), ps_key }, /* player selection */ + { nhStr("plsel_quit"), plsel_quit }, /* player selection dialog */ + { nhStr("plsel_play"), plsel_play }, /* player selection dialog */ + { nhStr("plsel_rnd"), plsel_randomize }, /* player selection dialog */ { nhStr("race_key"), race_key }, /* race selection */ { nhStr("gend_key"), gend_key }, /* gender selection */ { nhStr("algn_key"), algn_key }, /* alignment selection */ @@ -1271,6 +1274,7 @@ char **argv; (void) seteuid(savuid); x_inited = TRUE; /* X is now initialized */ + plsel_ask_name = FALSE; release_default_resources(); @@ -1469,6 +1473,20 @@ X11_askname() { Widget popup, dialog; Arg args[1]; + char *defplname = (char *)0; + +#ifdef UNIX + defplname = get_login_name(); +#endif + (void) strncpy(plname, defplname ? defplname : "Mumbles", + sizeof plname - 1); + plname[sizeof plname - 1] = '\0'; + + if (iflags.wc_player_selection == VIA_DIALOG) { + /* X11_player_selection_dialog() handles name query */ + plsel_ask_name = TRUE; + return; + } /* else iflags.wc_player_selection == VIA_PROMPTS */ XtSetArg(args[0], XtNallowShellResize, True); @@ -1481,7 +1499,7 @@ X11_askname() (XtCallbackProc) 0); SetDialogPrompt(dialog, nhStr("What is your name?")); /* set prompt */ - SetDialogResponse(dialog, nhStr(""), PL_NSIZ); /* set default answer */ + SetDialogResponse(dialog, plname, PL_NSIZ); /* set default answer */ XtRealizeWidget(popup); positionpopup(popup, TRUE); /* center,bottom */ diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 7f71b0ca3..5837bc761 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -18,9 +18,12 @@ #include #include #include +#include #include +#include #include #include +#include #include /* for index() */ #include @@ -52,6 +55,17 @@ static int ec_nchars = 0; static char ec_chars[EC_NCHARS]; static Time ec_time; +boolean plsel_ask_name; + +static const char plsel_dialog_translations[] = "#override\n\ + Escape: plsel_quit()\n\ + Return: plsel_play()"; + +static const char plsel_input_accelerators[] = "#override\n\ + Escape: plsel_quit()\n\ + Return: plsel_play()\n\ + Tab: \n"; + static const char extended_command_translations[] = "#override\n\ Left: scroll(4)\n\ Right: scroll(6)\n\ @@ -83,6 +97,23 @@ static Widget FDECL(make_menu, (const char *, const char *, const char *, XtCallbackProc, int, const char **, Widget **, XtCallbackProc, Widget *)); +void NDECL(X11_player_selection_setupOthers); +void NDECL(X11_player_selection_randomize); + +/* Bad Hack alert. Using integers instead of XtPointers */ +XtPointer +i2xtp(i) +int i; +{ + return (XtPointer)(long)i; +} +int +xtp2i(x) +XtPointer x; +{ + return (long)x; +} + /* Player Selection -------------------------------------------------------- */ /* ARGSUSED */ @@ -298,10 +329,860 @@ Cardinal *num_params; exit_x_event = TRUE; } +int plsel_n_races, plsel_n_roles; +Widget *plsel_race_radios = (Widget *) 0; +Widget *plsel_role_radios = (Widget *) 0; +Widget *plsel_gend_radios = (Widget *) 0; +Widget *plsel_align_radios = (Widget *) 0; + +Widget plsel_name_input; + +Widget plsel_btn_play; + +void +plsel_dialog_acceptvalues() +{ + Arg args[2]; + String s; + + flags.initrace = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; + flags.initrole = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + flags.initgend = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0]))-1; + flags.initalign = xtp2i(XawToggleGetCurrent(plsel_align_radios[0]))-1; + + XtSetArg(args[0], nhStr(XtNstring), &s); + XtGetValues(plsel_name_input, args, ONE); + (void) strncpy(plname, (char *) s, sizeof plname - 1); + plname[sizeof plname - 1] = '\0'; +} + +/* ARGSUSED */ +void +plsel_quit(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + ps_selected = PS_QUIT; + exit_x_event = TRUE; /* leave event loop */ +} + +/* ARGSUSED */ +void +plsel_play(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + plsel_dialog_acceptvalues(); + exit_x_event = TRUE; /* leave event loop */ +} + +/* ARGSUSED */ +void +plsel_randomize(w, event, params, num_params) +Widget w; +XEvent *event; +String *params; +Cardinal *num_params; +{ + X11_player_selection_randomize(); +} + +/* enable or disable the Play button */ +void +plsel_set_play_button(state) +boolean state; +{ + Arg args[2]; + + XtSetArg(args[0], nhStr(XtNsensitive), !state); + XtSetValues(plsel_btn_play, args, ONE); +} + +void +plsel_set_sensitivities(setcurr) +boolean setcurr; +{ + Arg args[2]; + int j, valid; + int c = 0; + + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + + plsel_set_play_button(ra < 0 || ro < 0); + + if (ra < 0 || ro < 0) + return; + + valid = -1; + + for (j = 0; roles[j].name.m; j++) { + boolean v = validrace(j, ra); + + if (j == ro) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_role_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validrace(ro, c)) + c = valid; + + if (setcurr) { + int tmpc = c+1; + XawToggleSetCurrent(plsel_role_radios[0], i2xtp(tmpc)); + } + + valid = -1; + + for (j = 0; races[j].noun; j++) { + boolean v = validrace(ro, j); + + if (j == ra) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_race_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validrace(ro, c)) + c = valid; + + if (setcurr) { + int tmpc = c+1; + XawToggleSetCurrent(plsel_race_radios[0], i2xtp(tmpc)); + } + + X11_player_selection_setupOthers(); +} + +void +X11_player_selection_randomize() +{ + int nrole = plsel_n_roles; + int nrace = plsel_n_races; + int ro, ra; + boolean fully_specified_role; + boolean choose_race_first; + int a, g; + XtPointer xtp; + int tmpx; + + boolean picksomething = (flags.initrole == ROLE_NONE + || flags.initrace == ROLE_NONE + || flags.initgend == ROLE_NONE + || flags.initalign == ROLE_NONE); + + if (flags.randomall && picksomething) { + if (flags.initrole == ROLE_NONE) + flags.initrole == ROLE_RANDOM; + if (flags.initrace == ROLE_NONE) + flags.initrace == ROLE_RANDOM; + if (flags.initgend == ROLE_NONE) + flags.initgend == ROLE_RANDOM; + if (flags.initalign == ROLE_NONE) + flags.initalign == ROLE_RANDOM; + } + + rigid_role_checks(); + + /* Randomize race and role, unless specified in config */ + ro = flags.initrole; + if (ro == ROLE_NONE || ro == ROLE_RANDOM) { + ro = rn2(nrole); + if (flags.initrole != ROLE_RANDOM) { + fully_specified_role = FALSE; + } + } + ra = flags.initrace; + if (ra == ROLE_NONE || ra == ROLE_RANDOM) { + ra = rn2(nrace); + if (flags.initrace != ROLE_RANDOM) { + fully_specified_role = FALSE; + } + } + + /* make sure we have a valid combination, honoring + the users request if possible. */ + choose_race_first = FALSE; + if (flags.initrace >= 0 && flags.initrole < 0) { + choose_race_first = TRUE; + } + + while (!validrace(ro,ra)) { + if (choose_race_first) { + ro = rn2(nrole); + if (flags.initrole != ROLE_RANDOM) { + fully_specified_role = FALSE; + } + } else { + ra = rn2(nrace); + if (flags.initrace != ROLE_RANDOM) { + fully_specified_role = FALSE; + } + } + } + + g = flags.initgend; + if (g == ROLE_NONE) { + g = rn2(ROLE_GENDERS); + fully_specified_role = FALSE; + } + while (!validgend(ro,ra,g)) { + g = rn2(ROLE_GENDERS); + } + + a = flags.initalign; + if (a == ROLE_NONE) { + a = rn2(ROLE_ALIGNS); + fully_specified_role = FALSE; + } + while (!validalign(ro,ra,a)) { + a = rn2(ROLE_ALIGNS); + } + + tmpx = g+1; XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(tmpx)); + tmpx = a+1; XawToggleSetCurrent(plsel_align_radios[0], i2xtp(tmpx)); + tmpx = ra+1; XawToggleSetCurrent(plsel_race_radios[0], i2xtp(tmpx)); + tmpx = ro+1; XawToggleSetCurrent(plsel_role_radios[0], i2xtp(tmpx)); + plsel_set_sensitivities(FALSE); +} + +void +X11_player_selection_setupOthers() +{ + Arg args[2]; + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + + int valid = -1; + int c = 0; + int j; + int k; + + int gchecked = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0]))-1; + int achecked = xtp2i(XawToggleGetCurrent(plsel_align_radios[0]))-1; + + if (ro < 0 || ra < 0) + return; + + for (j = 0; j < ROLE_GENDERS; j++) { + boolean v = validgend(ro, ra, j); + if (j == gchecked) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_gend_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validgend(ro, ra, c)) + c = valid; + + k = c+1; + XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(k)); + + valid = -1; + + for (j = 0; j < ROLE_ALIGNS; j++) { + boolean v = validalign(ro, ra, j); + if (j == achecked) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_align_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validalign(ro, ra, c)) + c = valid; + + k = c+1; + XawToggleSetCurrent(plsel_align_radios[0], i2xtp(k)); +} + +static void +racetoggleCallback(w, client, call) +Widget w; +caddr_t client, call; +{ + Arg args[2]; + int i, j, valid; + int c = 0; + + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + + plsel_set_play_button(ra < 0 || ro < 0); + + if (ra < 0 || ro < 0) + return; + + valid = -1; + + for (j = 0; roles[j].name.m; j++) { + boolean v = validrace(j, ra); + if (j == ro) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_role_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validrace(c, ra)) + c = valid; + + j = c+1; + XawToggleSetCurrent(plsel_role_radios[0], i2xtp(j)); + + X11_player_selection_setupOthers(); +} + +static void +roletoggleCallback(w, client, call) +Widget w; +caddr_t client, call; +{ + Arg args[2]; + + int i, j, valid; + int c = 0; + + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + + plsel_set_play_button(ra < 0 || ro < 0); + + if (ra < 0 || ro < 0) + return; + + valid = -1; + + for (j = 0; races[j].noun; j++) { + boolean v = validrace(ro, j); + if (j == ra) + c = j; + XtSetArg(args[0], nhStr(XtNsensitive), v); + XtSetValues(plsel_race_radios[j], args, ONE); + if (valid < 0 && v) + valid = j; + } + if (!validrace(ro, c)) + c = valid; + + j = c+1; + XawToggleSetCurrent(plsel_race_radios[0], i2xtp(j)); + + X11_player_selection_setupOthers(); +} + +static void +gendertoggleCallback(w, client, call) +Widget w; +caddr_t client, call; +{ + int r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; + + plsel_set_play_button(r < 0); +} + +static void +aligntoggleCallback(w, client, call) +Widget w; +caddr_t client, call; +{ + int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1; + + plsel_set_play_button(r < 0); +} + +static void +plsel_random_btn_callback(w, client, call) +Widget w; +XtPointer client; +XtPointer call; +{ + X11_player_selection_randomize(); +} + +static void +plsel_play_btn_callback(w, client, call) +Widget w; +XtPointer client; +XtPointer call; +{ + plsel_dialog_acceptvalues(); + exit_x_event = TRUE; /* leave event loop */ +} + +static void +plsel_quit_btn_callback(w, client, call) +Widget w; +XtPointer client; +XtPointer call; +{ + ps_selected = PS_QUIT; + exit_x_event = TRUE; /* leave event loop */ +} + +Widget +X11_create_player_selection_name(form) +Widget form; +{ + Widget namelabel, name_vp, name_form; + Arg args[10]; + Cardinal num_args; + + /* name viewport */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, False); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + name_vp = XtCreateManagedWidget("name_vp", viewportWidgetClass, form, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + name_form = XtCreateManagedWidget("name_form", formWidgetClass, name_vp, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Name"); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + + namelabel = XtCreateManagedWidget("name_label", + labelWidgetClass, name_form, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), namelabel); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; + XtSetArg(args[num_args], nhStr(XtNeditType), !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++; + XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++; + XtSetArg(args[num_args], nhStr(XtNstring), plname); num_args++; + XtSetArg(args[num_args], XtNinsertPosition, strlen(plname)); num_args++; + XtSetArg(args[num_args], nhStr(XtNaccelerators), + XtParseAcceleratorTable(plsel_input_accelerators)); num_args++; + plsel_name_input = XtCreateManagedWidget("name_input", + asciiTextWidgetClass, name_form, + args, num_args); + + if (plsel_ask_name) { + XtInstallAccelerators(plsel_name_input, plsel_name_input); + XtSetKeyboardFocus(form, plsel_name_input); + } else { + XtSetArg(args[0], XtNdisplayCaret, False); + XtSetValues(plsel_name_input, args, ONE); + } + + return name_vp; +} + +void +X11_player_selection_dialog() +{ + Widget popup, popup_vp; + Widget form; + Widget name_vp; + Widget racelabel, race_form, race_vp, race_form2; + Widget rolelabel, role_form, role_vp, role_form2; + Widget gendlabel, gend_form, gend_radio_m, gend_radio_f, gend_vp, gend_form2; + Widget alignlabel, align_form, align_radio_l, align_radio_n, align_radio_c, align_vp, align_form2; + Widget btn_vp, btn_form, random_btn, play_btn, quit_btn; + Widget gamelabel; + Widget tmpwidget; + boolean use_tmpwidget = FALSE; + Arg args[10]; + Cardinal num_args; + Dimension tmpdim; + int i; + int winwid = 400; + int cwid = (winwid / 3) - 14; + + num_args = 0; + XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; + XtSetArg(args[num_args], XtNtitle, "Player Selection"); num_args++; + popup = XtCreatePopupShell("player_selection_dialog", + transientShellWidgetClass, + toplevel, args, num_args); + + + num_args = 0; + XtSetArg(args[num_args], XtNtranslations, + XtParseTranslationTable(plsel_dialog_translations)); num_args++; + popup_vp = XtCreateManagedWidget("plsel_vp", viewportWidgetClass, + popup, args, num_args); + + num_args = 0; + XtSetArg(args[num_args], XtNtranslations, + XtParseTranslationTable(plsel_dialog_translations)); num_args++; + form = XtCreateManagedWidget("plsel_form", formWidgetClass, popup_vp, + args, num_args); + + + name_vp = X11_create_player_selection_name(form); + + num_args = 0; + XtSetArg(args[num_args], XtNwidth, winwid); num_args++; + XtSetValues(name_vp, args, num_args); + + + /********************************************/ + + /* Race */ + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++; + race_form = XtCreateManagedWidget("race_form", formWidgetClass, form, + args, num_args); + + /* race label */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Race"); num_args++; + racelabel = XtCreateManagedWidget("race_label", + labelWidgetClass, race_form, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), racelabel); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, True); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + race_vp = XtCreateManagedWidget("race_vp", viewportWidgetClass, race_form, + args, num_args); + + num_args = 0; + race_form2 = XtCreateManagedWidget("race_form2", formWidgetClass, race_vp, + args, num_args); + + + for (i = 0; races[i].noun; i++) ; + plsel_n_races = i; + + plsel_race_radios = (Widget *)alloc(sizeof(Widget) * plsel_n_races); + + /* race radio buttons */ + for (i = 0; races[i].noun; i++) { + Widget racewidget; + + num_args = 0; + if (i > 0) + XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + if (i > 0) + XtSetArg(args[num_args], XtNradioGroup, plsel_race_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, (i+1)); num_args++; + + racewidget = XtCreateManagedWidget(races[i].noun, + toggleWidgetClass, + race_form2, + args, num_args); + XtAddCallback(racewidget, XtNcallback, racetoggleCallback, i2xtp(i)); + tmpwidget = racewidget; + plsel_race_radios[i] = racewidget; + } + + XawToggleUnsetCurrent(plsel_race_radios[0]); + + /********************************************/ + + /* Role */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), race_form); num_args++; + role_form = XtCreateManagedWidget("role_form", formWidgetClass, form, + args, num_args); + + + /* role label */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Role"); num_args++; + rolelabel = XtCreateManagedWidget("role_label", + labelWidgetClass, role_form, + args, num_args); + + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), rolelabel); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, True); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + role_vp = XtCreateManagedWidget("role_vp", viewportWidgetClass, role_form, + args, num_args); + + num_args = 0; + role_form2 = XtCreateManagedWidget("role_form2", formWidgetClass, role_vp, + args, num_args); + + + + for (i = 0; roles[i].name.m; i++) ; + plsel_n_roles = i; + + plsel_role_radios = (Widget *)alloc(sizeof(Widget) * plsel_n_roles); + + /* role radio buttons */ + for (i = 0; roles[i].name.m; i++) { + Widget rolewidget; + + num_args = 0; + if (i > 0) + XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++; + if (i > 0) + XtSetArg(args[num_args], XtNradioGroup, plsel_role_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, (i+1)); num_args++; + + rolewidget = XtCreateManagedWidget(roles[i].name.m, + toggleWidgetClass, + role_form2, + args, num_args); + XtAddCallback(rolewidget, XtNcallback, roletoggleCallback, i2xtp(i)); + tmpwidget = rolewidget; + plsel_role_radios[i] = rolewidget; + } + XawToggleUnsetCurrent(plsel_role_radios[0]); + + /********************************************/ + + /* Gender*/ + + plsel_gend_radios = (Widget *)alloc(sizeof(Widget) * ROLE_GENDERS); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++; + gend_form = XtCreateManagedWidget("gender_form", formWidgetClass, form, + args, num_args); + + /* gender label */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Gender"); num_args++; + gendlabel = XtCreateManagedWidget("gender_label", + labelWidgetClass, gend_form, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), gendlabel); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, True); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + gend_vp = XtCreateManagedWidget("gender_vp", viewportWidgetClass, gend_form, + args, num_args); + + num_args = 0; + gend_form2 = XtCreateManagedWidget("gender_form2", formWidgetClass, gend_vp, + args, num_args); + + /* gender radio buttons */ + num_args = 0; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], XtNradioData, 1); num_args++; + plsel_gend_radios[0] = gend_radio_m = XtCreateManagedWidget("Male", + toggleWidgetClass, + gend_form2, + args, num_args); + num_args = 0; + XtSetArg(args[num_args], XtNfromVert, gend_radio_m); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], XtNradioGroup, plsel_gend_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, 2); num_args++; + plsel_gend_radios[1] = gend_radio_f = XtCreateManagedWidget("Female", + toggleWidgetClass, + gend_form2, + args, num_args); + + XawToggleUnsetCurrent(plsel_gend_radios[0]); + + XtAddCallback(gend_radio_m, XtNcallback, gendertoggleCallback, (caddr_t) (1)); + XtAddCallback(gend_radio_f, XtNcallback, gendertoggleCallback, (caddr_t) (2)); + + /********************************************/ + + /* Alignment */ + + plsel_align_radios = (Widget *)alloc(sizeof(Widget) * ROLE_ALIGNS); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), gend_form); num_args++; + XtSetArg(args[num_args], XtNvertDistance, 30); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++; + align_form = XtCreateManagedWidget("align_form", formWidgetClass, form, + args, num_args); + + /* align label */ + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNjustify), XtJustifyLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Alignment"); num_args++; + alignlabel = XtCreateManagedWidget("align_label", + labelWidgetClass, align_form, + args, num_args); + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), alignlabel); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, True); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + align_vp = XtCreateManagedWidget("align_vp", viewportWidgetClass, align_form, + args, num_args); + + num_args = 0; + align_form2 = XtCreateManagedWidget("align_form2", formWidgetClass, align_vp, + args, num_args); + + + num_args = 0; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], XtNradioData, 1); num_args++; + plsel_align_radios[0] = align_radio_l = XtCreateManagedWidget("Lawful", + toggleWidgetClass, + align_form2, + args, num_args); + num_args = 0; + XtSetArg(args[num_args], XtNfromVert, align_radio_l); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], XtNradioGroup, plsel_align_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, 2); num_args++; + plsel_align_radios[1] = align_radio_n = XtCreateManagedWidget("Neutral", + toggleWidgetClass, + align_form2, + args, num_args); + num_args = 0; + XtSetArg(args[num_args], XtNfromVert, align_radio_n); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], XtNradioGroup, plsel_align_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, 3); num_args++; + plsel_align_radios[2] = align_radio_c = XtCreateManagedWidget("Chaotic", + toggleWidgetClass, + align_form2, + args, num_args); + + XawToggleUnsetCurrent(plsel_align_radios[0]); + + XtAddCallback(align_radio_l, XtNcallback, aligntoggleCallback, (caddr_t) (1)); + XtAddCallback(align_radio_n, XtNcallback, aligntoggleCallback, (caddr_t) (2)); + XtAddCallback(align_radio_c, XtNcallback, aligntoggleCallback, (caddr_t) (3)); + + /********************************************/ + + /* Buttons! */ + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), align_form); num_args++; + XtSetArg(args[num_args], XtNvertDistance, 30); num_args++; + XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++; + XtSetArg(args[num_args], XtNforceBars, False); num_args++; + XtSetArg(args[num_args], XtNallowVert, False); num_args++; + XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; + btn_vp = XtCreateManagedWidget("btn_vp", viewportWidgetClass, form, + args, num_args); + + num_args = 0; + btn_form = XtCreateManagedWidget("btn_form", formWidgetClass, btn_vp, + args, num_args); + + /* "Random" button */ + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNtop), XtChainTop); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Random"); num_args++; + random_btn = XtCreateManagedWidget("random", commandWidgetClass, btn_form, + args, num_args); + XtAddCallback(random_btn, XtNcallback, plsel_random_btn_callback, form); + + /* "Play" button */ + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), random_btn); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Play"); num_args++; + plsel_btn_play = play_btn = XtCreateManagedWidget("play", commandWidgetClass, btn_form, + args, num_args); + XtAddCallback(play_btn, XtNcallback, plsel_play_btn_callback, form); + + /* "Quit" button */ + + num_args = 0; + XtSetArg(args[num_args], nhStr(XtNfromVert), play_btn); num_args++; + XtSetArg(args[num_args], nhStr(XtNbottom), XtChainBottom); num_args++; + XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; + XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; + XtSetArg(args[num_args], XtNwidth, cwid); num_args++; + XtSetArg(args[num_args], nhStr(XtNlabel), "Quit"); num_args++; + quit_btn = XtCreateManagedWidget("quit", commandWidgetClass, btn_form, + args, num_args); + XtAddCallback(quit_btn, XtNcallback, plsel_quit_btn_callback, form); + + /********************************************/ + + XtRealizeWidget(popup); + X11_player_selection_randomize(); + + ps_selected = -1; + + positionpopup(popup, TRUE); /* center,bottom */ + nh_XtPopup(popup, (int) XtGrabExclusive, form); + + /* The callback will enable the event loop exit. */ + (void) x_event(EXIT_ON_EXIT); + + nh_XtPopdown(popup); + XtDestroyWidget(popup); + + if (plsel_race_radios) + free(plsel_race_radios); + + if (plsel_role_radios) + free(plsel_role_radios); + + if (plsel_gend_radios) + free(plsel_gend_radios); + + if (plsel_align_radios) + free(plsel_align_radios); + + if (ps_selected == PS_QUIT || program_state.done_hup) { + clearlocks(); + X11_exit_nhwindows((char *) 0); + nh_terminate(0); + } +} + /* Global functions ========================================================= */ void -X11_player_selection() +X11_player_selection_prompts() { int num_roles, num_races, num_gends, num_algns, i, availcount, availindex; Widget popup, player_form; @@ -586,6 +1467,16 @@ X11_player_selection() } } +void +X11_player_selection() +{ + if (iflags.wc_player_selection == VIA_DIALOG) { + X11_player_selection_dialog(); + } else { /* iflags.wc_player_selection == VIA_PROMPTS */ + X11_player_selection_prompts(); + } +} + int X11_get_ext_cmd() { From 9ec7e961d3d98faf66717dba122097598112c0a9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 13 Oct 2017 23:34:44 +0300 Subject: [PATCH 31/43] Fix copypaste error in Qt4 and X11 plsel dialogs --- win/Qt4/qt4plsel.cpp | 8 ++++---- win/X11/winmisc.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index 72859c423..7ff47aaa9 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -286,13 +286,13 @@ void NetHackQtPlayerSelector::Randomize() if (flags.randomall && picksomething) { if (flags.initrole == ROLE_NONE) - flags.initrole == ROLE_RANDOM; + flags.initrole = ROLE_RANDOM; if (flags.initrace == ROLE_NONE) - flags.initrace == ROLE_RANDOM; + flags.initrace = ROLE_RANDOM; if (flags.initgend == ROLE_NONE) - flags.initgend == ROLE_RANDOM; + flags.initgend = ROLE_RANDOM; if (flags.initalign == ROLE_NONE) - flags.initalign == ROLE_RANDOM; + flags.initalign = ROLE_RANDOM; } rigid_role_checks(); diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 5837bc761..f7f8feddd 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -480,13 +480,13 @@ X11_player_selection_randomize() if (flags.randomall && picksomething) { if (flags.initrole == ROLE_NONE) - flags.initrole == ROLE_RANDOM; + flags.initrole = ROLE_RANDOM; if (flags.initrace == ROLE_NONE) - flags.initrace == ROLE_RANDOM; + flags.initrace = ROLE_RANDOM; if (flags.initgend == ROLE_NONE) - flags.initgend == ROLE_RANDOM; + flags.initgend = ROLE_RANDOM; if (flags.initalign == ROLE_NONE) - flags.initalign == ROLE_RANDOM; + flags.initalign = ROLE_RANDOM; } rigid_role_checks(); From 1d8aea1ca3d265ad1e70337943b45cbb1b1563e5 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 01:33:56 +0300 Subject: [PATCH 32/43] Qt4: Don't use version string directly --- win/Qt4/qt4plsel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win/Qt4/qt4plsel.cpp b/win/Qt4/qt4plsel.cpp index 7ff47aaa9..81bf5f023 100644 --- a/win/Qt4/qt4plsel.cpp +++ b/win/Qt4/qt4plsel.cpp @@ -6,7 +6,6 @@ extern "C" { #include "hack.h" -#include "date.h" } #undef Invisible #undef Warning @@ -38,7 +37,7 @@ namespace nethack_qt4 { void centerOnMain( QWidget* w ); // end temporary -static const char nh_attribution[] = "
NetHack " VERSION_STRING "" +static const char nh_attribution[] = "
NetHack %1" "
by the NetHack DevTeam
"; class NhPSListViewItem : public QTableWidgetItem { @@ -185,7 +184,8 @@ NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QButtonGroup *aligngroup = new QButtonGroup(this); QVBoxLayout* vbgb = new QVBoxLayout(genderbox); QVBoxLayout* vbab = new QVBoxLayout(alignbox); - QLabel* logo = new QLabel(nh_attribution, this); + char versionbuf[QBUFSZ]; + QLabel* logo = new QLabel(QString(nh_attribution).arg(version_string(versionbuf)), this); l->addWidget( namebox, 0,0,1,3 ); #ifdef QT_CHOOSE_RACE_FIRST From 7f019d8115fe55d81a4ab16e05562127729a144d Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 13 Oct 2017 16:35:39 -0700 Subject: [PATCH 33/43] suppress 'unused arg' warning for !DUMPLOG --- src/end.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/end.c b/src/end.c index 31914dbb5..d0fb09bc5 100644 --- a/src/end.c +++ b/src/end.c @@ -763,6 +763,7 @@ time_t when; /* date+time at end of game */ dump_redirect(FALSE); #else nhUse(how); + nhUse(when); #endif } From 842c66750a850bb8a0e14d63fe55fdcee61e85c2 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 13 Oct 2017 17:56:25 -0700 Subject: [PATCH 34/43] X11 player selection compile warnings This eliminates nearly 40 warnings, most by suppressing complaints of used function arguments but a few for unused local variables. There's also some reformatting thrown in.... There are still 18 warnings about uses of XtSetArg(), about assigning const to non-const. --- win/X11/winmisc.c | 168 +++++++++++++++++++++++++++++----------------- 1 file changed, 105 insertions(+), 63 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index f7f8feddd..5ee440f5a 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -364,6 +364,11 @@ XEvent *event; String *params; Cardinal *num_params; { + nhUse(w); + nhUse(event); + nhUse(params); + nhUse(num_params); + ps_selected = PS_QUIT; exit_x_event = TRUE; /* leave event loop */ } @@ -376,6 +381,11 @@ XEvent *event; String *params; Cardinal *num_params; { + nhUse(w); + nhUse(event); + nhUse(params); + nhUse(num_params); + plsel_dialog_acceptvalues(); exit_x_event = TRUE; /* leave event loop */ } @@ -388,6 +398,11 @@ XEvent *event; String *params; Cardinal *num_params; { + nhUse(w); + nhUse(event); + nhUse(params); + nhUse(num_params); + X11_player_selection_randomize(); } @@ -470,7 +485,6 @@ X11_player_selection_randomize() boolean fully_specified_role; boolean choose_race_first; int a, g; - XtPointer xtp; int tmpx; boolean picksomething = (flags.initrole == ROLE_NONE @@ -610,12 +624,16 @@ Widget w; caddr_t client, call; { Arg args[2]; - int i, j, valid; + int j, valid; int c = 0; int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + nhUse(w); + nhUse(client); + nhUse(call); + plsel_set_play_button(ra < 0 || ro < 0); if (ra < 0 || ro < 0) @@ -648,12 +666,16 @@ caddr_t client, call; { Arg args[2]; - int i, j, valid; + int j, valid; int c = 0; int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0]))-1; int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0]))-1; + nhUse(w); + nhUse(client); + nhUse(call); + plsel_set_play_button(ra < 0 || ro < 0); if (ra < 0 || ro < 0) @@ -673,7 +695,7 @@ caddr_t client, call; if (!validrace(ro, c)) c = valid; - j = c+1; + j = c + 1; XawToggleSetCurrent(plsel_race_radios[0], i2xtp(j)); X11_player_selection_setupOthers(); @@ -686,6 +708,10 @@ caddr_t client, call; { int r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; + nhUse(w); + nhUse(client); + nhUse(call); + plsel_set_play_button(r < 0); } @@ -696,6 +722,10 @@ caddr_t client, call; { int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1; + nhUse(w); + nhUse(client); + nhUse(call); + plsel_set_play_button(r < 0); } @@ -705,6 +735,10 @@ Widget w; XtPointer client; XtPointer call; { + nhUse(w); + nhUse(client); + nhUse(call); + X11_player_selection_randomize(); } @@ -714,6 +748,10 @@ Widget w; XtPointer client; XtPointer call; { + nhUse(w); + nhUse(client); + nhUse(call); + plsel_dialog_acceptvalues(); exit_x_event = TRUE; /* leave event loop */ } @@ -724,6 +762,10 @@ Widget w; XtPointer client; XtPointer call; { + nhUse(w); + nhUse(client); + nhUse(call); + ps_selected = PS_QUIT; exit_x_event = TRUE; /* leave event loop */ } @@ -769,15 +811,16 @@ Widget form; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; XtSetArg(args[num_args], nhStr(XtNresizable), True); num_args++; - XtSetArg(args[num_args], nhStr(XtNeditType), !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++; + XtSetArg(args[num_args], nhStr(XtNeditType), + !plsel_ask_name ? XawtextRead : XawtextEdit); num_args++; XtSetArg(args[num_args], nhStr(XtNresize), XawtextResizeWidth); num_args++; XtSetArg(args[num_args], nhStr(XtNstring), plname); num_args++; XtSetArg(args[num_args], XtNinsertPosition, strlen(plname)); num_args++; XtSetArg(args[num_args], nhStr(XtNaccelerators), XtParseAcceleratorTable(plsel_input_accelerators)); num_args++; plsel_name_input = XtCreateManagedWidget("name_input", - asciiTextWidgetClass, name_form, - args, num_args); + asciiTextWidgetClass, name_form, + args, num_args); if (plsel_ask_name) { XtInstallAccelerators(plsel_name_input, plsel_name_input); @@ -798,15 +841,14 @@ X11_player_selection_dialog() Widget name_vp; Widget racelabel, race_form, race_vp, race_form2; Widget rolelabel, role_form, role_vp, role_form2; - Widget gendlabel, gend_form, gend_radio_m, gend_radio_f, gend_vp, gend_form2; - Widget alignlabel, align_form, align_radio_l, align_radio_n, align_radio_c, align_vp, align_form2; + Widget gendlabel, gend_form, + gend_radio_m, gend_radio_f, gend_vp, gend_form2; + Widget alignlabel, align_form, + align_radio_l, align_radio_n, align_radio_c, align_vp, align_form2; Widget btn_vp, btn_form, random_btn, play_btn, quit_btn; - Widget gamelabel; Widget tmpwidget; - boolean use_tmpwidget = FALSE; Arg args[10]; Cardinal num_args; - Dimension tmpdim; int i; int winwid = 400; int cwid = (winwid / 3) - 14; @@ -818,7 +860,6 @@ X11_player_selection_dialog() transientShellWidgetClass, toplevel, args, num_args); - num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(plsel_dialog_translations)); num_args++; @@ -831,7 +872,6 @@ X11_player_selection_dialog() form = XtCreateManagedWidget("plsel_form", formWidgetClass, popup_vp, args, num_args); - name_vp = X11_create_player_selection_name(form); num_args = 0; @@ -869,11 +909,11 @@ X11_player_selection_dialog() race_form2 = XtCreateManagedWidget("race_form2", formWidgetClass, race_vp, args, num_args); - - for (i = 0; races[i].noun; i++) ; + for (i = 0; races[i].noun; i++) + continue; plsel_n_races = i; - plsel_race_radios = (Widget *)alloc(sizeof(Widget) * plsel_n_races); + plsel_race_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_races); /* race radio buttons */ for (i = 0; races[i].noun; i++) { @@ -881,11 +921,13 @@ X11_player_selection_dialog() num_args = 0; if (i > 0) - XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), + tmpwidget); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; if (i > 0) - XtSetArg(args[num_args], XtNradioGroup, plsel_race_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, (i+1)); num_args++; + XtSetArg(args[num_args], XtNradioGroup, + plsel_race_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, (i + 1)); num_args++; racewidget = XtCreateManagedWidget(races[i].noun, toggleWidgetClass, @@ -907,7 +949,6 @@ X11_player_selection_dialog() role_form = XtCreateManagedWidget("role_form", formWidgetClass, form, args, num_args); - /* role label */ num_args = 0; XtSetArg(args[num_args], nhStr(XtNleft), XtChainLeft); num_args++; @@ -918,7 +959,6 @@ X11_player_selection_dialog() labelWidgetClass, role_form, args, num_args); - num_args = 0; XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; XtSetArg(args[num_args], nhStr(XtNfromVert), rolelabel); num_args++; @@ -932,9 +972,8 @@ X11_player_selection_dialog() role_form2 = XtCreateManagedWidget("role_form2", formWidgetClass, role_vp, args, num_args); - - - for (i = 0; roles[i].name.m; i++) ; + for (i = 0; roles[i].name.m; i++) + continue; plsel_n_roles = i; plsel_role_radios = (Widget *)alloc(sizeof(Widget) * plsel_n_roles); @@ -945,11 +984,13 @@ X11_player_selection_dialog() num_args = 0; if (i > 0) - XtSetArg(args[num_args], nhStr(XtNfromVert), tmpwidget); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), + tmpwidget); num_args++; XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++; if (i > 0) - XtSetArg(args[num_args], XtNradioGroup, plsel_role_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, (i+1)); num_args++; + XtSetArg(args[num_args], XtNradioGroup, + plsel_role_radios[0]); num_args++; + XtSetArg(args[num_args], XtNradioData, (i + 1)); num_args++; rolewidget = XtCreateManagedWidget(roles[i].name.m, toggleWidgetClass, @@ -989,35 +1030,35 @@ X11_player_selection_dialog() XtSetArg(args[num_args], XtNforceBars, False); num_args++; XtSetArg(args[num_args], XtNallowVert, True); num_args++; XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; - gend_vp = XtCreateManagedWidget("gender_vp", viewportWidgetClass, gend_form, - args, num_args); + gend_vp = XtCreateManagedWidget("gender_vp", viewportWidgetClass, + gend_form, args, num_args); num_args = 0; - gend_form2 = XtCreateManagedWidget("gender_form2", formWidgetClass, gend_vp, - args, num_args); + gend_form2 = XtCreateManagedWidget("gender_form2", formWidgetClass, + gend_vp, args, num_args); /* gender radio buttons */ num_args = 0; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], XtNradioData, 1); num_args++; - plsel_gend_radios[0] = gend_radio_m = XtCreateManagedWidget("Male", - toggleWidgetClass, - gend_form2, - args, num_args); + plsel_gend_radios[0] = gend_radio_m + = XtCreateManagedWidget("Male", toggleWidgetClass, + gend_form2, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNfromVert, gend_radio_m); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], XtNradioGroup, plsel_gend_radios[0]); num_args++; XtSetArg(args[num_args], XtNradioData, 2); num_args++; - plsel_gend_radios[1] = gend_radio_f = XtCreateManagedWidget("Female", - toggleWidgetClass, - gend_form2, - args, num_args); + plsel_gend_radios[1] = gend_radio_f + = XtCreateManagedWidget("Female", toggleWidgetClass, + gend_form2, args, num_args); XawToggleUnsetCurrent(plsel_gend_radios[0]); - XtAddCallback(gend_radio_m, XtNcallback, gendertoggleCallback, (caddr_t) (1)); - XtAddCallback(gend_radio_f, XtNcallback, gendertoggleCallback, (caddr_t) (2)); + XtAddCallback(gend_radio_m, XtNcallback, + gendertoggleCallback, (caddr_t) (1)); + XtAddCallback(gend_radio_f, XtNcallback, + gendertoggleCallback, (caddr_t) (2)); /********************************************/ @@ -1048,30 +1089,27 @@ X11_player_selection_dialog() XtSetArg(args[num_args], XtNforceBars, False); num_args++; XtSetArg(args[num_args], XtNallowVert, True); num_args++; XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; - align_vp = XtCreateManagedWidget("align_vp", viewportWidgetClass, align_form, - args, num_args); + align_vp = XtCreateManagedWidget("align_vp", viewportWidgetClass, + align_form, args, num_args); num_args = 0; - align_form2 = XtCreateManagedWidget("align_form2", formWidgetClass, align_vp, - args, num_args); - + align_form2 = XtCreateManagedWidget("align_form2", formWidgetClass, + align_vp, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], XtNradioData, 1); num_args++; - plsel_align_radios[0] = align_radio_l = XtCreateManagedWidget("Lawful", - toggleWidgetClass, - align_form2, - args, num_args); + plsel_align_radios[0] = align_radio_l + = XtCreateManagedWidget("Lawful", toggleWidgetClass, + align_form2, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNfromVert, align_radio_l); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], XtNradioGroup, plsel_align_radios[0]); num_args++; XtSetArg(args[num_args], XtNradioData, 2); num_args++; - plsel_align_radios[1] = align_radio_n = XtCreateManagedWidget("Neutral", - toggleWidgetClass, - align_form2, - args, num_args); + plsel_align_radios[1] = align_radio_n + = XtCreateManagedWidget("Neutral", toggleWidgetClass, + align_form2, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNfromVert, align_radio_n); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; @@ -1084,9 +1122,12 @@ X11_player_selection_dialog() XawToggleUnsetCurrent(plsel_align_radios[0]); - XtAddCallback(align_radio_l, XtNcallback, aligntoggleCallback, (caddr_t) (1)); - XtAddCallback(align_radio_n, XtNcallback, aligntoggleCallback, (caddr_t) (2)); - XtAddCallback(align_radio_c, XtNcallback, aligntoggleCallback, (caddr_t) (3)); + XtAddCallback(align_radio_l, XtNcallback, + aligntoggleCallback, (caddr_t) (1)); + XtAddCallback(align_radio_n, XtNcallback, + aligntoggleCallback, (caddr_t) (2)); + XtAddCallback(align_radio_c, XtNcallback, + aligntoggleCallback, (caddr_t) (3)); /********************************************/ @@ -1101,11 +1142,11 @@ X11_player_selection_dialog() XtSetArg(args[num_args], XtNallowVert, False); num_args++; XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; btn_vp = XtCreateManagedWidget("btn_vp", viewportWidgetClass, form, - args, num_args); + args, num_args); num_args = 0; btn_form = XtCreateManagedWidget("btn_form", formWidgetClass, btn_vp, - args, num_args); + args, num_args); /* "Random" button */ @@ -1127,8 +1168,9 @@ X11_player_selection_dialog() XtSetArg(args[num_args], nhStr(XtNright), XtChainRight); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], nhStr(XtNlabel), "Play"); num_args++; - plsel_btn_play = play_btn = XtCreateManagedWidget("play", commandWidgetClass, btn_form, - args, num_args); + plsel_btn_play = play_btn + = XtCreateManagedWidget("play", commandWidgetClass, btn_form, + args, num_args); XtAddCallback(play_btn, XtNcallback, plsel_play_btn_callback, form); /* "Quit" button */ @@ -1141,7 +1183,7 @@ X11_player_selection_dialog() XtSetArg(args[num_args], XtNwidth, cwid); num_args++; XtSetArg(args[num_args], nhStr(XtNlabel), "Quit"); num_args++; quit_btn = XtCreateManagedWidget("quit", commandWidgetClass, btn_form, - args, num_args); + args, num_args); XtAddCallback(quit_btn, XtNcallback, plsel_quit_btn_callback, form); /********************************************/ From 8723742015b52d17a3e025aabf5c38a57f7870e3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 09:15:07 +0300 Subject: [PATCH 35/43] Don't output x11 tile compilation info into stderr --- win/X11/tile2x11.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index 8b7b455e1..d8169b37b 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -117,7 +117,7 @@ char *fname; } merge_text_colormap(); count = convert_tiles(&curr_tb, header.ntiles); - Fprintf(stderr, "%s: %lu tiles\n", fname, count); + printf("%s: %lu tiles\n", fname, count); header.ntiles += count; fclose_text_file(); } @@ -199,7 +199,7 @@ char **argv; } process_file(argv[i]); } - Fprintf(stderr, "Total tiles: %ld\n", header.ntiles); + printf("Total tiles: %ld\n", header.ntiles); /* round size up to the end of the row */ if ((header.ntiles % header.per_row) != 0) { From 1e3c00d7607711ddd56f43f4f631ef6471fa94fa Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 14 Oct 2017 02:09:43 -0700 Subject: [PATCH 36/43] fix #6187 - attempting to eat inedible artifact Rearrange the tests for edibility of non-food so that touching an artifact won't happen unless the object could be eaten. Add a bit of bulletproofing for rust monsters trying to eat a rustproofed item and spitting it out. Wishing for rustproof iron ring, cursing it, wearing it, and attempting to eat it as a rust monster would remove the rustproofing and spit it onto the floor, ignoring the cursed state as far as taking it off goes. That was an issue in 3.4.3 and probably in 3.6.0, but in current code the 'rustproof' part of the wish would be ignored for an item which isn't subject to erosion damage, so hero-as-rust monster will successfully eat the ring instead of spitting it out. --- src/eat.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/eat.c b/src/eat.c index 6bbc1836b..a1b4bc33d 100644 --- a/src/eat.c +++ b/src/eat.c @@ -2443,10 +2443,7 @@ doeat() * mails, players who polymorph back to human in the middle of their * metallic meal, etc.... */ - if (!(carried(otmp) ? retouch_object(&otmp, FALSE) - : touch_artifact(otmp, &youmonst))) { - return 1; - } else if (!is_edible(otmp)) { + if (!is_edible(otmp)) { You("cannot eat that!"); return 0; } else if ((otmp->owornmask & (W_ARMOR | W_TOOL | W_AMUL | W_SADDLE)) @@ -2454,6 +2451,9 @@ doeat() /* let them eat rings */ You_cant("eat %s you're wearing.", something); return 0; + } else if (!(carried(otmp) ? retouch_object(&otmp, FALSE) + : touch_artifact(otmp, &youmonst))) { + return 1; /* got blasted so use a turn */ } if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) { @@ -2468,13 +2468,26 @@ doeat() /* The regurgitated object's rustproofing is gone now */ otmp->oerodeproof = 0; make_stunned((HStun & TIMEOUT) + (long) rn2(10), TRUE); - You("spit %s out onto the %s.", the(xname(otmp)), - surface(u.ux, u.uy)); - if (carried(otmp)) { - freeinv(otmp); - dropy(otmp); + /* + * We don't expect rust monsters to be wielding welded weapons + * or wearing cursed rings which were rustproofed, but guard + * against the possibility just in case. + */ + if (welded(otmp) || (otmp->cursed && (otmp->owornmask & W_RING))) { + otmp->bknown = 1; /* for ring; welded() does this for weapon */ + You("spit out %s.", the(xname(otmp))); + } else { + You("spit %s out onto the %s.", the(xname(otmp)), + surface(u.ux, u.uy)); + if (carried(otmp)) { + /* no need to check for leash in use; it's not metallic */ + if (otmp->owornmask) + remove_worn_item(otmp, FALSE); + freeinv(otmp); + dropy(otmp); + } + stackobj(otmp); } - stackobj(otmp); return 1; } /* KMH -- Slow digestion is... indigestible */ From 04b08298a3fdba78382a6d0f6f6cea418cb7dfea Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 13:10:34 +0300 Subject: [PATCH 37/43] Use the same macro for output in tile2x11 --- win/X11/tile2x11.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index d8169b37b..a51cb75cd 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -91,7 +91,7 @@ merge_text_colormap() if (j == header.ncolors) { /* couldn't find it */ #ifdef PRINT_COLORMAP - printf("color %2d: %3d %3d %3d\n", header.ncolors, + Fprintf(stdout, "color %2d: %3d %3d %3d\n", header.ncolors, ColorMap[CM_RED][i], ColorMap[CM_GREEN][i], ColorMap[CM_BLUE][i]); #endif @@ -117,7 +117,7 @@ char *fname; } merge_text_colormap(); count = convert_tiles(&curr_tb, header.ntiles); - printf("%s: %lu tiles\n", fname, count); + Fprintf(stdout, "%s: %lu tiles\n", fname, count); header.ntiles += count; fclose_text_file(); } @@ -157,7 +157,7 @@ FILE *fp; Fprintf(fp, "\",\n"); } - return fprintf(fp, "};\n") >= 0; + return Fprintf(fp, "};\n") >= 0; } #endif /* USE_XPM */ @@ -199,7 +199,7 @@ char **argv; } process_file(argv[i]); } - printf("Total tiles: %ld\n", header.ntiles); + Fprintf(stdout, "Total tiles: %ld\n", header.ntiles); /* round size up to the end of the row */ if ((header.ntiles % header.per_row) != 0) { From 1caa212bd946c85d57e11d736f09ebd4f17e464a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 13:48:44 +0300 Subject: [PATCH 38/43] Fix warnings --- win/X11/Window.c | 4 ++-- win/X11/winmisc.c | 54 +++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/win/X11/Window.c b/win/X11/Window.c index e6db07b58..09c753f33 100644 --- a/win/X11/Window.c +++ b/win/X11/Window.c @@ -121,7 +121,7 @@ Region region; /* unused */ nhUse(region); /* This isn't correct - we need to call the callback with region. */ - XtCallCallbacks(w, XtNexposeCallback, (caddr_t) event); + XtCallCallbacks(w, XtNexposeCallback, (XtPointer)event); } /* ARGSUSED */ @@ -129,7 +129,7 @@ static void Resize(w) Widget w; { - XtCallCallbacks(w, XtNresizeCallback, (caddr_t) 0); + XtCallCallbacks(w, XtNresizeCallback, (XtPointer) 0); } WindowClassRec windowClassRec = { diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 5ee440f5a..5da6730c8 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -621,7 +621,7 @@ X11_player_selection_setupOthers() static void racetoggleCallback(w, client, call) Widget w; -caddr_t client, call; +XtPointer client, call; { Arg args[2]; int j, valid; @@ -662,7 +662,7 @@ caddr_t client, call; static void roletoggleCallback(w, client, call) Widget w; -caddr_t client, call; +XtPointer client, call; { Arg args[2]; @@ -704,7 +704,7 @@ caddr_t client, call; static void gendertoggleCallback(w, client, call) Widget w; -caddr_t client, call; +XtPointer client, call; { int r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; @@ -718,7 +718,7 @@ caddr_t client, call; static void aligntoggleCallback(w, client, call) Widget w; -caddr_t client, call; +XtPointer client, call; { int r = xtp2i(XawToggleGetCurrent(plsel_align_radios[0])) - 1; @@ -826,7 +826,7 @@ Widget form; XtInstallAccelerators(plsel_name_input, plsel_name_input); XtSetKeyboardFocus(form, plsel_name_input); } else { - XtSetArg(args[0], XtNdisplayCaret, False); + XtSetArg(args[0], nhStr(XtNdisplayCaret), False); XtSetValues(plsel_name_input, args, ONE); } @@ -925,9 +925,9 @@ X11_player_selection_dialog() tmpwidget); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; if (i > 0) - XtSetArg(args[num_args], XtNradioGroup, + XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_race_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, (i + 1)); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++; racewidget = XtCreateManagedWidget(races[i].noun, toggleWidgetClass, @@ -988,9 +988,9 @@ X11_player_selection_dialog() tmpwidget); num_args++; XtSetArg(args[num_args], nhStr(XtNwidth), cwid); num_args++; if (i > 0) - XtSetArg(args[num_args], XtNradioGroup, + XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_role_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, (i + 1)); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++; rolewidget = XtCreateManagedWidget(roles[i].name.m, toggleWidgetClass, @@ -1040,15 +1040,15 @@ X11_player_selection_dialog() /* gender radio buttons */ num_args = 0; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], XtNradioData, 1); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++; plsel_gend_radios[0] = gend_radio_m = XtCreateManagedWidget("Male", toggleWidgetClass, gend_form2, args, num_args); num_args = 0; - XtSetArg(args[num_args], XtNfromVert, gend_radio_m); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), gend_radio_m); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], XtNradioGroup, plsel_gend_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, 2); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_gend_radios[0]); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++; plsel_gend_radios[1] = gend_radio_f = XtCreateManagedWidget("Female", toggleWidgetClass, gend_form2, args, num_args); @@ -1056,9 +1056,9 @@ X11_player_selection_dialog() XawToggleUnsetCurrent(plsel_gend_radios[0]); XtAddCallback(gend_radio_m, XtNcallback, - gendertoggleCallback, (caddr_t) (1)); + gendertoggleCallback, (XtPointer) (1)); XtAddCallback(gend_radio_f, XtNcallback, - gendertoggleCallback, (caddr_t) (2)); + gendertoggleCallback, (XtPointer) (2)); /********************************************/ @@ -1068,7 +1068,7 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), gend_form); num_args++; - XtSetArg(args[num_args], XtNvertDistance, 30); num_args++; + XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++; align_form = XtCreateManagedWidget("align_form", formWidgetClass, form, args, num_args); @@ -1098,23 +1098,23 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], XtNradioData, 1); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), 1); num_args++; plsel_align_radios[0] = align_radio_l = XtCreateManagedWidget("Lawful", toggleWidgetClass, align_form2, args, num_args); num_args = 0; - XtSetArg(args[num_args], XtNfromVert, align_radio_l); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_l); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], XtNradioGroup, plsel_align_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, 2); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_align_radios[0]); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), 2); num_args++; plsel_align_radios[1] = align_radio_n = XtCreateManagedWidget("Neutral", toggleWidgetClass, align_form2, args, num_args); num_args = 0; - XtSetArg(args[num_args], XtNfromVert, align_radio_n); num_args++; + XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_n); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], XtNradioGroup, plsel_align_radios[0]); num_args++; - XtSetArg(args[num_args], XtNradioData, 3); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_align_radios[0]); num_args++; + XtSetArg(args[num_args], nhStr(XtNradioData), 3); num_args++; plsel_align_radios[2] = align_radio_c = XtCreateManagedWidget("Chaotic", toggleWidgetClass, align_form2, @@ -1123,11 +1123,11 @@ X11_player_selection_dialog() XawToggleUnsetCurrent(plsel_align_radios[0]); XtAddCallback(align_radio_l, XtNcallback, - aligntoggleCallback, (caddr_t) (1)); + aligntoggleCallback, (XtPointer) (1)); XtAddCallback(align_radio_n, XtNcallback, - aligntoggleCallback, (caddr_t) (2)); + aligntoggleCallback, (XtPointer) (2)); XtAddCallback(align_radio_c, XtNcallback, - aligntoggleCallback, (caddr_t) (3)); + aligntoggleCallback, (XtPointer) (3)); /********************************************/ @@ -1135,7 +1135,7 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), align_form); num_args++; - XtSetArg(args[num_args], XtNvertDistance, 30); num_args++; + XtSetArg(args[num_args], nhStr(XtNvertDistance), 30); num_args++; XtSetArg(args[num_args], nhStr(XtNrightMargin), 0); num_args++; XtSetArg(args[num_args], nhStr(XtNfromHoriz), role_form); num_args++; XtSetArg(args[num_args], XtNforceBars, False); num_args++; From 1ff4dfee854be09b14c434d49c1f5bf680554e7d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 15:51:45 +0300 Subject: [PATCH 39/43] Reduce *nix Makefile verbosity Instead of showing all the CFLAGS and whatnot, just show "[CC] allmain.c" or whatever. The verbose output can be switched back on with VERBOSEMAKE=1 --- doc/fixes36.1 | 1 + sys/unix/Makefile.src | 19 ++++++++++++++++++- sys/unix/Makefile.utl | 20 ++++++++++++++++---- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index c037bade6..2032a283b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -709,6 +709,7 @@ X11: status display split into three columns to accomodate Stone/Deaf/Lev/&c; X11: more terminal-like default resources win32gui: save and load map colors from registry X11: add new character selection dialog, and obey player_selection:dialog +unix: reduce makefile verbosity by default NetHack Community Patches (or Variation) Included diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 8c27b612c..3696ce5c0 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -332,6 +332,9 @@ RANDOBJ = # used by `make depend' to reconstruct this Makefile; you shouldn't need this AWK = nawk + +#VERBOSEMAKE = 1 + # ---------------------------------------- # # Nothing below this line should have to be changed. @@ -339,6 +342,20 @@ AWK = nawk # Other things that have to be reconfigured are in config.h, # {unixconf.h, pcconf.h, tosconf.h}, and possibly system.h +# Verbosity +ACTUAL_CC := $(CC) +CC_V0 = @echo "[CC] $<"; $(ACTUAL_CC) +CC_V = $(CC_V0) +CC_V1 = $(ACTUAL_CC) +CC = $(CC_V$(VERBOSEMAKE)) + +ACTUAL_CXX := $(CXX) +CXX_V0 = @echo "[CXX] $<"; $(ACTUAL_CXX) +CXX_V = $(CXX_V0) +CXX_V1 = $(ACTUAL_CXX) +CXX = $(CXX_V$(VERBOSEMAKE)) + + MAKEDEFS = ../util/makedefs # timestamp files to reduce `make' overhead and shorten .o dependency lists @@ -438,7 +455,7 @@ $(GAME): $(SYSTEM) Sysunix: $(HOBJ) Makefile @echo "Loading ..." - $(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) + @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @touch Sysunix Sys3B2: $(HOBJ) Makefile diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index 3cd34906e..dc56d4fdf 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -130,6 +130,20 @@ LEXYYC = lex.yy.c # # Nothing below this line should have to be changed. +# Verbosity +ACTUAL_CC := $(CC) +CC_V0 = @echo "[CC] $<"; $(ACTUAL_CC) +CC_V = $(CC_V0) +CC_V1 = $(ACTUAL_CC) +CC = $(CC_V$(VERBOSEMAKE)) + +ACTUAL_CXX := $(CXX) +CXX_V0 = @echo "[CXX] $<"; $(ACTUAL_CXX) +CXX_V = $(CXX_V0) +CXX_V1 = $(ACTUAL_CXX) +CXX = $(CXX_V$(VERBOSEMAKE)) + + # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t @@ -232,8 +246,7 @@ lev_main.o: lev_main.c $(HACK_H) ../include/sp_lev.h ../include/tcap.h \ # egrep will return failure if it doesn't find anything, but we know there # is one "_cplusplus" inside a comment lev_lex.o: lev_lex.c $(HACK_H) ../include/lev_comp.h ../include/sp_lev.h - @echo $(CC) -c $(CFLAGS) lev_lex.c - @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus lev_lex.c` lev_lex.c + $(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus lev_lex.c` lev_lex.c # '$(YACC) -d' generates both $(YTABC) and $(YTABH) in one run ../include/lev_comp.h: lev_yacc.c @@ -270,8 +283,7 @@ dgn_main.o: dgn_main.c $(CONFIG_H) ../include/dlb.h # see dgn_comp.l for WEIRD_LEX discussion dgn_lex.o: dgn_lex.c $(CONFIG_H) ../include/dgn_comp.h ../include/dgn_file.h - @echo $(CC) -c $(CFLAGS) dgn_lex.c - @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus dgn_lex.c` dgn_lex.c + $(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus dgn_lex.c` dgn_lex.c # '$(YACC) -d' generates both $(YTABC) and $(YTABH) in one run ../include/dgn_comp.h: dgn_yacc.c From 87b94230b5bfbb5bce7cbdd6fff112b45fff471b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 17:38:06 +0300 Subject: [PATCH 40/43] X11: player selection enter should obey button active state --- win/X11/winmisc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index 5da6730c8..c4465ae54 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -381,13 +381,23 @@ XEvent *event; String *params; Cardinal *num_params; { + Arg args[2]; + Boolean state; + nhUse(w); nhUse(event); nhUse(params); nhUse(num_params); - plsel_dialog_acceptvalues(); - exit_x_event = TRUE; /* leave event loop */ + XtSetArg(args[0], nhStr(XtNsensitive), &state); + XtGetValues(plsel_btn_play, args, ONE); + + if (state) { + plsel_dialog_acceptvalues(); + exit_x_event = TRUE; /* leave event loop */ + } else { + X11_nhbell(); + } } /* ARGSUSED */ From 1b42b1499b090e476cfa813aff504bb4c3486e66 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 18:07:09 +0300 Subject: [PATCH 41/43] X11: player selection dialog tweaks --- win/X11/winmisc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index c4465ae54..a181770b1 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -832,8 +832,8 @@ Widget form; asciiTextWidgetClass, name_form, args, num_args); + XtInstallAccelerators(plsel_name_input, plsel_name_input); if (plsel_ask_name) { - XtInstallAccelerators(plsel_name_input, plsel_name_input); XtSetKeyboardFocus(form, plsel_name_input); } else { XtSetArg(args[0], nhStr(XtNdisplayCaret), False); @@ -1203,7 +1203,6 @@ X11_player_selection_dialog() ps_selected = -1; - positionpopup(popup, TRUE); /* center,bottom */ nh_XtPopup(popup, (int) XtGrabExclusive, form); /* The callback will enable the event loop exit. */ From 7d8ba1d46f679e114a632a879e401b2b1798ceee Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 21:00:47 +0300 Subject: [PATCH 42/43] Monsters hit by a boulder from your scroll of earth should get angry --- doc/fixes36.1 | 1 + src/read.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 2032a283b..9c74120fd 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -452,6 +452,7 @@ give feedback when released from a bear trap #version output left out "pattern matching via " if the basic NetHack features entry was split across two lines recovery of strength lost due to weakness from hunger was vulnerable to abuse +monsters hit by scroll of earth boulder did not get angry Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/read.c b/src/read.c index 9732fea96..ad1c75f37 100644 --- a/src/read.c +++ b/src/read.c @@ -1771,6 +1771,7 @@ boolean confused, byu; xname(helmet), mhim(mtmp)); } } + wakeup(mtmp, byu); mtmp->mhp -= mdmg; if (mtmp->mhp <= 0) { if (byu) { From 612a0cb909143d9e29e1f7b9e9b40ae62771d0b9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 14 Oct 2017 21:29:17 +0300 Subject: [PATCH 43/43] Make boulder dropping noise wake up monsters Also, don't bother waking up monsters who would end up dead anyway. --- src/read.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/read.c b/src/read.c index ad1c75f37..29513f7ef 100644 --- a/src/read.c +++ b/src/read.c @@ -1714,6 +1714,7 @@ boolean confused, helmet_protects, byu, skip_uswallow; } } else dmg = 0; + wake_nearto(u.ux, u.uy, 4 * 4); /* Must be before the losehp(), for bones files */ if (!flooreffects(otmp2, u.ux, u.uy, "fall")) { place_object(otmp2, u.ux, u.uy); @@ -1771,7 +1772,6 @@ boolean confused, byu; xname(helmet), mhim(mtmp)); } } - wakeup(mtmp, byu); mtmp->mhp -= mdmg; if (mtmp->mhp <= 0) { if (byu) { @@ -1780,7 +1780,10 @@ boolean confused, byu; pline("%s is killed.", Monnam(mtmp)); mondied(mtmp); } + } else { + wakeup(mtmp, byu); } + wake_nearto(x, y, 4 * 4); } else if (u.uswallow && mtmp == u.ustuck) { obfree(otmp2, (struct obj *) 0); /* fall through to player */