From e92b80b2ab86398f31598d1b2bef5bdc5a9ac0a1 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 00:52:51 +0200 Subject: [PATCH 01/32] Requiver pickup_thrown objects if quiver is empty Change via Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/invent.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 51e27e78d..ec5d44b9e 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -83,6 +83,7 @@ fix "killing by kicking something weird" when kicking an object causes death guard macros available for mextra fields similar to those for oextra fields compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting +requiver pickup_thrown objects if quiver is empty Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index 3f0c15b85..1e220bbc4 100644 --- a/src/invent.c +++ b/src/invent.c @@ -434,6 +434,7 @@ struct obj *obj; { struct obj *otmp, *prev; int saved_otyp = (int) obj->otyp; /* for panic */ + boolean obj_was_thrown; if (obj->where != OBJ_FREE) panic("addinv: obj not free"); @@ -442,6 +443,7 @@ struct obj *obj; obj->no_charge = 0; /* should not be set in hero's invent */ if (Has_contents(obj)) picked_container(obj); /* clear no_charge */ + obj_was_thrown = obj->was_thrown; obj->was_thrown = 0; /* not meaningful for invent */ addinv_core1(obj); @@ -476,6 +478,9 @@ struct obj *obj; } obj->where = OBJ_INVENT; + /* fill empty quiver if obj was thrown */ + if (flags.pickup_thrown && !uquiver && obj_was_thrown) + setuqwep(obj); added: addinv_core2(obj); carry_obj_effects(obj); /* carrying affects the obj */ From a049cd070b60879a97b3334438593542b0fe9085 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:04:56 +0200 Subject: [PATCH 02/32] Never route a travel path through boulders in Sokoban Change via Dynahack by Tung Nguyen --- src/hack.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hack.c b/src/hack.c index 3f6514678..6305ad1e7 100644 --- a/src/hack.c +++ b/src/hack.c @@ -827,6 +827,9 @@ int mode; } else if (mode == TEST_TRAV) { struct obj *obj; + /* never travel through boulders in Sokoban */ + if (Sokoban) return FALSE; + /* don't pick two boulders in a row, unless there's a way thru */ if (sobj_at(BOULDER, ux, uy) && !Sokoban) { if (!Passes_walls From db4120012dd4e18fa3402716cd671df5af24ad62 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:44:18 +0200 Subject: [PATCH 03/32] Make mimics mimicing walls or trees also block light --- doc/fixes36.1 | 1 + include/monst.h | 10 ++++++++++ src/display.c | 3 +-- src/mon.c | 3 +-- src/vision.c | 4 ++-- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ec5d44b9e..b44ce9f4b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -84,6 +84,7 @@ guard macros available for mextra fields similar to those for oextra fields compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting requiver pickup_thrown objects if quiver is empty +make mimics mimicing walls or trees also block light Platform- and/or Interface-Specific Fixes diff --git a/include/monst.h b/include/monst.h index 3c88d0172..7196026f9 100644 --- a/include/monst.h +++ b/include/monst.h @@ -159,6 +159,16 @@ struct monst { #define is_vampshifter(mon) \ ((mon)->cham == PM_VAMPIRE || (mon)->cham == PM_VAMPIRE_LORD \ || (mon)->cham == PM_VLAD_THE_IMPALER) + +/* mimic appearances that block vision/light */ +#define is_lightblocker_mappear(mon) \ + (is_obj_mappear(mon, BOULDER) || \ + ((mon)->m_ap_type == M_AP_FURNITURE \ + && ((mon)->mappearance == S_hcdoor \ + || (mon)->mappearance == S_vcdoor \ + || (mon)->mappearance < S_ndoor /* = walls */ \ + || (mon)->mappearance == S_tree))) + #define is_door_mappear(mon) ((mon)->m_ap_type == M_AP_FURNITURE \ && ((mon)->mappearance == S_hcdoor || (mon)->mappearance == S_vcdoor)) #define is_obj_mappear(mon,otyp) ((mon)->m_ap_type == M_AP_OBJECT \ diff --git a/src/display.c b/src/display.c index e75f74d53..333ed4d5b 100644 --- a/src/display.c +++ b/src/display.c @@ -1201,8 +1201,7 @@ set_mimic_blocking() for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; - if (mon->minvis && (is_door_mappear(mon) - || is_obj_mappear(mon,BOULDER))) { + if (mon->minvis && is_lightblocker_mappear(mon)) { if (See_invisible) block_point(mon->mx, mon->my); else diff --git a/src/mon.c b/src/mon.c index 40cdb0dca..3c272cbc7 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2616,8 +2616,7 @@ void seemimic(mtmp) register struct monst *mtmp; { - boolean is_blocker_appear = (is_door_mappear(mtmp) - || is_obj_mappear(mtmp, BOULDER)); + boolean is_blocker_appear = (is_lightblocker_mappear(mtmp)); if (has_mcorpsenm(mtmp)) freemcorpsenm(mtmp); diff --git a/src/vision.c b/src/vision.c index 77475af96..2dcc85b8b 100644 --- a/src/vision.c +++ b/src/vision.c @@ -175,9 +175,9 @@ register struct rm *lev; if (obj->otyp == BOULDER) return 1; - /* Mimics mimicing a door or boulder block light. */ + /* Mimics mimicing a door or boulder or ... block light. */ if ((mon = m_at(x, y)) && (!mon->minvis || See_invisible) - && (is_door_mappear(mon) || is_obj_mappear(mon,BOULDER))) + && is_lightblocker_mappear(mon)) return 1; return 0; From fd709d68400621439b8fa6ec1fbd3a2f4fbdd17b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 01:53:44 +0200 Subject: [PATCH 04/32] Clear mimic vision blocking after genocide Fix via Dynahack by Tung Nguyen --- src/mon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mon.c b/src/mon.c index 3c272cbc7..08333c250 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1653,6 +1653,8 @@ struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ remove_monster(mtmp->mx, mtmp->my); if (emits_light(mptr)) del_light_source(LS_MONSTER, monst_to_any(mtmp)); + if (mtmp->m_ap_type) + seemimic(mtmp); newsym(mtmp->mx, mtmp->my); unstuck(mtmp); fill_pit(mtmp->mx, mtmp->my); From d598cf536b05b7238f3f61ed18a63af34dcee1a2 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 16:17:38 -0800 Subject: [PATCH 05/32] fix #H4179 - lava vs boots Stepping onto lava destroyed water walking boots if they weren't fireproof but didn't do that for other types of boots unless hero was not fire resistant and got killed by the lava. Burn up all non-fireproof leather boots when stepping onto lava. --- doc/fixes36.1 | 2 ++ src/trap.c | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index b44ce9f4b..436a270b9 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -85,6 +85,8 @@ compile-time option for an alternate paniclog format for public server use make monsters forget where they stepped when fleeing or teleporting requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light +stepping onto lava destroyed non-fireproof water walking boots but left other + vulnerable boot types intact Platform- and/or Interface-Specific Fixes diff --git a/src/trap.c b/src/trap.c index b5cda7a5b..7f9a1ea7d 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 trap.c $NHDT-Date: 1451176031 2015/12/27 00:27:11 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.252 $ */ +/* NetHack 3.6 trap.c $NHDT-Date: 1452039453 2016/01/06 00:17:33 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.253 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4999,13 +4999,13 @@ lava_effects() && objects[obj->otyp].oc_oprop != FIRE_RES && obj->otyp != SCR_FIRE && obj->otyp != SPE_FIREBALL && !obj_resists(obj, 0, 0)) /* for invocation items */ - obj->in_use = TRUE; + obj->in_use = 1; /* Check whether we should burn away boots *first* so we know whether to * make the player sink into the lava. Assumption: water walking only * comes from boots. */ - if (Wwalking && uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { + if (uarmf && is_organic(uarmf) && !uarmf->oerodeproof) { obj = uarmf; pline("%s into flame!", Yobjnam2(obj, "burst")); iflags.in_lava_effects++; /* (see above) */ @@ -5119,6 +5119,9 @@ sink_into_lava() You("sink below the surface and die."); burn_away_slime(); /* add insult to injury? */ done(DISSOLVED); + /* can only get here via life-saving; try to get away from lava */ + u.utrap = 0; + (void) safe_teleds(TRUE); } else if (!u.umoved) { /* can't fully turn into slime while in lava, but might not have it be burned away until you've come awfully close */ From 2c9ae20c5a99e498514336e94d9f22f227a43640 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:04:13 +0200 Subject: [PATCH 06/32] Allow quickly moving cursor on monsters Original patch was mine, but this implementation took ideas from Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/do_name.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 436a270b9..16f77f7e7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -87,6 +87,7 @@ requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact +allow moving cursor to monsters with 'm' and 'M' when asked for map location Platform- and/or Interface-Specific Fixes diff --git a/src/do_name.c b/src/do_name.c index 889609034..5e5675b98 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -55,6 +55,7 @@ const char *goal; putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); + putstr(tmpwin, 0, "Use m or M to move the cursor on monster."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -71,6 +72,25 @@ const char *goal; destroy_nhwindow(tmpwin); } +static int +cmp_coord_distu(a, b) +const void *a; +const void *b; +{ + const coord *c1 = a; + const coord *c2 = b; + int dx, dy, dist1, dist2; + + dx = u.ux - c1->x; + dy = u.uy - c1->y; + dist1 = dx * dx + dy * dy; + dx = u.ux - c2->x; + dy = u.uy - c2->y; + dist2 = dx * dx + dy * dy; + + return dist1 - dist2; +} + int getpos(ccp, force, goal) coord *ccp; @@ -85,6 +105,9 @@ const char *goal; static const char pick_chars[] = ".,;:"; const char *cp; boolean hilite_state = FALSE; + coord *monarr = NULL; + int moncount = 0; + int monidx = 0; if (!goal) goal = "desired location"; @@ -217,6 +240,43 @@ const char *goal; cx = u.ux; cy = u.uy; goto nxtc; + } else if (c == 'm' || c == 'M') { + if (!monarr) { + moncount = 0; + monidx = 0; + struct monst *mtmp = fmon; + while (mtmp) { + if (canspotmon(mtmp) + && (mtmp->mx != u.ux && mtmp->my != u.uy)) + moncount++; + mtmp = mtmp->nmon; + } + monarr = (coord *)alloc(sizeof(coord) * moncount); + mtmp = fmon; + while (mtmp) { + if (canspotmon(mtmp) + && (mtmp->mx != u.ux && mtmp->my != u.uy)) { + monarr[monidx].x = mtmp->mx; + monarr[monidx].y = mtmp->my; + monidx++; + } + mtmp = mtmp->nmon; + } + qsort(monarr, moncount, sizeof(coord), cmp_coord_distu); + /* ready this for first increment/decrement to change to zero */ + monidx = (c == 'm') ? -1 : 1; + } + if (moncount) { + if (c == 'm') + monidx = (monidx + 1) % moncount; + else { + monidx--; + if (monidx < 0) monidx = moncount-1; + } + cx = monarr[monidx].x; + cy = monarr[monidx].y; + goto nxtc; + } } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; @@ -307,6 +367,8 @@ const char *goal; clear_nhwindow(WIN_MESSAGE); ccp->x = cx; ccp->y = cy; + if (monarr) + free(monarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; } From 31f883da0da89b3cf72455192cb71256f17d0ca6 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:17:32 +0200 Subject: [PATCH 07/32] Use appropriate place description for drum of earthquake shake Fix via Dynahack by Tung Nguyen --- src/music.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/music.c b/src/music.c index 89ff06127..73b855bc1 100644 --- a/src/music.c +++ b/src/music.c @@ -426,6 +426,23 @@ int force; } } +const char * +generic_lvl_desc() +{ + if (Is_astralevel(&u.uz)) + return "astral plane"; + else if (In_endgame(&u.uz)) + return "plane"; + else if (Is_sanctum(&u.uz)) + return "sanctum"; + else if (In_sokoban(&u.uz)) + return "puzzle"; + else if (In_V_tower(&u.uz)) + return "tower"; + else + return "dungeon"; +} + /* * The player is trying to extract something from his/her instrument. */ @@ -537,7 +554,8 @@ struct obj *instr; consume_obj_charge(instr, TRUE); You("produce a heavy, thunderous rolling!"); - pline_The("entire dungeon is shaking around you!"); + pline_The("entire %s is shaking around you!", + generic_lvl_desc()); do_earthquake((u.ulevel - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(ROWNO * COLNO); From ed1c592a9ae062d8b0398c2b09f9e1889d367bfa Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:23:24 +0200 Subject: [PATCH 08/32] Remove double defines of hunger states --- src/apply.c | 2 -- src/shk.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/apply.c b/src/apply.c index 0af45749a..0136421d3 100644 --- a/src/apply.c +++ b/src/apply.c @@ -773,8 +773,6 @@ beautiful() : "ugly"); } -#define WEAK 3 /* from eat.c */ - static const char look_str[] = "look %s."; STATIC_OVL int diff --git a/src/shk.c b/src/shk.c index ca3893b1f..b2208d399 100644 --- a/src/shk.c +++ b/src/shk.c @@ -3118,8 +3118,6 @@ quit: return 0; } -#define HUNGRY 2 - STATIC_OVL long getprice(obj, shk_buying) register struct obj *obj; From de5ed30cd7cadcaabbbc6553c9ffcddce7a397d2 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 17:29:36 -0800 Subject: [PATCH 09/32] fix #H4179 - death reason for rotted globs 'Poisoned by a rotted gray ooze corpse' should have been 'Poisoned by a rotted glob of gray ooze'. eatcorpse() is called for non-corpse globs and then corpse_xname() is called for them too to set up death reason for make_sick(), but it didn't know anything about globs. Now it does. Blob size is ignored since it's not relevant for cause of death. --- doc/fixes36.1 | 1 + src/objnam.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 16f77f7e7..dbbc0b0a6 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -88,6 +88,7 @@ make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact allow moving cursor to monsters with 'm' and 'M' when asked for map location +fix death reason when eating tainted glob of (not corpse) Platform- and/or Interface-Specific Fixes diff --git a/src/objnam.c b/src/objnam.c index 339a478a5..5dc1e8c2e 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1451683056 2016/01/01 21:17:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.162 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1452043772 2016/01/06 01:29:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.163 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1102,6 +1102,8 @@ register struct obj *otmp; || is_flammable(otmp)); } +/* format a corpse name (xname() omits monster type; doname() calls us); + eatcorpse() also uses us for death reason when eating tainted glob */ char * corpse_xname(otmp, adjective, cxn_flags) struct obj *otmp; @@ -1118,10 +1120,14 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ /* include "an" for "an ogre corpse */ any_prefix = (cxn_flags & CXN_ARTICLE) != 0, /* leave off suffix (do_name() appends "corpse" itself) */ - omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, possessive = FALSE; + omit_corpse = (cxn_flags & CXN_NOCORPSE) != 0, + possessive = FALSE, + glob = (otmp->otyp != CORPSE && otmp->globby); const char *mname; - if (omndx == NON_PM) { /* paranoia */ + if (glob) { + mname = OBJ_NAME(objects[otmp->otyp]); /* "glob of " */ + } else if (omndx == NON_PM) { /* paranoia */ mname = "thing"; /* [Possible enhancement: check whether corpse has monster traits attached in order to use priestname() for priests and minions.] */ @@ -1172,7 +1178,9 @@ unsigned cxn_flags; /* bitmask of CXN_xxx values */ any_prefix = FALSE; } - if (!omit_corpse) { + if (glob) { + ; /* omit_corpse doesn't apply; quantity is always 1 */ + } else if (!omit_corpse) { Strcat(nambuf, " corpse"); /* makeplural(nambuf) => append "s" to "corpse" */ if (otmp->quan > 1L && !ignore_quan) { From f314fe87bdeb9ed83c1409ca384a56141d5f8b7b Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:32:42 +0200 Subject: [PATCH 10/32] Fix unmapped branch stairs on premapped levels This happens when levelporting to the first Sokoban level in wizard mode before visiting the level, causing the branch stairs to not appear until the space it is in comes in sight of the player. The issue was that levels flagged premapped would cause the special level coder to call sokoban_detect() before fixup_special() had a chance to place the branch stairs properly. Fix from Dynahack by Tung Nguyen. --- include/extern.h | 1 + src/mkmaze.c | 4 +--- src/sp_lev.c | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/include/extern.h b/include/extern.h index 49ed2ec6a..1c9c9af6d 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1201,6 +1201,7 @@ E boolean FDECL(bad_location, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); E void FDECL(place_lregion, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, d_level *)); +E void NDECL(fixup_special); E void NDECL(fumaroles); E void NDECL(movebubbles); E void NDECL(water_friction); diff --git a/src/mkmaze.c b/src/mkmaze.c index f192a3f3c..246dafea4 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -19,7 +19,6 @@ STATIC_DCL void FDECL(maze0xy, (coord *)); STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, BOOLEAN_P, d_level *)); -STATIC_DCL void NDECL(fixup_special); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); @@ -362,7 +361,7 @@ d_level *lev; static boolean was_waterlevel; /* ugh... this shouldn't be needed */ /* this is special stuff that the level compiler cannot (yet) handle */ -STATIC_OVL void +void fixup_special() { register lev_region *r = lregions; @@ -577,7 +576,6 @@ register const char *s; if (*protofile) { Strcat(protofile, LEV_EXT); if (load_special(protofile)) { - fixup_special(); /* some levels can end up with monsters on dead mon list, including light source monsters */ dmonsfree(); diff --git a/src/sp_lev.c b/src/sp_lev.c index 61740b436..79a3bbcc8 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -5863,11 +5863,16 @@ sp_lev *lvl; count_features(); - if (coder->premapped) - sokoban_detect(); if (coder->solidify) solidify_map(); + /* This must be done before sokoban_detect(), + * otherwise branch stairs won't be premapped. */ + fixup_special(); + + if (coder->premapped) + sokoban_detect(); + if (coder->frame) { struct sp_frame *tmpframe; do { From 4d919b4d1f7bdc665cb71ad98a8a2a8daed5792f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 03:37:35 +0200 Subject: [PATCH 11/32] Update fixes entries --- doc/fixes36.1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index dbbc0b0a6..ab6ab16d7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -89,6 +89,8 @@ stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) +use appropriate place name for drum of earthquake shakes +fix unmapped branch stairs on sokoban level Platform- and/or Interface-Specific Fixes From 6b559d06f0f938e86ca4c2d94e5b09c2d4acb7f9 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 04:41:57 +0200 Subject: [PATCH 12/32] Redraw map when hilite_pile is toggled --- doc/fixes36.1 | 1 + src/options.c | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index ab6ab16d7..eae8a53ff 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -91,6 +91,7 @@ allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level +redraw map when hilite_pile is toggled to display the highlighting Platform- and/or Interface-Specific Fixes diff --git a/src/options.c b/src/options.c index 3e923e046..11a26c074 100644 --- a/src/options.c +++ b/src/options.c @@ -3384,6 +3384,7 @@ boolean tinitial, tfrom_file; need_redraw = TRUE; /* darkroom refresh */ } else if ((boolopt[i].addr) == &iflags.use_inverse || (boolopt[i].addr) == &flags.showrace + || (boolopt[i].addr) == &iflags.hilite_pile || (boolopt[i].addr) == &iflags.hilite_pet) { need_redraw = TRUE; #ifdef TEXTCOLOR From 4aeb2913cf58848ee4e3dadee59fffb737358f5f Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 04:58:37 +0200 Subject: [PATCH 13/32] Only requiver pickup_thrown ammo and throwing weapons --- include/extern.h | 1 + src/dothrow.c | 3 +-- src/invent.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/extern.h b/include/extern.h index 1c9c9af6d..5585692e0 100644 --- a/include/extern.h +++ b/include/extern.h @@ -498,6 +498,7 @@ E void FDECL(endmultishot, (BOOLEAN_P)); E void FDECL(hitfloor, (struct obj *)); E void FDECL(hurtle, (int, int, int, BOOLEAN_P)); E void FDECL(mhurtle, (struct monst *, int, int, int)); +E boolean FDECL(throwing_weapon, (struct obj *)); E void FDECL(throwit, (struct obj *, long, BOOLEAN_P)); E int FDECL(omon_adj, (struct monst *, struct obj *, BOOLEAN_P)); E int FDECL(thitmonst, (struct monst *, struct obj *)); diff --git a/src/dothrow.c b/src/dothrow.c index 8de02854d..fa02a1186 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -16,7 +16,6 @@ STATIC_DCL void FDECL(check_shop_obj, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); STATIC_DCL void FDECL(breakmsg, (struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(toss_up, (struct obj *, BOOLEAN_P)); -STATIC_DCL boolean FDECL(throwing_weapon, (struct obj *)); STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj * obj)); STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t, int, int)); @@ -943,7 +942,7 @@ boolean hitsroof; } /* return true for weapon meant to be thrown; excludes ammo */ -STATIC_OVL boolean +boolean throwing_weapon(obj) struct obj *obj; { diff --git a/src/invent.c b/src/invent.c index 1e220bbc4..0dd93861c 100644 --- a/src/invent.c +++ b/src/invent.c @@ -479,7 +479,8 @@ struct obj *obj; obj->where = OBJ_INVENT; /* fill empty quiver if obj was thrown */ - if (flags.pickup_thrown && !uquiver && obj_was_thrown) + if (flags.pickup_thrown && !uquiver && obj_was_thrown + && (throwing_weapon(obj) || is_ammo(obj))) setuqwep(obj); added: addinv_core2(obj); From cb4bb726314eedfd65d011516f714da9ec777046 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 5 Jan 2016 23:19:14 -0800 Subject: [PATCH 14/32] fix getpos() m,M to move to next monster Fixing a couple of warnings led to discovery of a couple of real bugs. Warnings: 1) -Wshadow warning for 'dist2' variable blocking access to dist2() function. 2) Declaration not at top of block not allowed for C89/C90 (let alone for pre-ANSI). Bugs: 3) there might be 0 visible monsters, in which case the code prior to qsort will call alloc(0). I think ANSI requires malloc(0) to return a unique pointer which can be freed, but pre-ANSI malloc might return Null to satisfy it, leading to panic from nethack's alloc(). 4) visible monsters in direct line with hero horizontally or vertically were unintentionally skipped when collecting monster locations. I think looking at monsters is the wrong way to implement this. It should be scanning the map for monster glyphs instead. (Coin toss as to whether it should also treat statues-shown-as-monsters as if they were monsters while doing this. I'm leaning towards yes. And what about warning glyphs and instances of the remembered-invisible monster glyph? They aren't interesting to look at but they might provide a shortcut to positioning the cursor near something else.) Using '^' to move to next trap moves from hero's position to end of hero's line, then columns 1 to N of next line, and so on to bottom right, then top left columns 1 to N, second line 1 to N, on down to hero's line. Having 'm' traverse monsters from nearest to farthest feels like a noticeable inconsistency between the two. Especially if you move the cursor with direction or topology keystrokes prior to 'm'. --- src/do_name.c | 54 ++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 5e5675b98..567720e67 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1450178550 2015/12/15 11:22:30 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1452064740 2016/01/06 07:19:00 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.84 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -6,6 +6,8 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); +STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, + const void *)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); @@ -30,7 +32,7 @@ nextmbuf() /* function for getpos() to highlight desired map locations. * parameter value 0 = initialize, 1 = highlight, 2 = done */ -void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; +static void FDECL((*getpos_hilitefunc), (int)) = (void FDECL((*), (int))) 0; void getpos_sethilite(f) @@ -55,7 +57,7 @@ const char *goal; putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); - putstr(tmpwin, 0, "Use m or M to move the cursor on monster."); + putstr(tmpwin, 0, "Use m or M to move the cursor to next monster."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -72,23 +74,23 @@ const char *goal; destroy_nhwindow(tmpwin); } -static int +STATIC_OVL int cmp_coord_distu(a, b) const void *a; const void *b; { const coord *c1 = a; const coord *c2 = b; - int dx, dy, dist1, dist2; + int dx, dy, dist_1, dist_2; dx = u.ux - c1->x; dy = u.uy - c1->y; - dist1 = dx * dx + dy * dy; + dist_1 = dx * dx + dy * dy; dx = u.ux - c2->x; dy = u.uy - c2->y; - dist2 = dx * dx + dy * dy; + dist_2 = dx * dx + dy * dy; - return dist1 - dist2; + return dist_1 - dist_2; } int @@ -215,7 +217,7 @@ const char *goal; if (c == '?' || redraw_cmd(c)) { if (c == '?') getpos_help(force, goal); - else /* ^R */ + else /* ^R */ docrt(); /* redraw */ /* update message window to reflect that we're still targetting */ show_goal_msg = TRUE; @@ -242,36 +244,35 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { + struct monst *mtmp; + moncount = 0; - monidx = 0; - struct monst *mtmp = fmon; - while (mtmp) { + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (canspotmon(mtmp) - && (mtmp->mx != u.ux && mtmp->my != u.uy)) + && (mtmp->mx != u.ux || mtmp->my != u.uy)) moncount++; - mtmp = mtmp->nmon; } - monarr = (coord *)alloc(sizeof(coord) * moncount); - mtmp = fmon; - while (mtmp) { + /* moncount + 1: always allocate a non-zero amount */ + monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); + monidx = 0; + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (canspotmon(mtmp) - && (mtmp->mx != u.ux && mtmp->my != u.uy)) { + && (mtmp->mx != u.ux || mtmp->my != u.uy)) { monarr[monidx].x = mtmp->mx; monarr[monidx].y = mtmp->my; monidx++; } - mtmp = mtmp->nmon; } - qsort(monarr, moncount, sizeof(coord), cmp_coord_distu); - /* ready this for first increment/decrement to change to zero */ + qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); + /* ready for first increment/decrement to change to zero */ monidx = (c == 'm') ? -1 : 1; } if (moncount) { - if (c == 'm') + if (c == 'm') { monidx = (monidx + 1) % moncount; - else { - monidx--; - if (monidx < 0) monidx = moncount-1; + } else { + if (--monidx < 0) + monidx = moncount - 1; } cx = monarr[monidx].x; cy = monarr[monidx].y; @@ -281,6 +282,7 @@ const char *goal; if (!index(quitchars, c)) { char matching[MAXPCHARS]; int pass, lo_x, lo_y, hi_x, hi_y, k = 0; + (void) memset((genericptr_t) matching, 0, sizeof matching); for (sidx = 1; sidx < MAXPCHARS; sidx++) if (c == defsyms[sidx].sym || c == (int) showsyms[sidx]) @@ -368,7 +370,7 @@ const char *goal; ccp->x = cx; ccp->y = cy; if (monarr) - free(monarr); + free((genericptr_t) monarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; } From e6fa0ce809c106f7872c0aef01dbcd7268c5fd2e Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 00:07:54 -0800 Subject: [PATCH 15/32] provisional fix for bz239 - '[tty] Enter key...' '... inconsistency in character creation menus'. During role selection, the final 'is this ok?' menu has 'yes' preselected so accepted or to answer yes. The pick-role, pick-race, &c menus prior to getting to that stage didn't have a default, so using meant nothing was chosen, and choosing nothing was treated as a request to quit. This changes that so it's a request for 'random' instead. 'Provisional fix' because it ought to do this by making 'random' be a pre-selected menu entry so that the default choice is visible. But that takes more effort than I'm inclined to expend on this. --- doc/fixes36.1 | 2 ++ win/tty/wintty.c | 9 +++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index eae8a53ff..dee5ca524 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,8 @@ 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 for confirmation with "Is this ok?" before starting play +tty: responding with or duing role, race, &c selection + behaved same as to quit; now it will pick [random] instead unix/X11: in top level Makefile, some commented out definitions of VARDATND misspelled pilemark.xbm (as pilemark.xpm) unix/tty: fix compile warning about 'has_colors' for some configurations diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 96cc9b1ee..58dee65a3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -441,7 +441,8 @@ makepicks: Strcpy(pbuf, "Pick a role or profession"); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); - choice = (n == 1) ? selected[0].item.a_int : ROLE_NONE; + choice = (n == 1) ? selected[0].item.a_int + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -526,7 +527,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -615,7 +616,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); @@ -700,7 +701,7 @@ makepicks: end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); choice = (n == 1) ? selected[0].item.a_int - : ROLE_NONE; + : (n == 0) ? ROLE_RANDOM : ROLE_NONE; if (selected) free((genericptr_t) selected), selected = 0; destroy_nhwindow(win); From fbdeaae2861ec02d8b65034c84f1196ccd818b08 Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 00:45:46 -0800 Subject: [PATCH 16/32] tribute: Equal Rites revisited The number of passages felt a little light, so split one of the long-ish ones into two. The punchline that now ends the first one was being watered down by continuing the text, and an interesting bit that was left out can be added to finish the second part. They both lose some context but I think they work ok separately. --- dat/tribute | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/dat/tribute b/dat/tribute index 6a7f63b31..53cfbd985 100644 --- a/dat/tribute +++ b/dat/tribute @@ -573,7 +573,7 @@ according its victims the dignity of hatred. It wouldn't even notice them. # # # -%title Equal Rites (9) +%title Equal Rites (10) # p. 118 (Signet edition; passage starts mid-sentence and ends mid-paragraph) %passage 1 [...] it is well known that a vital ingredient of success is not knowing @@ -650,11 +650,7 @@ rewrite them so that they don't apply to you. [Equal Rites, by Terry Pratchett] %e passage -# pp. 119-120 ("what is happening here?" actually omits "is" but -# must be a typo--fixed here to avoid bug reports; -# 'broomstick' is Esk's disguised wizard's staff; -# passage continues with questions about destination and -# why go overland when the river goes to the same place) +# pp. 119-120 (next passage is a direct continuation of this one) %passage 7 The town was smaller than Ohulan, and very different because it lay on the junction of three trade routes quite apart from the river itself. It was @@ -678,6 +674,13 @@ nevertheless, there were still people misguided enough to endure all this, plus long nights in uncomfortable surroundings, merely to get their hands on perfectly ordinary large boxes of jewels. + [Equal Rites, by Terry Pratchett] +%e passage +# pp. 120-121 (this passage is a direct continuation of preceding one; +# "I said, what is happening here?" actually omits "is" +# but must be a typo--fixed here to avoid bug reports; +# 'broomstick' is Esk's disguised wizard's staff) +%passage 8 So a town like Zemphis was the place where caravans split, mingled and came together again, as dozens of merchants and travellers banded together for protection against the socially disadvantaged on the trails ahead. @@ -704,10 +707,32 @@ He explained about the caravans. The child nodded. "Precisely." +"Where to?" + +"All sorts of places. Sto Lat, Pseudopolis... Ankh-Morpork, of course...." + +"But the river goes there," said Esk, reasonably. "Barges. The Zoons." + +"Ah, yes," said the merchant, "but they charge high prices and they can't +carry everything and, anyway, no one trusts them much." + +"But they're very honest!" + +"Huh, yes," he said. "But you know what they say: never trust an honest +man." He smiled knowingly. + +"Who says that?" + +"They do. You know. People," he said, a certain uneasiness entering his +voice. + +"Oh," said Esk. She thought about it. "They must be very silly," she said +primly. "Thank you, anyway." + [Equal Rites, by Terry Pratchett] %e passage # pp. 127-128 (this time broomstick is Granny's defective witch's broomstick) -%passage 8 +%passage 9 The broomstick lay between two trestles. Granny Weatherwax sat on a rock outcrop while a dwarf half her height, wearing an apron that was a mass of pockets, walked around the broom and occasionally poked it. @@ -759,7 +784,7 @@ back of his skull. [Equal Rites, by Terry Pratchett] %e passage # p. 185 (actually uses four periods to mark a sentence ending in a elipsis) -%passage 9 +%passage 10 There may be universes where librarianship is considered a peaceful sort of occupation, and where the risks are limited to large volumes falling off the shelves on to one's head, but the keeper of a /magic/ library is no job From 1bc05714b527737d671d065a2df5643c48a38e7a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 11:50:07 +0200 Subject: [PATCH 17/32] Fix bz66: Count number cannot be backspaced ... or at least partially fix it - ^H does now backspace. I can't be bothered to dive into the (n)curses raw-mode stuff. --- src/cmd.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/cmd.c b/src/cmd.c index 191ab71f3..dc1ae79df 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3874,6 +3874,7 @@ parse() #endif register int foo; boolean prezero = FALSE; + boolean backspaced = FALSE; multi = 0; context.move = 1; @@ -3885,13 +3886,23 @@ parse() if (!Cmd.num_pad || (foo = readchar()) == 'n') for (;;) { foo = readchar(); - if (foo >= '0' && foo <= '9') { - multi = 10 * multi + foo - '0'; + if ((foo >= '0' && foo <= '9') || (foo == '\b')) { + if (foo >= '0' && foo <= '9') + multi = 10 * multi + foo - '0'; + else { + multi = multi / 10; + backspaced = TRUE; + } if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; - if (multi > 9) { + if (multi > 9 || backspaced) { clear_nhwindow(WIN_MESSAGE); - Sprintf(in_line, "Count: %d", multi); + if (backspaced && !multi) + Sprintf(in_line, "Count: "); + else { + Sprintf(in_line, "Count: %d", multi); + backspaced = FALSE; + } pline1(in_line); mark_synch(); } From 4c016853d47dcb9d1b51865de9dfcfa673f6e260 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 13:50:16 +0200 Subject: [PATCH 18/32] Unify getting a count into single function --- doc/fixes36.1 | 2 ++ include/extern.h | 1 + src/cmd.c | 85 +++++++++++++++++++++++++++++++----------------- src/invent.c | 59 ++++++++++++--------------------- 4 files changed, 80 insertions(+), 67 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index dee5ca524..05118711c 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -92,6 +92,8 @@ fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting +make commands that accept a count prefix for item selection + show "Count:" like command repeating does Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 5585692e0..52ffc37aa 100644 --- a/include/extern.h +++ b/include/extern.h @@ -204,6 +204,7 @@ E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); +E char FDECL(get_count, (char *, char, long, long *)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); diff --git a/src/cmd.c b/src/cmd.c index dc1ae79df..693666050 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -3864,6 +3864,57 @@ int x, y, mod; return cmd; } +char +get_count(allowchars, inkey, max, count) +char *allowchars; +char inkey; +long max; +long *count; +{ + char qbuf[QBUFSZ]; + int key; + long cnt = 0; + boolean backspaced = FALSE; + char *ret; + for (;;) { + if (inkey) { + key = inkey; + inkey = '\0'; + } else + key = readchar(); + if (digit(key)) { + cnt = 10L * cnt + (long)(key - '0'); + } else if (key == '\b') { + cnt = cnt / 10; + backspaced = TRUE; + } else if (key == '\033') { + return '\033'; + } else if (allowchars) { + if (ret = index(allowchars, key)) { + *count = cnt; + return *ret; + } + } else { + *count = cnt; + return key; + } + if (max && (cnt > max)) + cnt = max; + if (cnt > 9 || backspaced) { + clear_nhwindow(WIN_MESSAGE); + if (backspaced && !cnt) + Sprintf(qbuf, "Count: "); + else { + Sprintf(qbuf, "Count: %d", cnt); + backspaced = FALSE; + } + pline1(qbuf); + mark_synch(); + } + } +} + + STATIC_OVL char * parse() { @@ -3883,35 +3934,11 @@ parse() #ifdef ALTMETA alt_esc = iflags.altmeta; /* readchar() hack */ #endif - if (!Cmd.num_pad || (foo = readchar()) == 'n') - for (;;) { - foo = readchar(); - if ((foo >= '0' && foo <= '9') || (foo == '\b')) { - if (foo >= '0' && foo <= '9') - multi = 10 * multi + foo - '0'; - else { - multi = multi / 10; - backspaced = TRUE; - } - if (multi < 0 || multi >= LARGEST_INT) - multi = LARGEST_INT; - if (multi > 9 || backspaced) { - clear_nhwindow(WIN_MESSAGE); - if (backspaced && !multi) - Sprintf(in_line, "Count: "); - else { - Sprintf(in_line, "Count: %d", multi); - backspaced = FALSE; - } - pline1(in_line); - mark_synch(); - } - last_multi = multi; - if (!multi && foo == '0') - prezero = TRUE; - } else - break; /* not a digit */ - } + if (!Cmd.num_pad || (foo = readchar()) == 'n') { + long tmpmulti = multi; + foo = get_count(NULL, '\0', LARGEST_INT, &tmpmulti); + last_multi = multi = tmpmulti; + } #ifdef ALTMETA alt_esc = FALSE; /* readchar() reset */ #endif diff --git a/src/invent.c b/src/invent.c index 0dd93861c..8b5a10a29 100644 --- a/src/invent.c +++ b/src/invent.c @@ -970,8 +970,8 @@ register const char *let, *word; boolean allownone = FALSE; boolean useboulder = FALSE; xchar foox = 0; - long cnt, prevcnt; - boolean prezero; + long cnt; + boolean cntgiven = FALSE; long dummymask; if (*let == ALLOW_COUNT) @@ -1163,9 +1163,7 @@ register const char *let, *word; } for (;;) { cnt = 0; - if (allowcnt == 2) - allowcnt = 1; /* abort previous count */ - prezero = FALSE; + cntgiven = FALSE; if (!buf[0]) { Sprintf(qbuf, "What do you want to %s? [*]", word); } else { @@ -1175,28 +1173,17 @@ register const char *let, *word; ilet = readchar(); else ilet = yn_function(qbuf, (char *) 0, '\0'); - if (digit(ilet) && !allowcnt) { - pline("No count allowed with this command."); - continue; - } - if (ilet == '0') - prezero = TRUE; - while (digit(ilet)) { - if (ilet != '?' && ilet != '*') - savech(ilet); - /* accumulate unless cnt has overflowed */ - if (allowcnt < 3) { - prevcnt = cnt; - cnt = 10L * cnt + (long) (ilet - '0'); - /* signal presence of cnt */ - allowcnt = (cnt >= prevcnt) ? 2 : 3; + if (digit(ilet)) { + long tmpcnt = 0; + if (!allowcnt) { + pline("No count allowed with this command."); + continue; + } + ilet = get_count(NULL, ilet, LARGEST_INT, &tmpcnt); + if (tmpcnt) { + cnt = tmpcnt; + cntgiven = TRUE; } - ilet = readchar(); - } - if (allowcnt == 3) { - /* overflow detected; force cnt to be invalid */ - cnt = -1L; - allowcnt = 2; } if (index(quitchars, ilet)) { if (flags.verbose) @@ -1237,9 +1224,7 @@ register const char *let, *word; continue; if (allowcnt && ctmp >= 0) { cnt = ctmp; - if (!cnt) - prezero = TRUE; - allowcnt = 2; + cntgiven = TRUE; } if (ilet == '\033') { if (flags.verbose) @@ -1267,23 +1252,21 @@ register const char *let, *word; * to your money supply. The LRS is the tax bureau * from Larn. */ - if (allowcnt == 2 && cnt <= 0) { - if (cnt < 0 || !prezero) + if (cntgiven && cnt <= 0) { + if (cnt < 0) pline_The( "LRS would be very interested to know you have that much."); return (struct obj *) 0; } } - if (allowcnt == 2 && !strcmp(word, "throw")) { + if (cntgiven && !strcmp(word, "throw")) { /* permit counts for throwing gold, but don't accept * counts for other things since the throw code will * split off a single item anyway */ - if (ilet != def_oc_syms[COIN_CLASS].sym - && !(otmp && otmp->oclass == COIN_CLASS)) - allowcnt = 1; - if (cnt == 0 && prezero) + if (cnt == 0) return (struct obj *) 0; - if (cnt > 1) { + if (cnt > 1 && (ilet != def_oc_syms[COIN_CLASS].sym + && !(otmp && otmp->oclass == COIN_CLASS))) { You("can only throw one item at a time."); continue; } @@ -1311,7 +1294,7 @@ register const char *let, *word; silly_thing(word, otmp); return (struct obj *) 0; } - if (allowcnt == 2) { /* cnt given */ + if (cntgiven) { if (cnt == 0) return (struct obj *) 0; if (cnt != otmp->quan) { From 5ccfd34328fa29a35d2c7cd8931679899ed563b3 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 14:05:24 +0200 Subject: [PATCH 19/32] Allow picking a used inventory letter from menu when #adjusting --- doc/fixes36.1 | 1 + src/invent.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 05118711c..7fd5aec74 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -94,6 +94,7 @@ fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does +allow picking a used inventory letter from menu when #adjusting Platform- and/or Interface-Specific Fixes diff --git a/src/invent.c b/src/invent.c index 8b5a10a29..a79c7d46b 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2182,7 +2182,7 @@ char avoidlet; } end_menu(win, "Inventory letters used:"); - n = select_menu(win, PICK_NONE, &selected); + n = select_menu(win, PICK_ONE, &selected); if (n > 0) { ret = selected[0].item.a_char; free((genericptr_t) selected); From 72f55fedb554102a7d8aacb2bb214972a810788c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 14:17:11 +0200 Subject: [PATCH 20/32] Zapping wand of opening at yourself, unlock carried boxes --- doc/fixes36.1 | 1 + src/zap.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 7fd5aec74..88bbeecb7 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -95,6 +95,7 @@ redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does allow picking a used inventory letter from menu when #adjusting +zapping wand of opening at yourself, unlock carried boxes Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 677921c2e..3295e690a 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2368,7 +2368,13 @@ boolean ordinary; } if (u.utrap) { /* escape web or bear trap */ (void) openholdingtrap(&youmonst, &learn_it); - } else { /* trigger previously escaped trapdoor */ + } else { + struct obj *otmp; + /* unlock carried boxes */ + for (otmp = invent; otmp; otmp = otmp->nobj) + if (Is_box(otmp)) + (void) boxlock(otmp, obj); + /* trigger previously escaped trapdoor */ (void) openfallingtrap(&youmonst, TRUE, &learn_it); } break; From 237c4a2787119a5fc72741f650943923f7e4b12c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 15:33:36 +0200 Subject: [PATCH 21/32] Allow dissolving iron bars with potion of acid Force-fight iron bars with wielded potion of acid to dissolve them This change comes via UnNetHack by Patric Mueller. --- doc/fixes36.1 | 1 + include/extern.h | 3 ++- src/hack.c | 13 +++++++++++ src/mthrowu.c | 59 ++++++++++++++++++++++++++++++++++++------------ src/trap.c | 4 +++- src/zap.c | 1 + 6 files changed, 64 insertions(+), 17 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 88bbeecb7..292a9ff31 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -96,6 +96,7 @@ make commands that accept a count prefix for item selection show "Count:" like command repeating does allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes +dissolve iron bars by force-fighting with wielded potion of acid Platform- and/or Interface-Specific Fixes diff --git a/include/extern.h b/include/extern.h index 52ffc37aa..ea89ad2ba 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1503,7 +1503,8 @@ E void FDECL(m_useupall, (struct monst *, struct obj *)); E void FDECL(m_useup, (struct monst *, struct obj *)); E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *)); -E boolean FDECL(hits_bars, (struct obj **, int, int, int, int)); +E void FDECL(hit_bars, (struct obj **, int, int, int, int, boolean, boolean)); +E boolean FDECL(hits_bars, (struct obj **, int, int, int, int, int, int)); /* ### muse.c ### */ diff --git a/src/hack.c b/src/hack.c index 6305ad1e7..098546579 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1437,6 +1437,19 @@ domove() } } + if (context.forcefight && levl[x][y].typ == IRONBARS && uwep) { + struct obj *obj = uwep; + if (breaktest(obj)) { + if (obj->quan > 1L) + obj = splitobj(obj, 1L); + else + setuwep((struct obj *)0); + freeinv(obj); + } + hit_bars(&obj, u.ux, u.uy, x, y, TRUE, TRUE); + return; + } + /* specifying 'F' with no monster wastes a turn */ if (context.forcefight /* remembered an 'I' && didn't use a move command */ diff --git a/src/mthrowu.c b/src/mthrowu.c index b63a47900..54ef961fd 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -318,7 +318,9 @@ struct obj *obj; /* missile (or stack providing it) */ || 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, 0, 0))) { + && hits_bars(&singleobj, + bhitpos.x, bhitpos.y, + bhitpos.x + dx, bhitpos.y + dy, 0, 0))) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } @@ -455,7 +457,10 @@ struct obj *obj; /* missile (or stack providing it) */ || 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, !rn2(5), 0)) + && 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)) { if (singleobj) /* hits_bars might have destroyed it */ @@ -831,11 +836,45 @@ int type; return (struct obj *) 0; } +void +hit_bars(objp, objx, objy, barsx, barsy, your_fault, from_invent) +struct obj **objp; /* *objp will be set to NULL if object breaks */ +int objx, objy, barsx, barsy; +boolean your_fault, from_invent; +{ + struct obj *otmp = *objp; + int obj_type = otmp->otyp; + boolean unbreakable = (levl[barsx][barsy].wall_info & W_NONDIGGABLE) != 0; + + if (your_fault + ? hero_breaks(otmp, objx, objy, from_invent) + : breaks(otmp, objx, objy)) { + *objp = 0; /* object is now gone */ + /* breakage makes its own noises */ + if (obj_type == POT_ACID) { + if (cansee(barsx, barsy) && !unbreakable) + pline_The("iron bars are dissolved!"); + else + You_hear(Hallucination ? "angry snakes!" : "a hissing noise."); + if (!unbreakable) + dissolve_bars(barsx, barsy); + } + } + else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) + pline("Whang!"); + else if (otmp->oclass == COIN_CLASS + || objects[obj_type].oc_material == GOLD + || objects[obj_type].oc_material == SILVER) + pline("Clink!"); + else + pline("Clonk!"); +} + /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ boolean -hits_bars(obj_p, x, y, always_hit, whodidit) +hits_bars(obj_p, x, y, barsx, barsy, always_hit, whodidit) struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */ -int x, y; +int x, y, barsx, barsy; int always_hit; /* caller can force a hit for items which would fit through */ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ { @@ -885,17 +924,7 @@ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ } if (hits && whodidit != -1) { - if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) - *obj_p = otmp = 0; /* object is now gone */ - /* breakage makes its own noises */ - else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) - pline("Whang!"); - else if (otmp->oclass == COIN_CLASS - || objects[obj_type].oc_material == GOLD - || objects[obj_type].oc_material == SILVER) - pline("Clink!"); - else - pline("Clonk!"); + hit_bars(obj_p, x,y, barsx,barsy, whodidit, FALSE); } return hits; diff --git a/src/trap.c b/src/trap.c index 7f9a1ea7d..71700c6c8 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1889,7 +1889,9 @@ int style; if (dist > 0 && isok(bhitpos.x + dx, bhitpos.y + dy) && levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ - if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { + if (hits_bars(&singleobj, + x2, y2, x2+dx, y2+dy, + !rn2(20), 0)) { if (!singleobj) { used_up = TRUE; launch_drop_spot((struct obj *) 0, 0, 0); diff --git a/src/zap.c b/src/zap.c index 3295e690a..1aaa3d14e 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3103,6 +3103,7 @@ struct obj **pobj; /* object tossed/used, set to NULL /* iron bars will block anything big enough */ if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && typ == IRONBARS && hits_bars(pobj, x - ddx, y - ddy, + bhitpos.x, bhitpos.y, point_blank ? 0 : !rn2(5), 1)) { /* caveat: obj might now be null... */ obj = *pobj; From da0e660110c85d2bfce393abb4ec71d836ed6504 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 16:05:40 +0200 Subject: [PATCH 22/32] Poison breath leaves a trail of poison gas clouds Original patch by L --- doc/fixes36.1 | 1 + src/zap.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 292a9ff31..e957b09fd 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -97,6 +97,7 @@ make commands that accept a count prefix for item selection allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid +poison breath leaves a trail of poison gas Platform- and/or Interface-Specific Fixes diff --git a/src/zap.c b/src/zap.c index 1aaa3d14e..0749c8dbf 100644 --- a/src/zap.c +++ b/src/zap.c @@ -4312,6 +4312,10 @@ short exploding_wand_typ; } break; /* ZT_COLD */ + case ZT_POISON_GAS: + (void) create_gas_cloud(x, y, 1, 8); + break; + case ZT_ACID: if (lev->typ == IRONBARS) { if ((lev->wall_info & W_NONDIGGABLE) != 0) { From c740425a90192595be4c81177e9db62e3a333bbf Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 16:23:48 +0200 Subject: [PATCH 23/32] Use define for iron ball weight increment --- include/hack.h | 3 +++ src/objnam.c | 2 +- src/read.c | 2 +- src/weapon.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/hack.h b/include/hack.h index 2eae9e6ba..816b7fee0 100644 --- a/include/hack.h +++ b/include/hack.h @@ -29,6 +29,9 @@ #define EXT_ENCUMBER 4 /* Overtaxed */ #define OVERLOADED 5 /* Overloaded */ +/* weight increment of heavy iron ball */ +#define IRON_BALL_W_INCR 160 + /* hunger states - see hu_stat in eat.c */ #define SATIATED 0 #define NOT_HUNGRY 1 diff --git a/src/objnam.c b/src/objnam.c index 5dc1e8c2e..8e98e07b8 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3533,7 +3533,7 @@ typfnd: } otmp->owt = weight(otmp); if (very && otmp->otyp == HEAVY_IRON_BALL) - otmp->owt += 160; + otmp->owt += IRON_BALL_W_INCR; return otmp; } diff --git a/src/read.c b/src/read.c index 94619ba11..4ba274146 100644 --- a/src/read.c +++ b/src/read.c @@ -2271,7 +2271,7 @@ struct obj *sobj; You("are being punished for your misbehavior!"); if (Punished) { Your("iron ball gets heavier."); - uball->owt += 160 * (1 + sobj->cursed); + uball->owt += IRON_BALL_W_INCR * (1 + sobj->cursed); return; } if (amorphous(youmonst.data) || is_whirly(youmonst.data) diff --git a/src/weapon.c b/src/weapon.c index cc14f35ec..cdbd440db 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -304,12 +304,12 @@ struct monst *mon; if (ptr == &mons[PM_SHADE] && !shade_glare(otmp)) tmp = 0; - /* "very heavy iron ball"; weight increase is in increments of 160 */ + /* "very heavy iron ball"; weight increase is in increments */ if (otyp == HEAVY_IRON_BALL && tmp > 0) { int wt = (int) objects[HEAVY_IRON_BALL].oc_weight; if ((int) otmp->owt > wt) { - wt = ((int) otmp->owt - wt) / 160; + wt = ((int) otmp->owt - wt) / IRON_BALL_W_INCR; tmp += rnd(4 * wt); if (tmp > 25) tmp = 25; /* objects[].oc_wldam */ From c2ceb88d3c5682974bc2b866b6cbec1a1fdd3578 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 17:28:41 +0200 Subject: [PATCH 24/32] Make vault guard accept names starting with number Fix via Dynahack by Tung Nguyen --- doc/fixes36.1 | 1 + src/vault.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index e957b09fd..6bdc85bad 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -98,6 +98,7 @@ allow picking a used inventory letter from menu when #adjusting zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas +make vault guard accept names starting with number Platform- and/or Interface-Specific Fixes diff --git a/src/vault.c b/src/vault.c index 5b73dadc5..52ca97660 100644 --- a/src/vault.c +++ b/src/vault.c @@ -376,7 +376,7 @@ invault() do { getlin("\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); - } while (!letter(buf[0]) && --trycount > 0); + } while (!buf[0] && --trycount > 0); if (u.ualign.type == A_LAWFUL /* ignore trailing text, in case player includes rank */ From 785aba242a6340511765eeef580c9d40c34dfbac Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:15:04 +0200 Subject: [PATCH 25/32] Fix the mtrack memset --- src/dog.c | 2 +- src/monmove.c | 2 +- src/teleport.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dog.c b/src/dog.c index 361c7de02..a5f8a5a75 100644 --- a/src/dog.c +++ b/src/dog.c @@ -325,7 +325,7 @@ boolean with_you; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); if (mtmp == u.usteed) return; /* don't place steed on the map */ diff --git a/src/monmove.c b/src/monmove.c index cae22b8b5..86432a6c5 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -272,7 +272,7 @@ boolean fleemsg; mtmp->mflee = 1; } /* ignore recently-stepped spaces when made to flee */ - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); } STATIC_OVL void diff --git a/src/teleport.c b/src/teleport.c index 47780e7da..43e97da63 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -980,7 +980,7 @@ register int x, y; } } - memset(mtmp->mtrack, MTSZ, sizeof(coord)); + memset(mtmp->mtrack, 0, sizeof(mtmp->mtrack)); place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); From 0a2550259319b65fb825bb4d8aa7f95a3e545593 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:25:17 +0200 Subject: [PATCH 26/32] Fix weight of containers in lev_comp --- doc/fixes36.1 | 1 + src/sp_lev.c | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 6bdc85bad..8b999752b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -99,6 +99,7 @@ zapping wand of opening at yourself, unlock carried boxes dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas make vault guard accept names starting with number +fix weight of containers in special levels Platform- and/or Interface-Specific Fixes diff --git a/src/sp_lev.c b/src/sp_lev.c index 79a3bbcc8..c4428d7ad 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1873,11 +1873,12 @@ struct mkroom *croom; } } } else { + struct obj *cobj = container_obj[container_idx - 1]; remove_object(otmp); - if (container_obj[container_idx - 1]) - (void) add_to_container(container_obj[container_idx - 1], - otmp); - else { + if (cobj) { + (void) add_to_container(cobj, otmp); + cobj->owt = weight(cobj); + } else { obj_extract_self(otmp); obfree(otmp, NULL); return; From caf872be05cb6a6d7d176af9902cc3e1f381c95c Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:40:41 +0200 Subject: [PATCH 27/32] Allow knife and stiletto as possible tin opening tools Via Dynahack, original idea from K-mod by Karadoc. --- doc/fixes36.1 | 1 + src/eat.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 8b999752b..922eecf7b 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -100,6 +100,7 @@ dissolve iron bars by force-fighting with wielded potion of acid poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels +allow knife and stiletto as possible tin opening tools Platform- and/or Interface-Specific Fixes diff --git a/src/eat.c b/src/eat.c index d041976dd..7591b9cc3 100644 --- a/src/eat.c +++ b/src/eat.c @@ -1431,6 +1431,8 @@ struct obj *otmp; case ELVEN_DAGGER: case ORCISH_DAGGER: case ATHAME: + case KNIFE: + case STILETTO: case CRYSKNIFE: tmp = 3; break; From c8d0b04c749babf06d9a8fa42dbceb3c40c55212 Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 18:54:21 +0200 Subject: [PATCH 28/32] Make the raven medusa level shortsighted This prevents all of the ravens mobbing the player immediately. Change via Dynahack by Tung Nguyen --- dat/medusa.des | 2 +- doc/fixes36.1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dat/medusa.des b/dat/medusa.des index 3e1a70521..b449a29e2 100644 --- a/dat/medusa.des +++ b/dat/medusa.des @@ -218,7 +218,7 @@ MONSTER:random,random LEVEL:"medusa-3" -FLAGS: noteleport,mazelevel +FLAGS: noteleport,mazelevel,shortsighted INIT_MAP:solidfill,' ' GEOMETRY:center,center # diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 922eecf7b..9df0bdc0a 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -101,6 +101,7 @@ poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels allow knife and stiletto as possible tin opening tools +make the raven medusa level shortsighted Platform- and/or Interface-Specific Fixes From 50359a35525bcaa534a07cf605ee761a40ff2fad Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 19:48:46 +0200 Subject: [PATCH 29/32] Fix possible lev_comp segfault when map was too tall --- doc/fixes36.1 | 1 + util/lev_main.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 9df0bdc0a..97fc2b360 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -102,6 +102,7 @@ make vault guard accept names starting with number fix weight of containers in special levels allow knife and stiletto as possible tin opening tools make the raven medusa level shortsighted +fix possible segfault in lev_comp when map was too tall Platform- and/or Interface-Specific Fixes diff --git a/util/lev_main.c b/util/lev_main.c index d3350e178..c95441bce 100644 --- a/util/lev_main.c +++ b/util/lev_main.c @@ -1351,7 +1351,7 @@ sp_lev *sp; register char *s1, *s2; int max_len = 0; int max_hig = 0; - char *tmpmap[ROWNO]; + char *tmpmap[MAP_Y_LIM+1]; int dx, dy; char *mbuf; @@ -1378,6 +1378,8 @@ sp_lev *sp; /* Then parse it now */ while (map && *map) { + if (max_hig > MAP_Y_LIM) + break; tmpmap[max_hig] = (char *) alloc(max_len); s1 = index(map, '\n'); if (s1) { From 5d1281c9ac38c30eb68e5e0e7df3182a04943e5a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Wed, 6 Jan 2016 21:42:45 +0200 Subject: [PATCH 30/32] Make getpos monster targeting use glyph lookup --- src/do_name.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index 567720e67..2341adb0e 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -244,24 +244,28 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { - struct monst *mtmp; + int x,y,s; moncount = 0; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (canspotmon(mtmp) - && (mtmp->mx != u.ux || mtmp->my != u.uy)) - moncount++; - } - /* moncount + 1: always allocate a non-zero amount */ - monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); - monidx = 0; - for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { - if (canspotmon(mtmp) - && (mtmp->mx != u.ux || mtmp->my != u.uy)) { - monarr[monidx].x = mtmp->mx; - monarr[monidx].y = mtmp->my; - monidx++; + for (s = 0; s < 2; s++) { + if (s) { + /* moncount + 1: always allocate a non-zero amount */ + monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); + monidx = 0; } + if (!s || s && moncount) + for (x = 0; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) + if (glyph_is_monster(glyph_at(x,y)) + && !(x == u.ux && y == u.uy)) { + if (!s) + moncount++; + else { + monarr[monidx].x = x; + monarr[monidx].y = y; + monidx++; + } + } } qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); /* ready for first increment/decrement to change to zero */ From c8cd550a5ae1350bbf4576a9c422c57e2d2eefca Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 15:37:46 -0800 Subject: [PATCH 31/32] get_count() cleanup Fix several warnings. Accept ASCII RUBOUT (aka DELETE) in addition to backspace. [Should use erase_char (and add support for kill_char) but that means pushing get_count() into the interface code.] Guard against user causing the count to wrap if someone ever adds a call to get_count() which doesn't specifying a maximum value. --- include/extern.h | 10 +++++----- src/cmd.c | 45 ++++++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/include/extern.h b/include/extern.h index ea89ad2ba..3e58ee565 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1451955077 2016/01/05 00:51:17 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.530 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1452123455 2016/01/06 23:37:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.535 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -204,7 +204,7 @@ E int FDECL(isok, (int, int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int, int, int)); -E char FDECL(get_count, (char *, char, long, long *)); +E char FDECL(get_count, (char *, CHAR_P, long, long *)); #ifdef HANGUPHANDLING E void FDECL(hangup, (int)); E void NDECL(end_of_input); @@ -1501,9 +1501,9 @@ E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *, int)); E void FDECL(m_useupall, (struct monst *, struct obj *)); E void FDECL(m_useup, (struct monst *, struct obj *)); -E void FDECL(m_throw, - (struct monst *, int, int, int, int, int, struct obj *)); -E void FDECL(hit_bars, (struct obj **, int, int, int, int, boolean, boolean)); +E void FDECL(m_throw, (struct monst *, int, int, int, int, int, struct obj *)); +E void FDECL(hit_bars, (struct obj **, int, int, int, int, + BOOLEAN_P, BOOLEAN_P)); E boolean FDECL(hits_bars, (struct obj **, int, int, int, int, int, int)); /* ### muse.c ### */ diff --git a/src/cmd.c b/src/cmd.c index 693666050..162234a76 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1451082253 2015/12/25 22:24:13 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.212 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1452123457 2016/01/06 23:37:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.216 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3865,53 +3865,56 @@ int x, y, mod; } char -get_count(allowchars, inkey, max, count) +get_count(allowchars, inkey, maxcount, count) char *allowchars; char inkey; -long max; +long maxcount; long *count; { char qbuf[QBUFSZ]; int key; - long cnt = 0; + long cnt = 0L; boolean backspaced = FALSE; - char *ret; + /* this should be done in port code so that we have erase_char + and kill_char available; we can at least fake erase_char */ +#define STANDBY_erase_char '\177' + for (;;) { if (inkey) { key = inkey; inkey = '\0'; } else key = readchar(); + if (digit(key)) { - cnt = 10L * cnt + (long)(key - '0'); - } else if (key == '\b') { + cnt = 10L * cnt + (long) (key - '0'); + if (cnt < 0) + cnt = 0; + else if (maxcount > 0 && cnt > maxcount) + cnt = maxcount; + } else if (key == '\b' || key == STANDBY_erase_char) { cnt = cnt / 10; backspaced = TRUE; } else if (key == '\033') { - return '\033'; - } else if (allowchars) { - if (ret = index(allowchars, key)) { - *count = cnt; - return *ret; - } - } else { + break; + } else if (!allowchars || index(allowchars, key)) { *count = cnt; - return key; + break; } - if (max && (cnt > max)) - cnt = max; + if (cnt > 9 || backspaced) { clear_nhwindow(WIN_MESSAGE); - if (backspaced && !cnt) + if (backspaced && !cnt) { Sprintf(qbuf, "Count: "); - else { - Sprintf(qbuf, "Count: %d", cnt); + } else { + Sprintf(qbuf, "Count: %ld", cnt); backspaced = FALSE; } pline1(qbuf); mark_synch(); } } + return key; } @@ -3925,7 +3928,6 @@ parse() #endif register int foo; boolean prezero = FALSE; - boolean backspaced = FALSE; multi = 0; context.move = 1; @@ -3936,6 +3938,7 @@ parse() #endif if (!Cmd.num_pad || (foo = readchar()) == 'n') { long tmpmulti = multi; + foo = get_count(NULL, '\0', LARGEST_INT, &tmpmulti); last_multi = multi = tmpmulti; } From 22685763d1a7f2a4d645d61e35028e56c36e8cfe Mon Sep 17 00:00:00 2001 From: PatR Date: Wed, 6 Jan 2016 16:47:30 -0800 Subject: [PATCH 32/32] getpos() for objects Extend the 'm' and 'M' functionality (move cursor to nearest monster or farthest monster, respectively, then to next nearest/next farthest when used successively) to 'o' and 'O' for objects. 'M' was picking the wrong monster (nearest) on first use; now fixed. Hero is now included in the monster list, and will be the last one reached if you cycle all the way through in either direction. (Makes it easier to tell that you have actually been all the way through. Unfortunately, objects don't have any seen-'em-all indicator. Perhaps the hero's coordinates should go on that list too?) --- doc/fixes36.1 | 15 ++++--- src/do_name.c | 117 +++++++++++++++++++++++++++++++++++++------------- 2 files changed, 96 insertions(+), 36 deletions(-) diff --git a/doc/fixes36.1 b/doc/fixes36.1 index 97fc2b360..2602460c0 100644 --- a/doc/fixes36.1 +++ b/doc/fixes36.1 @@ -87,20 +87,14 @@ requiver pickup_thrown objects if quiver is empty make mimics mimicing walls or trees also block light stepping onto lava destroyed non-fireproof water walking boots but left other vulnerable boot types intact -allow moving cursor to monsters with 'm' and 'M' when asked for map location fix death reason when eating tainted glob of (not corpse) use appropriate place name for drum of earthquake shakes fix unmapped branch stairs on sokoban level redraw map when hilite_pile is toggled to display the highlighting make commands that accept a count prefix for item selection show "Count:" like command repeating does -allow picking a used inventory letter from menu when #adjusting -zapping wand of opening at yourself, unlock carried boxes -dissolve iron bars by force-fighting with wielded potion of acid -poison breath leaves a trail of poison gas make vault guard accept names starting with number fix weight of containers in special levels -allow knife and stiletto as possible tin opening tools make the raven medusa level shortsighted fix possible segfault in lev_comp when map was too tall @@ -134,10 +128,17 @@ General New Features -------------------- naming Sting or Orcrist now breaks illiterate conduct different feedback for reading a scroll of mail created by writing with marker -wizard mode #wizintrinsic reading non-cursed scroll of enchant weapon uncurses welded tin opener if hero has no jumping ability but knows the jumping spell, the #jump command will attempt to cast the spell +allow moving cursor to monsters with 'm' (nearest first) and 'M' (furthest + first) when asked for map location, or to objects with 'o' and 'O' +allow picking a used inventory letter from menu when #adjusting +zapping wand of opening at yourself, unlock carried boxes +dissolve iron bars by force-fighting with wielded potion of acid +poison breath leaves a trail of poison gas +allow knife and stiletto as possible tin opening tools +wizard mode #wizintrinsic command additional tribute passages for The Colour of Magic, The Light Fantastic, Equal Rites, Snuff, and Raising Steam compile-time options SIMPLE_MAIL and SERVER_ADMIN_MSG for public server use diff --git a/src/do_name.c b/src/do_name.c index 2341adb0e..da48c07dc 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -8,6 +8,7 @@ STATIC_DCL char *NDECL(nextmbuf); STATIC_DCL void FDECL(getpos_help, (BOOLEAN_P, const char *)); STATIC_DCL int FDECL(CFDECLSPEC cmp_coord_distu, (const void *, const void *)); +STATIC_OVL void FDECL(gather_locs, (coord **, int *, BOOLEAN_P)); STATIC_DCL void NDECL(do_mname); STATIC_DCL boolean FDECL(alreadynamed, (struct monst *, char *, char *)); STATIC_DCL void FDECL(do_oname, (struct obj *)); @@ -58,6 +59,7 @@ const char *goal; putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); putstr(tmpwin, 0, "Use @ to move the cursor on yourself."); putstr(tmpwin, 0, "Use m or M to move the cursor to next monster."); + putstr(tmpwin, 0, "Use o or O to move the cursor to next object."); if (getpos_hilitefunc) putstr(tmpwin, 0, "Use $ to display valid locations."); putstr(tmpwin, 0, "Use # to toggle automatic description."); @@ -93,6 +95,61 @@ const void *b; return dist_1 - dist_2; } +/* gather locations for monsters or objects shown on the map */ +STATIC_OVL void +gather_locs(arr_p, cnt_p, do_mons) +coord **arr_p; +int *cnt_p; +boolean do_mons; +{ + int x, y, pass, glyph, idx; + + *cnt_p = idx = 0; + for (pass = 0; pass < 2; pass++) { + if (pass) { + /* *cnt_p + 1: always allocate a non-zero amount */ + *arr_p = (coord *) alloc(sizeof (coord) * (*cnt_p + 1)); + if (!*cnt_p) { + /* needed for caller's mon[0].x,.y==u.ux,.uy check */ + (*arr_p)[0].x = (*arr_p)[0].y = 0; + break; + } + } + for (x = 1; x < COLNO; x++) + for (y = 0; y < ROWNO; y++) { + glyph = glyph_at(x, y); + if (do_mons) { + /* unlike '/M', this skips monsters revealed by + * warning glyphs and remembered invisible ones; + * TODO: skip worm tails + */ + if (glyph_is_monster(glyph)) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } + } + } else { /* objects */ + /* TODO: skip boulders and rocks */ + if (glyph_is_object(glyph)) { + if (!pass) { + ++*cnt_p; + } else { + (*arr_p)[idx].x = x; + (*arr_p)[idx].y = y; + ++idx; + } + } + } + } + } /* pass */ + if (*cnt_p) + qsort(*arr_p, *cnt_p, sizeof (coord), cmp_coord_distu); +} + int getpos(ccp, force, goal) coord *ccp; @@ -107,9 +164,8 @@ const char *goal; static const char pick_chars[] = ".,;:"; const char *cp; boolean hilite_state = FALSE; - coord *monarr = NULL; - int moncount = 0; - int monidx = 0; + coord *monarr = (coord *) 0, *objarr = (coord *) 0; + int moncount = 0, monidx = 0, objcount = 0, objidx = 0; if (!goal) goal = "desired location"; @@ -244,32 +300,15 @@ const char *goal; goto nxtc; } else if (c == 'm' || c == 'M') { if (!monarr) { - int x,y,s; - - moncount = 0; - for (s = 0; s < 2; s++) { - if (s) { - /* moncount + 1: always allocate a non-zero amount */ - monarr = (coord *) alloc(sizeof (coord) * (moncount + 1)); - monidx = 0; - } - if (!s || s && moncount) - for (x = 0; x < COLNO; x++) - for (y = 0; y < ROWNO; y++) - if (glyph_is_monster(glyph_at(x,y)) - && !(x == u.ux && y == u.uy)) { - if (!s) - moncount++; - else { - monarr[monidx].x = x; - monarr[monidx].y = y; - monidx++; - } - } - } - qsort(monarr, moncount, sizeof (coord), cmp_coord_distu); - /* ready for first increment/decrement to change to zero */ - monidx = (c == 'm') ? -1 : 1; + gather_locs(&monarr, &moncount, TRUE); + /* when hero is first element (always, unless unseen), + we want first increment to reach 1 (nearest aside + from hero) or first decrement to reach moncount-1 + (farthest); if hero is not first element, we want + first increment to end up with 0 (nearest monster), + first decrement should still choose moncount-1 */ + monidx = (monarr[0].x == u.ux && monarr[0].y == u.uy) ? 0 + : (c == 'm') ? -1 : 0; } if (moncount) { if (c == 'm') { @@ -282,6 +321,24 @@ const char *goal; cy = monarr[monidx].y; goto nxtc; } + } else if (c == 'o' || c == 'O') { + if (!objarr) { + gather_locs(&objarr, &objcount, FALSE); + /* ready for first increment to change to zero + or first decrement to change to objcount-1 */ + objidx = (c == 'o') ? -1 : 0; + } + if (objcount) { + if (c == 'o') { + objidx = (objidx + 1) % objcount; + } else { + if (--objidx < 0) + objidx = objcount - 1; + } + cx = objarr[objidx].x; + cy = objarr[objidx].y; + goto nxtc; + } } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; @@ -375,6 +432,8 @@ const char *goal; ccp->y = cy; if (monarr) free((genericptr_t) monarr); + if (objarr) + free((genericptr_t) objarr); getpos_hilitefunc = (void FDECL((*), (int))) 0; return result; }