From 1af921274edbe1a7b9285620c344b25a51274b1f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 15 Oct 2017 18:00:56 +0300 Subject: [PATCH 01/11] More Makefile verbosity --- sys/unix/Makefile.src | 42 ++++++++++++++++++++++++++++-------------- sys/unix/Makefile.utl | 15 +++++++++++++-- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 3696ce5c0..451067a93 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -342,19 +342,33 @@ AWK = nawk # Other things that have to be reconfigured are in config.h, # {unixconf.h, pcconf.h, tosconf.h}, and possibly system.h -# Verbosity +# Verbosity definitions, begin +# Set VERBOSEMAKE=1 to output more stuff. +# CC and CXX obey verbosity, LD and LINK don't. +# AT is @ when not verbose, empty otherwise ACTUAL_CC := $(CC) +ACTUAL_CXX := $(CXX) +ACTUAL_LD := $(LD) +ACTUAL_LINK := $(LINK) + 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)) +LD = $(ACTUAL_LD) +LINK = $(ACTUAL_LINK) + +AT_V0 := @ +AT_V := $(AT_V0) +AT_V1 := +AT = $(AT_V$(VERBOSEMAKE)) +# Verbosity, end MAKEDEFS = ../util/makedefs @@ -454,33 +468,33 @@ $(GAME): $(SYSTEM) @echo "$(GAME) is up to date." Sysunix: $(HOBJ) Makefile - @echo "Loading ..." - @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) + @echo "Linking $(GAME)." + $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @touch Sysunix Sys3B2: $(HOBJ) Makefile - @echo "Loading ..." - @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc + @echo "Linking $(GAME)." + $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc @touch Sys3B2 Sysatt: $(HOBJ) Makefile - @echo "Loading ..." - @$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ) + @echo "Loading $(GAME)." + $(AT)$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ) @touch Sysatt Systos: $(HOBJ) Makefile - @echo "Loading ..." - @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) + @echo "Linking $(GAME)." + $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch Systos SysV-AT: DUMB.Setup $(HOBJ) Makefile - @echo "Loading ..." - @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) + @echo "Linking $(GAME)." + $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch SysV-AT SysBe: $(HOBJ) Makefile - @echo "Loading ..." - @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) + @echo "Linking $(GAME)." + $(AT)$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @xres -o $(GAME) ../win/BeOS/nethack.rsrc @mimeset -f $(GAME) @touch SysBe diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index dc56d4fdf..224df10a7 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -130,19 +130,30 @@ LEXYYC = lex.yy.c # # Nothing below this line should have to be changed. -# Verbosity +# Verbosity definitions, begin ACTUAL_CC := $(CC) +ACTUAL_CXX := $(CXX) +ACTUAL_LD := $(LD) +ACTUAL_LINK := $(LINK) + 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)) +LD = $(ACTUAL_LD) +LINK = $(ACTUAL_LINK) + +AT_V0 := @ +AT_V := $(AT_V0) +AT_V1 := +AT = V$(AT_$(VERBOSEMAKE)) +# Verbosity, end # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t From f1618fe6ddc50a0e658976dd4d4ce6eb0271f4ed Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sun, 15 Oct 2017 21:48:42 +0300 Subject: [PATCH 02/11] X11: Put yn prompts into message history --- win/X11/winX.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/win/X11/winX.c b/win/X11/winX.c index 8d097a791..c885e3d82 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -2081,6 +2081,8 @@ char def; /* default response if user hits or */ nh_XtPopdown(yn_popup); /* this removes the event grab */ } + pline("%s%c", buf, (yn_return != '\033') ? yn_return : '\0'); + return yn_return; } From ab04d12ccbc515d311695c14caa0aaec087a21e2 Mon Sep 17 00:00:00 2001 From: PatR Date: Sun, 15 Oct 2017 16:24:02 -0700 Subject: [PATCH 03/11] X11 player selection - wishlist and reformatting Add a comment about potential changes to make the X11 player selection dialog. Also, a bunch of minor formatting tweaks. --- win/X11/winmisc.c | 148 +++++++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 62 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index a181770b1..e062df7fd 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -434,7 +434,6 @@ 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; @@ -458,10 +457,8 @@ boolean setcurr; if (!validrace(ro, c)) c = valid; - if (setcurr) { - int tmpc = c+1; - XawToggleSetCurrent(plsel_role_radios[0], i2xtp(tmpc)); - } + if (setcurr) + XawToggleSetCurrent(plsel_role_radios[0], i2xtp(c + 1)); valid = -1; @@ -478,10 +475,8 @@ boolean setcurr; if (!validrace(ro, c)) c = valid; - if (setcurr) { - int tmpc = c+1; - XawToggleSetCurrent(plsel_race_radios[0], i2xtp(tmpc)); - } + if (setcurr) + XawToggleSetCurrent(plsel_race_radios[0], i2xtp(c + 1)); X11_player_selection_setupOthers(); } @@ -491,12 +486,8 @@ 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; - int tmpx; - + int ro, ra, a, g; + boolean fully_specified_role, choose_race_first; boolean picksomething = (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE @@ -570,10 +561,10 @@ X11_player_selection_randomize() 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)); + XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(g + 1)); + XawToggleSetCurrent(plsel_align_radios[0], i2xtp(a + 1)); + XawToggleSetCurrent(plsel_race_radios[0], i2xtp(ra + 1)); + XawToggleSetCurrent(plsel_role_radios[0], i2xtp(ro + 1)); plsel_set_sensitivities(FALSE); } @@ -581,22 +572,18 @@ 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; + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1; + int valid = -1, c = 0, j; + 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); @@ -607,13 +594,13 @@ X11_player_selection_setupOthers() if (!validgend(ro, ra, c)) c = valid; - k = c+1; - XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(k)); + XawToggleSetCurrent(plsel_gend_radios[0], i2xtp(c + 1)); 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); @@ -624,8 +611,7 @@ X11_player_selection_setupOthers() if (!validalign(ro, ra, c)) c = valid; - k = c+1; - XawToggleSetCurrent(plsel_align_radios[0], i2xtp(k)); + XawToggleSetCurrent(plsel_align_radios[0], i2xtp(c + 1)); } static void @@ -636,9 +622,8 @@ XtPointer client, call; 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; + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1; nhUse(w); nhUse(client); @@ -653,6 +638,7 @@ XtPointer client, call; for (j = 0; roles[j].name.m; j++) { boolean v = validrace(j, ra); + if (j == ro) c = j; XtSetArg(args[0], nhStr(XtNsensitive), v); @@ -663,7 +649,7 @@ XtPointer client, call; if (!validrace(c, ra)) c = valid; - j = c+1; + j = c + 1; XawToggleSetCurrent(plsel_role_radios[0], i2xtp(j)); X11_player_selection_setupOthers(); @@ -675,12 +661,10 @@ Widget w; XtPointer client, call; { 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; + int ra = xtp2i(XawToggleGetCurrent(plsel_race_radios[0])) - 1; + int ro = xtp2i(XawToggleGetCurrent(plsel_role_radios[0])) - 1; nhUse(w); nhUse(client); @@ -695,6 +679,7 @@ XtPointer client, call; for (j = 0; races[j].noun; j++) { boolean v = validrace(ro, j); + if (j == ra) c = j; XtSetArg(args[0], nhStr(XtNsensitive), v); @@ -888,6 +873,47 @@ X11_player_selection_dialog() XtSetArg(args[num_args], XtNwidth, winwid); num_args++; XtSetValues(name_vp, args, num_args); + /* + * Layout; role is centered rather than first: + * + * +------------------------------------+ + * | name | + * +------------------------------------+ + * +--------+ +------------+ +---------+ + * | human | |archeologist| | male | + * | elf | | barbarian | | female | + * | dwarf | | caveman | +---------+ + * | gnome | | healer | +---------+ + * | orc | | knight | | lawful | + * +--------+ | monk | | neutral | + * | priest | | chaotic | + * | rogue | +---------+ + * | ranger | +--------+ + * | samurai | + Random + + * | tourist | + Play + + * | valkyrie | + Quit + + * | wizard | +--------+ + * +------------+ + * + * TODO: + * make name box same width as race+gap+role+gap+gender/alignment + * (resize it after the other boxes have been placed); + * make Random/Play/Quit buttons same width as gender/alignment and + * align bottom of them with bottom of role (they already specify + * the same width for the label text but different decorations-- + * room for radio button box--of the other widgets results in the + * total width being different); + * update caveman/cavewoman and priest/priestess role labels when + * gender gets set to a particular value; + * add 'random' to each of the four boxes and Choose to the Random/ + * Play/Quit buttons; if none of the four 'random's are currently + * selected, gray-out Choose; conversely, when Choose or Play is + * clicked on, make the random assignments for any/all of the four + * boxes which have 'random' selected. + * Maybe: move gender box underneath race, bottom aligned with role + * and move alignment up to where gender currently is. If that's + * done, move role column first and race+gender to middle. + */ /********************************************/ @@ -965,9 +991,8 @@ X11_player_selection_dialog() 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); + rolelabel = XtCreateManagedWidget("role_label", labelWidgetClass, + role_form, args, num_args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; @@ -986,7 +1011,7 @@ X11_player_selection_dialog() continue; plsel_n_roles = i; - plsel_role_radios = (Widget *)alloc(sizeof(Widget) * plsel_n_roles); + plsel_role_radios = (Widget *) alloc(sizeof (Widget) * plsel_n_roles); /* role radio buttons */ for (i = 0; roles[i].name.m; i++) { @@ -1002,10 +1027,8 @@ X11_player_selection_dialog() plsel_role_radios[0]); num_args++; XtSetArg(args[num_args], nhStr(XtNradioData), (i + 1)); num_args++; - rolewidget = XtCreateManagedWidget(roles[i].name.m, - toggleWidgetClass, - role_form2, - args, 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; @@ -1016,7 +1039,7 @@ X11_player_selection_dialog() /* Gender*/ - plsel_gend_radios = (Widget *)alloc(sizeof(Widget) * ROLE_GENDERS); + plsel_gend_radios = (Widget *) alloc(sizeof (Widget) * ROLE_GENDERS); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), name_vp); num_args++; @@ -1030,9 +1053,8 @@ X11_player_selection_dialog() 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); + gendlabel = XtCreateManagedWidget("gender_label", labelWidgetClass, + gend_form, args, num_args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; @@ -1057,7 +1079,8 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), gend_radio_m); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_gend_radios[0]); 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, @@ -1074,7 +1097,7 @@ X11_player_selection_dialog() /* Alignment */ - plsel_align_radios = (Widget *)alloc(sizeof(Widget) * ROLE_ALIGNS); + plsel_align_radios = (Widget *) alloc(sizeof (Widget) * ROLE_ALIGNS); num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), gend_form); num_args++; @@ -1115,7 +1138,8 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_l); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_align_radios[0]); 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, @@ -1123,12 +1147,12 @@ X11_player_selection_dialog() num_args = 0; XtSetArg(args[num_args], nhStr(XtNfromVert), align_radio_n); num_args++; XtSetArg(args[num_args], XtNwidth, cwid); num_args++; - XtSetArg(args[num_args], nhStr(XtNradioGroup), plsel_align_radios[0]); 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, - args, num_args); + plsel_align_radios[2] = align_radio_c + = XtCreateManagedWidget("Chaotic", toggleWidgetClass, + align_form2, args, num_args); XawToggleUnsetCurrent(plsel_align_radios[0]); @@ -1257,7 +1281,7 @@ X11_player_selection_prompts() /* select a role */ for (num_roles = 0; roles[num_roles].name.m; ++num_roles) continue; - choices = (const char **) alloc(sizeof(char *) * num_roles); + choices = (const char **) alloc(sizeof (char *) * num_roles); for (;;) { availcount = 0; for (i = 0; i < num_roles; i++) { From 28061e98dc2d168aecf96fda78cb9a10830407c9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Oct 2017 10:35:33 +0300 Subject: [PATCH 04/11] Qt4: Use pixel-perfect tile scaling SmoothTransformation (bilinear filtering) causes artifacts at tile edges, and the blurry tiles look even worse. --- win/Qt4/qt4glyph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/Qt4/qt4glyph.cpp b/win/Qt4/qt4glyph.cpp index 3ba56be6f..942f3a1ab 100644 --- a/win/Qt4/qt4glyph.cpp +++ b/win/Qt4/qt4glyph.cpp @@ -130,7 +130,7 @@ void NetHackQtGlyphs::setSize(int w, int h) w*img.width()/tilefile_tile_W, h*img.height()/tilefile_tile_H, Qt::IgnoreAspectRatio, - Qt::SmoothTransformation + Qt::FastTransformation ); pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); QApplication::restoreOverrideCursor(); From 491b40897f58f7e15e89b5ce358334618b728b32 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Oct 2017 12:45:19 +0300 Subject: [PATCH 05/11] Ignore Qt specific config options silently If the binary wasn't compiled with Qt, don't complain about Qt specific config options. --- src/files.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/files.c b/src/files.c index 8abacce66..4c46d23d0 100644 --- a/src/files.c +++ b/src/files.c @@ -2674,24 +2674,29 @@ char *origbuf; } else if (match_varname(buf, "SOUND", 5)) { add_sound_mapping(bufp); #endif -#ifdef QT_GRAPHICS - /* These should move to wc_ options */ } else if (match_varname(buf, "QT_TILEWIDTH", 12)) { +#ifdef QT_GRAPHICS extern char *qt_tilewidth; if (qt_tilewidth == NULL) qt_tilewidth = dupstr(bufp); +#endif } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) { +#ifdef QT_GRAPHICS extern char *qt_tileheight; if (qt_tileheight == NULL) qt_tileheight = dupstr(bufp); +#endif } else if (match_varname(buf, "QT_FONTSIZE", 11)) { +#ifdef QT_GRAPHICS extern char *qt_fontsize; if (qt_fontsize == NULL) qt_fontsize = dupstr(bufp); +#endif } else if (match_varname(buf, "QT_COMPACT", 10)) { +#ifdef QT_GRAPHICS extern int qt_compact_mode; qt_compact_mode = atoi(bufp); From 7e28cc64f61f2c12e346c311061dbf1498e970ac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 16 Oct 2017 17:34:29 +0300 Subject: [PATCH 06/11] X11: Capitalize the main window correctly --- win/X11/winX.c | 1 + 1 file changed, 1 insertion(+) diff --git a/win/X11/winX.c b/win/X11/winX.c index c885e3d82..ff9b0ff51 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -1219,6 +1219,7 @@ char **argv; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; + XtSetArg(args[num_args], XtNtitle, "NetHack"); num_args++; toplevel = XtAppInitialize(&app_context, "NetHack", /* application */ (XrmOptionDescList) 0, 0, /* options list */ From da9c3f0ed47ca79f28a05994e3b93a1ab433b0d4 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 16 Oct 2017 22:19:35 -0700 Subject: [PATCH 07/11] X11 role selection: gender-specific role names A wishlist/TODO item: when "female" is highlighted, change "caveman" to "cavewoman" and "priest" to "priestess". If it gets toggled to "male", change them back. --- win/X11/winmisc.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/win/X11/winmisc.c b/win/X11/winmisc.c index e062df7fd..8ddb62a79 100644 --- a/win/X11/winmisc.c +++ b/win/X11/winmisc.c @@ -345,10 +345,10 @@ 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; + 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); @@ -701,13 +701,23 @@ gendertoggleCallback(w, client, call) Widget w; XtPointer client, call; { - int r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; + int i, r = xtp2i(XawToggleGetCurrent(plsel_gend_radios[0])) - 1; nhUse(w); nhUse(client); nhUse(call); plsel_set_play_button(r < 0); + + for (i = 0; roles[i].name.m; i++) { + if (roles[i].name.f) { + Arg args[2]; + + XtSetArg(args[0], XtNlabel, + (r < 1) ? roles[i].name.m : roles[i].name.f); + XtSetValues(plsel_role_radios[i], args, ONE); + } + } } static void @@ -903,8 +913,6 @@ X11_player_selection_dialog() * the same width for the label text but different decorations-- * room for radio button box--of the other widgets results in the * total width being different); - * update caveman/cavewoman and priest/priestess role labels when - * gender gets set to a particular value; * add 'random' to each of the four boxes and Choose to the Random/ * Play/Quit buttons; if none of the four 'random's are currently * selected, gray-out Choose; conversely, when Choose or Play is @@ -1112,9 +1120,8 @@ X11_player_selection_dialog() 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); + alignlabel = XtCreateManagedWidget("align_label", labelWidgetClass, + align_form, args, num_args); num_args = 0; XtSetArg(args[num_args], nhStr(XtNtopMargin), 0); num_args++; From 4fad1ba3cca44c2a8553c92531912fa05de4ab8a Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 19 Oct 2017 23:08:46 -0700 Subject: [PATCH 08/11] fix #H6285 - speaking vs strangulation Reading a scroll while blind is permitted if you know its label, but message is "as you pronounce the words, the scroll vanishes" unless you are poly'd into a form which can't make sounds, in which case you "cogitate" rather than "pronouce". Switch to the cogitate variant if you are suffering from strangulation. Casting spells didn't even have the distinction; you could cast them without regard to speech capability. Check for that. Unlike with scrolls, now you can't cast if you can't speak (or grunt or bark or whatever) instead of having a variant description of the action, so this is a bigger change. --- doc/fixes36.1 | 4 ++++ include/extern.h | 3 ++- src/mondata.c | 16 ++++++++++++++-- src/read.c | 21 +++++++++++++-------- src/spell.c | 5 ++++- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9c74120fd..2b20433be 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -453,6 +453,10 @@ give feedback when released from a bear trap 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 +hero could "pronounce the words on the scroll" when blind (if its label is + known) even while being strangled at the time +hero could cast spells while poly'd into a form which can't speak (or grunt,&c) + or while being strangled Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index fbbd8bd74..abc38311b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1505170345 2017/09/11 22:52:25 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.604 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1508479720 2017/10/20 06:08:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.618 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1423,6 +1423,7 @@ E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(mon_hates_silver, (struct monst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_blow, (struct monst *)); +E boolean FDECL(can_chant, (struct monst *)); E boolean FDECL(can_be_strangled, (struct monst *)); E boolean FDECL(can_track, (struct permonst *)); E boolean FDECL(breakarm, (struct permonst *)); diff --git a/src/mondata.c b/src/mondata.c index 32ea5bccc..d849658f9 100644 --- a/src/mondata.c +++ b/src/mondata.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mondata.c $NHDT-Date: 1492733172 2017/04/21 00:06:12 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.62 $ */ +/* NetHack 3.6 mondata.c $NHDT-Date: 1508479720 2017/10/20 06:08:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.63 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -325,7 +325,7 @@ struct permonst *mptr; /* returns True if monster can blow (whistle, etc) */ boolean can_blow(mtmp) -register struct monst *mtmp; +struct monst *mtmp; { if ((is_silent(mtmp->data) || mtmp->data->msound == MS_BUZZ) && (breathless(mtmp->data) || verysmall(mtmp->data) @@ -336,6 +336,18 @@ register struct monst *mtmp; return TRUE; } +/* for casting spells and reading scrolls while blind */ +boolean +can_chant(mtmp) +struct monst *mtmp; +{ + if ((mtmp == &youmonst && Strangled) + || is_silent(mtmp->data) || !has_head(mtmp->data) + || mtmp->data->msound == MS_BUZZ || mtmp->data->msound == MS_BURBLE) + return FALSE; + return TRUE; +} + /* True if mon is vulnerable to strangulation */ boolean can_be_strangled(mon) diff --git a/src/read.c b/src/read.c index 29513f7ef..69d588427 100644 --- a/src/read.c +++ b/src/read.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 read.c $NHDT-Date: 1467718299 2016/07/05 11:31:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.140 $ */ +/* NetHack 3.6 read.c $NHDT-Date: 1508479721 2017/10/20 06:08:41 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.148 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -192,6 +192,7 @@ doread() return 1; } else if (scroll->otyp == T_SHIRT || scroll->otyp == ALCHEMY_SMOCK) { char buf[BUFSZ]; + if (Blind) { You_cant("feel any Braille writing."); return 0; @@ -237,10 +238,13 @@ doread() : card_msgs[scroll->o_id % (SIZE(card_msgs) - 1)]); } /* Make a credit card number */ - pline("\"%d0%d %d%d1 0%d%d0\"", ((scroll->o_id % 89) + 10), - (scroll->o_id % 4), (((scroll->o_id * 499) % 899999) + 100000), - (scroll->o_id % 10), (!(scroll->o_id % 3)), - ((scroll->o_id * 7) % 10)); + pline("\"%d0%d %ld%d1 0%d%d0\"", + (((int) scroll->o_id % 89) + 10), + ((int) scroll->o_id % 4), + ((((long) scroll->o_id * 499L) % 899999L) + 100000L), + ((int) scroll->o_id % 10), + (!((int) scroll->o_id % 3)), + (((int) scroll->o_id * 7) % 10)); u.uconduct.literate++; return 1; } else if (scroll->otyp == CAN_OF_GREASE) { @@ -339,6 +343,8 @@ doread() } scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ if (scroll->otyp != SCR_BLANK_PAPER) { + boolean silently = !can_chant(&youmonst); + /* a few scroll feedback messages describe something happening to the scroll itself, so avoid "it disappears" for those */ nodisappear = (scroll->otyp == SCR_FIRE @@ -348,7 +354,7 @@ doread() pline(nodisappear ? "You %s the formula on the scroll." : "As you %s the formula on it, the scroll disappears.", - is_silent(youmonst.data) ? "cogitate" : "pronounce"); + silently ? "cogitate" : "pronounce"); else pline(nodisappear ? "You read the scroll." : "As you read the scroll, it disappears."); @@ -357,8 +363,7 @@ doread() pline("Being so trippy, you screw up..."); else pline("Being confused, you %s the magic words...", - is_silent(youmonst.data) ? "misunderstand" - : "mispronounce"); + silently ? "misunderstand" : "mispronounce"); } } if (!seffects(scroll)) { diff --git a/src/spell.c b/src/spell.c index 955620f57..0447da70b 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 spell.c $NHDT-Date: 1450584420 2015/12/20 04:07:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.75 $ */ +/* NetHack 3.6 spell.c $NHDT-Date: 1508479722 2017/10/20 06:08:42 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ @@ -644,6 +644,9 @@ rejectcasting() if (Stunned) { You("are too impaired to cast a spell."); return TRUE; + } else if (!can_chant(&youmonst)) { + You("are unable to chant the incantation."); + return TRUE; } else if (!freehand()) { /* Note: !freehand() occurs when weapon and shield (or two-handed * weapon) are welded to hands, so "arms" probably doesn't need From 0bf824a81e67e4a4723f74aa34b3a6370734f1a7 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Fri, 20 Oct 2017 16:15:02 +0300 Subject: [PATCH 09/11] Prevent adjusting items to the dash inventory letter The #adjust command allowed, due to compactified buf, putting items into the '-' inventory letter, which is usually reserved for "empty hands", zeroobj. This caused problems down the line when user was allowed to pick that letter for dropping. --- src/invent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/invent.c b/src/invent.c index ab1ffc004..46d441e84 100644 --- a/src/invent.c +++ b/src/invent.c @@ -3622,7 +3622,7 @@ doorganize() /* inventory organizer by Del Lamb */ pline1(Never_mind); return 0; } - if ((letter(let) && let != '@') || index(buf, let)) + if ((letter(let) && let != '@') || index(buf, let) && let != '-') break; /* got one */ if (trycnt == 5) goto noadjust; From 08a3297f6466a435a76461e49eb60fde89ebca49 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 20 Oct 2017 18:31:07 -0700 Subject: [PATCH 10/11] boulder pickup: contradictory message sequence Poly'd into a giant with a full inventory that already contains at least one boulder, moving onto a boulder (that can't be pushed due to a wall or other obstacle) yielded You try to move the boulder, but in vain. However, you can easily pick it up. You are carrying too much stuff to pick up another boulder. You see here a boulder. The second and third statements contradict each other. Make the code that dishes out the second message smarter. If autopickup is set for it and you will pick up the boulder: However, you easily pick it up. If autopickup is not set for it but would have worked if it was: However, you could easily pick it up. If your inventory is full and you have a boulder (or are in Sokoban) However, you easily push it aside. That last one is instead of "however, you can squeeze yourself into a small opening" that you'd get if not a giant and not carrying much. --- doc/fixes36.1 | 3 +++ include/extern.h | 3 ++- src/hack.c | 26 +++++++++++++++++++++----- src/pickup.c | 5 ++--- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 2b20433be..7403cbaf4 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -457,6 +457,9 @@ hero could "pronounce the words on the scroll" when blind (if its label is known) even while being strangled at the time hero could cast spells while poly'd into a form which can't speak (or grunt,&c) or while being strangled +when poly'd into a giant and moving onto a boulder's spot, you could get "you + try to move the boulder, but in vain", "however, you can easily pick + it up", "you are carrying too much stuff to pick up another boulder" Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/extern.h b/include/extern.h index abc38311b..bc1c183ab 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1508479720 2017/10/20 06:08:40 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.618 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1508549428 2017/10/21 01:30:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.619 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1830,6 +1830,7 @@ E int FDECL(use_container, (struct obj **, int, BOOLEAN_P)); E int FDECL(loot_mon, (struct monst *, int *, boolean *)); E int NDECL(dotip); E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P)); +E boolean FDECL(autopick_testobj, (struct obj *, BOOLEAN_P)); /* ### pline.c ### */ diff --git a/src/hack.c b/src/hack.c index 1aabddbdc..64bc25e3b 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1496619131 2017/06/04 23:32:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.175 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1508549436 2017/10/21 01:30:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.180 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -315,14 +315,30 @@ moverock() feel_location(sx, sy); cannot_push: if (throws_rocks(youmonst.data)) { + boolean + canpickup = (!Sokoban + /* similar exception as in can_lift(): + when poly'd into a giant, you can + pick up a boulder if you have a free + slot or into the overflow ('#') slot + unless already carrying at least one */ + && (inv_cnt(FALSE) < 52 || !carrying(BOULDER))), + willpickup = (canpickup && autopick_testobj(otmp, TRUE)); + if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { You("aren't skilled enough to %s %s from %s.", - (flags.pickup && !Sokoban) ? "pick up" : "push aside", + willpickup ? "pick up" : "push aside", the(xname(otmp)), y_monnam(u.usteed)); } else { - pline("However, you can easily %s.", - (flags.pickup && !Sokoban) ? "pick it up" - : "push it aside"); + /* + * willpickup: you easily pick it up + * canpickup: you could easily pick it up + * otherwise: you easily push it aside + */ + pline("However, you %seasily %s.", + (willpickup || !canpickup) ? "" : "could ", + (willpickup || canpickup) ? "pick it up" + : "push it aside"); sokoban_guilt(); break; } diff --git a/src/pickup.c b/src/pickup.c index 56ff922f9..aa147080b 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pickup.c $NHDT-Date: 1498078877 2017/06/21 21:01:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.185 $ */ +/* NetHack 3.6 pickup.c $NHDT-Date: 1508549438 2017/10/21 01:30:38 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.192 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -21,7 +21,6 @@ STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *)); #if 0 /* not used */ STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *)); #endif -STATIC_DCL boolean FDECL(autopick_testobj, (struct obj *, BOOLEAN_P)); STATIC_DCL int FDECL(autopick, (struct obj *, int, menu_item **)); STATIC_DCL int FDECL(count_categories, (struct obj *, int)); STATIC_DCL long FDECL(carry_count, (struct obj *, struct obj *, long, @@ -743,7 +742,7 @@ boolean grab; /* forced pickup, rather than forced leave behind? */ return FALSE; } -STATIC_OVL boolean +boolean autopick_testobj(otmp, calc_costly) struct obj *otmp; boolean calc_costly; From a8fb18d6fee31ba93b4f10497248e530937c21a1 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 21 Oct 2017 16:02:48 -0700 Subject: [PATCH 11/11] more #adjust: '$' and '#' handling The recent fix to prevent #adjust from letting the player move things into slot '-' (if compactify() reduced any sequence of consecutive letters to x-y, introducing dash into the string of characters that could be chosen from) was triggering a complaint about mixing && and || without parentheses. Fixing that was trivial, but I ended up making a much more substantial change. If the '#' overflow slot is in use, you can move something into it even when you no longer have all 52 regular slots in use. (When it isn't already in use, you can't access it. Previously you could swap from '#' to any letter but not vice versa.) If you manage to get gold in multiple slots or in some slot other than '$', you can move or merge it into the '$' slot. And when that situation isn't present (if even possible--I had to force it with a debugger to test), then gold will no longer be listed among the inventory letters to adjust. (That became an issue when GOLDINV came into use, but either nobody ever noticed or at least never reported. "Adjust what? [$abd]", then pick '$' and be told you can't adjust gold. Prior to GOLDINV, '$' wasn't included in the list of candidates.) --- doc/fixes36.1 | 2 ++ src/invent.c | 79 ++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7403cbaf4..ff470d323 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -460,6 +460,8 @@ hero could cast spells while poly'd into a form which can't speak (or grunt,&c) when poly'd into a giant and moving onto a boulder's spot, you could get "you try to move the boulder, but in vain", "however, you can easily pick it up", "you are carrying too much stuff to pick up another boulder" +improve #adjust command's handling of the '$' and '#' inventory slots +prevent #adjust from allowing anything to be moved into the special '-' slot Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/invent.c b/src/invent.c index 46d441e84..0c61b3dee 100644 --- a/src/invent.c +++ b/src/invent.c @@ -392,7 +392,7 @@ struct obj **potmp, **pobj; otmp->quan += obj->quan; /* temporary special case for gold objects!!!! */ if (otmp->oclass == COIN_CLASS) - otmp->owt = weight(otmp); + otmp->owt = weight(otmp), otmp->bknown = 0; /* and puddings!!!1!!one! */ else if (!Is_pudding(otmp)) otmp->owt += obj->owt; @@ -1223,6 +1223,8 @@ register const char *let, *word; || (!strcmp(word, "charge") && !is_chargeable(otmp)) || (!strcmp(word, "open") && otyp != TIN) || (!strcmp(word, "call") && !objtyp_is_callable(otyp)) + || (!strcmp(word, "adjust") && otmp->oclass == COIN_CLASS + && !usegold) ) { foo--; } @@ -3537,12 +3539,16 @@ int doorganize() /* inventory organizer by Del Lamb */ { struct obj *obj, *otmp, *splitting, *bumped; - int ix, cur, trycnt; + int ix, cur, trycnt, goldstacks; char let; - char alphabet[52 + 1], buf[52 + 1]; +#define GOLD_INDX 0 +#define GOLD_OFFSET 1 +#define OVRFLW_INDX (GOLD_OFFSET + 52) /* past gold and 2*26 letters */ + char lets[1 + 52 + 1 + 1]; /* room for '$a-zA-Z#\0' */ char qbuf[QBUFSZ]; - char allowall[3]; /* { ALLOW_COUNT, ALL_CLASSES, 0 } */ + char allowall[4]; /* { ALLOW_COUNT, ALL_CLASSES, 0, 0 } */ const char *adj_type; + boolean ever_mind = FALSE; if (!invent) { You("aren't carrying anything to adjust."); @@ -3555,6 +3561,20 @@ doorganize() /* inventory organizer by Del Lamb */ allowall[0] = ALLOW_COUNT; allowall[1] = ALL_CLASSES; allowall[2] = '\0'; + for (goldstacks = 0, otmp = invent; otmp; otmp = otmp->nobj) { + /* gold should never end up in a letter slot, nor should two '$' + slots occur, but if they ever do, allow #adjust to handle them + (in the past, things like this have happened, usually due to + bknown being erroneously set on one stack, clear on another; + object merger isn't fooled by that anymore) */ + if (otmp->oclass == COIN_CLASS + && (otmp->invlet != GOLD_SYM || ++goldstacks > 1)) { + allowall[1] = COIN_CLASS; + allowall[2] = ALL_CLASSES; + allowall[3] = '\0'; + break; + } + } if (!(obj = getobj(allowall, "adjust"))) return 0; @@ -3568,39 +3588,43 @@ doorganize() /* inventory organizer by Del Lamb */ } /* initialize the list with all lower and upper case letters */ - for (ix = 0, let = 'a'; let <= 'z';) - alphabet[ix++] = let++; + lets[GOLD_INDX] = (obj->oclass == COIN_CLASS) ? GOLD_SYM : ' '; + for (ix = GOLD_OFFSET, let = 'a'; let <= 'z';) + lets[ix++] = let++; for (let = 'A'; let <= 'Z';) - alphabet[ix++] = let++; - alphabet[ix] = '\0'; + lets[ix++] = let++; + lets[OVRFLW_INDX] = ' '; + lets[sizeof lets - 1] = '\0'; /* for floating inv letters, truncate list after the first open slot */ if (!flags.invlet_constant && (ix = inv_cnt(FALSE)) < 52) - alphabet[ix + (splitting ? 0 : 1)] = '\0'; + lets[ix + (splitting ? 0 : 1)] = '\0'; - /* blank out all the letters currently in use in the inventory */ - /* except those that will be merged with the selected object */ + /* blank out all the letters currently in use in the inventory + except those that will be merged with the selected object */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp != obj && !mergable(otmp, obj)) { let = otmp->invlet; if (let >= 'a' && let <= 'z') - alphabet[let - 'a'] = ' '; + lets[GOLD_OFFSET + let - 'a'] = ' '; else if (let >= 'A' && let <= 'Z') - alphabet[let - 'A' + 26] = ' '; + lets[GOLD_OFFSET + let - 'A' + 26] = ' '; + /* overflow defaults to off, but it we find a stack using that + slot, switch to on -- the opposite of normal invlet handling */ + else if (let == NOINVSYM) + lets[OVRFLW_INDX] = NOINVSYM; } /* compact the list by removing all the blanks */ - for (ix = cur = 0; alphabet[ix]; ix++) - if (alphabet[ix] != ' ') - buf[cur++] = alphabet[ix]; - if (!cur && obj->invlet == NOINVSYM) - buf[cur++] = NOINVSYM; - buf[cur] = '\0'; + for (ix = cur = 0; lets[ix]; ix++) + if (lets[ix] != ' ' && cur++ < ix) + lets[cur - 1] = lets[ix]; + lets[cur] = '\0'; /* and by dashing runs of letters */ if (cur > 5) - compactify(buf); + compactify(lets); /* get 'to' slot to use as destination */ - Sprintf(qbuf, "Adjust letter to what [%s]%s?", buf, + Sprintf(qbuf, "Adjust letter to what [%s]%s?", lets, invent ? " (? see used letters)" : ""); for (trycnt = 1; ; ++trycnt) { let = yn_function(qbuf, (char *) 0, '\0'); @@ -3619,10 +3643,19 @@ doorganize() /* inventory organizer by Del Lamb */ noadjust: if (splitting) (void) merged(&splitting, &obj); - pline1(Never_mind); + if (!ever_mind) + pline1(Never_mind); return 0; + } else if (let == GOLD_SYM && obj->oclass != COIN_CLASS) { + pline("Only gold coins may be moved into the '%c' slot.", + GOLD_SYM); + ever_mind = TRUE; + goto noadjust; } - if ((letter(let) && let != '@') || index(buf, let) && let != '-') + /* letter() classifies '@' as one; compactify() can put '-' in lets; + the only thing of interest that index() might find is '$' or '#' + since letter() catches everything else that we put into lets[] */ + if ((letter(let) && let != '@') || (index(lets, let) && let != '-')) break; /* got one */ if (trycnt == 5) goto noadjust;