From 600261d81f14bdc256373bc8a7c20a62414e6a4a Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 3 Jan 2019 17:37:00 -0800 Subject: [PATCH 1/4] fix github #172 - ^T inconsistencies; add m^T Fixes #172 Casting teleport-away via ^T used different requirements for energy, strength, and hunger than casting it via 'Z'. The strength and hunger requirements were more stringent, the energy one more lenient. When it rejected a cast attempt due to any of those, it used up the move, but 'Z' didn't. When testing my fix, I wanted an easier way than a debugger to control how ^T interacts with wizard mode, so finally got around to a first cut at being able to invoke it via wizard mode but not override those energy/strength/hunger requirements. It uses the 'm' prefix to ask for a menu. 'm^T' gives four options about how to teleport. (There are other permutations which aren't handled.) Also noticed while testing: ^T wouldn't attempt to cast teleport-away if you didn't know the corresponding spellbook. 'Z' will attempt that because it is possible to forget a book and still know its spell. --- doc/fixes36.2 | 9 ++- include/extern.h | 3 +- src/cmd.c | 6 +- src/spell.c | 62 ++++++++++++++- src/teleport.c | 201 ++++++++++++++++++++++++++++++++++++----------- 5 files changed, 230 insertions(+), 51 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index beeed33a7..015ce2c20 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.221 $ $NHDT-Date: 1546467443 2019/01/02 22:17:23 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.222 $ $NHDT-Date: 1546565812 2019/01/04 01:36:52 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -322,6 +322,11 @@ since knives became stackable in 3.6.0, fake player monsters could be given using 'O' to attempt to set bouldersym to a monster letter or warning digit while it still had its default value would override the display value for it to be ('\0') after 'badoption' feedback +when ^T resorted to the teleport-away spell if hero didn't have intrinsic + telepotation, it used different hunger/strength/energy requirements + than casting with 'Z'; ^T also required that the corresponding book + be known even though knowing and casting a spell should be (and is + with 'Z') possible after forgetting the spellbook due to amnesia Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -493,6 +498,8 @@ when sortloot is enabled, gems are grouped in subsets (1) unseen gems and (4) identified glass, (5) unseen stones (includes unseen rocks), (6) seen but unidentified gray stones, (7) identified gray stones, and (8) seen rocks (IDed/unIDed not applicable) +in wizard mode, ^T can be preceded by 'm' prefix in order to test teleporting + without having wizard mode override various restrictions NetHack Community Patches (or Variation) Included diff --git a/include/extern.h b/include/extern.h index dbef64c22..8e3f54294 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1545964581 2018/12/28 02:36:21 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.678 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1546565812 2019/01/04 01:36:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.680 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2329,6 +2329,7 @@ E void NDECL(age_spells); E int NDECL(docast); E int FDECL(spell_skilltype, (int)); E int FDECL(spelleffects, (int, BOOLEAN_P)); +E int FDECL(tport_spell, (int)); E void NDECL(losespells); E int NDECL(dovspell); E void FDECL(initialspell, (struct obj *)); diff --git a/src/cmd.c b/src/cmd.c index 04df10458..061b15690 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1546038393 2018/12/28 23:06:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.323 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1546565813 2019/01/04 01:36:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.324 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4408,8 +4408,8 @@ int NDECL((*cmd_func)); || cmd_func == doloot /* travel: pop up a menu of interesting targets in view */ || cmd_func == dotravel - /* wizard mode ^V */ - || cmd_func == wiz_level_tele + /* wizard mode ^V and ^T */ + || cmd_func == wiz_level_tele || cmd_func == dotelecmd /* 'm' prefix allowed for some extended commands */ || cmd_func == doextcmd || cmd_func == doextlist) return TRUE; diff --git a/src/spell.c b/src/spell.c index a7fd388ca..9cbb9a480 100644 --- a/src/spell.c +++ b/src/spell.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 spell.c $NHDT-Date: 1542765363 2018/11/21 01:56:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.87 $ */ +/* NetHack 3.6 spell.c $NHDT-Date: 1546565814 2019/01/04 01:36:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.88 $ */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ @@ -923,6 +923,10 @@ boolean atme; } else if (spellknow(spell) <= KEEN / 10) { /* 2000 turns left */ Your("recall of this spell is gradually fading."); } + /* + * Note: dotele() also calculates energy use and checks nutrition + * and strength requirements; it any of these change, update it too. + */ energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */ if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { @@ -1269,6 +1273,62 @@ throwspell() return 1; } +/* add/hide/remove/unhide teleport-away on behalf of dotelecmd() to give + more control to behavior of ^T when used in wizard mode */ +int +tport_spell(what) +int what; +{ + static struct tport_hideaway { + struct spell savespell; + int tport_indx; + } save_tport; + int i; +/* also defined in teleport.c */ +#define NOOP_SPELL 0 +#define HIDE_SPELL 1 +#define ADD_SPELL 2 +#define UNHIDESPELL 3 +#define REMOVESPELL 4 + + for (i = 0; i < MAXSPELL; i++) + if (spellid(i) == SPE_TELEPORT_AWAY || spellid(i) == NO_SPELL) + break; + if (i == MAXSPELL) { + impossible("tport_spell: spellbook full"); + /* wizard mode ^T is not able to honor player's menu choice */ + } else if (spellid(i) == NO_SPELL) { + if (what == HIDE_SPELL || what == REMOVESPELL) { + save_tport.tport_indx = MAXSPELL; + } else if (what == UNHIDESPELL) { + /*assert( save_tport.savespell.sp_id == SPE_TELEPORT_AWAY );*/ + spl_book[save_tport.tport_indx] = save_tport.savespell; + save_tport.tport_indx = MAXSPELL; /* burn bridge... */ + } else if (what == ADD_SPELL) { + save_tport.savespell = spl_book[i]; + save_tport.tport_indx = i; + spl_book[i].sp_id = SPE_TELEPORT_AWAY; + spl_book[i].sp_lev = objects[SPE_TELEPORT_AWAY].oc_level; + spl_book[i].sp_know = KEEN; + return REMOVESPELL; /* operation needed to reverse */ + } + } else { /* spellid(i) == SPE_TELEPORT_AWAY */ + if (what == ADD_SPELL || what == UNHIDESPELL) { + save_tport.tport_indx = MAXSPELL; + } else if (what == REMOVESPELL) { + /*assert( i == save_tport.tport_indx );*/ + spl_book[i] = save_tport.savespell; + save_tport.tport_indx = MAXSPELL; + } else if (what == HIDE_SPELL) { + save_tport.savespell = spl_book[i]; + save_tport.tport_indx = i; + spl_book[i].sp_id = NO_SPELL; + return UNHIDESPELL; /* operation needed to reverse */ + } + } + return NOOP_SPELL; +} + /* forget a random selection of known spells due to amnesia; they used to be lost entirely, as if never learned, but now we just set the memory retention to zero so that they can't be cast */ diff --git a/src/teleport.c b/src/teleport.c index 9aedc0c3e..e2a6c32dc 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 teleport.c $NHDT-Date: 1544401270 2018/12/10 00:21:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 teleport.c $NHDT-Date: 1546565815 2019/01/04 01:36:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$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. */ @@ -496,17 +496,114 @@ struct obj *scroll; return result; } +/* ^T command; 'm ^T' == choose among several teleport modes */ int dotelecmd() { - return dotele((wizard) ? TRUE : FALSE); + long save_HTele, save_ETele; + int res, added, hidden; + boolean ignore_restrictions = FALSE; +/* also defined in spell.c */ +#define NOOP_SPELL 0 +#define HIDE_SPELL 1 +#define ADD_SPELL 2 +#define UNHIDESPELL 3 +#define REMOVESPELL 4 + + /* normal mode; ignore 'm' prefix if it was given */ + if (!wizard) + return dotele(FALSE); + + added = hidden = NOOP_SPELL; + save_HTele = HTeleportation, save_ETele = ETeleportation; + if (!iflags.menu_requested) { + ignore_restrictions = TRUE; + } else { + static const struct tporttypes { + char menulet; + const char *menudesc; + } tports[] = { + /* + * Potential combinations: + * 1) attempt ^T without intrinsic, not know spell; + * 2) via intrinsic, not know spell, obey restrictions; + * 3) via intrinsic, not know spell, ignore restrictions; + * 4) via intrinsic, know spell, obey restrictions; + * 5) via intrinsic, know spell, ignore restrictions; + * 6) via spell, not have intrinsic, obey restrictions; + * 7) via spell, not have intrinsic, ignore restrictions; + * 8) force, obey other restrictions; + * 9) force, ignore restrictions. + * We only support the 1st (t), 2nd (n), 6th (s), and 9th (w). + * + * This ignores the fact that there is an experience level + * (or poly-form) requirement which might make normal ^T fail. + */ + { 'n', "normal ^T on demand; no spell, obey restrictions" }, + { 's', "via spellcast; no intrinsic teleport" }, + { 't', "try ^T without having it; no spell" }, + { 'w', "debug mode; ignore restrictions" }, /* trad wizard mode */ + }; + menu_item *picks = (menu_item *) 0; + anything any; + winid win; + int i, tmode; + + win = create_nhwindow(NHW_MENU); + start_menu(win); + any = zeroany; + for (i = 0; i < SIZE(tports); ++i) { + any.a_int = (int) tports[i].menulet; + add_menu(win, NO_GLYPH, &any, (char) any.a_int, 0, ATR_NONE, + tports[i].menudesc, MENU_UNSELECTED); + } + end_menu(win, "Which way do you want to teleport?"); + if (select_menu(win, PICK_ONE, &picks) > 0) { + tmode = picks[0].item.a_int; + free((genericptr_t) picks); + } else { + return 0; + } + destroy_nhwindow(win); + switch (tmode) { + case 'n': + HTeleportation |= I_SPECIAL; /* confer intrinsic teleportation */ + hidden = tport_spell(HIDE_SPELL); /* hide teleport-away */ + break; + case 's': + HTeleportation = ETeleportation = 0L; /* suppress intrinsic */ + added = tport_spell(ADD_SPELL); /* add teleport-away */ + break; + case 't': + HTeleportation = ETeleportation = 0L; /* suppress intrinsic */ + hidden = tport_spell(HIDE_SPELL); /* hide teleport-away */ + break; + case 'w': + ignore_restrictions = TRUE; + break; + } + } + + /* if dotele() can be fatal, final disclosure might lie about + intrinsic teleportation; we should be able to live with that + since the menu finagling is only applicable in wizard mode */ + res = dotele(ignore_restrictions); + + HTeleportation = save_HTele; + ETeleportation = save_ETele; + if (added != NOOP_SPELL || hidden != NOOP_SPELL) + /* can't both be non-NOOP so addition will yield the non-NOOP one */ + (void) tport_spell(added + hidden - NOOP_SPELL); + + return res; } int dotele(break_the_rules) -boolean break_the_rules; +boolean break_the_rules; /* True: wizard mode ^T */ { struct trap *trap; + const char *cantdoit; boolean trap_once = FALSE; trap = t_at(u.ux, u.uy); @@ -517,9 +614,9 @@ boolean break_the_rules; trap_once = trap->once; /* trap may get deleted, save this */ if (trap->once) { pline("This is a vault teleport, usable once only."); - if (yn("Jump in?") == 'n') + if (yn("Jump in?") == 'n') { trap = 0; - else { + } else { deltrap(trap); newsym(u.ux, u.uy); } @@ -534,58 +631,72 @@ boolean break_the_rules; if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12) && !can_teleport(youmonst.data))) { - /* Try to use teleport away spell. */ - if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion) - for (sp_no = 0; sp_no < MAXSPELL; sp_no++) - if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) { - castit = TRUE; - break; - } - if (!break_the_rules) { - if (!castit) { - if (!Teleportation) - You("don't know that spell."); - else - You("are not able to teleport at will."); - return 0; - } + /* Try to use teleport away spell. + 3.6.2: this used to require that you know the spellbook + (probably just intended as an optimization to skip the + lookup loop) but it is possible to know and cast a spell + after forgetting its book due to amnesia. */ + for (sp_no = 0; sp_no < MAXSPELL; sp_no++) + if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) + break; + /* casting isn't inhibited by being Stunned (...it ought to be) */ + castit = (sp_no < MAXSPELL && !Confusion); + if (!castit && !break_the_rules) { + You("%s.", + !Teleportation ? ((sp_no < MAXSPELL) + ? "can't cast that spell" + : "don't know that spell") + : "are not able to teleport at will"); + return 0; } } - if (u.uhunger <= 100 || ACURR(A_STR) < 6) { - if (!break_the_rules) { - You("lack the strength %s.", - castit ? "for a teleport spell" : "to teleport"); - return 1; - } + cantdoit = 0; + /* 3.6.2: the magic numbers for hunger, strength, and energy + have been changed to match the ones used in spelleffects(). + Also, failing these tests used to return 1 and use a move + even though casting failure due to these reasons doesn't. + [Note: this spellev() is different from the one in spell.c + but they both yield the same result.] */ +#define spellev(spell_otyp) ((int) objects[spell_otyp].oc_level) + energy = 5 * spellev(SPE_TELEPORT_AWAY); + if (break_the_rules) { + if (!castit) + energy = 0; + /* spell will cost more if carrying the Amulet, but the + amount is rnd(2 * energy) so we can't know by how much; + average is twice the normal cost, but could be triple; + the extra energy is spent even if that results in not + having enough to cast (which also uses the move) */ + else if (u.uen < energy) + u.uen = energy; + } else if (u.uhunger <= 10) { + cantdoit = "are too weak from hunger"; + } else if (ACURR(A_STR) < 4) { + cantdoit = "lack the strength"; + } else if (energy > u.uen) { + cantdoit = "lack the energy"; } - - energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2; - if (u.uen <= energy) { - if (break_the_rules) - energy = u.uen; - else { - You("lack the energy %s.", - castit ? "for a teleport spell" : "to teleport"); - return 1; - } + if (cantdoit) { + You("%s %s.", cantdoit, + castit ? "for a teleport spell" : "to teleport"); + return 0; + } else if (check_capacity( + "Your concentration falters from carrying so much.")) { + return 1; /* this failure in spelleffects() also uses the move */ } - if (check_capacity( - "Your concentration falters from carrying so much.")) - return 1; - if (castit) { + /* energy cost is deducted in spelleffects() */ exercise(A_WIS, TRUE); if (spelleffects(sp_no, TRUE)) return 1; else if (!break_the_rules) return 0; } else { - if (!break_the_rules) { - u.uen -= energy; - context.botl = 1; - } + /* bypassing spelleffects(); apply energy cost directly */ + u.uen -= energy; + context.botl = 1; } } @@ -596,7 +707,7 @@ boolean break_the_rules; tele(); (void) next_to_u(); } else { - You1(shudder_for_moment); + You("%s", shudder_for_moment); return 0; } if (!trap) From 9bcc42957b624d870c031407e8daf9dc67786646 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 4 Jan 2019 18:28:50 -0800 Subject: [PATCH 2/4] 'm ^T' menu fix Fix fuzzer feedback. The new wizard mode ^T menu had an early return which bypassed destroy_nhwindow(), leaving the menu around. Fuzzer eventually got "No window slots!" panic from tty. Make sure that the menu window is torn down fully before returning. Also, make the normal wizard mode teleportation chioce be preselected so that not picking anything doesn't lead to an early return any more. ESC still does though. --- doc/fixes36.2 | 4 +++- src/teleport.c | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 015ce2c20..102c61f6b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.222 $ $NHDT-Date: 1546565812 2019/01/04 01:36:52 $ +$NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.223 $ $NHDT-Date: 1546655319 2019/01/05 02:28:39 $ This fixes36.2 file is here to capture information about updates in the 3.6.x lineage following the release of 3.6.1 in April 2018. Please note, however, @@ -371,6 +371,8 @@ wizard mode ^G, creating a monster via class name using "lo" through "long wor" if bouldersym bug (via 'O', above) put a ('\0') on the map, examining that spot matched placeholder monster class #0 and triggered impossible "Alphabet soup: 'an("")'." +wizard mode m^T, not selecting a teleport choice didn't teardown the menu + properly and could eventually lead to "No window slots!" panic tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status diff --git a/src/teleport.c b/src/teleport.c index e2a6c32dc..fb99e6331 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 teleport.c $NHDT-Date: 1546565815 2019/01/04 01:36:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.82 $ */ +/* NetHack 3.6 teleport.c $NHDT-Date: 1546655319 2019/01/05 02:28:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.83 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -555,16 +555,25 @@ dotelecmd() for (i = 0; i < SIZE(tports); ++i) { any.a_int = (int) tports[i].menulet; add_menu(win, NO_GLYPH, &any, (char) any.a_int, 0, ATR_NONE, - tports[i].menudesc, MENU_UNSELECTED); + tports[i].menudesc, + (tports[i].menulet == 'w') ? MENU_SELECTED + : MENU_UNSELECTED); } end_menu(win, "Which way do you want to teleport?"); - if (select_menu(win, PICK_ONE, &picks) > 0) { + i = select_menu(win, PICK_ONE, &picks); + destroy_nhwindow(win); + if (i > 0) { tmode = picks[0].item.a_int; + /* if we got 2, use the one which wasn't preselected */ + if (i > 1 && tmode == 'w') + tmode = picks[1].item.a_int; free((genericptr_t) picks); - } else { + } else if (i == 0) { + /* preselected one was explicitly chosen and got toggled off */ + tmode = 'w'; + } else { /* ESC */ return 0; } - destroy_nhwindow(win); switch (tmode) { case 'n': HTeleportation |= I_SPECIAL; /* confer intrinsic teleportation */ From c0cce3110e9b5a63628c18fc675fc2462fac32f5 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 4 Jan 2019 18:47:00 -0800 Subject: [PATCH 3/4] src formatting Remove a couple of tabs, and for the affected files, put 'goto' labels in column 2 where they're easier to spot. --- src/drawing.c | 4 ++-- src/hack.c | 29 +++++++++++++++-------------- src/pager.c | 6 +++--- 3 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/drawing.c b/src/drawing.c index ec11bb843..e9a1e08e1 100644 --- a/src/drawing.c +++ b/src/drawing.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 drawing.c $NHDT-Date: 1546212616 2018/12/30 23:30:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.58 $ */ +/* NetHack 3.6 drawing.c $NHDT-Date: 1546656404 2019/01/05 02:46:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) NetHack Development Team 1992. */ /* NetHack may be freely redistributed. See license for details. */ @@ -505,7 +505,7 @@ int nondefault; #endif # ifdef CURSES_GRAPHICS if (SYMHANDLING(H_CURS) && cursesgraphics_mode_callback) - (*cursesgraphics_mode_callback)(); + (*cursesgraphics_mode_callback)(); # endif } else { init_l_symbols(); diff --git a/src/hack.c b/src/hack.c index 0e3f3f6f2..f8bfb6f5e 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1545530973 2018/12/23 02:09:33 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.202 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1546656413 2019/01/05 02:46:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.203 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -279,7 +279,7 @@ moverock() /* note: reset to zero after save/restore cycle */ static NEARDATA long lastmovetime; #endif - dopush: + dopush: if (!u.usteed) { if (moves > lastmovetime + 2 || moves < lastmovetime) pline("With %s effort you move %s.", @@ -304,7 +304,7 @@ moverock() newsym(sx, sy); } } else { - nopushmsg: + nopushmsg: if (u.usteed) pline("%s tries to move %s, but cannot.", upstart(y_monnam(u.usteed)), the(xname(otmp))); @@ -312,7 +312,7 @@ moverock() You("try to move %s, but in vain.", the(xname(otmp))); if (Blind) feel_location(sx, sy); - cannot_push: + cannot_push: if (throws_rocks(youmonst.data)) { boolean canpickup = (!Sokoban @@ -797,7 +797,7 @@ int mode; return FALSE; } } else { - testdiag: + testdiag: if (dx && dy && !Passes_walls && (!doorless_door(x, y) || block_door(x, y))) { /* Diagonal moves into a door are not allowed. */ @@ -955,8 +955,8 @@ int mode; uy = u.uy; } - noguess: - (void) memset((genericptr_t) travel, 0, sizeof(travel)); + noguess: + (void) memset((genericptr_t) travel, 0, sizeof travel); travelstepx[0][0] = tx; travelstepy[0][0] = ty; @@ -1141,7 +1141,7 @@ int mode; return FALSE; } -found: + found: u.dx = 0; u.dy = 0; nomul(0); @@ -1294,7 +1294,7 @@ struct trap *desttrap; /* nonnull if another trap at */ Norep("You are %s %s.", predicament, culprit); } } else { -wriggle_free: + wriggle_free: if (u.usteed) pline("%s finally %s free.", upstart(steedname), !anchored ? "lurches" : "wrenches the ball"); @@ -1493,7 +1493,7 @@ domove() case 0: case 1: case 2: - pull_free: + pull_free: You("pull free from %s.", mon_nam(u.ustuck)); u.ustuck = 0; break; @@ -2203,7 +2203,7 @@ boolean pick; } mnexto(mtmp); /* have to move the monster */ } -spotdone: + spotdone: if (!--inspoteffects) { spotterrain = STONE; /* 0 */ spotloc.x = spotloc.y = 0; @@ -2581,7 +2581,8 @@ dopickup(VOID_ARGS) int count, tmpcount, ret; /* awful kludge to work around parse()'s pre-decrement */ - count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup))) ? multi + 1 : 0; + count = (multi || (save_cm && *save_cm == cmd_from_func(dopickup))) + ? multi + 1 : 0; multi = 0; /* always reset */ if ((ret = pickup_checks() >= 0)) @@ -2654,7 +2655,7 @@ lookaround() } goto bcorr; } else if (levl[x][y].typ == CORR) { - bcorr: + bcorr: if (levl[u.ux][u.uy].typ != ROOM) { if (context.run == 1 || context.run == 3 || context.run == 8) { @@ -2712,7 +2713,7 @@ lookaround() || ((y == u.uy - u.dy) && (x != u.ux + u.dx))) continue; } - stop: + stop: nomul(0); return; } /* end for loops */ diff --git a/src/pager.c b/src/pager.c index 5b7f43c48..693a412fa 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1546144745 2018/12/30 04:39:05 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.146 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1546656415 2019/01/05 02:46:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.147 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -117,7 +117,7 @@ char *outbuf; } else if (mon->m_ap_type == M_AP_OBJECT /* remembered glyph, not glyph_at() which is 'mon' */ && glyph_is_object(glyph)) { - objfrommap: + objfrommap: otmp = (struct obj *) 0; fakeobj = object_from_map(glyph, x, y, &otmp); Strcat(outbuf, (otmp && otmp->otyp != STRANGE_OBJECT) @@ -1421,7 +1421,7 @@ boolean without_asking; } else { textp = suptext2; gang = ""; - } + } datawin = create_nhwindow(NHW_MENU); for (i = 0; textp[i]; i++) { char buf[BUFSZ]; From ab5b400aeca97040ce1861803ac9e4c0027b9b3f Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 4 Jan 2019 19:03:34 -0800 Subject: [PATCH 4/4] options.c formatting; glob as named fruit This started out removing one tab and I got carried away. It moves some labels to column 2, removes some parentheses where sizeof is used on strings rather than types, adds or revises several comments, replaces a couple of 'while' loops which can be simplified as 'for' loops, and updates named fruit handling. "glob of black pudding" became "candied glob of black pudding" if used as a fruit name, but "small glob of black pudding" was used as-is and became indistinguishable from an actual small glob. Unless you had more than one; then you could try to check whether they merged into a stack or coalesced into a bigger glob (but if neither of those changes happened, you still couldn't tell which was the glob and which was the named fruit). --- src/options.c | 276 +++++++++++++++++++++++++++----------------------- 1 file changed, 147 insertions(+), 129 deletions(-) diff --git a/src/options.c b/src/options.c index ef440e855..b3fb0b79e 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1546212618 2018/12/30 23:30:18 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.350 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1546657409 2019/01/05 03:03:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.351 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -279,7 +279,7 @@ static struct Comp_Opt { { "catname", "the name of your (first) cat (e.g., catname:Tabby)", PL_PSIZ, DISP_IN_GAME }, { "disclose", "the kinds of information to disclose at end of game", - sizeof(flags.end_disclose) * 2, SET_IN_GAME }, + sizeof flags.end_disclose * 2, SET_IN_GAME }, { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ, DISP_IN_GAME }, { "dungeon", "the symbols to use in drawing the dungeon map", @@ -720,7 +720,7 @@ initoptions_init() #endif #ifdef SYSFLAGS Strcpy(sysflags.sysflagsid, "sysflags"); - sysflags.sysflagsid[9] = (char) sizeof(struct sysflag); + sysflags.sysflagsid[9] = (char) sizeof (struct sysflag); #endif flags.end_own = FALSE; flags.end_top = 3; @@ -908,6 +908,8 @@ int maxlen; /* * escapes(): escape expansion for showsyms. C-style escapes understood * include \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). + * (Note: unlike in C, leading digit 0 is not used to indicate octal; + * the letter o (either upper or lower case) is used for that. * The ^-prefix for control characters is also understood, and \[mM] * has the effect of 'meta'-ing the value which follows (so that the * alternate character set will be enabled). @@ -1013,7 +1015,7 @@ const char *optname; /* # errors: -OPTIONS=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +OPTIONS=aaaaaaaaaa[ more than 247 (255 - 8 for 'OPTIONS=') total ]aaaaaaaaaa OPTIONS OPTIONS= MSGTYPE=stop"You swap places with " @@ -1386,7 +1388,7 @@ char *str; /* allow "lightblue", "light blue", and "light-blue" to match "light blue" (also junk like "_l i-gh_t---b l u e" but we won't worry about that); - also copes with trailing space; mungspaces removed any leading space */ + also copes with trailing space; caller has removed any leading space */ for (i = 0; i < SIZE(colornames); i++) if (colornames[i].name && fuzzymatch(str, colornames[i].name, " -_", TRUE)) { @@ -1613,8 +1615,7 @@ msgtype_add(typ, pattern) int typ; char *pattern; { - struct plinemsg_type - *tmp = (struct plinemsg_type *) alloc(sizeof (struct plinemsg_type)); + struct plinemsg_type *tmp = (struct plinemsg_type *) alloc(sizeof *tmp); tmp->msgtype = typ; tmp->regex = regex_init(); @@ -1785,7 +1786,7 @@ int c, a; if (!str) return FALSE; - tmp = (struct menucoloring *) alloc(sizeof (struct menucoloring)); + tmp = (struct menucoloring *) alloc(sizeof *tmp); tmp->match = regex_init(); if (!regex_compile(str, tmp->match)) { config_error_add("%s: %s", re_error, regex_error_desc(tmp->match)); @@ -1846,7 +1847,6 @@ char *tmpstr; tmps++; } } - return add_menu_coloring_parsed(tmps, c, a); } @@ -1870,15 +1870,13 @@ int *color, *attr; void free_menu_coloring() { - struct menucoloring *tmp = menu_colorings; - - while (tmp) { - struct menucoloring *tmp2 = tmp->next; + struct menucoloring *tmp, *tmp2; + for (tmp = menu_colorings; tmp; tmp = tmp2) { + tmp2 = tmp->next; regex_free(tmp->match); free((genericptr_t) tmp->origstr); free((genericptr_t) tmp); - tmp = tmp2; } } @@ -1911,13 +1909,11 @@ int idx; /* 0 .. */ STATIC_OVL int count_menucolors(VOID_ARGS) { + struct menucoloring *tmp; int count = 0; - struct menucoloring *tmp = menu_colorings; - while (tmp) { + for (tmp = menu_colorings; tmp; tmp = tmp->next) count++; - tmp = tmp->next; - } return count; } @@ -2066,7 +2062,7 @@ boolean tinitial, tfrom_file; /* align:string */ fullname = "align"; - if (match_optname(opts, fullname, sizeof("align") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "align" - 1, TRUE)) { if (parse_role_opts(negated, fullname, opts, &op)) { if ((flags.initalign = str2align(op)) == ROLE_NONE) { config_error_add("Unknown %s '%s'", fullname, op); @@ -2620,7 +2616,7 @@ boolean tinitial, tfrom_file; } } } - goodfruit: + goodfruit: nmcpy(pl_fruit, op, PL_FSIZ); sanitize_name(pl_fruit); /* OBJ_NAME(objects[SLIME_MOLD]) won't work for this after @@ -2793,16 +2789,16 @@ boolean tinitial, tfrom_file; /* WINCAP * align_status:[left|top|right|bottom] */ fullname = "align_status"; - if (match_optname(opts, fullname, sizeof("align_status") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "align_status" - 1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { - if (!strncmpi(op, "left", sizeof("left") - 1)) + if (!strncmpi(op, "left", sizeof "left" - 1)) iflags.wc_align_status = ALIGN_LEFT; - else if (!strncmpi(op, "top", sizeof("top") - 1)) + else if (!strncmpi(op, "top", sizeof "top" - 1)) iflags.wc_align_status = ALIGN_TOP; - else if (!strncmpi(op, "right", sizeof("right") - 1)) + else if (!strncmpi(op, "right", sizeof "right" - 1)) iflags.wc_align_status = ALIGN_RIGHT; - else if (!strncmpi(op, "bottom", sizeof("bottom") - 1)) + else if (!strncmpi(op, "bottom", sizeof "bottom" - 1)) iflags.wc_align_status = ALIGN_BOTTOM; else { config_error_add("Unknown %s parameter '%s'", fullname, op); @@ -2818,18 +2814,18 @@ boolean tinitial, tfrom_file; /* WINCAP * align_message:[left|top|right|bottom] */ fullname = "align_message"; - if (match_optname(opts, fullname, sizeof("align_message") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "align_message" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { - if (!strncmpi(op, "left", sizeof("left") - 1)) + if (!strncmpi(op, "left", sizeof "left" - 1)) iflags.wc_align_message = ALIGN_LEFT; - else if (!strncmpi(op, "top", sizeof("top") - 1)) + else if (!strncmpi(op, "top", sizeof "top" - 1)) iflags.wc_align_message = ALIGN_TOP; - else if (!strncmpi(op, "right", sizeof("right") - 1)) + else if (!strncmpi(op, "right", sizeof "right" - 1)) iflags.wc_align_message = ALIGN_RIGHT; - else if (!strncmpi(op, "bottom", sizeof("bottom") - 1)) + else if (!strncmpi(op, "bottom", sizeof "bottom" - 1)) iflags.wc_align_message = ALIGN_BOTTOM; else { config_error_add("Unknown %s parameter '%s'", fullname, op); @@ -2883,7 +2879,7 @@ boolean tinitial, tfrom_file; pp = index(op, ' '); if (pp) *pp = '\0'; - /* we aren't matching option names but match_optname + /* we aren't matching option names but match_optname() does what we want once we've broken the space delimited aggregate into separate tokens */ for (i = 0; i < SIZE(paranoia); ++i) { @@ -2968,8 +2964,8 @@ boolean tinitial, tfrom_file; /* types of objects to pick up automatically */ fullname = "pickup_types"; if (match_optname(opts, fullname, 8, TRUE)) { - char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ], - abuf[BUFSZ] = DUMMY; + char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], + qbuf[QBUFSZ], abuf[BUFSZ]; int oc_sym; boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu; @@ -2995,6 +2991,7 @@ boolean tinitial, tfrom_file; use_menu = FALSE; Sprintf(qbuf, "New %s: [%s am] (%s)", fullname, ocl, *tbuf ? tbuf : "all"); + abuf[0] = '\0'; getlin(qbuf, abuf); wasspace = (abuf[0] == ' '); /* before mungspaces */ op = mungspaces(abuf); @@ -3004,6 +3001,8 @@ boolean tinitial, tfrom_file; op = tbuf; /* restore */ else if (abuf[0] == 'm') use_menu = TRUE; + /* note: abuf[0]=='a' is already handled via clearing the + the old value (above) as a default action */ } if (use_menu) { if (wizard && !index(ocl, VENOM_SYM)) @@ -3087,18 +3086,18 @@ boolean tinitial, tfrom_file; } /* WINCAP - * player_selection: dialog | prompts */ + * player_selection: dialog | prompt/prompts/prompting */ fullname = "player_selection"; - if (match_optname(opts, fullname, sizeof("player_selection") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "player_selection" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { - if (!strncmpi(op, "dialog", sizeof("dialog") - 1)) + if (!strncmpi(op, "dialog", sizeof "dialog" - 1)) { iflags.wc_player_selection = VIA_DIALOG; - else if (!strncmpi(op, "prompt", sizeof("prompt") - 1)) + } else if (!strncmpi(op, "prompt", sizeof "prompt" - 1)) { iflags.wc_player_selection = VIA_PROMPTS; - else { + } else { config_error_add("Unknown %s parameter '%s'", fullname, op); return FALSE; } @@ -3120,11 +3119,13 @@ boolean tinitial, tfrom_file; * end_disclose[NUM_DISCLOSURE_OPT]; * with option settings for the each of the following: * iagvc [see disclosure_options in decl.c]: - * Legal setting values in that array are: + * Allowed setting values in that array are: * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask + * DISCLOSE_PROMPT_DEFAULT_SPECIAL for 'vanquished' only... + * DISCLOSE_SPECIAL_WITHOUT_PROMPT ...to set up sort order. * * Those setting values can be used in the option * string as a prefix to get the desired behaviour. @@ -3360,33 +3361,33 @@ boolean tinitial, tfrom_file; * |ascii8x12|ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */ fullname = "map_mode"; - if (match_optname(opts, fullname, sizeof("map_mode") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "map_mode" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); if (op && !negated) { - if (!strncmpi(op, "tiles", sizeof("tiles") - 1)) + if (!strncmpi(op, "tiles", sizeof "tiles" - 1)) iflags.wc_map_mode = MAP_MODE_TILES; - else if (!strncmpi(op, "ascii4x6", sizeof("ascii4x6") - 1)) + else if (!strncmpi(op, "ascii4x6", sizeof "ascii4x6" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII4x6; - else if (!strncmpi(op, "ascii6x8", sizeof("ascii6x8") - 1)) + else if (!strncmpi(op, "ascii6x8", sizeof "ascii6x8" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII6x8; - else if (!strncmpi(op, "ascii8x8", sizeof("ascii8x8") - 1)) + else if (!strncmpi(op, "ascii8x8", sizeof "ascii8x8" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII8x8; - else if (!strncmpi(op, "ascii16x8", sizeof("ascii16x8") - 1)) + else if (!strncmpi(op, "ascii16x8", sizeof "ascii16x8" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII16x8; - else if (!strncmpi(op, "ascii7x12", sizeof("ascii7x12") - 1)) + else if (!strncmpi(op, "ascii7x12", sizeof "ascii7x12" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII7x12; - else if (!strncmpi(op, "ascii8x12", sizeof("ascii8x12") - 1)) + else if (!strncmpi(op, "ascii8x12", sizeof "ascii8x12" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII8x12; - else if (!strncmpi(op, "ascii16x12", sizeof("ascii16x12") - 1)) + else if (!strncmpi(op, "ascii16x12", sizeof "ascii16x12" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII16x12; - else if (!strncmpi(op, "ascii12x16", sizeof("ascii12x16") - 1)) + else if (!strncmpi(op, "ascii12x16", sizeof "ascii12x16" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII12x16; - else if (!strncmpi(op, "ascii10x18", sizeof("ascii10x18") - 1)) + else if (!strncmpi(op, "ascii10x18", sizeof "ascii10x18" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII10x18; else if (!strncmpi(op, "fit_to_screen", - sizeof("fit_to_screen") - 1)) + sizeof "fit_to_screen" - 1)) iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN; else { config_error_add("Unknown %s parameter '%s'", fullname, op); @@ -3453,7 +3454,7 @@ boolean tinitial, tfrom_file; /* WINCAP * tile_width:nn */ fullname = "tile_width"; - if (match_optname(opts, fullname, sizeof("tile_width") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "tile_width" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); @@ -3468,7 +3469,7 @@ boolean tinitial, tfrom_file; /* WINCAP * tile_file:name */ fullname = "tile_file"; - if (match_optname(opts, fullname, sizeof("tile_file") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "tile_file" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); if ((op = string_for_opt(opts, FALSE)) != 0) { @@ -3482,7 +3483,7 @@ boolean tinitial, tfrom_file; /* WINCAP * tile_height:nn */ fullname = "tile_height"; - if (match_optname(opts, fullname, sizeof("tile_height") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "tile_height" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); @@ -3498,7 +3499,7 @@ boolean tinitial, tfrom_file; /* WINCAP * vary_msgcount:nn */ fullname = "vary_msgcount"; - if (match_optname(opts, fullname, sizeof("vary_msgcount") - 1, TRUE)) { + if (match_optname(opts, fullname, sizeof "vary_msgcount" - 1, TRUE)) { if (duplicate) complain_about_duplicate(opts, 1); op = string_for_opt(opts, negated); @@ -3521,7 +3522,8 @@ boolean tinitial, tfrom_file; * OPTIONS=windowtype:Foo * as the first non-comment line of the file. * Making it first in NETHACKOPTIONS requires it to be at the _end_ - * because option strings are processed from right to left. + * because comma-separated option strings are processed from right + * to left. */ fullname = "windowtype"; if (match_optname(opts, fullname, 3, TRUE)) { @@ -3540,7 +3542,7 @@ boolean tinitial, tfrom_file; choose_windows(buf); } else { nmcpy(chosen_windowtype, op, WINTYPELEN); - } + } } else return FALSE; return retval; @@ -3582,7 +3584,7 @@ boolean tinitial, tfrom_file; /* WINCAP2 * term_cols:amount */ fullname = "term_cols"; - if (match_optname(opts, fullname, sizeof("term_cols")-1, TRUE)) { + if (match_optname(opts, fullname, sizeof "term_cols" - 1, TRUE)) { op = string_for_opt(opts, negated); iflags.wc2_term_cols = atoi(op); if (negated) @@ -3593,7 +3595,7 @@ boolean tinitial, tfrom_file; /* WINCAP2 * term_rows:amount */ fullname = "term_rows"; - if (match_optname(opts, fullname, sizeof("term_rows")-1, TRUE)) { + if (match_optname(opts, fullname, sizeof "term_rows" - 1, TRUE)) { op = string_for_opt(opts, negated); iflags.wc2_term_rows = atoi(op); if (negated) @@ -3604,7 +3606,7 @@ boolean tinitial, tfrom_file; /* WINCAP2 * petattr:string */ fullname = "petattr"; - if (match_optname(opts, fullname, sizeof("petattr")-1, TRUE)) { + if (match_optname(opts, fullname, sizeof "petattr" - 1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { #ifdef CURSES_GRAPHICS @@ -3625,7 +3627,7 @@ boolean tinitial, tfrom_file; /* WINCAP2 * windowborders:n */ fullname = "windowborders"; - if (match_optname(opts, fullname, sizeof("windowborders")-1, TRUE)) { + if (match_optname(opts, fullname, sizeof "windowborders" - 1, TRUE)) { op = string_for_opt(opts, negated); if (negated && op) bad_negation(fullname, TRUE); @@ -3637,10 +3639,9 @@ boolean tinitial, tfrom_file; else /* Value supplied */ iflags.wc2_windowborders = atoi(op); if ((iflags.wc2_windowborders > 3) - || (iflags.wc2_windowborders < 1)) { + || (iflags.wc2_windowborders < 1)) { iflags.wc2_windowborders = 0; - config_error_add( - "Badoption - windowborders %s.", opts); + config_error_add("Badoption - windowborders %s.", opts); } } return retval; @@ -3722,10 +3723,10 @@ boolean tinitial, tfrom_file; escapes(op, op_buf); c = *op_buf; - if (illegal_menu_cmd_key(c)) { + if (illegal_menu_cmd_key(c)) return FALSE; - } else - add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); + + add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); } return retval; } @@ -3887,8 +3888,9 @@ boolean tinitial, tfrom_file; #endif /* ?(MAC_GRAPHICS_ENV && BACKWARD_COMPAT) */ } /* "MACgraphics" */ - /* OK, if we still haven't recognized the option, check the boolean - * options list + /* + * OK, if we still haven't recognized the option, check the boolean + * options list. */ for (i = 0; boolopt[i].name; i++) { if (match_optname(opts, boolopt[i].name, 3, TRUE)) { @@ -4121,8 +4123,8 @@ char from_ch, to_ch; mapped_menu_cmds[n_menu_mapped] = from_ch; mapped_menu_op[n_menu_mapped] = to_ch; n_menu_mapped++; - mapped_menu_cmds[n_menu_mapped] = 0; - mapped_menu_op[n_menu_mapped] = 0; + mapped_menu_cmds[n_menu_mapped] = '\0'; + mapped_menu_op[n_menu_mapped] = '\0'; } } @@ -4349,17 +4351,14 @@ doset() /* changing options via menu by Per Liboriussen */ and adjust the format string accordingly */ longest_name_len = 0; for (pass = 0; pass <= 2; pass++) - for (i = 0; (name = ((pass == 0) - ? boolopt[i].name - : (pass == 1) - ? compopt[i].name + for (i = 0; (name = ((pass == 0) ? boolopt[i].name + : (pass == 1) ? compopt[i].name : othropt[i].name)) != 0; i++) { if (pass == 0 && !boolopt[i].addr) continue; optflags = (pass == 0) ? boolopt[i].optflags - : (pass == 1) - ? compopt[i].optflags - : othropt[i].optflags; + : (pass == 1) ? compopt[i].optflags + : othropt[i].optflags; if (optflags < startpass || optflags > endpass) continue; if ((is_wc_option(name) && !wc_supported(name)) @@ -4511,8 +4510,7 @@ doset() /* changing options via menu by Per Liboriussen */ preference_update(compopt[opt_indx].name); } } - free((genericptr_t) pick_list); - pick_list = (menu_item *) 0; + free((genericptr_t) pick_list), pick_list = (menu_item *) 0; } destroy_nhwindow(tmpwin); @@ -4524,6 +4522,7 @@ doset() /* changing options via menu by Per Liboriussen */ return 0; } +/* common to msg-types, menu-colors, autopickup-exceptions */ STATIC_OVL int handle_add_list_remove(optname, numtotal) const char *optname; @@ -4572,7 +4571,7 @@ int numtotal; } struct symsetentry *symset_list = 0; /* files.c will populate this with - list of available sets */ + * list of available sets */ STATIC_OVL boolean special_handling(optname, setinitial, setfromfile) @@ -4777,24 +4776,24 @@ boolean setinitial, setfromfile; start_menu(tmpwin); any = zeroany; any.a_char = GPCOORDS_COMPASS; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS, - 0, ATR_NONE, "compass ('east' or '3s' or '2n,4w')", + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMPASS, 0, ATR_NONE, + "compass ('east' or '3s' or '2n,4w')", (gp == GPCOORDS_COMPASS) ? MENU_SELECTED : MENU_UNSELECTED); any.a_char = GPCOORDS_COMFULL; add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_COMFULL, 0, ATR_NONE, "full compass ('east' or '3south' or '2north,4west')", (gp == GPCOORDS_COMFULL) ? MENU_SELECTED : MENU_UNSELECTED); any.a_char = GPCOORDS_MAP; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP, - 0, ATR_NONE, "map ", + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_MAP, 0, ATR_NONE, + "map ", (gp == GPCOORDS_MAP) ? MENU_SELECTED : MENU_UNSELECTED); any.a_char = GPCOORDS_SCREEN; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_SCREEN, - 0, ATR_NONE, "screen [row,column]", + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_SCREEN, 0, ATR_NONE, + "screen [row,column]", (gp == GPCOORDS_SCREEN) ? MENU_SELECTED : MENU_UNSELECTED); any.a_char = GPCOORDS_NONE; - add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, - 0, ATR_NONE, "none (no coordinates displayed)", + add_menu(tmpwin, NO_GLYPH, &any, GPCOORDS_NONE, 0, ATR_NONE, + "none (no coordinates displayed)", (gp == GPCOORDS_NONE) ? MENU_SELECTED : MENU_UNSELECTED); any.a_long = 0L; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); @@ -4802,7 +4801,7 @@ boolean setinitial, setfromfile; 1, 0, COLNO - 1, ROWNO - 1, flags.verbose ? "; column 0 unused, off left edge" : ""); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); - if (strcmp(windowprocs.name, "tty")) + if (strcmp(windowprocs.name, "tty")) /* only show for non-tty */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "screen: row is offset to accommodate tty interface's use of top line", MENU_UNSELECTED); @@ -5002,7 +5001,7 @@ boolean setinitial, setfromfile; int opt_idx, nmt, mttyp; char mtbuf[BUFSZ] = DUMMY; - msgtypes_again: + msgtypes_again: nmt = msgtype_count(); opt_idx = handle_add_list_remove("message type", nmt); if (opt_idx == 3) { /* done */ @@ -5064,11 +5063,11 @@ boolean setinitial, setfromfile; int opt_idx, nmc, mcclr, mcattr; char mcbuf[BUFSZ] = DUMMY; - menucolors_again: + menucolors_again: nmc = count_menucolors(); opt_idx = handle_add_list_remove("menucolor", nmc); if (opt_idx == 3) { /* done */ - menucolors_done: + menucolors_done: if (nmc > 0 && !iflags.use_menu_color) pline( "To have menu colors become active, toggle 'menucolors' option to True."); @@ -5139,15 +5138,18 @@ boolean setinitial, setfromfile; } } else if (!strcmp("autopickup_exception", optname)) { int opt_idx, pass, totalapes = 0, numapes[2] = { 0, 0 }; - char apebuf[1 + BUFSZ] = DUMMY; /* so &apebuf[1] is BUFSZ long for getlin() */ + char apebuf[1 + BUFSZ]; /* so &apebuf[1] is BUFSZ long for getlin() */ struct autopickup_exception *ape; - ape_again: + ape_again: totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); opt_idx = handle_add_list_remove("autopickup exception", totalapes); if (opt_idx == 3) { /* done */ return TRUE; } else if (opt_idx == 0) { /* add new */ + /* EDIT_GETLIN: assume user doesn't user want previous + exception used as default input string for this one... */ + apebuf[0] = apebuf[1] = '\0'; getlin("What new autopickup exception pattern?", &apebuf[1]); mungspaces(&apebuf[1]); /* regularize whitespace */ if (apebuf[1] == '\033') @@ -5219,7 +5221,6 @@ boolean setinitial, setfromfile; symset[which_set].name = (char *) 0; res = read_sym_file(which_set); - /* put symset name back */ symset[which_set].name = symset_name; @@ -5698,9 +5699,10 @@ char *buf; #ifdef CURSES_GRAPHICS } else if (!strcmp(optname,"windowborders")) { Sprintf(buf, "%s", - iflags.wc2_windowborders == 1 ? "1=on" : - iflags.wc2_windowborders == 2 ? "2=off" : - iflags.wc2_windowborders == 3 ? "3=auto" : defopt); + (iflags.wc2_windowborders == 1) ? "1=on" + : (iflags.wc2_windowborders == 2) ? "2=off" + : (iflags.wc2_windowborders == 3) ? "3=auto" + : defopt); #endif } else if (!strcmp(optname, "windowtype")) { Sprintf(buf, "%s", windowprocs.name); @@ -5725,10 +5727,9 @@ char *buf; #endif } - if (buf[0]) - return buf; - else - return "unknown"; + if (!buf[0]) + Strcpy(buf, "unknown"); + return buf; } int @@ -5807,13 +5808,12 @@ STATIC_OVL void remove_autopickup_exception(whichape) struct autopickup_exception *whichape; { - struct autopickup_exception *ape, *prev = 0; + struct autopickup_exception *ape, *freeape, *prev = 0; int chain = whichape->grab ? AP_GRAB : AP_LEAVE; for (ape = iflags.autopickup_exceptions[chain]; ape;) { if (ape == whichape) { - struct autopickup_exception *freeape = ape; - + freeape = ape; ape = ape->next; if (prev) prev->next = ape; @@ -6006,7 +6006,8 @@ const char *strval; /* data for option_help() */ static const char *opt_intro[] = { - "", " NetHack Options Help:", "", + "", + " NetHack Options Help:", "", #define CONFIG_SLOT 3 /* fill in next value at run-time */ (char *) 0, #if !defined(MICRO) && !defined(MAC) @@ -6016,7 +6017,8 @@ static const char *opt_intro[] = { #ifdef VMS "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", #endif - "or press \"O\" while playing and use the menu.", "", + "or press \"O\" while playing and use the menu.", + "", "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", (char *) 0 }; @@ -6024,7 +6026,8 @@ static const char *opt_intro[] = { static const char *opt_epilog[] = { "", "Some of the options can be set only before the game is started; those", - "items will not be selectable in the 'O' command's menu.", (char *) 0 + "items will not be selectable in the 'O' command's menu.", + (char *) 0 }; void @@ -6121,11 +6124,11 @@ struct fruit *replace_fruit; { register int i; register struct fruit *f; - int highest_fruit_id = 0; + int highest_fruit_id = 0, globpfx; char buf[PL_FSIZ], altname[PL_FSIZ]; boolean user_specified = (str == pl_fruit); /* if not user-specified, then it's a fruit name for a fruit on - * a bones level... + * a bones level or from orctown raider's loot... */ /* Note: every fruit has an id (kept in obj->spe) of at least 1; @@ -6136,39 +6139,54 @@ struct fruit *replace_fruit; /* force fruit to be singular; this handling is not needed--or wanted--for fruits from bones because - they already received it in their original game */ + they already received it in their original game; + str==pl_fruit but makesingular() creates a copy + so we need to copy that back into pl_fruit */ nmcpy(pl_fruit, makesingular(str), PL_FSIZ); + /* (assertion doesn't matter; we use 'pl_fruit' from here on out) */ /* assert( str == pl_fruit ); */ /* disallow naming after other foods (since it'd be impossible - * to tell the difference) + * to tell the difference); globs might have a size prefix which + * needs to be skipped in order to match the object type name */ + globpfx = (!strncmp(pl_fruit, "small ", 6) + || !strncmp(pl_fruit, "large ", 6)) ? 6 + : (!strncmp(pl_fruit, "very large ", 11)) ? 11 + : 0; for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) { - if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { + if (!strcmp(OBJ_NAME(objects[i]), pl_fruit) + || (globpfx > 0 + && !strcmp(OBJ_NAME(objects[i]), &pl_fruit[globpfx]))) { found = TRUE; break; } } - { + if (!found) { char *c; for (c = pl_fruit; *c >= '0' && *c <= '9'; c++) continue; - if (isspace((uchar) *c) || *c == 0) + if (!*c || isspace((uchar) *c)) numeric = TRUE; } if (found || numeric - || !strncmp(str, "cursed ", 7) - || !strncmp(str, "uncursed ", 9) - || !strncmp(str, "blessed ", 8) - || !strncmp(str, "partly eaten ", 13) - || (!strncmp(str, "tin of ", 7) - && (!strcmp(str + 7, "spinach") - || name_to_mon(str + 7) >= LOW_PM)) - || !strcmp(str, "empty tin") - || ((str_end_is(str, " corpse") - || str_end_is(str, " egg")) - && name_to_mon(str) >= LOW_PM)) { + /* these checks for applying food attributes to actual items + are case sensitive; "glob of foo" is caught by 'found' + if 'foo' is a valid glob; when not valid, allow it as-is */ + || !strncmp(pl_fruit, "cursed ", 7) + || !strncmp(pl_fruit, "uncursed ", 9) + || !strncmp(pl_fruit, "blessed ", 8) + || !strncmp(pl_fruit, "partly eaten ", 13) + || (!strncmp(pl_fruit, "tin of ", 7) + && (!strcmp(pl_fruit + 7, "spinach") + || name_to_mon(pl_fruit + 7) >= LOW_PM)) + || !strcmp(pl_fruit, "empty tin") + || (!strcmp(pl_fruit, "glob") + || (globpfx > 0 && !strcmp("glob", &pl_fruit[globpfx]))) + || ((str_end_is(pl_fruit, " corpse") + || str_end_is(pl_fruit, " egg")) + && name_to_mon(pl_fruit) >= LOW_PM)) { Strcpy(buf, pl_fruit); Strcpy(pl_fruit, "candied "); nmcpy(pl_fruit + 8, buf, PL_FSIZ - 8); @@ -6186,11 +6204,11 @@ struct fruit *replace_fruit; /* replace_fruit is already part of the fruit chain; update it in place rather than looking it up again */ f = replace_fruit; - copynchars(f->fname, str, PL_FSIZ - 1); + copynchars(f->fname, pl_fruit, PL_FSIZ - 1); goto nonew; } } else { - /* not user_supplied, so assumed to be from bones */ + /* not user_supplied, so assumed to be from bones (or orc gang) */ copynchars(altname, str, PL_FSIZ - 1); sanitize_name(altname); flags.made_fruit = TRUE; /* for safety. Any fruit name added from a