From dc6827ce120e00c6f450b0223287de0d13877ad9 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 21 Jun 2016 17:32:02 -0700 Subject: [PATCH 01/15] more monkeys My old monkey patch was a bit more extensive than Pasi's, although it didn't originally include letting apes be tameable with bananas. No sense in throwing it away: 1) Make monkeys and apes be omnivores instead of carnivores. 2) Make bananas be preferred food for herbivore/omnivore subset of Y-class, so excludes carniverous ape, owlbear, and yeti. [Sasquatch remain omnivorous but aren't tameable with bananas.] 3) While updating befriend_with_food(), make horses be affected only by food they might eat, not by meat and corpses and tins. So they'll be somewhat harder to cope with for characters not strong enough to kill them. [Dogs and cats are unchanged.] Not included (not even implemented...): 0) Allow archeologists to choose monkey for starting pet. [The one in "Raiders of the Lost Ark" didn't actually belong to Indiana Jones but spent a lot of time accompanying him.] --- include/mondata.h | 16 ++++++++++++---- src/dog.c | 4 ++-- src/monst.c | 6 ++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/mondata.h b/include/mondata.h index 229617782..cdb299007 100644 --- a/include/mondata.h +++ b/include/mondata.h @@ -193,10 +193,18 @@ (vegan(ptr) \ || ((ptr)->mlet == S_PUDDING && (ptr) != &mons[PM_BLACK_PUDDING])) +/* monkeys are tameable via bananas but not pacifiable via food, + otherwise their theft attack could be nullified too easily; + dogs and cats can be tamed by anything they like to eat and are + pacified by any other food; + horses can be tamed by always-veggy food or lichen corpses but + not tamed or pacified by other corpses or tins of veggy critters */ #define befriend_with_obj(ptr, obj) \ - (((obj)->oclass == FOOD_CLASS && is_domestic(ptr)) \ - || ((obj)->otyp == BANANA && \ - ((ptr) == &mons[PM_MONKEY] \ - || (ptr) == &mons[PM_APE]))) + (((ptr) == &mons[PM_MONKEY] || (ptr) == &mons[PM_APE]) \ + ? (obj)->otyp == BANANA \ + : (is_domestic(ptr) && (obj)->oclass == FOOD_CLASS \ + && ((ptr)->mlet != S_UNICORN \ + || objects[(obj)->otyp].oc_material == VEGGY \ + || ((obj)->otyp == CORPSE && (obj)->corpsenm == PM_LICHEN)))) #endif /* MONDATA_H */ diff --git a/src/dog.c b/src/dog.c index f2993751d..0d55baad8 100644 --- a/src/dog.c +++ b/src/dog.c @@ -814,8 +814,8 @@ register struct obj *obj; case CARROT: return herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD; case BANANA: - return (mptr->mlet == S_YETI) - ? DOGFOOD + return (mptr->mlet == S_YETI && herbi) + ? DOGFOOD /* for monkey and ape (tameable), sasquatch */ : (herbi || starving) ? ACCFOOD : MANFOOD; diff --git a/src/monst.c b/src/monst.c index 7839b06cc..b99e44531 100644 --- a/src/monst.c +++ b/src/monst.c @@ -1915,16 +1915,18 @@ struct permonst _mons2[] = { /* * Apelike beasts */ + /* tameable via banana; does not grow up into ape... + not flagged as domestic, so no guilt penalty for eating non-pet one */ MON("monkey", S_YETI, LVL(2, 12, 6, 0, 0), (G_GENO | 1), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 50, MS_GROWL, MZ_SMALL), 0, 0, - M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY), + M1_ANIMAL | M1_HUMANOID | M1_OMNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY), MON("ape", S_YETI, LVL(4, 12, 6, 0, 0), (G_GENO | G_SGROUP | 2), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1100, 500, MS_GROWL, MZ_LARGE), 0, 0, - M1_ANIMAL | M1_HUMANOID | M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, + M1_ANIMAL | M1_HUMANOID | M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), MON("owlbear", S_YETI, LVL(5, 12, 5, 0, 0), (G_GENO | 3), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), From f32a9778b2bab1ca150a9db934cea7e643e9b4ef Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 22 Jun 2016 21:59:29 +0300 Subject: [PATCH 02/15] Unify mon throwing missile collision check --- src/mthrowu.c | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/mthrowu.c b/src/mthrowu.c index bff417325..a448ba8e6 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -414,6 +414,24 @@ boolean verbose; /* give message(s) even when you can't see what happened */ return 0; } +#define MT_FLIGHTCHECK(pre) \ + (/* missile hits edge of screen */ \ + !isok(bhitpos.x + dx, bhitpos.y + dy) \ + /* missile hits the wall */ \ + || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) \ + /* missile hit closed door */ \ + || closed_door(bhitpos.x + dx, bhitpos.y + dy) \ + /* missile might hit iron bars */ \ + /* the random chance for small objects hitting bars is */ \ + /* skipped when reaching them at point blank range */ \ + || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS \ + && hits_bars(&singleobj, \ + bhitpos.x, bhitpos.y, \ + bhitpos.x + dx, bhitpos.y + dy, \ + ((pre) ? 0 : !rn2(5)), 0)) \ + /* Thrown objects "sink" */ \ + || (!(pre) && IS_SINK(levl[bhitpos.x][bhitpos.y].typ))) + void m_throw(mon, x, y, dx, dy, range, obj) struct monst *mon; /* launching monster */ @@ -471,17 +489,7 @@ struct obj *obj; /* missile (or stack providing it) */ } } - /* pre-check for doors, walls and boundaries. - Also need to pre-check for bars regardless of direction; - the random chance for small objects hitting bars is - skipped when reaching them at point blank range */ - if (!isok(bhitpos.x + dx, bhitpos.y + dy) - || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) - || closed_door(bhitpos.x + dx, bhitpos.y + dy) - || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS - && hits_bars(&singleobj, - bhitpos.x, bhitpos.y, - bhitpos.x + dx, bhitpos.y + dy, 0, 0))) { + if (MT_FLIGHTCHECK(TRUE)) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } @@ -611,20 +619,7 @@ struct obj *obj; /* missile (or stack providing it) */ } } if (!range /* reached end of path */ - /* missile hits edge of screen */ - || !isok(bhitpos.x + dx, bhitpos.y + dy) - /* missile hits the wall */ - || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ) - /* missile hit closed door */ - || closed_door(bhitpos.x + dx, bhitpos.y + dy) - /* missile might hit iron bars */ - || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS - && hits_bars(&singleobj, - bhitpos.x, bhitpos.y, - bhitpos.x + dx, bhitpos.y + dy, - !rn2(5), 0)) - /* Thrown objects "sink" */ - || IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) { + || MT_FLIGHTCHECK(FALSE)) { if (singleobj) { /* hits_bars might have destroyed it */ if (m_shot.n > 1 && (cansee(bhitpos.x, bhitpos.y) || (archer && canseemon(archer)))) @@ -648,6 +643,8 @@ struct obj *obj; /* missile (or stack providing it) */ } } +#undef MT_FLIGHTCHECK + /* Monster throws item at another monster */ int thrwmm(mtmp, mtarg) From ce26d2616d63d8c0e75164f0ed4f8200ec0b8a3a Mon Sep 17 00:00:00 2001 From: keni Date: Wed, 22 Jun 2016 19:28:23 -0400 Subject: [PATCH 03/15] add docs for the cmdhelp conditionals --- src/pager.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/pager.c b/src/pager.c index 661cf04a5..b00c425a9 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1465114189 2016/06/05 08:09:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.107 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1466638086 2016/06/22 23:28:06 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.111 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1307,6 +1307,35 @@ doidtrap() return 0; } +/* + Implements a rudimentary if/elif/else/endif interpretor and use + conditionals in dat/cmdhelp to describe what command each keystroke + currently invokes, so that there isn't a lot of "(debug mode only)" + and "(if number_pad is off)" cluttering the feedback that the user + sees. (The conditionals add quite a bit of clutter to the raw data + but users don't see that. number_pad produces a lot of conditional + commands: basic letters vs digits, 'g' vs 'G' for '5', phone + keypad vs normal layout of digits, and QWERTZ keyboard swap between + y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.) + + The interpretor understands + '&#' for comment, + '&? option' for 'if' (also '&? !option' + or '&? option=value[,value2,...]' + or '&? !option=value[,value2,...]'), + '&: option' for 'elif' (with argument variations same as 'if'; + any number of instances for each 'if'), + '&:' for 'else' (also '&: #comment'; + 0 or 1 instance for a given 'if'), and + '&.' for 'endif' (also '&. #comment'; required for each 'if'). + + The option handling is a bit of a mess, with no generality for + which options to deal with and only a comma separated list of + integer values for the '=value' part. number_pad is the only + supported option that has a value; the few others (wizard/debug, + rest_on_space, #if SHELL, #if SUSPEND) are booleans. +*/ + STATIC_DCL void whatdoes_help() { From 5f35d4910530ea4bb75b87c3daa544717c566e8a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 23 Jun 2016 09:44:07 +0300 Subject: [PATCH 04/15] X11: Make statue tiles look like grayscale monsters --- sys/unix/Makefile.dat | 6 ++++-- win/X11/tile2x11.c | 11 +++++++++-- win/share/tile.doc | 4 +++- win/share/tile.h | 1 + win/share/tilemap.c | 2 +- win/share/tiletext.c | 21 +++++++++++++++++++++ 6 files changed, 39 insertions(+), 6 deletions(-) diff --git a/sys/unix/Makefile.dat b/sys/unix/Makefile.dat index f0566650c..535e7a808 100644 --- a/sys/unix/Makefile.dat +++ b/sys/unix/Makefile.dat @@ -31,9 +31,11 @@ all: $(VARDAT) spec_levs quest_levs dungeon (cd ../util ; $(MAKE) tile2bmp) x11tiles: ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ - ../win/share/other.txt + ../win/share/other.txt \ + ../win/share/monsters.txt ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ - ../win/share/other.txt + ../win/share/other.txt \ + -grayscale ../win/share/monsters.txt beostiles: ../util/tile2beos ../win/share/monsters.txt \ ../win/share/objects.txt \ diff --git a/win/X11/tile2x11.c b/win/X11/tile2x11.c index c9e410f46..8b7b455e1 100644 --- a/win/X11/tile2x11.c +++ b/win/X11/tile2x11.c @@ -177,7 +177,7 @@ char **argv; header.per_row = TILES_PER_ROW; if (argc == 1) { - Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]); + Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...] [-grayscale txt_fileN]\n", argv[0]); exit(1); } @@ -190,8 +190,15 @@ char **argv; /* don't leave garbage at end of partial row */ (void) memset((genericptr_t) tile_bytes, 0, sizeof(tile_bytes)); - for (i = 1; i < argc; i++) + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "-grayscale", 10)) { + set_grayscale(TRUE); + if (i < (argc - 1)) i++; + } else { + set_grayscale(FALSE); + } process_file(argv[i]); + } Fprintf(stderr, "Total tiles: %ld\n", header.ntiles); /* round size up to the end of the row */ diff --git a/win/share/tile.doc b/win/share/tile.doc index 8137f0f6e..1817982a7 100644 --- a/win/share/tile.doc +++ b/win/share/tile.doc @@ -57,8 +57,10 @@ boolean read_text_tile(pixel[TILE_Y][TILE_X]); boolean write_text_tile(pixel[TILE_Y][TILE_X]); writes tile -There are two additional shared routines provided for writers: +There are some additional shared routines provided for writers: +void set_grayscale(boolean g); + do grayscale color substitutions when reading the tile text file void init_colormap(); initialize the output colormap from the input one must be called before opening output file as colormap is part of header diff --git a/win/share/tile.h b/win/share/tile.h index 566cc386c..db4f124f1 100644 --- a/win/share/tile.h +++ b/win/share/tile.h @@ -35,6 +35,7 @@ extern boolean FDECL(read_text_tile, (pixel(*) [TILE_X])); extern boolean FDECL(write_text_tile, (pixel(*) [TILE_X])); extern int NDECL(fclose_text_file); +extern void FDECL(set_grayscale, (boolean)); extern void NDECL(init_colormap); extern void NDECL(merge_colormap); diff --git a/win/share/tilemap.c b/win/share/tilemap.c index f7acba0e8..cae25fdfb 100644 --- a/win/share/tilemap.c +++ b/win/share/tilemap.c @@ -21,7 +21,7 @@ extern void FDECL(exit, (int)); #endif #endif -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) || defined(WIN32) || defined(X11_GRAPHICS) #define STATUES_LOOK_LIKE_MONSTERS #endif diff --git a/win/share/tiletext.c b/win/share/tiletext.c index 5837ae422..fb6adb118 100644 --- a/win/share/tiletext.c +++ b/win/share/tiletext.c @@ -37,6 +37,20 @@ static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X])); "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ "(%d, %d, %d) " +static boolean grayscale = FALSE; +/* grayscale color mapping */ +static const int graymappings[] = { + /* . A B C D E F G H I J K L M N O P */ + 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14 +}; + +void +set_grayscale(g) +boolean g; +{ + grayscale = g; +} + static void read_text_colormap(txtfile) FILE *txtfile; @@ -135,6 +149,13 @@ pixel (*pixels)[TILE_X]; return FALSE; } k = color_index[(int) c[0]]; + if (grayscale) { + if (k > (SIZE(graymappings) - 1)) + Fprintf(stderr, "Gray mapping issue %d > %d.\n", k, + SIZE(graymappings) - 1); + else + k = graymappings[k]; + } if (k == -1) Fprintf(stderr, "color %c not in colormap!\n", c[0]); else { From 030e3c0dfd75b7ca98d401826c3a309fd3315a4c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 23 Jun 2016 10:15:55 +0300 Subject: [PATCH 05/15] Use the graymapping stuff in the tile lib --- win/share/tile2bmp.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/win/share/tile2bmp.c b/win/share/tile2bmp.c index 7a6c736a4..d0fb36333 100644 --- a/win/share/tile2bmp.c +++ b/win/share/tile2bmp.c @@ -237,6 +237,7 @@ char *argv[]; } initflag = 1; } + set_grayscale(pass == 3); /* printf("Colormap initialized\n"); */ while (read_text_tile(tilepixels)) { build_bmptile(tilepixels); @@ -327,11 +328,6 @@ BITMAPINFOHEADER *pbmih; pbmih->biClrImportant = (DWORD) 0; } -static int graymappings[] = { - /* . A B C D E F G H I J K L M N O P */ - 0, 1, 17, 18, 19, 20, 27, 22, 23, 24, 25, 26, 21, 15, 13, 14, 14 -}; - static void build_bmptile(pixels) pixel (*pixels)[TILE_X]; @@ -351,14 +347,6 @@ pixel (*pixels)[TILE_X]; Fprintf(stderr, "color not in colormap!\n"); y = (MAX_Y - 1) - (cur_y + yoffset); apply_color = cur_color; - if (pass == 3) { - /* map to shades of gray */ - if (cur_color > (SIZE(graymappings) - 1)) - Fprintf(stderr, "Gray mapping issue %d %d.\n", cur_color, - SIZE(graymappings) - 1); - else - apply_color = graymappings[cur_color]; - } #if BITCOUNT == 4 x = (cur_x / 2) + xoffset; bmp.packtile[y][x] = cur_x % 2 From 1f787c077bf7f4d60beec2bb2daaff29da7bf61c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jun 2016 06:19:45 -0700 Subject: [PATCH 06/15] tiles lint FDECL(foo, (boolean)) ought to have been using (BOOLEAN_P), but the tiles code isn't including the header which defines that, so change the argument to int. --- win/share/tile.h | 4 ++-- win/share/tiletext.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/win/share/tile.h b/win/share/tile.h index db4f124f1..7c01fb067 100644 --- a/win/share/tile.h +++ b/win/share/tile.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 tile.h $NHDT-Date: 1432512803 2015/05/25 00:13:23 $ $NHDT-Branch: master $:$NHDT-Revision: 1.10 $ */ +/* NetHack 3.6 tile.h $NHDT-Date: 1466687973 2016/06/23 13:19:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */ typedef unsigned char pixval; typedef struct pixel_s { @@ -35,7 +35,7 @@ extern boolean FDECL(read_text_tile, (pixel(*) [TILE_X])); extern boolean FDECL(write_text_tile, (pixel(*) [TILE_X])); extern int NDECL(fclose_text_file); -extern void FDECL(set_grayscale, (boolean)); +extern void FDECL(set_grayscale, (int)); extern void NDECL(init_colormap); extern void NDECL(merge_colormap); diff --git a/win/share/tiletext.c b/win/share/tiletext.c index fb6adb118..8d913f897 100644 --- a/win/share/tiletext.c +++ b/win/share/tiletext.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 tiletext.c $NHDT-Date: 1454464783 2016/02/03 01:59:43 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.12 $ */ +/* NetHack 3.6 tiletext.c $NHDT-Date: 1466687974 2016/06/23 13:19:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.14 $ */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" @@ -37,7 +37,7 @@ static void FDECL(write_txttile, (FILE *, pixel (*)[TILE_X])); "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.] = " \ "(%d, %d, %d) " -static boolean grayscale = FALSE; +static int grayscale = 0; /* grayscale color mapping */ static const int graymappings[] = { /* . A B C D E F G H I J K L M N O P */ @@ -46,7 +46,7 @@ static const int graymappings[] = { void set_grayscale(g) -boolean g; +int g; { grayscale = g; } From 02db340cd64df0d30f40b5ce92b2fe1f67d3610c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 23 Jun 2016 06:21:58 -0700 Subject: [PATCH 07/15] spell lint Mark an unused function argument as UNUSED. Also, hurtle_step is the recoil from throwing or kicking while levitating, which isn't related to the recently added spellcasting line-of-sight check, so rename spell_hurtle_step to spell_aim_step. --- src/spell.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/spell.c b/src/spell.c index 40969a62e..dba05de6c 100644 --- a/src/spell.c +++ b/src/spell.c @@ -43,7 +43,7 @@ STATIC_DCL int NDECL(throwspell); STATIC_DCL void NDECL(cast_protection); STATIC_DCL void FDECL(spell_backfire, (int)); STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); -STATIC_DCL boolean FDECL(spell_hurtle_step, (genericptr_t, int, int)); +STATIC_DCL boolean FDECL(spell_aim_step, (genericptr_t, int, int)); /* The roles[] table lists the role-specific values for tuning * percent_success(). @@ -1181,12 +1181,14 @@ boolean atme; return 1; } +/*ARGSUSED*/ STATIC_OVL boolean -spell_hurtle_step(arg, x, y) -genericptr_t arg; +spell_aim_step(arg, x, y) +genericptr_t arg UNUSED; int x, y; { - if (!isok(x,y)) return FALSE; + if (!isok(x,y)) + return FALSE; if (!ZAP_POS(levl[x][y].typ) && !(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_ISOPEN))) return FALSE; @@ -1233,7 +1235,7 @@ throwspell() uc.x = u.ux; uc.y = u.uy; - walk_path(&uc, &cc, spell_hurtle_step, NULL); + walk_path(&uc, &cc, spell_aim_step, (genericptr_t) 0); u.dx = cc.x; u.dy = cc.y; From eb1add85006b86f75c9c4d736bf9f86444004f85 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 24 Jun 2016 16:21:53 -0700 Subject: [PATCH 08/15] fix #H4407 - avoiding floor-food while blind Accept the 'm' prefix for eat, offer, and apply. Allows 'me' to eat from inventory without checking for floor food. Primarily for use after blind character used 'm' to move somewhere without touching a suspected cockatrice corpse there. 'm#offer' and 'ma' accomplish similar floor-object-skipping when offering a sacrifice or applying a tinning-kit. (All three commands share floorfood() to pick the item to use.) Report suggested replacing pick-from-floor followed by pick-from- invent with use of slash'em-style pick-from-invent with explicit pick-from-floor choice in list of inventory letters "[abc or ,]" (slash'em used period for 'here'; I've always liked comma better since the action is to pick an item rather than a location). I implemented that for nethack a long time ago, but it was mixed in with other stuff that wasn't ready for prime time and vanished when I lost access to the VMS system I used to use). Using 'm' prefix to skip part of a multi-part operation is a lot simpler to implement but doesn't include an in-game reminder that it is available. Revised Guidebook.mn is tested, Guidebook.tex is not. --- doc/Guidebook.mn | 21 +++++++++++++++++++-- doc/Guidebook.tex | 23 ++++++++++++++++++++--- src/cmd.c | 6 ++++++ src/eat.c | 4 +++- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index b76fa5a69..8b9f8e630 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -570,9 +570,21 @@ Figure 2 Go in that direction until you hit a wall or run into something. .lp m[yuhjklbn] Prefix: move without picking up objects or fighting (even if you remember -a monster there) +a monster there). +.lp "" +A few non-movement commands use the `m' prefix to request operating +via menu (to temporarily override the +.op menustyle:Traditional +option). +Primarily useful for `,' (pickup) when there is only one class of +objects present (where there won't be any ``what kinds of objects?'' prompt, +so no opportunity to answer `m' at that prompt). +.lp "" +A few other commands (eat food, offer sacrifice, apply tinning-kit) use +the `m' prefix to skip checking for applicable objects on the floor +and go straight to checking inventory. .lp F[yuhjklbn] -Prefix: fight a monster (even if you only guess one is there) +Prefix: fight a monster (even if you only guess one is there). .lp M[yuhjklbn] Prefix: move far, no pickup. .lp "g[yuhjklbn] @@ -640,6 +652,11 @@ D%u - drop only unpaid food. Kick something (usually a door). .lp e Eat food. +.lp "" +Normally checks for edible item(s) on the floor, then if none are found +or none are chosen, checks for edible item(s) in inventory. +Precede `e' with the `m' prefix to bypass attempting to eat +anything off the floor. .\" Make sure Elbereth is not hyphenated below, the exact spelling matters .hw Elbereth .lp E diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 54dc5a542..df4282d7e 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -690,10 +690,22 @@ Go in that direction until you hit a wall or run into something. %.lp \item[\tb{m[yuhjklbn]}] Prefix: move without picking up objects or fighting (even if you remember -a monster there) +a monster there).\\ +%.lp "" +A few non-movement commands use the `{\tt m}' prefix to request operating +via menu (to temporarily override the +{\it menustyle:Traditional\/} +option). +Primarily useful for `{\tt ,}' (pickup) when there is only one class of +objects present (where there won't be any ``what kinds of objects?'' prompt, +so no opportunity to answer `{\tt m}' at that prompt).\\ +%.lp "" +A few other commands (eat food, offer sacrifice, apply tinning-kit) use +the `{\tt m}' prefix to skip checking for applicable objects on the floor +and go straight to checking inventory. %.lp \item[\tb{F[yuhjklbn]}] -Prefix: fight a monster (even if you only guess one is there) +Prefix: fight a monster (even if you only guess one is there). %.lp \item[\tb{M[yuhjklbn]}] Prefix: Move far, no pickup. @@ -775,7 +787,12 @@ the bless\-ed/\-un\-curs\-ed/\-curs\-ed groups may be typed.\\ Kick something (usually a door). %.lp \item[\tb{e}] -Eat food. +Eat food.\\ +%.lp "" +Normally checks for edible item(s) on the floor, then if none are found +or none are chosen, checks for edible item(s) in inventory. +Precede `{\tt e}' with the `{\tt m}' prefix to bypass attempting to eat +anything off the floor. %.lp % Make sure Elbereth is not hyphenated below, the exact spelling matters. % (Only specified here to parallel Guidebook.mn; use of \tt font implicity diff --git a/src/cmd.c b/src/cmd.c index 4feb9bf94..5dfb3dbc7 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3445,11 +3445,17 @@ boolean initial; Cmd.move_SW = Cmd.dirchars[7]; } +/* non-movement commands which accept 'm' prefix to request menu operation */ STATIC_OVL boolean accept_menu_prefix(cmd_func) int NDECL((*cmd_func)); { if (cmd_func == dopickup || cmd_func == dotip + /* eat, #offer, and apply tinning-kit all use floorfood() to pick + an item on floor or in invent; 'm' skips picking from floor + (ie, inventory only) rather than request use of menu operation */ + || cmd_func == doeat || cmd_func == dosacrifice || cmd_func == doapply + /* 'm' prefix allowed for some extended commands */ || cmd_func == doextcmd || cmd_func == doextlist) return TRUE; return FALSE; diff --git a/src/eat.c b/src/eat.c index 5b8f08a8d..3b01dd8cf 100644 --- a/src/eat.c +++ b/src/eat.c @@ -2368,6 +2368,7 @@ doeat() if (u.uedibility) { int res = edibility_prompts(otmp); + if (res) { Your( "%s stops tingling and your sense of smell returns to normal.", @@ -2974,7 +2975,8 @@ int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ offering = !strcmp(verb, "sacrifice"); /* corpsecheck==1 */ /* if we can't touch floor objects then use invent food only */ - if (!can_reach_floor(TRUE) || (feeding && u.usteed) + if (iflags.menu_requested /* command was preceded by 'm' prefix */ + || !can_reach_floor(TRUE) || (feeding && u.usteed) || (is_pool_or_lava(u.ux, u.uy) && (Wwalking || is_clinger(youmonst.data) || (Flying && !Breathless)))) From 98a90e353b329281cb46f1eb92333f3e1b701fa0 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 25 Jun 2016 00:10:01 -0700 Subject: [PATCH 09/15] more #H4407 - #loot vs cockatrice corpse Previous fix was 'me' to eat from inventory without checking current location for edible items. The report describing the need for that also mentioned that you could #loot while blind and without gloves and not touch any objects except for the container you pick to loot. This adds a corpse touch check, plus `m#loot' to skip floor containers and go directly to using #loot for adjacent saddled creature. That, as well as the open command, will reveal adjacent container in some circumstances but I'm going to pretend that that doesn't matter. doloot() has turned into spaghetti. We should probably add #unsaddle or something of the sort and return #loot to container-access only. --- doc/Guidebook.mn | 18 +++++++++++++++--- doc/Guidebook.tex | 20 +++++++++++++++++--- src/cmd.c | 3 +++ src/pickup.c | 23 +++++++++++++++++++++-- 4 files changed, 56 insertions(+), 8 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 8b9f8e630..9e1a4c5c1 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -582,7 +582,9 @@ so no opportunity to answer `m' at that prompt). .lp "" A few other commands (eat food, offer sacrifice, apply tinning-kit) use the `m' prefix to skip checking for applicable objects on the floor -and go straight to checking inventory. +and go straight to checking inventory, +or (for ``#loot'' to remove a saddle), +skip containers and go straight to adjacent monsters. .lp F[yuhjklbn] Prefix: fight a monster (even if you only guess one is there). .lp M[yuhjklbn] @@ -945,6 +947,8 @@ Kick something. .lp #loot Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. +Precede with the `m' prefix to skip containers at your location +and go directly to removing a saddle. .lp #monster Use a monster's special ability (when polymorphed into monster form). .lp #name @@ -1303,13 +1307,21 @@ have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can -easily climb in and out of the saddle with the `#ride' command. Lead +easily climb in and out of the saddle with the ``#ride'' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. .pg -Riding skill is managed by the `#enhance' command. See the section +Riding skill is managed by the ``#enhance'' command. See the section on Weapon proficiency for more information about that. +.pg +Use the `a' (apply) command and pick a saddle in your inventory to +attempt to put that saddle on an adjacent creature. If successful, +it will be transferred to that creature's inventory. +.pg +Use the ``#loot'' command while adjacent to a saddled creature to +try to remove the saddle from that creature. If successful, it will +be transferred to your inventory. .hn 2 Bones levels .pg diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index df4282d7e..cca387b25 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -702,7 +702,9 @@ so no opportunity to answer `{\tt m}' at that prompt).\\ %.lp "" A few other commands (eat food, offer sacrifice, apply tinning-kit) use the `{\tt m}' prefix to skip checking for applicable objects on the floor -and go straight to checking inventory. +and go straight to checking inventory, +or (for ``{\tt \#loot}'' to remove a saddle), +skip containers and go straight to adjacent monsters. %.lp \item[\tb{F[yuhjklbn]}] Prefix: fight a monster (even if you only guess one is there). @@ -1136,6 +1138,8 @@ Kick something. \item[\tb{\#loot}] Loot a box or bag on the floor beneath you, or the saddle from a steed standing next to you. +Precede with the `{\tt m}' prefix to skip containers at your location +and go directly to removing a saddle. %.lp \item[\tb{\#monster}] Use a monster's special ability (when polymorphed into monster form). @@ -1591,15 +1595,25 @@ have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can -easily climb in and out of the saddle with the `{\tt \#ride}' command. Lead +easily climb in and out of the saddle with the ``{\tt \#ride}'' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. %.pg -Riding skill is managed by the `{\tt \#enhance}' command. See the section +Riding skill is managed by the ``{\tt \#enhance}'' command. See the section on Weapon proficiency for more information about that. +%.pg +Use the `{\tt a}' (apply) command and pick a saddle in your inventory to +attempt to put that saddle on an adjacent creature. If successful, +it will be transferred to that creature's inventory. + +%.pg +Use the ``{\tt \#loot}'' command while adjacent to a saddled creature to +try to remove the saddle from that creature. If successful, it will +be transferred to your inventory. + %.hn 2 \subsection*{Bones levels} diff --git a/src/cmd.c b/src/cmd.c index 5dfb3dbc7..13086a9c2 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3455,6 +3455,9 @@ int NDECL((*cmd_func)); an item on floor or in invent; 'm' skips picking from floor (ie, inventory only) rather than request use of menu operation */ || cmd_func == doeat || cmd_func == dosacrifice || cmd_func == doapply + /* 'm' for removing saddle from adjacent monster without checking + for containers at */ + || cmd_func == doloot /* 'm' prefix allowed for some extended commands */ || cmd_func == doextcmd || cmd_func == doextlist) return TRUE; diff --git a/src/pickup.c b/src/pickup.c index 9be8c809f..1fccc65d6 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -1630,7 +1630,7 @@ doloot() char qbuf[BUFSZ]; int prev_inquiry = 0; boolean prev_loot = FALSE; - int num_conts; + int num_conts = 0; abort_looting = FALSE; @@ -1653,13 +1653,30 @@ doloot() cc.x = u.ux; cc.y = u.uy; -lootcont: + if (iflags.menu_requested) + goto lootmon; + + lootcont: if ((num_conts = container_at(cc.x, cc.y, TRUE)) > 0) { boolean anyfound = FALSE; if (!able_to_loot(cc.x, cc.y, TRUE)) return 0; + if (Blind && !uarmg) { + /* if blind and without gloves, attempting to #loot at the + location of a cockatrice corpse is fatal before asking + whether to manipulate any containers */ + for (nobj = sobj_at(CORPSE, cc.x, cc.y); nobj; + nobj = nxtobj(nobj, CORPSE, TRUE)) + if (will_feel_cockatrice(nobj, FALSE)) { + feel_cockatrice(nobj, FALSE); + /* if life-saved (or poly'd into stone golem), + terminate attempt to loot */ + return 1; + } + } + if (num_conts > 1) { /* use a menu to loot many containers */ int n, i; @@ -1722,9 +1739,11 @@ lootcont: } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) { You("need to dig up the grave to effectively loot it..."); } + /* * 3.3.1 introduced directional looting for some things. */ + lootmon: if (c != 'y' && mon_beside(u.ux, u.uy)) { if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location", u.ux, u.uy, &cc)) From 66e7b840775d865f5af4391bc98012afbe208040 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 25 Jun 2016 14:59:52 -0700 Subject: [PATCH 10/15] flyers vs kelp Flying monsters that want to pick up items tend to get stuck above kelp fronds, particularly on the Medusa level. They're allowed to move to the water location, but can't reach an underwater item so end up doing nothing. --- doc/fixes36.1 | 1 + src/monmove.c | 14 ++++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index cb61f0231..e74e647e1 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -302,6 +302,7 @@ conduct: wishing for an artifact and not getting it because it already exists avoid ring of poison resistance as starting equipment for orcish wizard gelatinous cube shouldn't be able to eat a scroll of scare monster make fireballs or cones of cold cast a skilled or higher not go through walls +prevent flying monsters from hovering over unreachable underwater objects Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/monmove.c b/src/monmove.c index c703f2231..c032db504 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -979,15 +979,21 @@ not_special: * mpickstuff() as well. */ if (xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) { - /* don't get stuck circling around an object that's - underneath - an immobile or hidden monster; paralysis victims - excluded */ + /* don't get stuck circling around object that's + underneath an immobile or hidden monster; + paralysis victims excluded */ if ((mtoo = m_at(xx, yy)) != 0 && (mtoo->msleeping || mtoo->mundetected || (mtoo->mappearance && !mtoo->iswiz) || !mtoo->data->mmove)) continue; + /* the mfndpos() test for whether to allow a move to a + water location accepts flyers, but they can't reach + underwater objects, so being able to move to a spot + is insufficient for deciding whether to do so */ + if ((is_pool(xx, yy) && !is_swimmer(ptr)) + || (is_lava(xx, yy) && !likes_lava(ptr))) + continue; if (((likegold && otmp->oclass == COIN_CLASS) || (likeobjs && index(practical, otmp->oclass) From 2c32d69a23cfb0ebac42aadd31a48a8ea6d2a980 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Mon, 27 Jun 2016 12:03:34 +0300 Subject: [PATCH 11/15] Fixes entry --- doc/fixes36.1 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e74e647e1..a6040c18f 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -366,6 +366,7 @@ X11: support pre-selected entries in menu windows X11: make the extended command menu be easier to use and look a little nicer X11: make the getline text entry widget display a bigger text entry area X11: color didn't work when the map was displayed as text rather than tiles +X11: use grayscale monster tiles for statues General New Features From 6e56c796c90831aa24a7528568fbaa9e940db238 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 27 Jun 2016 04:56:06 -0700 Subject: [PATCH 12/15] fix #H4414 - orcs vs elven gear I considered several potential interactions for orcs with elven armor (and elves with orcish armor), such as longer wear/unwear delay, reduced AC, or reduced magic cancellation/negation. None of them seemed worth doing. In the end I just went with lembas wafer tweaks: new message when orc hero eats one, reduced nutrition for that combination, different new message when elf hero eats one, and increased nutrition for this combination. Also, less increased nutrition when a dwarf hero eats a cram ration. I'm not particularly happy with either of the new messages, and changing nutrition on the fly may lead to bugs. --- doc/fixes36.1 | 2 ++ src/eat.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a6040c18f..a7d320c31 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -303,6 +303,8 @@ avoid ring of poison resistance as starting equipment for orcish wizard gelatinous cube shouldn't be able to eat a scroll of scare monster make fireballs or cones of cold cast a skilled or higher not go through walls prevent flying monsters from hovering over unreachable underwater objects +lembas wafer gives increased nutrition to elves, reduced nutrition to orcs; + cram ration gives increase nutrition to dwarves Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/src/eat.c b/src/eat.c index 3b01dd8cf..52e29def5 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 eat.c $NHDT-Date: 1466289475 2016/06/18 22:37:55 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.169 $ */ +/* NetHack 3.6 eat.c $NHDT-Date: 1467028559 2016/06/27 11:55:59 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.171 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,6 +13,7 @@ STATIC_PTR int NDECL(unfaint); STATIC_DCL const char *FDECL(food_xname, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(choke, (struct obj *)); STATIC_DCL void NDECL(recalc_wt); +STATIC_DCL unsigned FDECL(obj_nutrition, (struct obj *)); STATIC_DCL struct obj *FDECL(touchfood, (struct obj *)); STATIC_DCL void NDECL(do_reset_eat); STATIC_DCL void FDECL(done_eating, (BOOLEAN_P)); @@ -296,6 +297,32 @@ reset_eat() return; } +/* base nutrition of a food-class object */ +STATIC_OVL unsigned +obj_nutrition(otmp) +struct obj *otmp; +{ + unsigned nut = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit + : otmp->globby ? otmp->owt + : (unsigned) objects[otmp->otyp].oc_nutrition; + + if (otmp->otyp == LEMBAS_WAFER) { + if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) + nut += nut / 4; /* 800 -> 1000 */ + else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) + nut -= nut / 4; /* 800 -> 600 */ + /* prevent polymorph making a partly eaten wafer + become more nutritious than an untouched one */ + if (otmp->oeaten >= nut) + otmp->oeaten = (otmp->oeaten < objects[LEMBAS_WAFER].oc_nutrition) + ? (nut - 1) : nut; + } else if (otmp->otyp == CRAM_RATION) { + if (maybe_polyd(is_dwarf(youmonst.data), Race_if(PM_DWARF))) + nut += nut / 6; /* 600 -> 700 */ + } + return nut; +} + STATIC_OVL struct obj * touchfood(otmp) struct obj *otmp; @@ -310,9 +337,7 @@ struct obj *otmp; if (!otmp->oeaten) { costly_alteration(otmp, COST_BITE); - otmp->oeaten = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit - : otmp->globby ? otmp->owt - : (unsigned) objects[otmp->otyp].oc_nutrition; + otmp->oeaten = obj_nutrition(otmp); } if (carried(otmp)) { @@ -1741,6 +1766,15 @@ struct obj *otmp; make_vomiting((long) rn1(context.victual.reqtime, 14), FALSE); } break; + case LEMBAS_WAFER: + if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) { + pline("%s", "!#?&* elf kibble!"); + break; + } else if (maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) { + pline("A little goes a long way."); + break; + } + goto give_feedback; case MEATBALL: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: @@ -2578,9 +2612,7 @@ doeat() } /* re-calc the nutrition */ - basenutrit = (otmp->otyp == CORPSE) ? mons[otmp->corpsenm].cnutrit - : otmp->globby ? otmp->owt - : (unsigned) objects[otmp->otyp].oc_nutrition; + basenutrit = (int) obj_nutrition(otmp); debugpline3( "before rounddiv: victual.reqtime == %d, oeaten == %d, basenutrit == %d", @@ -3087,10 +3119,9 @@ struct obj *obj; { long uneaten_amt, full_amount; + /* get full_amount first; obj_nutrition() might modify obj->oeaten */ + full_amount = (long) obj_nutrition(obj); uneaten_amt = (long) obj->oeaten; - full_amount = (long) ((obj->otyp == CORPSE) ? mons[obj->corpsenm].cnutrit - : obj->globby ? obj->owt - : (unsigned) objects[obj->otyp].oc_nutrition); if (uneaten_amt > full_amount) { impossible( "partly eaten food (%ld) more nutritious than untouched food (%ld)", From 805f7c5644fc816a2f82e1e521a1daa189fd9311 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 27 Jun 2016 17:20:28 -0700 Subject: [PATCH 13/15] fix #H4418/#H4419 - #tip of gold inside shops The #tip command tries to reduce verbosity by formatting drop messages with just the object name instead of with full sentences, yielding Objects spill out: obj1, obj2, obj3, ..., objN. where the trailing comma or period is included with each successive object. If an intervening message occurs, such "25 zorkmids are added to your credit", the rest of the objects will no longer be extending the original sentence and end up looking silly. Objects spill out: obj1, obj2,--More-- 25 zorkmids are added to your credit. obj3, ..., objN. This fix causes the post-interruption messages to revert to verbose format. Objects spill out: obj1, obj2,--More-- 25 zorkmids are added to your credit.--More-- obj3 drops to the floor.--More-- ... objN drops to the floor. The interrupting message still follows the comma of the partial sentence, but I don't see any sane way to fix that other than to abandon the terse format altogether, and doing that makes #tip way too verbose when the container has a lot of items in it. But #tip inside shops now does that, since there will always be buy/not- interested feedback interrupting the terse format in that situation. For other situations, a full sentence message might end up following a partial sentence list of dropped items. There was a more significant bug. Dropping a hero-owned container with gold in it onto shop floor sold the gold to shk, giving hero credit. Subsequent #tip gave the hero credit for that same gold when it spilled out. addtobill(obj) relies on obj->ox,oy to determine whether events are taking place in a shop, and #tip was relying on placement onto floor to set those, too late for shop billing. The fix yields suboptimal results: you're given credit when you drop the container, then during #tip when you spill the contents, credit for the gold is removed, then new credit for it is given. That's down to shop insanity, not tipping behavior. --- doc/fixes36.1 | 7 ++++++ include/flag.h | 1 + src/pickup.c | 58 +++++++++++++++++++++++++++++++++----------------- src/shk.c | 7 +++--- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index a7d320c31..3b8bd6ca1 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -305,6 +305,13 @@ make fireballs or cones of cold cast a skilled or higher not go through walls prevent flying monsters from hovering over unreachable underwater objects lembas wafer gives increased nutrition to elves, reduced nutrition to orcs; cram ration gives increase nutrition to dwarves +when #tip's terse object drop format got interrupted by a regular message, + it continued using "obj2, obj3, ..." for subsequent objects, where + the sentence grammar no longer made sense (the interrupting message + still follows the comma of a partial sentence--attempting to fix that + seems hopeless; leaving it is better than always using verbose format) +for #tip inside shop, credit was incorrectly given for spilled gold if that + gold's stale location coordinates didn't happen to be inside the shop Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository diff --git a/include/flag.h b/include/flag.h index a8a6d8593..55a544471 100644 --- a/include/flag.h +++ b/include/flag.h @@ -382,6 +382,7 @@ extern NEARDATA struct instance_flags iflags; #define PLNMSG_TOWER_OF_FLAME 2 /* scroll of fire */ #define PLNMSG_CAUGHT_IN_EXPLOSION 3 /* explode() feedback */ #define PLNMSG_OBJ_GLOWS 4 /* "the glows " */ +#define PLNMSG_OBJNAM_ONLY 5 /* xname/doname only, for #tip */ /* Usage: * pline("some message"); * pline: vsprintf + putstr + iflags.last_msg = PLNMSG_UNKNOWN; diff --git a/src/pickup.c b/src/pickup.c index 1fccc65d6..0f8b5b5d4 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -2902,20 +2902,27 @@ tipcontainer(box) struct obj *box; /* or bag */ { xchar ox = u.ux, oy = u.uy; /* #tip only works at hero's location */ - boolean empty_it = FALSE, - /* Shop handling: can't rely on the container's own unpaid - or no_charge status because contents might differ with it. - A carried container's contents will be flagged as unpaid - or not, as appropriate, and need no special handling here. - Items owned by the hero get sold to the shop without - confirmation as with other uncontrolled drops. A floor - container's contents will be marked no_charge if owned by - hero, otherwise they're owned by the shop. By passing - the contents through shop billing, they end up getting - treated the same as in the carried case. We do so one - item at a time instead of doing whole container at once - to reduce the chance of exhausting shk's billing capacity. */ - maybeshopgoods = !carried(box) && costly_spot(ox, oy); + boolean empty_it = FALSE, maybeshopgoods; + + /* box is either held or on floor at hero's spot; no need to check for + nesting; when held, we need to update its location to match hero's; + for floor, the coordinate updating is redundant */ + if (get_obj_location(box, &ox, &oy, 0)) + box->ox = ox, box->oy = oy; + + /* Shop handling: can't rely on the container's own unpaid + or no_charge status because contents might differ with it. + A carried container's contents will be flagged as unpaid + or not, as appropriate, and need no special handling here. + Items owned by the hero get sold to the shop without + confirmation as with other uncontrolled drops. A floor + container's contents will be marked no_charge if owned by + hero, otherwise they're owned by the shop. By passing + the contents through shop billing, they end up getting + treated the same as in the carried case. We do so one + item at a time instead of doing whole container at once + to reduce the chance of exhausting shk's billing capacity. */ + maybeshopgoods = !carried(box) && costly_spot(box->ox, box->oy); /* caveat: this assumes that cknown, lknown, olocked, and otrapped fields haven't been overloaded to mean something special for the @@ -2978,7 +2985,7 @@ struct obj *box; /* or bag */ if (empty_it) { struct obj *otmp, *nobj; - boolean verbose = FALSE, highdrop = !can_reach_floor(TRUE), + boolean terse, highdrop = !can_reach_floor(TRUE), altarizing = IS_ALTAR(levl[ox][oy].typ), cursed_mbag = (Is_mbag(box) && box->cursed); int held = carried(box); @@ -2986,20 +2993,27 @@ struct obj *box; /* or bag */ if (u.uswallow) highdrop = altarizing = FALSE; + terse = !(highdrop || altarizing || costly_spot(box->ox, box->oy)); box->cknown = 1; + /* Terse formatting is + * "Objects spill out: obj1, obj2, obj3, ..., objN." + * If any other messages intervene between objects, we revert to + * "ObjK drops to the floor.", "ObjL drops to the floor.", &c. + */ pline("%s out%c", box->cobj->nobj ? "Objects spill" : "An object spills", - !(highdrop || altarizing) ? ':' : '.'); + terse ? ':' : '.'); for (otmp = box->cobj; otmp; otmp = nobj) { nobj = otmp->nobj; obj_extract_self(otmp); + otmp->ox = box->ox, otmp->oy = box->oy; if (box->otyp == ICE_BOX) { removed_from_icebox(otmp); /* resume rotting for corpse */ } else if (cursed_mbag && !rn2(13)) { loss += mbag_item_gone(held, otmp); /* abbreviated drop format is no longer appropriate */ - verbose = TRUE; + terse = FALSE; continue; } @@ -3012,14 +3026,18 @@ struct obj *box; /* or bag */ /* might break or fall down stairs; handles altars itself */ hitfloor(otmp); } else { - if (altarizing) + if (altarizing) { doaltarobj(otmp); - else if (verbose) + } else if (!terse) { pline("%s %s to the %s.", Doname2(otmp), otense(otmp, "drop"), surface(ox, oy)); - else + } else { pline("%s%c", doname(otmp), nobj ? ',' : '.'); + iflags.last_msg = PLNMSG_OBJNAM_ONLY; + } dropy(otmp); + if (iflags.last_msg != PLNMSG_OBJNAM_ONLY) + terse = FALSE; /* terse formatting has been interrupted */ } if (maybeshopgoods) iflags.suppress_price--; /* reset */ diff --git a/src/shk.c b/src/shk.c index 586f5de6e..a914a56d7 100644 --- a/src/shk.c +++ b/src/shk.c @@ -2130,9 +2130,10 @@ boolean unpaid_only; return price; } +/* count amount of gold inside container 'obj' and any nested containers */ long contained_gold(obj) -register struct obj *obj; +struct obj *obj; { register struct obj *otmp; register long value = 0L; @@ -2867,12 +2868,12 @@ xchar x, y; boolean isgold = (obj->oclass == COIN_CLASS); boolean only_partially_your_contents = FALSE; + if (!*u.ushops) /* do cheapest exclusion test first */ + return; if (!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp)) return; if (!costly_spot(x, y)) return; - if (!*u.ushops) - return; if (obj->unpaid && !container && !isgold) { sub_one_frombill(obj, shkp); From cb0f508f1cca86cf6fed97c8604b9759ebded2f7 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 29 Jun 2016 18:55:02 -0700 Subject: [PATCH 14/15] tty message history line-wrapping fix Reported directly to devteam last October, for 3.4.3 on NAO, subject "UI flaw in message history": "Applying the stethoscope at self informs: "Status of Xxxxxxxx (piously neutral): Level 14 HP 138(138) AC -15, very "fast, invisible.--More-- This is reproducible with shorter character name "wizard" by being "nominally neutral" or "nominally chaotic". I had a 2 digit level but didn't notice that my AC took up only 1 digit and ended up using 125ish blessed potions of full healing to get 4 digits of hit points in order to get the line to wrap between "very" and "fast". "But the message history with Ctrl-P shows: "Message History " "Status of Xxxxxxxx (piously neutral): Level 14 HP 138(138) AC -15, very "invisible. The key was "Message History", indicating msg_window:full or other setting which causes ^P to bypass the top line message window and use a general text window to deliver all history lines at once. The original feedback splits the line by replacing the space between "very" and "fast" with a newline, which topline handling notices and processes as special, but then leaves in place. msg_window:full results in tty_putstr() case NHW_TEXT, which treats newline as an ordinary character since it doesn't expect to see that in text. Squeezing out three doubled spaces made room for "very\nfast," on the top line. process_text_window() attempted to write it there, but putchar() wrote up through "very," on one line, then output the newline which resulted in "fast," on the next line. Then explicit cursor positioning set things up to put "invisible" at the start of that line, overwriting "fast," so making it appear to be missing. --- doc/fixes36.1 | 2 ++ win/tty/topl.c | 17 ++++++++--------- win/tty/wintty.c | 35 ++++++++++++++++++++--------------- 3 files changed, 30 insertions(+), 24 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 3b8bd6ca1..90b9a6a8a 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -347,6 +347,8 @@ tty: if color is disabled and use_inverse is enabled, display lava in inverse tty: if "--More--" was written to leftmost column (beginning of second line) while hero was swallowed, cursor would end up in wrong place (at end of status line instead back on map) after message line was cleared +tty: long message lines which wrap when shown on the top line might be + re-displayed incorrectly by ^P for msg_window={full,combo,reverse} unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) unix: options file with CR+LF line ends and an invalid option line resulted in diff --git a/win/tty/topl.c b/win/tty/topl.c index 4c857cb81..dd6758a4e 100644 --- a/win/tty/topl.c +++ b/win/tty/topl.c @@ -8,7 +8,6 @@ #include "tcap.h" #include "wintty.h" -#include #ifndef C /* this matches src/cmd.c */ #define C(c) (0x1f & (c)) @@ -48,8 +47,7 @@ tty_doprev_message() do { morc = 0; if (cw->maxcol == cw->maxrow) { - ttyDisplay->dismiss_more = - C('p'); /* allowed at --More-- */ + ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */ redotoplin(toplines); cw->maxcol--; if (cw->maxcol < 0) @@ -57,8 +55,7 @@ tty_doprev_message() if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else if (cw->maxcol == (cw->maxrow - 1)) { - ttyDisplay->dismiss_more = - C('p'); /* allowed at --More-- */ + ttyDisplay->dismiss_more = C('p'); /* ^P ok at --More-- */ redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) @@ -130,6 +127,7 @@ redotoplin(str) const char *str; { int otoplin = ttyDisplay->toplin; + home(); if (*str & 0x80) { /* kludge for the / command, the only time we ever want a */ @@ -251,10 +249,11 @@ register const char *bp; (void) strncpy(toplines, bp, TBUFSZ); toplines[TBUFSZ - 1] = 0; - for (tl = toplines; n0 >= CO;) { + for (tl = toplines; n0 >= CO; ) { otl = tl; - for (tl += CO - 1; tl != otl && !isspace(*tl); --tl) - ; + for (tl += CO - 1; tl != otl; --tl) + if (*tl == ' ') + break; if (tl == otl) { /* Eek! A huge token. Try splitting after it. */ tl = index(otl, ' '); @@ -299,7 +298,7 @@ char c; break; default: if (ttyDisplay->curx == CO - 1) - topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */ + topl_putsym('\n'); /* 1 <= curx < CO; avoid CO */ #ifdef WIN32CON (void) putchar(c); #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 8ceb1dc4e..e38e3e7c8 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -2443,22 +2443,27 @@ compress_str(str) const char *str; { static char cbuf[BUFSZ]; - /* compress in case line too long */ - if ((int) strlen(str) >= CO) { - register const char *bp0 = str; - register char *bp1 = cbuf; + /* compress out consecutive spaces if line is too long; + topline wrapping converts space at wrap point into newline, + we reverse that here */ + if ((int) strlen(str) >= CO || index(str, '\n')) { + register const char *bp0 = str; + char c, nxtc, *bp1 = cbuf, *endbp1 = &cbuf[sizeof cbuf - 1]; + + cbuf[0] = cbuf[sizeof cbuf - 1] = '\0'; /* superfluous */ + nxtc = (*bp0 == '\n') ? ' ' : *bp0; do { -#ifdef CLIPPING - if (*bp0 != ' ' || bp0[1] != ' ') -#else - if (*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ') -#endif - *bp1++ = *bp0; - } while (*bp0++); - } else - return str; - return cbuf; + c = nxtc; + nxtc = bp0[1]; + if (nxtc == '\n') + nxtc = ' '; + if (c != ' ' || nxtc != ' ') + *bp1++ = c; + } while (*bp0++ && bp1 < endbp1); + str = cbuf; + } + return str; } void @@ -2601,7 +2606,7 @@ const char *str; } if (cw->data[cw->cury]) free((genericptr_t) cw->data[cw->cury]); - n0 = strlen(str) + 1; + n0 = (long) strlen(str) + 1L; ob = cw->data[cw->cury] = (char *) alloc((unsigned) n0 + 1); *ob++ = (char) (attr + 1); /* avoid nuls, for convenience */ Strcpy(ob, str); From 9f89c0792ce23ad9fab52cff9d91f14f4292f9ce Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 30 Jun 2016 06:03:51 -0700 Subject: [PATCH 15/15] fix #H3907 - wrinkled spellbook tile Reported 11 months ago for 3.4.3, the tile for wrinkled spellbook has a spurious brown spot on the far right. Several other books have spots drawn outside the book proper for tile decoration, but that doesn't seem to apply here. The report suggested changing 'K' to 'M', but that just changes it into a spurious white spot. Change the stray 'K' to '.' to make the odd spot go away. --- doc/fixes36.1 | 1 + win/share/objects.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 90b9a6a8a..605268883 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -332,6 +332,7 @@ when picking a destination for #jump, '$' to show valid dest. is more accurate Platform- and/or Interface-Specific Fixes ----------------------------------------- +tiles: wrinkled spellbook had a spurious brown pixel on far right edge of tile tty: M-N gave "Unknown command 'M-" with "'." finishing the sentence on the line below it, leaving bogus '.' displayed on the top row of the map tty: specifying all four of role, race, gender, and alignment still prompted diff --git a/win/share/objects.txt b/win/share/objects.txt index 996c59198..15c6181e8 100644 --- a/win/share/objects.txt +++ b/win/share/objects.txt @@ -7108,7 +7108,7 @@ Z = (195, 195, 195) ..KKAKKAAKKKOAA. .JKKKAAAKKKOKA.. .KKKKKKKKKLOAA.. - .KOOLKKKKKOKA..K + .KOOLKKKKKOKA... ..JKOOKKKKOAA... ....JKLOOOKA.... ......JJKKAA....