diff --git a/.travis.yml b/.travis.yml index dba3f2649..dd9c6903b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,21 +1,37 @@ language: c matrix: include: - - os: linux - env: DESCR=linux-xenial-gcc HINTS=linux + - name: linux-xenial-gcc + os: linux + env: HINTS=linux LUA_VERSION=5.3.5 compiler: gcc - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make install" - - os: linux - env: DESCR=linux-bionic-gcc HINTS=linux + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make install + - name: linux-bionic-gcc + os: linux + env: HINTS=linux LUA_VERSION=5.3.5 dist: bionic compiler: gcc - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make install" - - os: linux - env: DESCR=linux-xenial-clang HINTS=linux + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make install + - name: linux-xenial-clang + os: linux + env: HINTS=linux LUA_VERSION=5.3.5 compiler: clang - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make install" - - os: linux - env: DESCR=linux-xenial-gcc-x11 HINTS=linux-x11 + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make install + - name: linux-xenial-gcc-x11 + os: linux + env: HINTS=linux-x11 LUA_VERSION=5.3.5 compiler: gcc addons: apt: @@ -23,9 +39,14 @@ matrix: - libx11-dev - libxaw7-dev - xfonts-utils - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make install" - - os: linux - env: DESCR=linux-xenial-gcc-qt5 HINTS=linux-qt5 + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make install + - name: linux-xenial-gcc-qt5 + os: linux + env: HINTS=linux-qt5 LUA_VERSION=5.3.5 compiler: gcc addons: apt: @@ -36,9 +57,14 @@ matrix: - qtbase5-dev - qtmultimedia5-dev - qtbase5-dev-tools - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make QT_SELECT=5 MOC=moc install" - - os: linux - env: DESCR=linux-bionic-gcc-x11 HINTS=linux-x11 + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make QT_SELECT=5 MOC=moc install + - name: linux-bionic-gcc-x11 + os: linux + env: HINTS=linux-x11 LUA_VERSION=5.3.5 dist: bionic compiler: gcc addons: @@ -47,9 +73,14 @@ matrix: - libx11-dev - libxaw7-dev - xfonts-utils - script: "cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ && make fetch-lua && make install" - - os: linux - env: DESCR=linux-xenial-gcc-minimal HINTS=linux-minimal + script: + - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ + - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - make install + - name: linux-xenial-gcc-minimal + os: linux + env: HINTS=linux-minimal LUA_VERSION=5.3.5 compiler: gcc script: | cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ @@ -72,31 +103,37 @@ matrix: sed -i '/^#define SHELL/d' include/unixconf.h sed -i '/^#define SUSPEND/d' include/unixconf.h sed -i 's/^#define TEXTCOLOR//' include/unixconf.h - make fetch-lua && make install + make fetch-lua + test -d "lib/lua-$LUA_VERSION/src" || exit 0 + make install cat dat/options - - os: windows - env: DESCR=windows-visualstudio + - name: windows-visualstudio + os: windows language: shell script: - ./win/win32/vs2017/travisci.sh - - os: windows + - name: windows-mingw + os: windows # install: choco install mingw - env: DESCR=windows-mingw script: - sh sys/winnt/travis-gcc.sh + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 + - test -d "lib/pdcurses" || exit 0 - export ADD_CURSES=Y - export PDCURSES_TOP=../lib/pdcurses - export LUA_VERSION=5.3.5 - cd src - cp ../sys/winnt/Makefile.gcc ./Makefile - mingw32-make install - - os: linux - env: DESCR=msdos-cross-on-linux HINTS=linux LUA_VERSION=5.3.5 + - name: msdos crosscompile on linux + os: linux + env: HINTS=linux LUA_VERSION=5.3.5 compiler: gcc script: # - export - cd sys/unix/ && sh setup.sh hints/$HINTS && cd ../../ - make fetch-lua + - test -d "lib/lua-$LUA_VERSION/src" || exit 0 - cd lib/lua-$LUA_VERSION/src && make a && cd ../../.. - sh sys/msdos/msdos-cross-compile.sh exclude: diff --git a/dat/dungeon.lua b/dat/dungeon.lua index 6112a25ad..014d3dab3 100644 --- a/dat/dungeon.lua +++ b/dat/dungeon.lua @@ -178,7 +178,8 @@ dungeon = { }, { name = "minend", - bonetag = "E", +-- 3.7.0: minend changed to no-bones to simplify achievement tracking +-- bonetag = "E" base = -1, nlevels = 3 }, diff --git a/dat/quest.lua b/dat/quest.lua index 891556987..7e484df1d 100644 --- a/dat/quest.lua +++ b/dat/quest.lua @@ -4,7 +4,7 @@ -- - export the quest string replacements to lua, instead of %H etc -- - allow checking if hero is carrying item (see comments for %Cp Arc 00042) -- - fold quest_portal, quest_portal_again, quest_portal_demand into one --- - some roles have no goal_alt, fold into goal_next? +-- - write tests to check questtext validity? -- - qt_pager hack(?): if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11")) @@ -25,6 +25,10 @@ questtext = { + -- If a role doesn't have a specific message, try a fallback + msg_fallbacks = { + goal_alt = "goal_next" + }, common = { TEST_PATTERN = { output = "text", diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 5f11df441..dace17425 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1,4 +1,4 @@ -.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.346 $ $NHDT-Date: 1578448653 2020/01/08 01:57:33 $ +.\" $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.347 $ $NHDT-Date: 1579262524 2020/01/17 12:02:04 $ .\" .\" This is an excerpt from the 'roff' man page from the 'groff' package. .\" NetHack's Guidebook.mn currently does *not* adhere to these guidelines. @@ -3160,7 +3160,11 @@ Cannot be set with the \(oqO\(cq command. .lp ignintr Ignore interrupt signals, including breaks (default off). Persistent. .lp implicit_uncursed -Omit "uncursed" from inventory lists, if possible (default on). +Omit \(lquncursed\(rq from object descriptions when it can be deduced from +other aspects of the description (default on). +Persistent. +.lp "" +If you use menu coloring, you may want to turn this off. .lp legacy Display an introductory message when starting the game (default on). Persistent. @@ -3180,6 +3184,7 @@ An obsolete synonym for \(lqgender:male\(rq. Cannot be set with the \(oqO\(cq command. .lp mention_walls Give feedback when walking against a wall (default off). +Persistent. .lp menucolors Enable coloring menu lines (default off). See \(lqConfiguring Menu Colors\(rq on how to configure the colors. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index d3041e154..f81348abe 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3436,6 +3436,7 @@ Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. + %.lp "" With the curses interface, the {\it petattr\/} option controls how to highlight pets and setting it will turn the @@ -3460,7 +3461,12 @@ Only available for TTY and Windows GUI, and only when statushilites is on. Ignore interrupt signals, including breaks (default off). Persistent. %.lp \item[\ib{implicit\verb+_+uncursed}] -Omit ``uncursed'' from inventory lists, if possible (default on). +Omit ``uncursed'' from object descriptions when it can be deduced from +other aspects of the description (default on). +Persistent. + +%.lp "" +If you use menu coloring, you may want to turn this off. %.lp \item[\ib{legacy}] Display an introductory message when starting the game (default on). @@ -3484,7 +3490,7 @@ An obsolete synonym for ``{\tt gender:male}''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{mention\verb+_+walls}] -Give feedback when walking against a wall (default off). +Give feedback when walking against a wall (default off). Persistent. %.lp \item[\ib{menucolors}] Enable coloring menu lines (default off). diff --git a/doc/fixes37.0 b/doc/fixes37.0 index bb7e14203..b2b555a40 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ $NHDT-Date: 1578896120 2020/01/13 06:15:20 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ $NHDT-Date: 1579899144 2020/01/24 20:52:24 $ General Fixes and Modified Features ----------------------------------- @@ -42,6 +42,11 @@ walking out of tethered-to-buried-object trap condition was supposed to attached chain that got dragged around but had no ball attached when poly'd into a giant and moving onto a boulder's spot, message given was confused about whether autopickup would occur so could be misleading +random role selection wasn't honoring unwanted alignment(s) properly +if at the edge of the map window, trying to move farther fails but used a turn +hero can no longer wear blindfold/towel/lenses when poly'd into headless form +revamp achievement tracking for exploring Mine's End and Sokoban (by acquiring + luckstone and bag of holding or amulet of reflection, respectively) Fixes to 3.7.0-x Problems that Were Exposed Via git Repository @@ -69,10 +74,13 @@ if running and Blind or Stunned or Fumbling or Dex < 10, encountering a closed data.base lookup of an entry with any blank lines would falsely claim that "'data' file in wrong fromat or corrupted" after some extra checks were added while investigating tab handling anomalies +using nhl_error() to report a Lua processing problem would clobber the stack Platform- and/or Interface-Specific Fixes ----------------------------------------- +tty: role and race selection menus weren't filtering out potential choices + which got excluded by OPTIONS=align:!lawful or !neutral or !chaotic General New Features @@ -108,6 +116,9 @@ tiny chance for randomly created spellbooks to be Discworld novels instead of having only one in the first book or scroll shop created (won't occur in hero's initial inventory or NPC priest inventory or be bestowed as a prayer boon or be found in statues) +'goldX', 'implicit_uncursed', and 'mention_walls' options changed to be + persistent across save/restore +wearing a wet towel confers "half damage from poison gas" attribute Platform- and/or Interface-Specific New Features @@ -118,8 +129,6 @@ NetHack Community Patches (or Variation) Included ------------------------------------------------- hallucinatory trap names from github pull request #174 autounlock feature originally from unnethack in github pull request #228 -applying a candelabrum with no candles gives a tip (github #265) -candelabrum now reads "(n of 7 candles attached)" (github #265) replace "You feel cold" message for freezing unseen door (github #265) applying a candelabrum with no candles gives a tip (github #265) candelabrum now reads "(n of 7 candles attached)" (github #265) diff --git a/doc/makedefs.txt b/doc/makedefs.txt index 97a1f0ac7..8d6c85bc1 100644 --- a/doc/makedefs.txt +++ b/doc/makedefs.txt @@ -30,20 +30,20 @@ SHORT COMMANDS through the same logic as that used by the --grep command; see the MDGREP FUNCTIONS section below for details. - -m Generate monster.c. - - -v Generate date.h and options file. It will read dat/gitinfo.txt, + -c Generate date.h and options file. It will read dat/gitinfo.txt, + only if it is present, to obtain githash= and gitbranch= + info and include related preprocessor #defines in date.h file. only if it is present, to obtain githash= and gitbranch= info and include related preprocessor #defines in date.h file. -p Generate pm.h - -q Generate quest.dat. - -r Generate the rumors file. -s Generate the bogusmon , engrave and epitaphfiles. + -s Generate the bogusmon , engrave and epitaphfiles. + -h Generate the oracles file. -z Generate vis_tab.c and vis_tab.h. @@ -148,4 +148,5 @@ COPYRIGHT -NETHACK 25 May 2015 MAKEDEFS(6) + +NETHACK 1 Jan 2020 MAKEDEFS(6) diff --git a/doc/nethack.6 b/doc/nethack.6 index 446568ffb..d599a0b1a 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -95,7 +95,7 @@ will identify the things you see on the screen. To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. -Few people achieve this; most never do. Those who have go down +Few people achieve this; most never do. Those who have done so go down in history as heroes among heroes - and then they find ways of making the game even harder. See the .I Guidebook diff --git a/doc/nethack.txt b/doc/nethack.txt index 95a220b4a..d1d187016 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -27,10 +27,10 @@ DESCRIPTION To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Few people achieve - this; most never do. Those who have go down in history as heroes among - heroes - and then they find ways of making the game even harder. See - the Guidebook section on Conduct if this game has gotten too easy for - you. + this; most never do. Those who have done so go down in history as he- + roes among heroes - and then they find ways of making the game even + harder. See the Guidebook section on Conduct if this game has gotten + too easy for you. When the game ends, whether by your dying, quitting, or escaping from the caves, NetHack will give you (a fragment of) the list of top scor- @@ -154,7 +154,7 @@ FILES nethack The program itself. data, oracles, rumors Data files used by NetHack. - quest.dat, bogusmon More data files. + bogusmon another data file. engrave, epitaph, tribute Still more data files. symbols Data file holding sets of specifications for how to display monsters, objects, and @@ -163,8 +163,8 @@ FILES build-time option settings. help, hh Help data files. cmdhelp, opthelp, wizhelp More help data files. - *.lev Predefined special levels. - dungeon Control file for special levels. + *.lua Predefined special levels, dungeon control + for special levels, quest texts history A short history of NetHack. license Rules governing redistribution. record The list of top scorers. @@ -192,8 +192,8 @@ FILES program is built with 'SYSCF' option enabled, ignored if not. - The location of 'sysconf' is specified at build time and can't be - changed except by updating source file "config.h" and rebuilding the + The location of 'sysconf' is specified at build time and can't be + changed except by updating source file "config.h" and rebuilding the program. In a perfect world, 'paniclog' would remain empty. @@ -211,21 +211,21 @@ ENVIRONMENT NETHACKOPTIONS String predefining several NetHack options. - If the same option is specified in both NETHACKOPTIONS and .nethackrc, + If the same option is specified in both NETHACKOPTIONS and .nethackrc, the value assigned in NETHACKOPTIONS takes precedence. SHOPTYPE and SPLEVTYPE can be used in debugging (wizard) mode. DEBUGFILES can be used if the program was built with 'DEBUG' enabled. SEE ALSO - dgn_comp(6), lev_comp(6), recover(6) + recover(6) BUGS Probably infinite. COPYRIGHT - This file is Copyright (C) Robert Patrick Rankin and was last modified - 2019/09/15 (version NetHack-3.6:1.16). NetHack may be freely redis- + This file is Copyright (C) Robert Patrick Rankin and was last modified + 2019/09/15 (version NetHack-3.6:1.16). NetHack may be freely redis- tributed. See license for details. Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. diff --git a/include/context.h b/include/context.h index 4e8b01f62..dafc0c3f8 100644 --- a/include/context.h +++ b/include/context.h @@ -105,6 +105,11 @@ struct novel_tracking { /* for choosing random passage when reading novel */ passage from the Death Quotes section of dat/tribute */ }; +struct achievement_tracking { + unsigned mines_prize_oid, soko_prize_oid; /* obj->o_id */ + short mines_prize_type, soko_prize_typ1, soko_prize_typ2; /* obj->otyp */ +}; + struct context_info { unsigned ident; /* social security number for each monster */ unsigned no_of_wizards; /* 0, 1 or 2 (wizard and his shadow) */ @@ -143,6 +148,7 @@ struct context_info { struct obj_split objsplit; /* track most recently split object stack */ struct tribute_info tribute; struct novel_tracking novel; + struct achievement_tracking achieveo; }; #endif /* CONTEXT_H */ diff --git a/include/decl.h b/include/decl.h index d6100e241..54a58aa03 100644 --- a/include/decl.h +++ b/include/decl.h @@ -215,7 +215,7 @@ typedef struct { boolean fieldlevel; /* fieldlevel saves saves each field individually */ boolean addinfo; /* if set, some additional context info from core */ boolean eof; /* place to mark eof reached */ - boolean bendian; /* set to true if executing on a big-endian machine */ + boolean bendian; /* set to true if executing on big-endian machine */ FILE *fpdef; /* file pointer for fieldlevel default style */ FILE *fpdefmap; /* file pointer mapfile for def format */ FILE *fplog; /* file pointer logfile */ @@ -1184,15 +1184,13 @@ struct instance_globals { char *lev_message; lev_region *lregions; int num_lregions; - /* positions touched by level elements explicitly defined in the des-file */ + /* positions touched by level elements explicitly defined in des-file */ char SpLev_Map[COLNO][ROWNO]; struct sp_coder *coder; xchar xstart, ystart; char xsize, ysize; boolean splev_init_present; boolean icedpools; - int mines_prize_count; - int soko_prize_count; /* achievements */ struct obj *container_obj[MAX_CONTAINMENT]; int container_idx; struct monst *invent_carrying_monster; diff --git a/include/flag.h b/include/flag.h index c94ae1549..0cfd3dabc 100644 --- a/include/flag.h +++ b/include/flag.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 flag.h $NHDT-Date: 1577050470 2019/12/22 21:34:30 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.167 $ */ +/* NetHack 3.7 flag.h $NHDT-Date: 1579261284 2020/01/17 11:41:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.172 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -36,10 +36,12 @@ struct flag { boolean goldX; /* for BUCX filtering, whether gold is X or U */ boolean help; /* look in data file for info about stuff */ boolean ignintr; /* ignore interrupts */ + boolean implicit_uncursed; /* maybe omit "uncursed" status in inventory */ boolean ins_chkpt; /* checkpoint as appropriate; INSURANCE */ boolean invlet_constant; /* let objects keep their inventory symbol */ boolean legacy; /* print game entry "story" */ boolean lit_corridor; /* show a dark corr as lit if it is in sight */ + boolean mention_walls; /* give feedback when bumping walls */ boolean nap; /* `timed_delay' option for display effects */ boolean null; /* OK to send nulls to the terminal */ boolean pickup; /* whether you pickup or move and look */ @@ -258,8 +260,6 @@ struct instance_flags { boolean echo; /* 1 to echo characters */ boolean force_invmenu; /* always menu when handling inventory */ boolean hilite_pile; /* mark piles of objects with a hilite */ - boolean implicit_uncursed; /* maybe omit "uncursed" status in inventory */ - boolean mention_walls; /* give feedback when bumping walls */ boolean menu_head_objsym; /* Show obj symbol in menu headings */ boolean menu_overlay; /* Draw menus over the map */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix diff --git a/include/obj.h b/include/obj.h index b31181394..6b0d9c5e9 100644 --- a/include/obj.h +++ b/include/obj.h @@ -346,19 +346,9 @@ struct obj { && !undiscovered_artifact(ART_EYES_OF_THE_OVERWORLD))) #define pair_of(o) ((o)->otyp == LENSES || is_gloves(o) || is_boots(o)) -/* 'PRIZE' values override obj->corpsenm so prizes mustn't be object types - which use that field for monster type (or other overloaded purpose) */ -#define MINES_PRIZE 1 -#define SOKO_PRIZE1 2 -#define SOKO_PRIZE2 3 -#define is_mines_prize(o) \ - ((o)->otyp == iflags.mines_prize_type \ - && (o)->record_achieve_special == MINES_PRIZE) -#define is_soko_prize(o) \ - (((o)->otyp == iflags.soko_prize_type1 \ - && (o)->record_achieve_special == SOKO_PRIZE1) \ - || ((o)->otyp == iflags.soko_prize_type2 \ - && (o)->record_achieve_special == SOKO_PRIZE2)) +/* achievement tracking; 3.6.x did this differently */ +#define is_mines_prize(o) ((o)->o_id == g.context.achieveo.mines_prize_oid) +#define is_soko_prize(o) ((o)->o_id == g.context.achieveo.soko_prize_oid) /* Flags for get_obj_location(). */ #define CONTAINED_TOO 0x1 diff --git a/include/patchlevel.h b/include/patchlevel.h index f5130c60f..51d8a6a14 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -1,4 +1,4 @@ -/* NetHack 3.7 patchlevel.h $NHDT-Date: 1577050471 2019/12/22 21:34:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.7 patchlevel.h $NHDT-Date: 1579261287 2020/01/17 11:41:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.148 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -14,7 +14,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 9 +#define EDITLEVEL 11 #define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2020" #define COPYRIGHT_BANNER_B \ diff --git a/include/youprop.h b/include/youprop.h index 20d1045e8..0faafe102 100644 --- a/include/youprop.h +++ b/include/youprop.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 youprop.h $NHDT-Date: 1568831820 2019/09/18 18:37:00 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.6 youprop.h $NHDT-Date: 1579655025 2020/01/22 01:03:45 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -374,4 +374,8 @@ #define Hate_silver (u.ulycn >= LOW_PM || hates_silver(g.youmonst.data)) +/* _Hitchhikers_Guide_to_the_Galaxy_ on uses for 'towel': "wrap it round + your head to ward off noxious fumes" [we require it to be damp or wet] */ +#define Half_gas_damage (ublindf && ublindf->otyp == TOWEL && ublindf->spe > 0) + #endif /* YOUPROP_H */ diff --git a/src/attrib.c b/src/attrib.c index 31c9fef67..eb069a1f0 100644 --- a/src/attrib.c +++ b/src/attrib.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 attrib.c $NHDT-Date: 1575245050 2019/12/02 00:04:10 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.66 $ */ +/* NetHack 3.6 attrib.c $NHDT-Date: 1579655026 2020/01/22 01:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ @@ -277,11 +277,12 @@ int typ, fatal; /* if fatal is 0, limit damage to adjattrib */ boolean thrown_weapon; /* thrown weapons are less deadly */ { int i, loss, kprefix = KILLED_BY_AN; + boolean blast = !strcmp(reason, "blast"); /* inform player about being poisoned unless that's already been done; "blast" has given a "blast of poison gas" message; "poison arrow", "poison dart", etc have implicitly given poison messages too... */ - if (strcmp(reason, "blast") && !strstri(reason, "poison")) { + if (!blast && !strstri(reason, "poison")) { boolean plural = (reason[strlen(reason) - 1] == 's') ? 1 : 0; /* avoid "The" Orcus's sting was poisoned... */ @@ -290,7 +291,7 @@ boolean thrown_weapon; /* thrown weapons are less deadly */ plural ? "were" : "was"); } if (Poison_resistance) { - if (!strcmp(reason, "blast")) + if (blast) shieldeff(u.ux, u.uy); pline_The("poison doesn't seem to affect you."); return; @@ -315,8 +316,12 @@ boolean thrown_weapon; /* thrown weapons are less deadly */ g.context.botl = TRUE; pline_The("poison was deadly..."); } else if (i > 5) { + boolean cloud = !strcmp(reason, "gas cloud"); + /* HP damage; more likely--but less severe--with missiles */ loss = thrown_weapon ? rnd(6) : rn1(10, 6); + if ((blast || cloud) && Half_gas_damage) /* worn towel */ + loss = (loss + 1) / 2; losehp(loss, pkiller, kprefix); /* poison damage */ } else { /* attribute loss; if typ is A_STR, reduction in current and diff --git a/src/bones.c b/src/bones.c index 8ebe47cea..6816baa87 100644 --- a/src/bones.c +++ b/src/bones.c @@ -165,14 +165,10 @@ boolean restore; if (mnum == PM_DOPPELGANGER && otmp->otyp == CORPSE) set_corpsenm(otmp, mnum); } - } else if ((otmp->otyp == iflags.mines_prize_type - && !Is_mineend_level(&u.uz)) - || ((otmp->otyp == iflags.soko_prize_type1 - || otmp->otyp == iflags.soko_prize_type2) - && !Is_sokoend_level(&u.uz))) { - /* "special prize" in this game becomes ordinary object - if loaded into another game */ - otmp->record_achieve_special = NON_PM; + } else if (is_mines_prize(otmp) || is_soko_prize(otmp)) { + /* achievement tracking; in case prize was moved off its + original level (which is always a no-bones level) */ + otmp->nomerge = 0; } else if (otmp->otyp == AMULET_OF_YENDOR) { /* no longer the real Amulet */ otmp->otyp = FAKE_AMULET_OF_YENDOR; diff --git a/src/cmd.c b/src/cmd.c index 11eb394b2..46f210f19 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1578764033 2020/01/11 17:33:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.391 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1579655026 2020/01/22 01:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.392 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -806,6 +806,24 @@ boolean pre, wiztower; continue; if (mtmp->isshk) setpaid(mtmp); + /* achievement tracking */ + { + static const char Unachieve[] = "%s achievement revoked."; + + if (Is_mineend_level(&u.uz)) { + if (u.uachieve.mines_luckstone) { + pline(Unachieve, "Mine's end"); + u.uachieve.mines_luckstone = 0; + } + g.context.achieveo.mines_prize_oid = 0; + } else if (Is_sokoend_level(&u.uz)) { + if (u.uachieve.finish_sokoban) { + pline(Unachieve, "Sokoban end"); + u.uachieve.finish_sokoban = 0; + } + g.context.achieveo.soko_prize_oid = 0; + } + } /* TODO? * Reduce 'born' tally for each monster about to be discarded * by savelev(), otherwise replacing heavily populated levels @@ -877,6 +895,7 @@ wiz_makemap(VOID_ARGS) { if (wizard) { boolean was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz); + makemap_prepost(TRUE, was_in_W_tower); /* create a new level; various things like bestowing a guardian angel on Astral or setting off alarm on Ft.Ludios are handled @@ -2984,6 +3003,8 @@ int final; enlght_halfdmg(HALF_PHDAM, final); if (Half_spell_damage) enlght_halfdmg(HALF_SPDAM, final); + if (Half_gas_damage) + enl_msg(You_, "take", "took", " reduced poison gas damage", ""); /* polymorph and other shape change */ if (Protection_from_shape_changers) you_are("protected from shape changers", diff --git a/src/decl.c b/src/decl.c index 8ae9aa6c7..79cbd199a 100644 --- a/src/decl.c +++ b/src/decl.c @@ -638,8 +638,6 @@ const struct instance_globals g_init = { UNDEFINED_VALUE, /* ysize */ FALSE, /* splev_init_present */ FALSE, /* icedpools */ - 0, /* mines_prize_count */ - 0, /* soki_prize_count */ { UNDEFINED_PTR }, /* container_obj */ 0, /* container_idx */ NULL, /* invent_carrying_monster */ diff --git a/src/do_wear.c b/src/do_wear.c index 584d9fb7c..663cb6947 100644 --- a/src/do_wear.c +++ b/src/do_wear.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_wear.c $NHDT-Date: 1575768410 2019/12/08 01:26:50 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.126 $ */ +/* NetHack 3.6 do_wear.c $NHDT-Date: 1579649788 2020/01/21 23:36:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.127 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1159,15 +1159,19 @@ void Blindf_off(otmp) struct obj *otmp; { - boolean was_blind = Blind, changed = FALSE; + boolean was_blind = Blind, changed = FALSE, + nooffmsg = !otmp; + if (!otmp) + otmp = ublindf; if (!otmp) { - impossible("Blindf_off without otmp"); + impossible("Blindf_off without eyewear?"); return; } g.context.takeoff.mask &= ~W_TOOL; setworn((struct obj *) 0, otmp->owornmask); - off_msg(otmp); + if (!nooffmsg) + off_msg(otmp); if (Blind) { if (was_blind) { @@ -1895,6 +1899,15 @@ struct obj *obj; return 1; } } else { + /* + * FIXME: + * except for the rings/nolimbs case, this allows you to put on + * accessories without having any hands to manipulate them, and + * to put them on when poly'd into a tiny or huge form where + * they shouldn't fit. [If the latter situation changes, make + * comparable change to break_armor(polyself.c).] + */ + /* accessory */ if (ring) { char answer, qbuf[QBUFSZ]; @@ -1965,6 +1978,11 @@ struct obj *obj; return 0; } } else if (eyewear) { + if (!has_head(g.youmonst.data)) { + You("have no head to wear %s on.", ansimpleoname(obj)); + return 0; + } + if (ublindf) { if (ublindf->otyp == TOWEL) Your("%s is already covered by a towel.", diff --git a/src/dothrow.c b/src/dothrow.c index ace9d4984..2369e1326 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1573688688 2019/11/13 23:44:48 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.164 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1579655027 2020/01/22 01:03:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.181 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1977,7 +1977,8 @@ boolean from_invent; explode_oil(obj, x, y); } else if (distu(x, y) <= 2) { if (!breathless(g.youmonst.data) || haseyes(g.youmonst.data)) { - if (obj->otyp != POT_WATER) { + /* wet towel protects both eyes and breathing */ + if (obj->otyp != POT_WATER && !Half_gas_damage) { if (!breathless(g.youmonst.data)) { /* [what about "familiar odor" when known?] */ You("smell a peculiar odor..."); diff --git a/src/hack.c b/src/hack.c index 06a99cf88..84639f63e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1578916008 2020/01/13 11:46:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.243 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1579261288 2020/01/17 11:41:28 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.245 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -750,7 +750,7 @@ int mode; return FALSE; } if (!(Passes_walls || passes_bars(g.youmonst.data))) { - if (mode == DO_MOVE && iflags.mention_walls) + if (mode == DO_MOVE && flags.mention_walls) You("cannot pass through the bars."); return FALSE; } @@ -772,7 +772,7 @@ int mode; else if (Passes_walls && !may_passwall(x, y) && In_sokoban(&u.uz)) pline_The("Sokoban walls resist your ability."); - else if (iflags.mention_walls) + else if (flags.mention_walls) pline("It's %s.", (IS_WALL(tmpr->typ) || tmpr->typ == SDOOR) ? "a wall" : IS_TREE(tmpr->typ) ? "a tree" @@ -842,7 +842,7 @@ int mode; if (mode == DO_MOVE) { if (Blind) feel_location(x, y); - if (Underwater || iflags.mention_walls) + if (Underwater || flags.mention_walls) You_cant("move diagonally into an intact doorway."); } return FALSE; @@ -896,7 +896,7 @@ int mode; if (dx && dy && !Passes_walls && IS_DOOR(ust->typ) && (!doorless_door(ux, uy) || block_entry(x, y))) { /* Can't move at a diagonal out of a doorway with door. */ - if (mode == DO_MOVE && iflags.mention_walls) + if (mode == DO_MOVE && flags.mention_walls) You_cant("move diagonally out of an intact doorway."); return FALSE; } @@ -904,7 +904,7 @@ int mode; if (sobj_at(BOULDER, x, y) && (Sokoban || !Passes_walls)) { if (!(Blind || Hallucination) && (g.context.run >= 2) && mode != TEST_TRAV) { - if (mode == DO_MOVE && iflags.mention_walls) + if (mode == DO_MOVE && flags.mention_walls) pline("A boulder blocks your path."); return FALSE; } @@ -1495,7 +1495,7 @@ domove_core() } } if (!isok(x, y)) { - if (iflags.mention_walls) { + if (flags.mention_walls) { int dx = u.dx, dy = u.dy; if (dx && dy) { /* diagonal */ @@ -1511,13 +1511,14 @@ domove_core() directionname(xytod(dx, dy))); } nomul(0); + g.context.move = 0; return; } if (((trap = t_at(x, y)) && trap->tseen) || (Blind && !Levitation && !Flying && !is_clinger(g.youmonst.data) && is_pool_or_lava(x, y) && levl[x][y].seenv)) { if (g.context.run >= 2) { - if (iflags.mention_walls) { + if (flags.mention_walls) { if (trap && trap->tseen) { You("stop in front of %s.", an(trapname(trap->ttyp, FALSE))); @@ -2728,7 +2729,7 @@ lookaround() if ((g.context.run != 1 && !mtmp->mtame) || (x == u.ux + u.dx && y == u.uy + u.dy && !g.context.travel)) { - if (iflags.mention_walls) + if (flags.mention_walls) pline("%s blocks your path.", upstart(a_monnam(mtmp))); goto stop; } @@ -2746,7 +2747,7 @@ lookaround() if (x != u.ux && y != u.uy) continue; if (g.context.run != 1) { - if (iflags.mention_walls) + if (flags.mention_walls) You("stop in front of the door."); goto stop; } @@ -2775,11 +2776,9 @@ lookaround() if (g.context.run == 1) goto bcorr; /* if you must */ if (x == u.ux + u.dx && y == u.uy + u.dy) { - if (iflags.mention_walls) { - + if (flags.mention_walls) You("stop in front of %s.", an(trapname(trap->ttyp, FALSE))); - } goto stop; } continue; @@ -2793,7 +2792,7 @@ lookaround() * to test boots by trying to SHIFT-direction * into a pool and seeing if the game allowed it */ - if (iflags.mention_walls) + if (flags.mention_walls) You("stop at the edge of the %s.", hliquid(is_pool(x,y) ? "water" : "lava")); goto stop; @@ -2816,7 +2815,7 @@ lookaround() } /* end for loops */ if (corrct > 1 && g.context.run == 2) { - if (iflags.mention_walls) + if (flags.mention_walls) pline_The("corridor widens here."); goto stop; } diff --git a/src/invent.c b/src/invent.c index 6c3d7c363..88d6fb1d3 100644 --- a/src/invent.c +++ b/src/invent.c @@ -835,20 +835,14 @@ struct obj *obj; } /* "special achievements" aren't discoverable during play, they - end up being recorded in XLOGFILE at end of game, nowhere else; - record_achieve_special overloads corpsenm which is ordinarily - initialized to NON_PM (-1) rather than to 0; any special prize - must never be a corpse, egg, tin, figurine, or statue because - their use of obj->corpsenm for monster type would conflict, - nor be a leash (corpsenm overloaded for m_id of leashed - monster) or a novel (corpsenm overloaded for novel index) */ + end up being recorded in XLOGFILE at end of game, nowhere else */ if (is_mines_prize(obj)) { u.uachieve.mines_luckstone = 1; - obj->record_achieve_special = NON_PM; + g.context.achieveo.mines_prize_oid = 0; obj->nomerge = 0; } else if (is_soko_prize(obj)) { u.uachieve.finish_sokoban = 1; - obj->record_achieve_special = NON_PM; + g.context.achieveo.soko_prize_oid = 0; obj->nomerge = 0; } } diff --git a/src/monmove.c b/src/monmove.c index b72353629..324eaeb05 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1575245074 2019/12/02 00:04:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.116 $ */ +/* NetHack 3.6 monmove.c $NHDT-Date: 1579616424 2020/01/21 14:20:24 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.128 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1286,20 +1286,27 @@ register int after; if (!m_in_out_region(mtmp, nix, niy)) return 3; + /* move a normal monster; for a long worm, remove_monster() and + place_monster() only manipulate the head; they leave tail as-is */ remove_monster(omx, omy); place_monster(mtmp, nix, niy); + /* for a long worm, insert a new segment to reconnect the head + with the tail; worm_move() keeps the end of the tail if worm + is scheduled to grow, removes that for move-without-growing */ + if (mtmp->wormno) + worm_move(mtmp); + for (j = MTSZ - 1; j > 0; j--) mtmp->mtrack[j] = mtmp->mtrack[j - 1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; - /* Place a segment at the old position. */ - if (mtmp->wormno) - worm_move(mtmp); } else { if (is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) { (void) rloc(mtmp, TRUE); return 1; } + /* for a long worm, shrink it (by discarding end of tail) when + it has failed to move */ if (mtmp->wormno) worm_nomove(mtmp); } diff --git a/src/nhlua.c b/src/nhlua.c index f215ea01c..bafefbfc2 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 nhlua.c $NHDT-Date: 1575246766 2019/12/02 00:32:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.16 $ */ +/* NetHack 3.7 nhlua.c $NHDT-Date: 1579901146 2020/01/24 21:25:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.29 $ */ /* Copyright (c) 2018 by Pasi Kallinen */ /* NetHack may be freely redistributed. See license for details. */ @@ -44,8 +44,16 @@ const char *msg; lua_getstack(L, 1, &ar); lua_getinfo(L, "lS", &ar); - Sprintf(buf, "%s (line %i%s)", msg, ar.currentline, ar.source); + Sprintf(buf, "%s (line %d ", msg, ar.currentline); + Sprintf(eos(buf), "%.*s)", + /* (max length of ar.short_src is actually LUA_IDSIZE + so this is overkill for it, but crucial for ar.source) */ + (int) (sizeof buf - (strlen(buf) + sizeof ")")), + ar.short_src); /* (used to be 'ar.source' here) */ lua_pushstring(L, buf); +#if 0 /* defined(PANICTRACE) && !defined(NO_SIGNALS) */ + panictrace_setsignals(FALSE); +#endif (void) lua_error(L); /*NOTREACHED*/ } @@ -923,16 +931,21 @@ lua_State *L; return 1; } +/* read lua code/data from a dlb module or an external file, insert the + file name as new first record so that we aren't at the mercy of whoever + edits it to maintain that, and since we're forced to muck with messy + details, replace comments with empty lines so that Lua won't need to */ boolean nhl_loadlua(L, fname) lua_State *L; const char *fname; { - boolean ret = TRUE; +#define LOADCHUNKSIZE (1L << 13) /* 8K */ + boolean ret = TRUE, is_comment; dlb *fh; - char *buf = (char *) 0; - long buflen; - int cnt, llret; + char *buf = (char *) 0, *bufin, *bufout, *p, *nl; + long buflen, ct, cnt, fnamesiz; + int llret, first = 0, spanlines = 0; fh = dlb_fopen(fname, "r"); if (!fh) { @@ -941,20 +954,117 @@ const char *fname; goto give_up; } + fnamesiz = strlen(fname) + 7L; /* 7: "--{" + "}--\n" (no '\0') */ dlb_fseek(fh, 0L, SEEK_END); buflen = dlb_ftell(fh); - buf = (char *) alloc(buflen + 1); dlb_fseek(fh, 0L, SEEK_SET); - if ((cnt = dlb_fread(buf, 1, buflen, fh)) != buflen) { - impossible("nhl_loadlua: Error loading %s, got %i/%li bytes", - fname, cnt, buflen); - ret = FALSE; - goto give_up; + /* extra +1: room to add final '\n' if missing */ + buf = bufout = (char *) alloc(fnamesiz + buflen + 1 + 1); + /* insert file name as first record so nhl_error() can report it; + leading dashes make it be a comment, trailing ones are for + symmetry; delimit file name with braces instead of spaces to + avoid an undesireable line split during error feedback */ + Sprintf(bufout, "--{%s}--\n", fname); + bufin = bufout = eos(buf); + + ct = 0L; + while (buflen > 0 || ct) { + /* + * Semi-arbitrarily limit reads to 8K at a time. That's big + * enough to cover the majority of our Lua files in one bite + * but small enough to fully exercise the partial record + * handling (when processing the castle's level description). + * + * [For an external file (non-DLB), VMS may only be able to + * read at most 32K-1 at a time depending on the file format + * in use, and fseek(SEEK_END) only yields an upper bound on + * the actual amount of data in that situation.] + */ + if ((cnt = dlb_fread(bufin, 1, min(buflen, LOADCHUNKSIZE), fh)) < 0L) + break; + buflen -= cnt; /* set up for next iteration, if any */ + if (cnt == 0L) { + *bufin = '\n'; /* very last line is unterminated? */ + cnt = 1; + } + bufin[cnt] = '\0'; /* fread() doesn't do this */ + + /* in case partial line was leftover from previous fread */ + bufin -= ct, cnt += ct, ct = 0; + + while (cnt > 0) { + if ((nl = index(bufin, '\n')) != 0) { + /* normal case, newline is present */ + ct = (long) (nl - bufin + 1L); /* +1: keep the newline */ + for (p = bufin; *p == ' '; ++p) + continue; + is_comment = (p[0] == '-' && p[1] == '-' && !spanlines); + if (spanlines && index("])}", *p)) + --spanlines; + if (!first++ && (*p == '\n' || is_comment)) { + /* if first line is blank or a comment, omit it so that + our "--{fname}--\n" line doesn't make the line count + be out of sync; note: when first line is code, line + number reported in error messages will be off by one */ + bufin = nl + 1; + } else if (is_comment) { + /* discard comment to shorten the string Lua will deal + with but keep the line to maintain Lua line counter */ +#if 0 + Strcpy(bufout, "--\n"), bufout += 3; +#else + Strcpy(bufout, "\n"), bufout += 1; +#endif + bufin += ct; + } else { + /* normal case; some text terminated by newline */ + for (p = bufin; p <= nl; ++p) + *bufout++ = *bufin++; + for (p = &bufout[-2]; *p == ' '; --p) /* [-1] is '\n' */ + continue; + if (index("[({", *p)) + ++spanlines; + } + if (*bufin == '\r') + ++bufin, ++ct; + /* update for next loop iteration */ + cnt -= ct; + ct = 0; + } else { + /* no newline => partial record; move unprocessed chars + to front of input buffer (bufin portion of buf[]) */ + ct = cnt = (long) (eos(bufin) - bufin); + for (p = bufout; cnt > 0; --cnt) + *p++ = *bufin++; + *p = '\0'; + bufin = p; /* next fread() populates buf[] starting here */ + /* cnt==0 so inner loop will terminate */ + } + } } - buf[buflen] = '\0'; + *bufout = '\0'; (void) dlb_fclose(fh); +#ifdef DEBUG + if (explicitdebug("loadlua")) { + FILE *fp; + char oname[QBUFSZ]; + + (void) strsubst(strcpy(oname, fname), ".lua", ".txt"); + if ((fp = fopen(oname, "w")) != 0) { + for (buflen = strlen(buf), p = buf; + buflen > 0; + buflen -= cnt, p += cnt) { + cnt = min(buflen, LOADCHUNKSIZE); + if ((long) fwrite(p, 1, cnt, fp) < cnt) + break; + } + (void) fclose(fp); + } + } +#endif + llret = luaL_loadstring(L, buf); if (llret != LUA_OK) { impossible("luaL_loadstring: Error loading %s (errcode %i)", @@ -973,8 +1083,7 @@ const char *fname; give_up: if (buf) { - free(buf); - buf = (char *) 0; + free((genericptr_t) buf); buflen = 0; } return ret; diff --git a/src/objnam.c b/src/objnam.c index 102dbb03e..b2897c906 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 objnam.c $NHDT-Date: 1578896203 2020/01/13 06:16:43 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.287 $ */ +/* NetHack 3.7 objnam.c $NHDT-Date: 1579261291 2020/01/17 11:41:31 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -998,7 +998,7 @@ unsigned doname_flags; Strcat(prefix, "cursed "); else if (obj->blessed) Strcat(prefix, "blessed "); - else if (!iflags.implicit_uncursed + else if (!flags.implicit_uncursed /* For most items with charges or +/-, if you know how many * charges are left or what the +/- is, then you must have * totally identified the item, so "uncursed" is unnecessary, diff --git a/src/options.c b/src/options.c index bbcc776e1..e1701782d 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1578996303 2020/01/14 10:05:03 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.396 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1579261293 2020/01/17 11:41:33 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.428 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -148,7 +148,7 @@ static const struct Bool_Opt { #else { "ignintr", (boolean *) 0, FALSE, SET_IN_FILE }, #endif - { "implicit_uncursed", &iflags.implicit_uncursed, TRUE, SET_IN_GAME }, + { "implicit_uncursed", &flags.implicit_uncursed, TRUE, SET_IN_GAME }, { "large_font", &iflags.obsolete, FALSE, SET_IN_FILE }, /* OBSOLETE */ { "legacy", &flags.legacy, TRUE, DISP_IN_GAME }, { "lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME }, @@ -158,7 +158,7 @@ static const struct Bool_Opt { #else { "mail", (boolean *) 0, TRUE, SET_IN_FILE }, #endif - { "mention_walls", &iflags.mention_walls, FALSE, SET_IN_GAME }, + { "mention_walls", &flags.mention_walls, FALSE, SET_IN_GAME }, { "menucolors", &iflags.use_menu_color, FALSE, SET_IN_GAME }, /* for menu debugging only*/ { "menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_WIZGAME }, @@ -739,9 +739,9 @@ initoptions_init() /* for "special achievement" tracking (see obj.h, create_object(sp_lev.c), addinv_core1(invent.c) */ - iflags.mines_prize_type = LUCKSTONE; - iflags.soko_prize_type1 = BAG_OF_HOLDING; - iflags.soko_prize_type2 = AMULET_OF_REFLECTION; + g.context.achieveo.mines_prize_type = LUCKSTONE; + g.context.achieveo.soko_prize_typ1 = BAG_OF_HOLDING; + g.context.achieveo.soko_prize_typ2 = AMULET_OF_REFLECTION; /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ (void) memcpy((genericptr_t) flags.inv_order, @@ -4086,7 +4086,7 @@ boolean tinitial, tfrom_file; g.context.botl = TRUE; } else if (boolopt[i].addr == &flags.invlet_constant || boolopt[i].addr == &flags.sortpack - || boolopt[i].addr == &iflags.implicit_uncursed) { + || boolopt[i].addr == &flags.implicit_uncursed) { if (!flags.invlet_constant) reassign(); update_inventory(); diff --git a/src/polyself.c b/src/polyself.c index 6c0f5c732..691e70c86 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 polyself.c $NHDT-Date: 1573290419 2019/11/09 09:06:59 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.135 $ */ +/* NetHack 3.6 polyself.c $NHDT-Date: 1579660157 2020/01/22 02:29:17 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.149 $ */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ @@ -462,14 +462,19 @@ int psflags; pline("I've never heard of such monsters."); else You_cant("polymorph into any of those."); + } else if (wizard && Upolyd && mntmp == u.umonster) { + /* in wizard mode, picking own role while poly'd reverts to + normal without newman()'s chance of level or sex change */ + rehumanize(); + goto made_change; } else if (iswere && (were_beastie(mntmp) == u.ulycn || mntmp == counter_were(u.ulycn) || (Upolyd && mntmp == PM_HUMAN))) { goto do_shift; - /* Note: humans are illegal as monsters, but an - * illegal monster forces newman(), which is what we - * want if they specified a human.... */ } else if (!polyok(&mons[mntmp]) + /* Note: humans are illegal as monsters, but an + illegal monster forces newman(), which is what + we want if they specified a human.... */ && !(mntmp == PM_HUMAN || your_race(&mons[mntmp]) || mntmp == g.urole.malenum || mntmp == g.urole.femalenum)) { @@ -934,7 +939,7 @@ break_armor() useup(uarmu); } } else if (sliparm(g.youmonst.data)) { - if (((otmp = uarm) != 0) && (racial_exception(&g.youmonst, otmp) < 1)) { + if ((otmp = uarm) != 0 && racial_exception(&g.youmonst, otmp) < 1) { if (donning(otmp)) cancel_don(); Your("armor falls around you!"); @@ -1016,6 +1021,21 @@ break_armor() dropp(otmp); } } + /* not armor, but eyewear shouldn't stay worn without a head to wear + it/them on (should also come off if head is too tiny or too huge, + but putting accessories on doesn't reject those cases [yet?]); + amulet stays worn */ + if ((otmp = ublindf) != 0 && !has_head(g.youmonst.data)) { + int l; + const char *eyewear = simpleonames(otmp); /* blindfold|towel|lenses */ + + if (!strncmp(eyewear, "pair of ", l = 8)) /* lenses */ + eyewear += l; + Your("%s %s off!", eyewear, vtense(eyewear, "fall")); + (void) Blindf_off((struct obj *) 0); /* Null: skip usual off mesg */ + dropp(otmp); + } + /* rings stay worn even when no hands */ } static void diff --git a/src/potion.c b/src/potion.c index 5032e4e51..612ba9388 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 potion.c $NHDT-Date: 1573848199 2019/11/15 20:03:19 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.167 $ */ +/* NetHack 3.6 potion.c $NHDT-Date: 1579655028 2020/01/22 01:03:48 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.179 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1627,13 +1627,19 @@ register struct obj *obj; remains in inventory where our caller expects it to be */ obj->in_use = 1; - switch (obj->otyp) { + /* wearing a wet towel protects both eyes and breathing, even when + the breath effect might be beneficial; we still pass down to the + naming opportunity in case potion was thrown at hero by a monster */ + switch (Half_gas_damage ? TOWEL : obj->otyp) { + case TOWEL: + pline("Some vapor passes harmlessly around you."); + break; case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: if (obj->cursed) { - if (!breathless(g.youmonst.data)) + if (!breathless(g.youmonst.data)) { pline("Ulch! That potion smells terrible!"); - else if (haseyes(g.youmonst.data)) { + } else if (haseyes(g.youmonst.data)) { const char *eyes = body_part(EYE); if (eyecount(g.youmonst.data) != 1) diff --git a/src/pray.c b/src/pray.c index 173996c09..3d4045141 100644 --- a/src/pray.c +++ b/src/pray.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pray.c $NHDT-Date: 1578895347 2020/01/13 06:02:27 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.138 $ */ +/* NetHack 3.6 pray.c $NHDT-Date: 1579401997 2020/01/19 02:46:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.139 $ */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ @@ -484,7 +484,7 @@ int trouble; what = rightglow; else if (otmp == uleft) what = leftglow; - decurse: + decurse: if (!otmp) { impossible("fix_worst_trouble: nothing to uncurse."); return; @@ -1496,7 +1496,7 @@ dosacrifice() if (otmp->otyp == AMULET_OF_YENDOR) { if (!highaltar) { - too_soon: + too_soon: if (altaralign == A_NONE && Inhell) /* hero has left Moloch's Sanctum so is in the process of getting away with the Amulet (outside of Gehennom, @@ -1526,7 +1526,8 @@ dosacrifice() /* Moloch's high altar */ if (u.ualign.record > -99) u.ualign.record = -99; - pline("An invisible choir chants in Latin, and you are bathed in darkness..."); + pline( + "An invisible choir chants, and you are bathed in darkness..."); /*[apparently shrug/snarl can be sensed without being seen]*/ pline("%s shrugs and retains dominion over %s,", Moloch, u_gname()); @@ -1593,7 +1594,7 @@ dosacrifice() } if (altaralign != u.ualign.type && highaltar) { - desecrate_high_altar: + desecrate_high_altar: /* * REAL BAD NEWS!!! High altars cannot be converted. Even an attempt * gets the god who owns it truly pissed off. @@ -1830,7 +1831,8 @@ boolean praying; /* false means no messages should be given */ } if (is_undead(g.youmonst.data) && !Inhell - && (g.p_aligntyp == A_LAWFUL || (g.p_aligntyp == A_NEUTRAL && !rn2(10)))) + && (g.p_aligntyp == A_LAWFUL + || (g.p_aligntyp == A_NEUTRAL && !rn2(10)))) g.p_type = -1; /* Note: when !praying, the random factor for neutrals makes the return value a non-deterministic approximation for enlightenment. diff --git a/src/questpgr.c b/src/questpgr.c index 85c272557..5df059fd1 100644 --- a/src/questpgr.c +++ b/src/questpgr.c @@ -432,9 +432,10 @@ boolean common UNUSED; } boolean -com_pager_core(section, msgid) +com_pager_core(section, msgid, showerror) const char *section; const char *msgid; +boolean showerror; { const char *const howtoput[] = { "pline", "window", "text", "menu", "default", NULL }; const int howtoput2i[] = { 1, 2, 2, 3, 0, 0 }; @@ -442,6 +443,7 @@ const char *msgid; lua_State *L; char *synopsis; char *text; + char *fallback_msgid = NULL; if (skip_pager(TRUE)) return FALSE; @@ -449,7 +451,8 @@ const char *msgid; L = nhl_init(); if (!nhl_loadlua(L, QTEXT_FILE)) { - impossible("com_pager: %s not found.", QTEXT_FILE); + if (showerror) + impossible("com_pager: %s not found.", QTEXT_FILE); lua_close(L); return FALSE; } @@ -457,21 +460,40 @@ const char *msgid; lua_settop(L, 0); lua_getglobal(L, "questtext"); if (!lua_istable(L, -1)) { - impossible("com_pager: questtext in %s is not a lua table", QTEXT_FILE); + if (showerror) + impossible("com_pager: questtext in %s is not a lua table", + QTEXT_FILE); lua_close(L); return FALSE; } lua_getfield(L, -1, section); if (!lua_istable(L, -1)) { - impossible("com_pager: questtext[%s] in %s is not a lua table", section, QTEXT_FILE); + if (showerror) + impossible("com_pager: questtext[%s] in %s is not a lua table", + section, QTEXT_FILE); lua_close(L); return FALSE; } - lua_getfield(L, -1, msgid); +tryagain: + lua_getfield(L, -1, fallback_msgid ? fallback_msgid : msgid); if (!lua_istable(L, -1)) { - impossible("com_pager: questtext[%s][%s] in %s is not a lua table", section, msgid, QTEXT_FILE); + if (!fallback_msgid) { + /* Do we have questtxt[msg_fallbacks][]? */ + lua_getfield(L, -3, "msg_fallbacks"); + if (lua_istable(L, -1)) { + fallback_msgid = get_table_str_opt(L, msgid, NULL); + lua_pop(L, 2); + if (fallback_msgid) + goto tryagain; + } + } + + if (showerror) + impossible("com_pager: questtext[%s][%s] in %s is not a lua table", + section, msgid, QTEXT_FILE); + free(fallback_msgid); lua_close(L); return FALSE; } @@ -487,9 +509,11 @@ const char *msgid; nelems = (int) lua_tointeger(L, -1); lua_pop(L, 1); if (nelems < 2) { - impossible( - "com_pager: questtext[%s][%s] in %s in not an array of strings", + if (showerror) + impossible( + "com_pager: questtext[%s][%s] in %s in not an array of strings", section, msgid, QTEXT_FILE); + free(fallback_msgid); lua_close(L); return FALSE; } @@ -518,6 +542,7 @@ const char *msgid; free(synopsis); } + free(fallback_msgid); free(text); lua_close(L); return TRUE; @@ -527,15 +552,15 @@ void com_pager(msgid) const char *msgid; { - com_pager_core("common", msgid); + com_pager_core("common", msgid, TRUE); } void qt_pager(msgid) const char *msgid; { - if (!com_pager_core(g.urole.filecode, msgid)) - com_pager_core("common", msgid); + if (!com_pager_core(g.urole.filecode, msgid, FALSE)) + com_pager_core("common", msgid, TRUE); } struct permonst * diff --git a/src/region.c b/src/region.c index cc2215e7e..aca233561 100644 --- a/src/region.c +++ b/src/region.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 region.c $NHDT-Date: 1573957877 2019/11/17 02:31:17 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.45 $ */ +/* NetHack 3.6 region.c $NHDT-Date: 1579655029 2020/01/22 01:03:49 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.60 $ */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -1024,7 +1024,10 @@ genericptr_t p2; pline("%s is burning your %s!", Something, makeplural(body_part(LUNG))); You("cough and spit blood!"); - losehp(Maybe_Half_Phys(rnd(dam) + 5), "gas cloud", KILLED_BY_AN); + dam = Maybe_Half_Phys(rnd(dam) + 5); + if (Half_gas_damage) /* worn towel */ + dam = (dam + 1) / 2; + losehp(dam, "gas cloud", KILLED_BY_AN); return FALSE; } else { You("cough!"); diff --git a/src/role.c b/src/role.c index 1a1a88986..f93859da1 100644 --- a/src/role.c +++ b/src/role.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 role.c $NHDT-Date: 1574648943 2019/11/25 02:29:03 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.65 $ */ +/* NetHack 3.6 role.c $NHDT-Date: 1578947634 2020/01/13 20:33:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.68 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1047,8 +1047,8 @@ int racenum, gendnum, alignnum, pickhow; gendnum, alignnum) && ok_gend(i, racenum, (gendnum >= 0) ? gendnum : ROLE_RANDOM, alignnum) - && ok_race(i, racenum, - gendnum, (alignnum >= 0) ? alignnum : ROLE_RANDOM)) + && ok_align(i, racenum, + gendnum, (alignnum >= 0) ? alignnum : ROLE_RANDOM)) set[roles_ok++] = i; } if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID)) @@ -1221,7 +1221,7 @@ int alignnum; /* random; check whether any selection is possible */ for (i = 0; i < ROLE_ALIGNS; i++) { if (g.rfilter.mask & aligns[i].allow) - return FALSE; + continue; allow = aligns[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles) - 1 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) @@ -1909,9 +1909,13 @@ boolean preselect; add_menu(where, NO_GLYPH, &any, RS_menu_let[which], 0, ATR_NONE, buf, MENU_ITEMFLAGS_NONE); } else if (which == RS_filter) { + char setfiltering[40]; + any.a_int = RS_menu_arg(RS_filter); + Sprintf(setfiltering, "%s role/race/&c filtering", + gotrolefilter() ? "Reset" : "Set"); add_menu(where, NO_GLYPH, &any, '~', 0, ATR_NONE, - "Reset role/race/&c filtering", MENU_ITEMFLAGS_NONE); + setfiltering, MENU_ITEMFLAGS_NONE); } else if (which == ROLE_RANDOM) { any.a_int = ROLE_RANDOM; add_menu(where, NO_GLYPH, &any, '*', 0, ATR_NONE, "Random", diff --git a/src/sp_lev.c b/src/sp_lev.c index c463c8b74..3a76dbb72 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -1569,32 +1569,34 @@ struct mkroom *croom; if (o->id != -1) { static const char prize_warning[] = "multiple prizes on %s level"; - /* if this is a specific item of the right type and it is being - created on the right level, flag it as the designated item - used to detect a special achievement (to whit, reaching and - exploring the target level, although the exploration part - might be short-circuited if a monster brings object to hero) */ - if (Is_mineend_level(&u.uz)) { - if (otmp->otyp == iflags.mines_prize_type) { - if (!g.mines_prize_count++) { - /* Note: the first luckstone on lev will become the prize - even if its not the explicit one, but random */ - otmp->record_achieve_special = MINES_PRIZE; - /* prevent stacking; cleared when achievement is recorded */ - otmp->nomerge = 1; - } + /* + * If this is a specific item of the right type and it is being + * created on the right level, flag it as the designated item + * used to detect a special achievement (to whit, reaching and + * exploring the target level, although the exploration part + * might be short-circuited if a monster brings object to hero). + * + * Random items of the appropriate type won't trigger a false + * match--they'll fail the (id != -1) test above--but the level + * definition should not include a second instance of any prize. + */ + if (Is_mineend_level(&u.uz) + && otmp->otyp == g.context.achieveo.mines_prize_type) { + if (!g.context.achieveo.mines_prize_oid) { + g.context.achieveo.mines_prize_oid = otmp->o_id; + /* prevent stacking; cleared when achievement is recorded */ + otmp->nomerge = 1; + } else { + impossible(prize_warning, "mines end"); } - } else if (Is_sokoend_level(&u.uz)) { - if (otmp->otyp == iflags.soko_prize_type1) { - otmp->record_achieve_special = SOKO_PRIZE1; + } else if (Is_sokoend_level(&u.uz) + && (otmp->otyp == g.context.achieveo.soko_prize_typ1 + || otmp->otyp == g.context.achieveo.soko_prize_typ2)) { + if (!g.context.achieveo.soko_prize_oid) { + g.context.achieveo.soko_prize_oid = otmp->o_id; otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */ - if (++g.soko_prize_count > 1) - impossible(prize_warning, "sokoban end"); - } else if (otmp->otyp == iflags.soko_prize_type2) { - otmp->record_achieve_special = SOKO_PRIZE2; - otmp->nomerge = 1; /* redundant; Sokoban prizes don't stack */ - if (++g.soko_prize_count > 1) - impossible(prize_warning, "sokoban end"); + } else { + impossible(prize_warning, "sokoban end"); } } } @@ -2590,14 +2592,26 @@ const char *s; /* find by object name */ for (i = 0; i < NUM_OBJECTS; i++) { - objname = obj_descr[i].oc_name; + objname = OBJ_NAME(objects[i]); if (objname && !strcmpi(s, objname)) return i; } + /* + * FIXME: + * If the file specifies "orange potion", the actual object + * description is just "orange" and won't match. [There's a + * reason that wish handling is insanely complicated.] And + * even if that gets fixed, if the file specifies "gray stone" + * it will start matching but would always pick the first one. + * + * "orange potion" is an unlikely thing to have in a special + * level description but "gray stone" is not.... + */ + /* find by object description */ for (i = 0; i < NUM_OBJECTS; i++) { - objname = obj_descr[i].oc_descr; + objname = OBJ_DESCR(objects[i]); if (objname && !strcmpi(s, objname)) return i; } @@ -5419,10 +5433,6 @@ sp_level_coder_init() g.splev_init_present = FALSE; g.icedpools = FALSE; - /* achievement tracking; static init would suffice except we need to - reset if #wizmakemap is used to recreate mines' end or sokoban end; - once either level is created, these values can be forgotten */ - g.mines_prize_count = g.soko_prize_count = 0; for (tmpi = 0; tmpi <= MAX_NESTED_ROOMS; tmpi++) { coder->tmproomlist[tmpi] = (struct mkroom *) 0; diff --git a/src/weapon.c b/src/weapon.c index e61a7438f..d55f8e4e9 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 weapon.c $NHDT-Date: 1559998716 2019/06/08 12:58:36 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.70 $ */ +/* NetHack 3.6 weapon.c $NHDT-Date: 1579648295 2020/01/21 23:11:35 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.82 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -95,13 +95,17 @@ struct obj *obj; switch (skill) { case P_NONE: /* not a weapon or weptool: use item class name; - override class name "food" for corpses, tins, and eggs, - "large rock" for statues and boulders, and "tool" for towels */ + override class name for things where it sounds strange and + for things that aren't unexpected to find being wielded: + corpses, tins, eggs, and globs avoid "food", + statues and boulders avoid "large rock", + and towels and tin openers avoid "tool" */ descr = (obj->otyp == CORPSE || obj->otyp == TIN || obj->otyp == EGG || obj->otyp == STATUE || obj->otyp == BOULDER - || obj->otyp == TOWEL) - ? OBJ_NAME(objects[obj->otyp]) - : def_oc_syms[(int) obj->oclass].name; + || obj->otyp == TOWEL || obj->otyp == TIN_OPENER) + ? OBJ_NAME(objects[obj->otyp]) + : obj->globby ? "glob" + : def_oc_syms[(int) obj->oclass].name; break; case P_SLING: if (is_ammo(obj)) diff --git a/src/worm.c b/src/worm.c index 3d7fb3f93..c5395cbe9 100644 --- a/src/worm.c +++ b/src/worm.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worm.c $NHDT-Date: 1561340880 2019/06/24 01:48:00 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.30 $ */ +/* NetHack 3.6 worm.c $NHDT-Date: 1579616437 2020/01/21 14:20:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.40 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -218,6 +218,13 @@ struct monst *worm; seg->nseg = new_seg; /* attach it to the end of the list */ wheads[wnum] = new_seg; /* move the end pointer */ + /* + * [maybe] FIXME? + * scheduling wgrowtime[] seems to be based on normal movement + * speed (12) but long worms move at 1/4 of that (3), so they'll + * reach the scheduled 'moves' more quickly (in terms of their + * actual movement) and grow faster than was probably intended. + */ if (wgrowtime[wnum] <= g.moves) { if (!wgrowtime[wnum]) wgrowtime[wnum] = g.moves + rnd(5); diff --git a/sys/msdos/msdos-cross-compile.sh b/sys/msdos/msdos-cross-compile.sh index 4dd7ee617..3de2b701b 100644 --- a/sys/msdos/msdos-cross-compile.sh +++ b/sys/msdos/msdos-cross-compile.sh @@ -74,6 +74,12 @@ fi cd ../ +# Don't fail the build if lua fetch failed because we cannot do anything about it +# but don't bother proceeding forward either +if [ ! -d "lib/lua-$LUA_VERSION/src" ]; then + exit 0 +fi + #echo after dos extender cd src diff --git a/sys/winnt/travis-gcc.sh b/sys/winnt/travis-gcc.sh index 562b1a142..6f731cea8 100644 --- a/sys/winnt/travis-gcc.sh +++ b/sys/winnt/travis-gcc.sh @@ -2,7 +2,7 @@ set -x mkdir -p lib cd lib git clone --depth 1 https://github.com/wmcbrine/PDCurses.git pdcurses -git clone --depth 1 https://github.com/universal-ctags/ctags.git ctags +#git clone --depth 1 https://github.com/universal-ctags/ctags.git ctags curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz tar zxf lua-5.3.5.tar.gz cd ../ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 0fbe47648..a6ad2f7a2 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1575245194 2019/12/02 00:06:34 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.227 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1578947635 2020/01/13 20:33:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.244 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -582,8 +582,7 @@ tty_player_selection() role_menu_extra(RS_RACE, win, FALSE); role_menu_extra(RS_GENDER, win, FALSE); role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); + role_menu_extra(RS_filter, win, FALSE); role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ Strcpy(pbuf, "Pick a role or profession"); end_menu(win, pbuf); @@ -681,8 +680,7 @@ tty_player_selection() role_menu_extra(RS_ROLE, win, FALSE); role_menu_extra(RS_GENDER, win, FALSE); role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); + role_menu_extra(RS_filter, win, FALSE); role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ Strcpy(pbuf, "Pick a race or species"); end_menu(win, pbuf); @@ -774,8 +772,7 @@ tty_player_selection() role_menu_extra(RS_ROLE, win, FALSE); role_menu_extra(RS_RACE, win, FALSE); role_menu_extra(RS_ALGNMNT, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); + role_menu_extra(RS_filter, win, FALSE); role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ Strcpy(pbuf, "Pick a gender or sex"); end_menu(win, pbuf); @@ -863,8 +860,7 @@ tty_player_selection() role_menu_extra(RS_ROLE, win, FALSE); role_menu_extra(RS_RACE, win, FALSE); role_menu_extra(RS_GENDER, win, FALSE); - if (gotrolefilter()) - role_menu_extra(RS_filter, win, FALSE); + role_menu_extra(RS_filter, win, FALSE); role_menu_extra(ROLE_NONE, win, FALSE); /* quit */ Strcpy(pbuf, "Pick an alignment or creed"); end_menu(win, pbuf); @@ -1032,6 +1028,7 @@ reset_role_filtering() winid win; anything any; int i, n; + char filterprompt[QBUFSZ]; menu_item *selected = 0; win = create_nhwindow(NHW_MENU); @@ -1058,10 +1055,12 @@ reset_role_filtering() "Unacceptable alignments", MENU_ITEMFLAGS_NONE); setup_algnmenu(win, FALSE, ROLE_NONE, ROLE_NONE, ROLE_NONE); - end_menu(win, "Pick all that apply"); + Sprintf(filterprompt, "Pick all that apply%s", + gotrolefilter() ? " and/or unpick any that no longer apply" : ""); + end_menu(win, filterprompt); n = select_menu(win, PICK_ANY, &selected); - if (n > 0) { + if (n >= 0) { /* n==0: clear current filters and don't set new ones */ clearrolefilter(); for (i = 0; i < n; i++) setrolefilter(selected[i].item.a_string); @@ -1093,7 +1092,11 @@ int race, gend, algn; /* all ROLE_NONE for !filtering case */ any = cg.zeroany; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { - role_ok = ok_role(i, race, gend, algn); + /* role can be constrained by any of race, gender, or alignment */ + role_ok = (ok_role(i, race, gend, algn) + && ok_race(i, race, gend, algn) + && ok_gend(i, race, gend, algn) + && ok_align(i, race, gend, algn)); if (filtering && !role_ok) continue; if (filtering) @@ -1137,7 +1140,10 @@ int role, gend, algn; any = cg.zeroany; for (i = 0; races[i].noun; i++) { - race_ok = ok_race(role, i, gend, algn); + /* no ok_gend(); race isn't constrained by gender */ + race_ok = (ok_race(role, i, gend, algn) + && ok_role(role, i, gend, algn) + && ok_align(role, i, gend, algn)); if (filtering && !race_ok) continue; if (filtering) @@ -1171,7 +1177,10 @@ int role, race, algn; any = cg.zeroany; for (i = 0; i < ROLE_GENDERS; i++) { - gend_ok = ok_gend(role, race, i, algn); + /* no ok_align(); gender isn't constrained by alignment */ + gend_ok = (ok_gend(role, race, i, algn) + && ok_role(role, race, i, algn) + && ok_race(role, race, i, algn)); if (filtering && !gend_ok) continue; if (filtering) @@ -1203,7 +1212,10 @@ int role, race, gend; any = cg.zeroany; for (i = 0; i < ROLE_ALIGNS; i++) { - algn_ok = ok_align(role, race, gend, i); + /* no ok_gend(); alignment isn't constrained by gender */ + algn_ok = (ok_align(role, race, gend, i) + && ok_role(role, race, gend, i) + && ok_race(role, race, gend, i)); if (filtering && !algn_ok) continue; if (filtering) diff --git a/win/win32/vs2017/travisci.sh b/win/win32/vs2017/travisci.sh index b3e7de13e..7c16f6c9c 100644 --- a/win/win32/vs2017/travisci.sh +++ b/win/win32/vs2017/travisci.sh @@ -24,15 +24,21 @@ export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER export LIB=/c/Program\ Files\ \(x86\)/Microsoft\ Visual\ Studio/$VSVER/$TOOLSVER/VC/Tools/MSVC/$MSVER/lib/x86:$LIB export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/ucrt/x86:$LIB export LIB=/c/Program\ Files\ \(x86\)/Windows\ Kits/10/lib/$WKITVER/um/x86:$LIB +export LUA_VERSION=5.3.5 mkdir -p lib cd lib git clone --depth 1 https://github.com/wmcbrine/PDCurses.git pdcurses -git clone --depth 1 https://github.com/universal-ctags/ctags.git ctags +#git clone --depth 1 https://github.com/universal-ctags/ctags.git ctags curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz tar zxf lua-5.3.5.tar.gz -cd ctags -nmake -f mk_mvc.mak -cd ../../ +#cd ctags +#nmake -f mk_mvc.mak +#cd ../../ +cd ../ +test -d "lib/lua-$LUA_VERSION/src" || echo "Lua-$LUA_VERSION fetch failed" +test -d "lib/pdcurses" || echo "pdcurses fetch failed" +test -d "lib/pdcurses" || exit 0 +test -d "lib/lua-$LUA_VERSION/src" || exit 0 export ADD_CURSES=Y export PDCURSES_TOP=../lib/pdcurses export