From 5688f8f5cd4dc9b010129eb6470317735f9d93da Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Thu, 4 Aug 2016 16:40:41 -0400 Subject: [PATCH 01/24] fix typo in comment --- win/X11/winX.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/win/X11/winX.c b/win/X11/winX.c index 25229541a..bba84f6c4 100644 --- a/win/X11/winX.c +++ b/win/X11/winX.c @@ -2292,7 +2292,7 @@ void nh_XtPopup(w, g, childwid) Widget w; /* widget */ int g; /* type of grab */ -Widget childwid; /* child to recieve focus (can be None) */ +Widget childwid; /* child to receive focus (can be None) */ { XtPopup(w, (XtGrabKind) g); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1); From 2c231f57bdaf619eb22e0b44c30f21c1bde88cb4 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 14 Sep 2018 15:08:22 -0700 Subject: [PATCH 02/24] git pull request #133 - reassess worn equipment Fixes #133 Monsters who lost an amulet of life saving while having their life saved wouldn't attempt to put on another amulet unless/until they picked up some object. Likewise if they had a worn item stolen. (There are probably other events which should re-check worn gear.) The suggested commit had a life-saved monster re-check equipment during life-saving which might have led to reports about them effectively getting extra moves, especially if two-weapon fighting or zap rebound with sequence of kill/life-save/kill-again allowed the target to put on a replacement amulet of life-saving prior to the second kill. It also wasn't amenable to dealing with stolen equipment. This alternate fix sets a flag to have monster check its equipment on its next move. --- doc/fixes36.2 | 3 +++ src/mhitm.c | 3 +++ src/mon.c | 26 ++++++++++++++++++++------ src/uhitm.c | 3 +++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3c514a8a4..a8202713e 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -117,6 +117,9 @@ for hilite_status of string status fields (title, dungeon-level, alignment), jumping into or over a Sokoban pit, or over a fire trap, triggers trap twice mimics created by #wizgenesis could block or not block vision incorrectly handle monsters inside the invocation area +give monsters who have had a worn item stolen or who have been life-saved + (used up amulet) a chance to wear replacement gear on next move + instead of having to wait until they pick something up Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/mhitm.c b/src/mhitm.c index 3b0f11855..95413843c 100644 --- a/src/mhitm.c +++ b/src/mhitm.c @@ -1268,6 +1268,9 @@ register struct attack *mattk; mwepgone(mdef); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); + /* give monster a chance to wear other equipment on its next + move instead of waiting until it picks something up */ + mdef->misc_worn_check |= I_SPECIAL; } /* add_to_minv() might free otmp [if it merges] */ if (vis) diff --git a/src/mon.c b/src/mon.c index 39e777a26..335e5b6b8 100644 --- a/src/mon.c +++ b/src/mon.c @@ -731,6 +731,17 @@ movemon() if (minliquid(mtmp)) continue; + /* after losing equipment, try to put on replacement */ + if (mtmp->misc_worn_check & I_SPECIAL) { + long oldworn; + + mtmp->misc_worn_check &= ~I_SPECIAL; + oldworn = mtmp->misc_worn_check; + m_dowear(mtmp, FALSE); + if (mtmp->misc_worn_check != oldworn || !mtmp->mcanmove) + continue; + } + if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ if (restrap(mtmp)) @@ -1796,6 +1807,8 @@ struct monst *mtmp; pline_The("medallion crumbles to dust!"); } m_useup(mtmp, lifesave); + /* equip replacement amulet, if any, on next move */ + mtmp->misc_worn_check |= I_SPECIAL; surviver = !(mvitals[monsndx(mtmp->data)].mvflags & G_GENOD); mtmp->mcanmove = 1; @@ -1806,13 +1819,14 @@ struct monst *mtmp; if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; mtmp->mhp = mtmp->mhpmax; - if (surviver) - return; - /* genocided monster can't be life-saved */ - if (cansee(mtmp->mx, mtmp->my)) - pline("Unfortunately, %s is still genocided...", mon_nam(mtmp)); - mtmp->mhp = 0; + if (!surviver) { + /* genocided monster can't be life-saved */ + if (cansee(mtmp->mx, mtmp->my)) + pline("Unfortunately, %s is still genocided...", + mon_nam(mtmp)); + mtmp->mhp = 0; + } } } diff --git a/src/uhitm.c b/src/uhitm.c index 0e482d6ec..b240eef26 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -1484,6 +1484,9 @@ struct attack *mattk; setmnotwielded(mdef, otmp); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); + /* give monster a chance to wear other equipment on its next + move instead of waiting until it picks something up */ + mdef->misc_worn_check |= I_SPECIAL; if (otmp == stealoid) /* special message for final item */ pline("%s finishes taking off %s suit.", Monnam(mdef), From 3eded06669b09db2abf610efc4feecf32c4c8d0b Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 14 Sep 2018 17:34:33 -0700 Subject: [PATCH 03/24] fix #H7156 - perm_invent Bug report #H7156 listed three items, all relating to perm_invent: 1) it shouldn't persist across save/restore since restore might be on a system which doesn't have enough room to display it (report actually complained that config file setting was ignored when restoring old games, which is an expected side-effect for options that persist across save/restore); 2) permanent inventory wasn't updated when using scroll of charging; 3) attempts to update permanent inventory during restore could lead to crash if it tries to access shop cost for unpaid items. Items (2) and (3) have already been fixed. This fixes (1). Replace 'flags.perm_invent' with a dummy flag, preserving save files while removing it from flags. Add 'iflags.perm_invent' to hold the value of the perm_invent option. The win32 files that are updated here haven't been tested. Whichever branch contains the curses interface needs to be updated; ditto for any other pending/potential interfaces which support perm_invent. --- doc/Guidebook.mn | 1 - doc/Guidebook.tex | 1 - doc/fixes36.2 | 2 ++ include/flag.h | 3 ++- src/end.c | 2 +- src/invent.c | 6 +++--- src/options.c | 3 ++- src/restore.c | 12 ++++++++---- win/X11/winmenu.c | 2 +- win/win32/mhmain.c | 4 ++-- win/win32/mhmenu.c | 6 +++--- win/win32/mswproc.c | 6 +++--- 12 files changed, 27 insertions(+), 21 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e1db1cd85..151b25f5a 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -3004,7 +3004,6 @@ such as ``paranoid_confirmation:attack pray Remove''. .lp perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. -Persistent. .lp pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 7cc9b7de6..4d3352d84 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -3501,7 +3501,6 @@ such as ``{\it par\-a\-noid\verb+_+con\-fir\-ma\-tion:attack~pray~Remove}''. \item[\ib{perm\verb+_+invent}] If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. -Persistent. %.lp \item[\ib{pettype}] Specify the type of your initial pet, if you are playing a character class diff --git a/doc/fixes36.2 b/doc/fixes36.2 index a8202713e..3454dda9e 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -136,6 +136,8 @@ tty: ensure that current status fields are always copied to prior status Platform- and/or Interface-Specific Fixes ----------------------------------------- +move 'perm_invent' value from flags to iflags to keep it out of save files; + affects X11, win32, and curses windows-gui: In nethackw, there could be conflicts between menu accelerators and an extra choice accelerator to fix H7132. windows-gui: recognize new BL_RESET in status_update; no change in behavior yet diff --git a/include/flag.h b/include/flag.h index 8d386decf..f2339f6c0 100644 --- a/include/flag.h +++ b/include/flag.h @@ -40,7 +40,7 @@ struct flag { boolean lit_corridor; /* show a dark corr as lit if it is in sight */ boolean nap; /* `timed_delay' option for display effects */ boolean null; /* OK to send nulls to the terminal */ - boolean perm_invent; /* keep full inventories up until dismissed */ + boolean p__obsolete; /* [3.6.2: perm_invent moved to iflags] */ boolean pickup; /* whether you pickup or move and look */ boolean pickup_thrown; /* auto-pickup items you threw */ boolean pushweapon; /* When wielding, push old weapon into second slot */ @@ -292,6 +292,7 @@ struct instance_flags { boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean news; /* print news */ boolean num_pad; /* use numbers for movement commands */ + boolean perm_invent; /* keep full inventories up until dismissed */ boolean renameallowed; /* can change hero name during role selection */ boolean renameinprogress; /* we are changing hero name */ boolean status_updates; /* allow updates to bottom status lines; diff --git a/src/end.c b/src/end.c index 4d176323b..fd5d73db9 100644 --- a/src/end.c +++ b/src/end.c @@ -1280,7 +1280,7 @@ int how; if (WIN_INVEN != WIN_ERR) { destroy_nhwindow(WIN_INVEN), WIN_INVEN = WIN_ERR; /* precaution in case any late update_inventory() calls occur */ - flags.perm_invent = 0; + iflags.perm_invent = 0; } display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP), WIN_MAP = WIN_ERR; diff --git a/src/invent.c b/src/invent.c index 25280839b..4262a5153 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2511,7 +2511,7 @@ long *out_cnt; if (lets && !*lets) lets = 0; /* simplify tests: (lets) instead of (lets && *lets) */ - if (flags.perm_invent && (lets || xtra_choice)) { + if (iflags.perm_invent && (lets || xtra_choice)) { /* partial inventory in perm_invent setting; don't operate on full inventory window, use an alternate one instead; create the first time needed and keep it for re-use as needed later */ @@ -2536,7 +2536,7 @@ long *out_cnt; * more than 1; for the last one, we don't need a precise number. * For perm_invent update we force 'more than 1'. */ - n = (flags.perm_invent && !lets && !want_reply) ? 2 + n = (iflags.perm_invent && !lets && !want_reply) ? 2 : lets ? (int) strlen(lets) : !invent ? 0 : !invent->nobj ? 1 : 2; /* for xtra_choice, there's another 'item' not included in initial 'n'; @@ -2670,7 +2670,7 @@ nextclass: nothing has been listed (because there isn't anyhing to list; recognized via any.a_char still being zero; the n==0 case above gets skipped for perm_invent), put something into the menu */ - if (flags.perm_invent && !lets && !any.a_char) { + if (iflags.perm_invent && !lets && !any.a_char) { any = zeroany; add_menu(win, NO_GLYPH, &any, 0, 0, 0, not_carrying_anything, MENU_UNSELECTED); diff --git a/src/options.c b/src/options.c index a283f4283..490d68a0a 100644 --- a/src/options.c +++ b/src/options.c @@ -173,7 +173,8 @@ static struct Bool_Opt { #else { "page_wait", (boolean *) 0, FALSE, SET_IN_FILE }, #endif - { "perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME }, + /* 3.6.2: move perm_invent from flags to inflags and out of save file */ + { "perm_invent", &iflags.perm_invent, FALSE, SET_IN_GAME }, { "pickup_thrown", &flags.pickup_thrown, TRUE, SET_IN_GAME }, { "popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME }, /*WC*/ { "preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME }, /*WC*/ diff --git a/src/restore.c b/src/restore.c index f7e92da76..f638875b8 100644 --- a/src/restore.c +++ b/src/restore.c @@ -543,9 +543,12 @@ unsigned int *stuckid, *steedid; /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost of unpaid items before shopkeeper's bill is available is a no-no; - named fruit names aren't accessible yet either */ - defer_perm_invent = flags.perm_invent; - flags.perm_invent = FALSE; + named fruit names aren't accessible yet either + [3.6.2: moved perm_invent from flags to iflags to keep it out of + save files; retaining the override here is simpler than trying to + to figure out where it really belongs now] */ + defer_perm_invent = iflags.perm_invent; + iflags.perm_invent = FALSE; /* wizard and discover are actually flags.debug and flags.explore; player might be overriding the save file values for them; in the discover case, we don't want to set that for a normal @@ -595,6 +598,7 @@ unsigned int *stuckid, *steedid; u.uz.dlevel = 1; /* revert to pre-restore option settings */ iflags.deferred_X = FALSE; + iflags.perm_invent = defer_perm_invent; flags = newgameflags; #ifdef SYSFLAGS sysflags = newgamesysflags; @@ -672,7 +676,7 @@ unsigned int *stuckid, *steedid; relink_timers(FALSE); relink_light_sources(FALSE); /* inventory display is now viable */ - flags.perm_invent = defer_perm_invent; + iflags.perm_invent = defer_perm_invent; return TRUE; } diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index 75c99b57a..a3287737c 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -826,7 +826,7 @@ menu_item **menu_list; * each time. */ if (menu_info->valid_widgets - && (window != WIN_INVEN || !flags.perm_invent)) { + && (window != WIN_INVEN || !iflags.perm_invent)) { XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; menu_info->is_up = FALSE; diff --git a/win/win32/mhmain.c b/win/win32/mhmain.c index 6c6bfea7d..41e7733fa 100644 --- a/win/win32/mhmain.c +++ b/win/win32/mhmain.c @@ -700,7 +700,7 @@ mswin_layout_main_window(HWND changed_child) GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom; /* adjust map window size only if perm_invent is set */ - if (flags.perm_invent) + if (iflags.perm_invent) GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left; } @@ -712,7 +712,7 @@ mswin_layout_main_window(HWND changed_child) /* kludge - inventory window should have its own type (same as menu-text as a matter of fact) */ - if (flags.perm_invent && i == WIN_INVEN) { + if (iflags.perm_invent && i == WIN_INVEN) { mswin_get_window_placement(NHW_INVEN, &rt); } else { mswin_get_window_placement(GetNHApp()->windowlist[i].type, diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index c8d71b4e6..6b0b4fda2 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -251,7 +251,7 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, /* If we just used the permanent inventory window to pick something, * set the menu back to its display inventory state. */ - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN && how != PICK_NONE) { data->menu.prompt[0] = '\0'; SetMenuListType(hWnd, PICK_NONE); @@ -322,7 +322,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); @@ -334,7 +334,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) GetWindowRect(hWnd, &rt); ScreenToClient(GetNHApp()->hMainWnd, (LPPOINT) &rt); ScreenToClient(GetNHApp()->hMainWnd, ((LPPOINT) &rt) + 1); - if (flags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) + if (iflags.perm_invent && mswin_winid_from_handle(hWnd) == WIN_INVEN) mswin_update_window_placement(NHW_INVEN, &rt); else mswin_update_window_placement(NHW_MENU, &rt); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index feabf49b2..ce9b14d5f 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1194,7 +1194,7 @@ mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) ShowWindow(GetNHApp()->windowlist[wid].win, SW_SHOW); nReturned = mswin_menu_window_select_menu( GetNHApp()->windowlist[wid].win, how, selected, - !(flags.perm_invent && wid == WIN_INVEN + !(iflags.perm_invent && wid == WIN_INVEN && how == PICK_NONE) /* don't activate inventory window if perm_invent is on */ ); @@ -1211,7 +1211,7 @@ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); - if (flags.perm_invent && program_state.something_worth_saving + if (iflags.perm_invent && program_state.something_worth_saving && iflags.window_inited && WIN_INVEN != WIN_ERR) display_inventory(NULL, FALSE); } @@ -2243,7 +2243,7 @@ mswin_popup_destroy(HWND hWnd) DrawMenuBar(GetNHApp()->hMainWnd); /* Don't hide the permanent inventory window ... leave it showing */ - if (!flags.perm_invent || mswin_winid_from_handle(hWnd) != WIN_INVEN) + if (!iflags.perm_invent || mswin_winid_from_handle(hWnd) != WIN_INVEN) ShowWindow(hWnd, SW_HIDE); GetNHApp()->hPopupWnd = NULL; From bd23a56f2949613b0140241fc688f23aa0da56cf Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 15 Sep 2018 11:29:13 +0300 Subject: [PATCH 04/24] Update commented out perm_invent stuff --- win/Qt/qt_win.cpp | 4 ++-- win/Qt4/qt4bind.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/win/Qt/qt_win.cpp b/win/Qt/qt_win.cpp index c809c48e5..bd281d3c5 100644 --- a/win/Qt/qt_win.cpp +++ b/win/Qt/qt_win.cpp @@ -2906,7 +2906,7 @@ int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) if (dialog->result()<0) qApp->enter_loop(); } - //if ( (nhid != WIN_INVEN || !flags.perm_invent) ) // doesn't work yet + //if ( (nhid != WIN_INVEN || !iflags.perm_invent) ) // doesn't work yet { dialog->hide(); } @@ -4840,7 +4840,7 @@ void NetHackQtBind::qt_update_inventory() if (main) main->updateInventory(); /* doesn't work yet - if (program_state.something_worth_saving && flags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, FALSE); */ } diff --git a/win/Qt4/qt4bind.cpp b/win/Qt4/qt4bind.cpp index 27db51868..b143b8e8d 100644 --- a/win/Qt4/qt4bind.cpp +++ b/win/Qt4/qt4bind.cpp @@ -401,7 +401,7 @@ void NetHackQtBind::qt_update_inventory() if (main) main->updateInventory(); /* doesn't work yet - if (program_state.something_worth_saving && flags.perm_invent) + if (program_state.something_worth_saving && iflags.perm_invent) display_inventory(NULL, false); */ } From adf070eb0454505c20de87adaad056f697e0bd7a Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 15 Sep 2018 17:19:26 +0300 Subject: [PATCH 05/24] Use is_pit macro to check for (spiked) pit --- include/trap.h | 2 ++ src/ball.c | 4 ++-- src/dig.c | 16 +++++++--------- src/display.c | 2 +- src/do.c | 2 +- src/dokick.c | 2 +- src/dothrow.c | 2 +- src/hack.c | 9 ++++----- src/mhitu.c | 2 +- src/mklev.c | 4 ++-- src/mon.c | 8 ++++---- src/mthrowu.c | 2 +- src/muse.c | 2 +- src/music.c | 2 +- src/pager.c | 2 +- src/sp_lev.c | 2 +- src/trap.c | 42 ++++++++++++++++++++---------------------- src/zap.c | 2 +- 18 files changed, 52 insertions(+), 55 deletions(-) diff --git a/include/trap.h b/include/trap.h index 16d096812..3b8e036bf 100644 --- a/include/trap.h +++ b/include/trap.h @@ -83,4 +83,6 @@ enum trap_types { TRAPNUM }; +#define is_pit(ttyp) ((ttyp) == PIT || (ttyp) == SPIKED_PIT) + #endif /* TRAP_H */ diff --git a/src/ball.c b/src/ball.c index be5b7815f..cd631eee5 100644 --- a/src/ball.c +++ b/src/ball.c @@ -599,7 +599,7 @@ drag: || !is_pool(uball->ox, uball->oy) || levl[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(uchain->ox, uchain->oy)) - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE + && (is_pit(t->ttyp) || t->ttyp == HOLE || t->ttyp == TRAPDOOR))) { if (Levitation) { You_feel("a tug from the iron ball."); @@ -745,7 +745,7 @@ xchar x, y; if (!Levitation && !MON_AT(x, y) && !u.utrap && (is_pool(x, y) || ((t = t_at(x, y)) - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT + && (is_pit(t->ttyp) || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { u.ux = x; u.uy = y; diff --git a/src/dig.c b/src/dig.c index 488673b22..0a1669813 100644 --- a/src/dig.c +++ b/src/dig.c @@ -312,8 +312,7 @@ dig(VOID_ARGS) } if (context.digging.effort <= 50 - || (ttmp && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == PIT - || ttmp->ttyp == SPIKED_PIT))) { + || (ttmp && (ttmp->ttyp == TRAPDOOR || is_pit(ttmp->ttyp)))) { return 1; } else if (ttmp && (ttmp->ttyp == LANDMINE || (ttmp->ttyp == BEAR_TRAP && !u.utrap))) { @@ -803,7 +802,7 @@ coord *cc; } } else if ((boulder_here = sobj_at(BOULDER, dig_x, dig_y)) != 0) { - if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) + if (ttmp && is_pit(ttmp->ttyp) && rn2(2)) { pline_The("boulder settles into the %spit.", (dig_x != u.ux || dig_y != u.uy) ? "adjacent " : ""); @@ -1087,7 +1086,7 @@ struct obj *obj; KILLED_BY); } else if (u.utrap && u.utraptype == TT_PIT && trap && (trap_with_u = t_at(u.ux, u.uy)) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) + && is_pit(trap->ttyp) && !conjoined_pits(trap, trap_with_u, FALSE)) { int idx; @@ -1462,8 +1461,7 @@ zap_dig() struct trap *adjpit = t_at(zx, zy); if ((diridx < 8) && !conjoined_pits(adjpit, trap_with_u, FALSE)) { digdepth = 0; /* limited to the adjacent location only */ - if (!(adjpit && (adjpit->ttyp == PIT - || adjpit->ttyp == SPIKED_PIT))) { + if (!(adjpit && is_pit(adjpit->ttyp))) { char buf[BUFSZ]; cc.x = zx; cc.y = zy; @@ -1477,7 +1475,7 @@ zap_dig() } } if (adjpit - && (adjpit->ttyp == PIT || adjpit->ttyp == SPIKED_PIT)) { + && is_pit(adjpit->ttyp)) { int adjidx = (diridx + 4) % 8; trap_with_u->conjoined |= (1 << diridx); adjpit->conjoined |= (1 << adjidx); @@ -1566,7 +1564,7 @@ zap_dig() if (pitflow && isok(flow_x, flow_y)) { struct trap *ttmp = t_at(flow_x, flow_y); - if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT)) { + if (ttmp && is_pit(ttmp->ttyp)) { schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE); if (filltyp != ROOM) pit_flow(ttmp, filltyp); @@ -1681,7 +1679,7 @@ struct trap *trap; schar filltyp; { if (trap && (filltyp != ROOM) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + && is_pit(trap->ttyp)) { struct trap t; int idx; diff --git a/src/display.c b/src/display.c index 5b8eba8a7..a142eab91 100644 --- a/src/display.c +++ b/src/display.c @@ -783,7 +783,7 @@ register int x, y; /* if monster is in a physical trap, you see the trap too */ - if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT + if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) { trap->tseen = TRUE; } diff --git a/src/do.c b/src/do.c index 8f878af79..d8ba1a725 100644 --- a/src/do.c +++ b/src/do.c @@ -149,7 +149,7 @@ const char *verb; if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) { return TRUE; } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT + && (is_pit(t->ttyp) || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { diff --git a/src/dokick.c b/src/dokick.c index 950d03553..09fb44c36 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -495,7 +495,7 @@ xchar x, y; return 0; if ((trap = t_at(x, y)) != 0) { - if (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls) + if ((is_pit(trap->ttyp) && !Passes_walls) || trap->ttyp == WEB) { if (!trap->tseen) find_trap(trap); diff --git a/src/dothrow.c b/src/dothrow.c index b9d122a7d..38f8d9923 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -744,7 +744,7 @@ int x, y; dotrap(ttmp, 0); /* doesn't print messages */ } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp, 0); - } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT + } else if ((is_pit(ttmp->ttyp) || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) && Sokoban) { /* air currents overcome the recoil in Sokoban; diff --git a/src/hack.c b/src/hack.c index cb92b93ad..70671b45f 100644 --- a/src/hack.c +++ b/src/hack.c @@ -151,8 +151,7 @@ moverock() if (mtmp && !noncorporeal(mtmp->data) && (!mtmp->mtrapped - || !(ttmp && ((ttmp->ttyp == PIT) - || (ttmp->ttyp == SPIKED_PIT))))) { + || !(ttmp && is_pit(ttmp->ttyp)))) { if (Blind) feel_location(sx, sy); if (canspotmon(mtmp)) { @@ -1205,7 +1204,7 @@ struct trap *desttrap; /* nonnull if another trap at */ break; case TT_PIT: if (desttrap && desttrap->tseen - && (desttrap->ttyp == PIT || desttrap->ttyp == SPIKED_PIT)) + && is_pit(desttrap->ttyp)) return TRUE; /* move into adjacent pit */ /* try to escape; position stays same regardless of success */ climb_pit(); @@ -1736,7 +1735,7 @@ domove() u.ux = mtmp->mx, u.uy = mtmp->my; /* resume swapping positions */ if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) + && is_pit(trap->ttyp) && sobj_at(BOULDER, trap->tx, trap->ty)) { /* can't swap places with pet pinned in a pit by a boulder */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ @@ -2100,7 +2099,7 @@ boolean pick; * If not a pit, pickup before triggering trap. * If pit, trigger trap before pickup. */ - pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); + pit = (trap && is_pit(trap->ttyp)); if (pick && !pit) (void) pickup(1); diff --git a/src/mhitu.c b/src/mhitu.c index c429a0241..97229ba60 100644 --- a/src/mhitu.c +++ b/src/mhitu.c @@ -1744,7 +1744,7 @@ struct attack *mattk; if (!engulf_target(mtmp, &youmonst)) return 0; - if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) + if ((t && is_pit(t->ttyp)) && sobj_at(BOULDER, u.ux, u.uy)) return 0; diff --git a/src/mklev.c b/src/mklev.c index f704db27d..acbf5b76d 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1349,7 +1349,7 @@ coord *tm; m = *tm; } else { register int tryct = 0; - boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT + boolean avoid_boulder = (is_pit(kind) || kind == TRAPDOOR || kind == HOLE); do { @@ -1390,7 +1390,7 @@ coord *tm; in a pit and yet not be able to identify that the pit is there. */ if (lvl <= (unsigned) rnd(4) && kind != SQKY_BOARD && kind != RUST_TRAP - && kind != PIT && kind != SPIKED_PIT && kind < HOLE) { + && !is_pit(kind) && kind < HOLE) { /* Object generated by the trap; initially NULL, stays NULL if we fail to generate an object or if the trap doesn't generate objects. */ diff --git a/src/mon.c b/src/mon.c index 335e5b6b8..d199c2ae5 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1446,7 +1446,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby, if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP - && ((ttmp->ttyp != PIT && ttmp->ttyp != SPIKED_PIT + && ((!is_pit(ttmp->ttyp) && ttmp->ttyp != TRAPDOOR && ttmp->ttyp != HOLE) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || Sokoban) @@ -2256,7 +2256,7 @@ int xkill_flags; /* 1: suppress message, 2: suppress corpse, 4: pacifist */ } if (mtmp->mtrapped && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { if (sobj_at(BOULDER, x, y)) nocorpse = TRUE; /* Prevent corpses/treasure being created "on top" of boulder that is about to fall in. @@ -2943,7 +2943,7 @@ register struct monst *mtmp; || rn2(3) || mtmp == u.ustuck /* can't hide while trapped except in pits */ || (mtmp->mtrapped && (t = t_at(mtmp->mx, mtmp->my)) != 0 - && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT)) + && !is_pit(t->ttyp)) || (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) return FALSE; @@ -2971,7 +2971,7 @@ struct monst *mtmp; ; /* can't hide if holding you or held by you */ } else if (is_u ? (u.utrap && u.utraptype != TT_PIT) : (mtmp->mtrapped && (t = t_at(x, y)) != 0 - && !(t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { + && !is_pit(t->ttyp))) { ; /* can't hide while stuck in a non-pit trap */ } else if (mtmp->data->mlet == S_EEL) { undetected = (is_pool(x, y) && !Is_waterlevel(&u.uz)); diff --git a/src/mthrowu.c b/src/mthrowu.c index e2ec346aa..28a979940 100644 --- a/src/mthrowu.c +++ b/src/mthrowu.c @@ -126,7 +126,7 @@ int x, y; if (create && !((mtmp = m_at(x, y)) != 0 && mtmp->mtrapped && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT))) { + && is_pit(t->ttyp))) { int objgone = 0; if (down_gate(x, y) != -1) diff --git a/src/muse.c b/src/muse.c index e0403003b..ac462cea2 100644 --- a/src/muse.c +++ b/src/muse.c @@ -489,7 +489,7 @@ struct monst *mtmp; /* kludge to cut down on trap destruction (particularly portals) */ t = t_at(x, y); - if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == WEB + if (t && (is_pit(t->ttyp) || t->ttyp == WEB || t->ttyp == BEAR_TRAP)) t = 0; /* ok for monster to dig here */ diff --git a/src/music.c b/src/music.c index 24e1c559e..71253f6e1 100644 --- a/src/music.c +++ b/src/music.c @@ -249,7 +249,7 @@ int force; unsigned tu_pit = 0; if (trap_at_u) - tu_pit = (trap_at_u->ttyp == PIT || trap_at_u->ttyp == SPIKED_PIT); + tu_pit = is_pit(trap_at_u->ttyp); start_x = u.ux - (force * 2); start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); diff --git a/src/pager.c b/src/pager.c index d44efb795..a82431aa0 100644 --- a/src/pager.c +++ b/src/pager.c @@ -279,7 +279,7 @@ int x, y; int tt = t ? t->ttyp : NO_TRAP; /* newsym lets you know of the trap, so mention it here */ - if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB) + if (tt == BEAR_TRAP || is_pit(tt) || tt == WEB) Sprintf(eos(buf), ", trapped in %s", an(defsyms[trap_to_defsym(tt)].explanation)); } diff --git a/src/sp_lev.c b/src/sp_lev.c index af1cdc678..c1a0c70aa 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2660,7 +2660,7 @@ fill_empty_maze() maze1xy(&mm, DRY); trytrap = rndtrap(); if (sobj_at(BOULDER, mm.x, mm.y)) - while (trytrap == PIT || trytrap == SPIKED_PIT + while (is_pit(trytrap) || trytrap == TRAPDOOR || trytrap == HOLE) trytrap = rndtrap(); (void) maketrap(mm.x, mm.y, trytrap); diff --git a/src/trap.c b/src/trap.c index 6e7e3ed78..c4a96c99c 100644 --- a/src/trap.c +++ b/src/trap.c @@ -328,8 +328,7 @@ int x, y, typ; if (u.utrap && x == u.ux && y == u.uy && ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) || (u.utraptype == TT_WEB && typ != WEB) - || (u.utraptype == TT_PIT && typ != PIT - && typ != SPIKED_PIT))) + || (u.utraptype == TT_PIT && !is_pit(typ)))) u.utrap = 0; /* old remain valid */ } else if (IS_FURNITURE(lev->typ) @@ -862,7 +861,7 @@ unsigned trflags; nomul(0); /* KMH -- You can't escape the Sokoban level traps */ - if (Sokoban && (ttype == PIT || ttype == SPIKED_PIT + if (Sokoban && (is_pit(ttype) || ttype == HOLE || ttype == TRAPDOOR)) { /* The "air currents" message is still appropriate -- even when * the hero isn't flying or levitating -- because it conveys the @@ -875,7 +874,7 @@ unsigned trflags; /* then proceed to normal trap effect */ } else if (already_seen && !forcetrap) { if ((Levitation || (Flying && !plunged)) - && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE + && (is_pit(ttype) || ttype == HOLE || ttype == BEAR_TRAP)) { You("%s over %s %s.", Levitation ? "float" : "fly", a_your[trap->madeby_u], @@ -885,7 +884,7 @@ unsigned trflags; if (!Fumbling && ttype != MAGIC_PORTAL && ttype != VIBRATING_SQUARE && ttype != ANTI_MAGIC && !forcebungle && !plunged && !conj_pit && !adj_pit - && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) + && (!rn2(5) || (is_pit(ttype) && is_clinger(youmonst.data)))) { You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" @@ -2075,8 +2074,8 @@ register struct monst *mtmp; mtmp->mtrapped = 0; /* perhaps teleported? */ } else if (mtmp->mtrapped) { /* is currently in the trap */ if (!trap->tseen && cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) - && (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP - || trap->ttyp == HOLE || trap->ttyp == PIT + && (is_pit(trap->ttyp) || trap->ttyp == BEAR_TRAP + || trap->ttyp == HOLE || trap->ttyp == WEB)) { /* If you come upon an obviously trapped monster, then * you must be able to see the trap it's in too. @@ -2086,7 +2085,7 @@ register struct monst *mtmp; if (!rn2(40)) { if (sobj_at(BOULDER, mtmp->mx, mtmp->my) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + && is_pit(trap->ttyp)) { if (!rn2(2)) { mtmp->mtrapped = 0; if (canseemon(mtmp)) @@ -2818,7 +2817,7 @@ int x, y; struct obj *otmp; struct trap *t; - if ((t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) + if ((t = t_at(x, y)) && is_pit(t->ttyp) && (otmp = sobj_at(BOULDER, x, y))) { obj_extract_self(otmp); (void) flooreffects(otmp, x, y, "settle"); @@ -2865,7 +2864,7 @@ long hmask, emask; /* might cancel timeout */ if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || ((trap = t_at(uball->ox, uball->oy)) - && ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) + && (is_pit(trap->ttyp) || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { u.ux0 = u.ux; u.uy0 = u.uy; @@ -4313,7 +4312,7 @@ boolean force; if (ttmp) { Strcpy(the_trap, the(trapdescr)); if (boxcnt) { - if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { + if (is_pit(ttmp->ttyp)) { You_cant("do much about %s%s.", the_trap, u.utrap ? " that you're stuck in" : " while standing on the edge of it"); @@ -4615,8 +4614,7 @@ boolean *noticed; /* set to true iff hero notices the effect; */ /* if no trap here or it's not a falling trap, we're done (note: falling rock traps have a trapdoor in the ceiling) */ if (!t || ((t->ttyp != TRAPDOOR && t->ttyp != ROCKTRAP) - && (trapdoor_only || (t->ttyp != HOLE && t->ttyp != PIT - && t->ttyp != SPIKED_PIT)))) + && (trapdoor_only || (t->ttyp != HOLE && !is_pit(t->ttyp))))) return FALSE; if (ishero) { @@ -4875,8 +4873,8 @@ boolean u_entering_trap2; if (!trap1 || !trap2) return FALSE; if (!isok(trap2->tx, trap2->ty) || !isok(trap1->tx, trap1->ty) - || !(trap2->ttyp == PIT || trap2->ttyp == SPIKED_PIT) - || !(trap1->ttyp == PIT || trap1->ttyp == SPIKED_PIT) + || !is_pit(trap2->ttyp) + || !is_pit(trap1->ttyp) || (u_entering_trap2 && !(u.utrap && u.utraptype == TT_PIT))) return FALSE; dx = sgn(trap2->tx - trap1->tx); @@ -4901,14 +4899,14 @@ struct trap *trap; int diridx, adjidx, x, y; struct trap *t; - if (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { + if (trap && is_pit(trap->ttyp)) { for (diridx = 0; diridx < 8; ++diridx) { if (trap->conjoined & (1 << diridx)) { x = trap->tx + xdir[diridx]; y = trap->ty + ydir[diridx]; if (isok(x, y) && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { adjidx = (diridx + 4) % 8; t->conjoined &= ~(1 << adjidx); } @@ -4925,8 +4923,8 @@ struct trap *adjtrap; struct trap *trap_with_u = t_at(u.ux0, u.uy0); if (trap_with_u && adjtrap && u.utrap && u.utraptype == TT_PIT && - (trap_with_u->ttyp == PIT || trap_with_u->ttyp == SPIKED_PIT) && - (adjtrap->ttyp == PIT || adjtrap->ttyp == SPIKED_PIT)) { + is_pit(trap_with_u->ttyp) && + is_pit(adjtrap->ttyp)) { int idx; for (idx = 0; idx < 8; idx++) { if (xdir[idx] == u.dx && ydir[idx] == u.dy) @@ -4955,7 +4953,7 @@ struct trap *trap; y = trap->ty + ydir[diridx]; if (isok(x, y)) { if ((t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT)) { + && is_pit(t->ttyp)) { trap->conjoined |= (1 << diridx); join_adjacent_pits(t); } else @@ -4973,7 +4971,7 @@ uteetering_at_seen_pit(trap) struct trap *trap; { if (trap && trap->tseen && (!u.utrap || u.utraptype != TT_PIT) - && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) + && is_pit(trap->ttyp)) return TRUE; else return FALSE; @@ -4987,7 +4985,7 @@ register struct trap *ttmp; /* some of these are arbitrary -dlc */ if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) - || (ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) + || is_pit(ttmp->ttyp) || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) diff --git a/src/zap.c b/src/zap.c index 8c4458347..35ce7a9e3 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3373,7 +3373,7 @@ struct obj **pobj; /* object tossed/used, set to NULL The(distant_name(obj, xname))); /* lame */ range = 0; } else if (Sokoban && (t = t_at(x, y)) != 0 - && (t->ttyp == PIT || t->ttyp == SPIKED_PIT + && (is_pit(t->ttyp) || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { /* hero falls into the trap, so ball stops */ range = 0; From e0318008800b61076cdcabc270b21eb0a320ad9e Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Sat, 15 Sep 2018 17:57:57 +0300 Subject: [PATCH 06/24] Use is_hole macro to check for trapdoors and holes --- include/trap.h | 1 + src/ball.c | 5 ++--- src/do.c | 5 ++--- src/dokick.c | 4 ++-- src/dothrow.c | 3 +-- src/mklev.c | 8 +++----- src/mon.c | 3 +-- src/muse.c | 2 +- src/objnam.c | 2 +- src/pager.c | 3 +-- src/sp_lev.c | 5 ++--- src/teleport.c | 2 +- src/trap.c | 11 ++++------- src/zap.c | 3 +-- 14 files changed, 23 insertions(+), 34 deletions(-) diff --git a/include/trap.h b/include/trap.h index 3b8e036bf..8eacc6ccd 100644 --- a/include/trap.h +++ b/include/trap.h @@ -84,5 +84,6 @@ enum trap_types { }; #define is_pit(ttyp) ((ttyp) == PIT || (ttyp) == SPIKED_PIT) +#define is_hole(ttyp) ((ttyp) == HOLE || (ttyp) == TRAPDOOR) #endif /* TRAP_H */ diff --git a/src/ball.c b/src/ball.c index cd631eee5..762de85f8 100644 --- a/src/ball.c +++ b/src/ball.c @@ -599,8 +599,7 @@ drag: || !is_pool(uball->ox, uball->oy) || levl[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(uchain->ox, uchain->oy)) - && (is_pit(t->ttyp) || t->ttyp == HOLE - || t->ttyp == TRAPDOOR))) { + && (is_pit(t->ttyp) || is_hole(t->ttyp)))) { if (Levitation) { You_feel("a tug from the iron ball."); if (t) @@ -746,7 +745,7 @@ xchar x, y; && (is_pool(x, y) || ((t = t_at(x, y)) && (is_pit(t->ttyp) - || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { + || is_hole(t->ttyp))))) { u.ux = x; u.uy = y; } else { diff --git a/src/do.c b/src/do.c index d8ba1a725..81bbb6235 100644 --- a/src/do.c +++ b/src/do.c @@ -149,8 +149,7 @@ const char *verb; if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) { return TRUE; } else if (obj->otyp == BOULDER && (t = t_at(x, y)) != 0 - && (is_pit(t->ttyp) - || t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { + && (is_pit(t->ttyp) || is_hole(t->ttyp))) { if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { if (*verb) @@ -956,7 +955,7 @@ dodown() if (trap && uteetering_at_seen_pit(trap)) { dotrap(trap, TOOKPLUNGE); return 1; - } else if (!trap || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) + } else if (!trap || !is_hole(trap->ttyp) || !Can_fall_thru(&u.uz) || !trap->tseen) { if (flags.autodig && !context.nopick && uwep && is_pick(uwep)) { return use_pick_axe2(uwep); diff --git a/src/dokick.c b/src/dokick.c index 09fb44c36..874db822a 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1515,7 +1515,7 @@ boolean shop_floor_obj; /* boulders never fall through trap doors, but they might knock other things down before plugging the hole */ if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0) - && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { + && is_hole(t->ttyp)) { if (impact) impact_drop(otmp, x, y, 0); return FALSE; /* let caller finish the drop */ @@ -1717,7 +1717,7 @@ xchar x, y; } if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) - && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) { + && is_hole(ttmp->ttyp)) { gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door" : "through the hole"; return MIGR_RANDOM; diff --git a/src/dothrow.c b/src/dothrow.c index 38f8d9923..00978165f 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -744,8 +744,7 @@ int x, y; dotrap(ttmp, 0); /* doesn't print messages */ } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp, 0); - } else if ((is_pit(ttmp->ttyp) - || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) + } else if ((is_pit(ttmp->ttyp) || is_hole(ttmp->ttyp)) && Sokoban) { /* air currents overcome the recoil in Sokoban; when jumping, caller performs last step and enters trap */ diff --git a/src/mklev.c b/src/mklev.c index acbf5b76d..aecba88fa 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -503,8 +503,7 @@ int trap_type; if (trap_type || !rn2(4)) { rm->typ = SCORR; if (trap_type) { - if ((trap_type == HOLE || trap_type == TRAPDOOR) - && !Can_fall_thru(&u.uz)) + if (is_hole(trap_type) && !Can_fall_thru(&u.uz)) trap_type = ROCKTRAP; ttmp = maketrap(xx, yy + dy, trap_type); if (ttmp) { @@ -1342,15 +1341,14 @@ coord *tm; } while (kind == NO_TRAP); } - if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz)) + if (is_hole(kind) && !Can_fall_thru(&u.uz)) kind = ROCKTRAP; if (tm) { m = *tm; } else { register int tryct = 0; - boolean avoid_boulder = (is_pit(kind) - || kind == TRAPDOOR || kind == HOLE); + boolean avoid_boulder = (is_pit(kind) || is_hole(kind)); do { if (++tryct > 200) diff --git a/src/mon.c b/src/mon.c index d199c2ae5..cbdde81ba 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1446,8 +1446,7 @@ nexttry: /* eels prefer the water, but if there is no water nearby, if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP - && ((!is_pit(ttmp->ttyp) - && ttmp->ttyp != TRAPDOOR && ttmp->ttyp != HOLE) + && ((!is_pit(ttmp->ttyp) && !is_hole(ttmp->ttyp)) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || Sokoban) && (ttmp->ttyp != SLP_GAS_TRAP || !resists_sleep(mon)) diff --git a/src/muse.c b/src/muse.c index ac462cea2..600bdd903 100644 --- a/src/muse.c +++ b/src/muse.c @@ -439,7 +439,7 @@ struct monst *mtmp; || onscary(xx, yy, mtmp)) continue; /* use trap if it's the correct type */ - if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE) + if (is_hole(t->ttyp) && !is_floater(mtmp->data) && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && Can_fall_thru(&u.uz)) { diff --git a/src/objnam.c b/src/objnam.c index b44ddbf2e..0b68f73dc 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -3508,7 +3508,7 @@ wiztrap: if (strncmpi(tname, bp, strlen(tname))) continue; /* found it; avoid stupid mistakes */ - if ((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz)) + if (is_hole(trap) && !Can_fall_thru(&u.uz)) trap = ROCKTRAP; if ((t = maketrap(x, y, trap)) != 0) { trap = t->ttyp; diff --git a/src/pager.c b/src/pager.c index a82431aa0..9c2d74946 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1362,8 +1362,7 @@ doidtrap() break; tt = trap->ttyp; if (u.dz) { - if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) - : tt == ROCKTRAP) + if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP) break; } tt = what_trap(tt); diff --git a/src/sp_lev.c b/src/sp_lev.c index c1a0c70aa..4f8df6b9c 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -2660,8 +2660,7 @@ fill_empty_maze() maze1xy(&mm, DRY); trytrap = rndtrap(); if (sobj_at(BOULDER, mm.x, mm.y)) - while (is_pit(trytrap) - || trytrap == TRAPDOOR || trytrap == HOLE) + while (is_pit(trytrap) || is_hole(trytrap)) trytrap = rndtrap(); (void) maketrap(mm.x, mm.y, trytrap); } @@ -4495,7 +4494,7 @@ ensure_way_out() while (ttmp) { if ((ttmp->ttyp == MAGIC_PORTAL || ttmp->ttyp == VIBRATING_SQUARE - || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) + || is_hole(ttmp->ttyp)) && !selection_getpoint(ttmp->tx, ttmp->ty, ov)) selection_floodfill(ov, ttmp->tx, ttmp->ty, TRUE); ttmp = ttmp->ntrap; diff --git a/src/teleport.c b/src/teleport.c index a79429c46..5003ed82d 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1159,7 +1159,7 @@ int in_sight; d_level tolevel; int migrate_typ = MIGR_RANDOM; - if ((tt == HOLE || tt == TRAPDOOR)) { + if (is_hole(tt)) { if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { diff --git a/src/trap.c b/src/trap.c index c4a96c99c..bdf944b31 100644 --- a/src/trap.c +++ b/src/trap.c @@ -406,8 +406,7 @@ int x, y, typ; case HOLE: case TRAPDOOR: if (*in_rooms(x, y, SHOPBASE) - && (typ == HOLE || typ == TRAPDOOR - || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) + && (is_hole(typ) || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) && !context.mon_moving) @@ -861,8 +860,7 @@ unsigned trflags; nomul(0); /* KMH -- You can't escape the Sokoban level traps */ - if (Sokoban && (is_pit(ttype) - || ttype == HOLE || ttype == TRAPDOOR)) { + if (Sokoban && (is_pit(ttype) || is_hole(ttype))) { /* The "air currents" message is still appropriate -- even when * the hero isn't flying or levitating -- because it conveys the * reason why the player cannot escape the trap with a dexterity @@ -2864,8 +2862,7 @@ long hmask, emask; /* might cancel timeout */ if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || ((trap = t_at(uball->ox, uball->oy)) - && (is_pit(trap->ttyp) - || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { + && (is_pit(trap->ttyp) || is_hole(trap->ttyp))))) { u.ux0 = u.ux; u.uy0 = u.uy; u.ux = uball->ox; @@ -4986,7 +4983,7 @@ register struct trap *ttmp; if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) || is_pit(ttmp->ttyp) - || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) + || is_hole(ttmp->ttyp) || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) || (ttmp->ttyp == ANTI_MAGIC))) { diff --git a/src/zap.c b/src/zap.c index 35ce7a9e3..14b47902a 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3373,8 +3373,7 @@ struct obj **pobj; /* object tossed/used, set to NULL The(distant_name(obj, xname))); /* lame */ range = 0; } else if (Sokoban && (t = t_at(x, y)) != 0 - && (is_pit(t->ttyp) - || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { + && (is_pit(t->ttyp) || is_hole(t->ttyp))) { /* hero falls into the trap, so ball stops */ range = 0; } From 89237fc96d9632a29474d7f61d906480ba71a931 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 15 Sep 2018 19:23:29 -0700 Subject: [PATCH 07/24] fix #H7157 - cancel self as clay golem The report was "doesn't kill even if unchanging", but it does cause rehumanize() when not Unchanging, the same thing that happens when you die due to loss of hit points. But losing the activating word(s) and then having Unchanging retain the clay golem shape does seem wrong, so make losing the word(s) while being unable to revert to normal form be fatal. Poly'd hero (without Unchanging) reverts to normal when cancelled, so make monsters behave that way. Previously, only werecritters in beast form were forced to human form. This changes cancellation to make shapechangers and hiding mimics take on normal form too. Cancelled shapechangers now behave as if the hero has the Protection_from_shape_changes attribute and will be unable to change their shape (after having been forced into normal form). Getting polymorphed in any fashion uncancels them prior to giving new shape. [There may be some newcham() situations that should be disallowed when cancelled rather proceeding and consequently uncancelling.] --- doc/fixes36.2 | 5 +++++ src/mon.c | 10 +++++++++- src/zap.c | 40 ++++++++++++++++++++++++++++++---------- 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 3454dda9e..8fb98475e 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -120,6 +120,11 @@ handle monsters inside the invocation area give monsters who have had a worn item stolen or who have been life-saved (used up amulet) a chance to wear replacement gear on next move instead of having to wait until they pick something up +Unchanging hero in clay golem form will be killed when cancelled +poly'd shapechanger and hiding mimic will revert to normal when cancelled, + like werecreature in beast form and non-Unchanging hero +cancelled shapeshifter is no longer able to change shape +cancelled shapeshifter hit by polymorph magic will become uncancelled Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/mon.c b/src/mon.c index cbdde81ba..9cdf9b6d9 100644 --- a/src/mon.c +++ b/src/mon.c @@ -2900,7 +2900,8 @@ restartcham() for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; - mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (!mtmp->mcan) + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && cansee(mtmp->mx, mtmp->my)) { set_mimic_sym(mtmp); @@ -3417,6 +3418,13 @@ boolean msg; /* "The oldmon turns into a newmon!" */ anomalous extinction feedback during final disclsoure */ if (mbirth_limit(monsndx(olddata)) < MAXMONNO) return 0; + /* cancelled shapechangers become uncancelled prior + to being given a new shape */ + if (mtmp->mcan && !Protection_from_shape_changers) { + mtmp->cham = pm_to_cham(monsndx(mtmp->data)); + if (mtmp->cham != NON_PM) + mtmp->mcan = 0; + } } if (msg) { diff --git a/src/zap.c b/src/zap.c index 14b47902a..37b38e8ab 100644 --- a/src/zap.c +++ b/src/zap.c @@ -2306,7 +2306,7 @@ boolean ordinary; case WAN_CANCELLATION: case SPE_CANCELLATION: - (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); + (void) cancel_monst(&youmonst, obj, TRUE, TRUE, TRUE); break; case SPE_DRAIN_LIFE: @@ -2675,25 +2675,45 @@ boolean youattack, allow_cancel_kill, self_cancel; /* now handle special cases */ if (youdefend) { - if (Upolyd) { - if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) - pline(writing_vanishes, your); - - if (Unchanging) + if (Upolyd) { /* includes lycanthrope in creature form */ + /* + * Return to normal form unless Unchanging. + * Hero in clay golem form dies if Unchanging. + * Does not cure lycanthropy or stop timed random polymorph. + */ + if (u.umonnum == PM_CLAY_GOLEM) { + if (!Blind) + pline(writing_vanishes, your); + else /* note: "dark" rather than "heavy" is intentional... */ + You_feel("%s headed.", Hallucination ? "dark" : "light"); + u.mh = 0; /* fatal; death handled by rehumanize() */ + } + if (Unchanging && u.mh > 0) Your("amulet grows hot for a moment, then cools."); else rehumanize(); } } else { - mdef->mcan = TRUE; - - if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) + mdef->mcan = 1; + /* force shapeshifter into its base form */ + if (mdef->m_ap_type != M_AP_NOTHING) + seemimic(mdef); + /* [not 'else if'; chameleon might have been hiding as a mimic] */ + if (mdef->cham >= LOW_PM) { + /* note: newcham() uncancels shapechangers (resets m->mcan + to 0), but only for shapechangers whose m->cham is already + NON_PM and we just verified that it's LOW_PM or higher */ + newcham(mdef, &mons[mdef->cham], FALSE, FALSE); + mdef->cham = NON_PM; /* cancelled shapeshifter can't shift */ + } + if (is_were(mdef->data) && !is_human(mdef->data)) were_change(mdef); if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (canseemon(mdef)) pline(writing_vanishes, s_suffix(mon_nam(mdef))); - + /* !allow_cancel_kill is for Magicbane, where clay golem + will be killed somewhere back up the call/return chain... */ if (allow_cancel_kill) { if (youattack) killed(mdef); From 712381232727c00211828c4def939d092643ddc3 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 17 Sep 2018 15:46:47 -0400 Subject: [PATCH 08/24] try to coax an error code for display on tile_file failure If the underlying error is that Windows LoadImage() just wasn't happy with the format of the image file, you'll just get a 0x0 result, which won't help much. If, however, it shows a 0x2 result that means it couldn't find the file to load it. --- win/win32/mswproc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index ce9b14d5f..3512f2627 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -2118,6 +2118,7 @@ initMapTiles(void) HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; + DWORD errcode; int tl_num; SIZE map_size; extern int total_tiles_used; @@ -2131,8 +2132,13 @@ initMapTiles(void) NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE); if (hBmp == NULL) { - raw_print( - "Cannot load tiles from the file. Reverting back to default."); + char errmsg[BUFSZ]; + + errcode = GetLastError(); + Sprintf(errmsg, "%s (0x%x).", + "Cannot load tiles from the file. Reverting back to default", + errcode); + raw_print(errmsg); return FALSE; } From b34400094b348693fa7f57b44b6e9740847b8555 Mon Sep 17 00:00:00 2001 From: PatR Date: Mon, 17 Sep 2018 18:28:49 -0700 Subject: [PATCH 09/24] fix #H7060 - polymorph zap vs long worm A polymoprh zap which creates a long worm can hit and transform the same monster again depending upon tail segment placement. Similar behavior occurs if monpolycontrol is set in wizard mode and player chooses 'long worm' for what to transform an existing one into (in which case polymorph fails and zap might hit that same worm again in another segment, prompting player to choose its new shape again). Simplest fix would be to make tail segments be immune to polymorph, but that would prevent players from deliberately attacking the tail (for polymorph attacks only). Next simplest would be to make long worms M2_NOPOLY so that polymorph can't create them, then just live with multiple promptings when monpolycontrol is set. This fix tracks whether a long worm has just been created via polymorph (or explicitly retained its shape via monpolycontrol) and makes further hits on same creature on same zap have no effect. It does so by setting mon->mextra->mcorpsenm to PM_LONG_WORM when a long worm is result of polymorph, and setting context.bypasses to get end-of-zap cleanup. (It doesn't bother discarding mon->mextra if reset of mcorpsenm leaves mextra empty.) --- doc/fixes36.2 | 2 ++ src/worn.c | 18 +++++++++++++++++- src/zap.c | 25 +++++++++++++++++++++++-- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 8fb98475e..4a4fd0fc3 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -125,6 +125,8 @@ poly'd shapechanger and hiding mimic will revert to normal when cancelled, like werecreature in beast form and non-Unchanging hero cancelled shapeshifter is no longer able to change shape cancelled shapeshifter hit by polymorph magic will become uncancelled +polymorph zap which creates a new long worm (or retains an old one via wizard + mode monpolycontrol) can hit that worm multiple times (tail segments) Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/worn.c b/src/worn.c index e7860c655..1eb1ed671 100644 --- a/src/worn.c +++ b/src/worn.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 worn.c $NHDT-Date: 1526728754 2018/05/19 11:19:14 $ $NHDT-Branch: NetHack-3.6.2 $:$NHDT-Revision: 1.51 $ */ +/* NetHack 3.6 worn.c $NHDT-Date: 1537234121 2018/09/18 01:28:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.55 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -710,6 +710,13 @@ clear_bypasses() struct obj *otmp, *nobj; struct monst *mtmp; + /* + * 'Object' bypass is also used for one monster function: + * polymorph control of long worms. Activated via setting + * context.bypasses even if no specific object has been + * bypassed. + */ + for (otmp = fobj; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->bypass) { @@ -741,10 +748,19 @@ clear_bypasses() continue; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; + /* long worm created by polymorph has mon->mextra->mcorpsenm set + to PM_LONG_WORM to flag it as not being subject to further + polymorph (so polymorph zap won't hit monster to transform it + into a long worm, then hit that worm's tail and transform it + again on same zap); clearing mcorpsenm reverts worm to normal */ + if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) + MCORPSENM(mtmp) = NON_PM; } for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; + /* no MCORPSENM(mtmp)==PM_LONG_WORM check here; long worms can't + be just created by polymorph and migrating at the same time */ } /* billobjs and mydogs chains don't matter here */ context.bypasses = FALSE; diff --git a/src/zap.c b/src/zap.c index 37b38e8ab..7a5ab3416 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1525012627 2018/04/29 14:37:07 $ $NHDT-Branch: master $:$NHDT-Revision: 1.277 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1537234123 2018/09/18 01:28:43 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.287 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -222,7 +222,11 @@ struct obj *otmp; case WAN_POLYMORPH: case SPE_POLYMORPH: case POT_POLYMORPH: - if (resists_magm(mtmp)) { + if (mtmp->data == &mons[PM_LONG_WORM] && has_mcorpsenm(mtmp)) { + /* if a long worm has mcorpsenm set, it was polymophed by + the current zap and shouldn't be affected if hit again */ + ; + } else if (resists_magm(mtmp)) { /* magic resistance protects from polymorph traps, so make it guard against involuntary polymorph attacks too... */ shieldeff(mtmp->mx, mtmp->my); @@ -238,6 +242,7 @@ struct obj *otmp; if (polyspot) for (obj = mtmp->minvent; obj; obj = obj->nobj) bypass_obj(obj); + /* natural shapechangers aren't affected by system shock (unless protection from shapechangers is interfering with their metabolism...) */ @@ -261,6 +266,22 @@ struct obj *otmp; || (u.uswallow && mtmp == u.ustuck))) learn_it = TRUE; } + + /* do this even if polymorphed failed (otherwise using + flags.mon_polycontrol prompting to force mtmp to remain + 'long worm' would prompt again if zap hit another segment) */ + if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_LONG_WORM]) { + if (!has_mcorpsenm(mtmp)) + newmcorpsenm(mtmp); + /* flag to indicate that mtmp became a long worm + on current zap, so further hits (on mtmp's new + tail) don't do further transforms */ + MCORPSENM(mtmp) = PM_LONG_WORM; + /* flag to indicate that cleanup is needed; object + bypass cleanup also clears mon->mextra->mcorpsenm + for all long worms on the level */ + context.bypasses = TRUE; + } } break; case WAN_CANCELLATION: From 9eb783081977d6754348a3f71196a1581d2d1d26 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 18 Sep 2018 18:35:13 -0400 Subject: [PATCH 10/24] Gnomish Mines changes involving "Orctown" level variant Changes to be committed: modified: include/decl.h modified: include/dungeon.h modified: include/extern.h modified: include/hack.h modified: src/decl.c modified: src/do_name.c modified: src/dog.c modified: src/dokick.c modified: src/makemon.c modified: src/mkmaze.c modified: src/mkobj.c modified: src/pager.c This commit is an attempt to address the complaints about the orc town variation taking away lots of stuff that is normally available in mine town. The statement in the level description says "A tragic accident has occurred in Frontier Town...It has been overrun by orcs." The changes in this commit attempt to uphold that premise, while making things a bit more interesting and perhaps more palatable for the player. This update does the following in keeping with the mythos: - While many of the orcs still remain to wander about the level, many of the orcs took off deeper into the mines with some of the stuff that they plundered. You may now be able to hunt some of it down. - Adds some appearance of this particular horde of marauding orcs working as part of a larger collective. - This evolves the Orc Town mine town variation into a a feature over multiple levels of The Gnomish Mines, rather than just the single-level "feature" that it was previously. - You may have to work longer and a bit harder for some things than other mine town variations, but at least with these changes, there is hope that some of it may be found elsewhere. Game mechanics notes (maybe spoily?) - Add mechanism to place objects into limbo (okay, really place them onto the migrating_objs list for transferring between levels etc.) and destine them to become part of the monster inventory of a particular species. In this particular usage case, it's using the M2_ORC flag setting to identify the recipients. - At present, there is no mechanism in the level compiler for placing objects onto the migrating objects, nor with more sophisticated landing logic, so a somewhat kludgy hard-coded fixup and supporting routines were used. Some day the need for that might change if additional capabilities move to the level compiler. This is a NetHack-3.6.2-beta01 update. Please give it a workout. Fixes #127 --- include/decl.h | 1 + include/dungeon.h | 3 +- include/extern.h | 6 +- include/hack.h | 6 ++ src/decl.c | 1 + src/do_name.c | 46 ++++++++++++++- src/dog.c | 6 ++ src/dokick.c | 45 +++++++++++++++ src/makemon.c | 3 + src/mkmaze.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++ src/mkobj.c | 17 ++++++ src/pager.c | 97 +++++++++++++++++++++++++++---- 12 files changed, 357 insertions(+), 16 deletions(-) diff --git a/include/decl.h b/include/decl.h index f0d806dc8..53902a07f 100644 --- a/include/decl.h +++ b/include/decl.h @@ -160,6 +160,7 @@ E NEARDATA struct sinfo { } program_state; E boolean restoring; +E boolean ransacked; E const char quitchars[]; E const char vowels[]; diff --git a/include/dungeon.h b/include/dungeon.h index f7b16cf2a..45246f150 100644 --- a/include/dungeon.h +++ b/include/dungeon.h @@ -146,7 +146,8 @@ typedef struct branch { #define MIGR_WITH_HERO 9 /* mon: followers; obj: trap door */ #define MIGR_NOBREAK 1024 /* bitmask: don't break on delivery */ #define MIGR_NOSCATTER 2048 /* don't scatter on delivery */ - +#define MIGR_TO_SPECIES 4096 /* migrating to species as they are made */ +#define MIGR_LEFTOVERS 8192 /* grab remaining MIGR_TO_SPECIES objects */ /* level information (saved via ledger number) */ struct linfo { diff --git a/include/extern.h b/include/extern.h index abd4be118..ed186e667 100644 --- a/include/extern.h +++ b/include/extern.h @@ -428,6 +428,8 @@ E const char *NDECL(roguename); E struct obj *FDECL(realloc_obj, (struct obj *, int, genericptr_t, int, const char *)); E char *FDECL(coyotename, (struct monst *, char *)); +E char *FDECL(rndorcname, (char *)); +E struct monst *FDECL(christen_orc, (struct monst *, char *)); E const char *FDECL(noveltitle, (int *)); E const char *FDECL(lookup_novel, (const char *, int *)); @@ -519,6 +521,7 @@ E void FDECL(container_impact_dmg, (struct obj *, XCHAR_P, XCHAR_P)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *, XCHAR_P, XCHAR_P, BOOLEAN_P)); E void FDECL(obj_delivery, (BOOLEAN_P)); +E void FDECL(deliver_obj_to_mon, (struct monst *mtmp, unsigned long)); E schar FDECL(down_gate, (XCHAR_P, XCHAR_P)); E void FDECL(impact_drop, (struct obj *, XCHAR_P, XCHAR_P, XCHAR_P)); @@ -1283,6 +1286,7 @@ E void FDECL(new_omailcmd, (struct obj *, const char *)); E void FDECL(free_omailcmd, (struct obj *)); E struct obj *FDECL(mkobj_at, (CHAR_P, int, int, BOOLEAN_P)); E struct obj *FDECL(mksobj_at, (int, int, int, BOOLEAN_P, BOOLEAN_P)); +E struct obj *FDECL(mksobj_migr_to_species, (int, unsigned, BOOLEAN_P, BOOLEAN_P)); E struct obj *FDECL(mkobj, (CHAR_P, BOOLEAN_P)); E int NDECL(rndmonnum); E boolean FDECL(bogon_is_pname, (CHAR_P)); @@ -1753,7 +1757,7 @@ E char *FDECL(self_lookat, (char *)); E void FDECL(mhidden_description, (struct monst *, BOOLEAN_P, char *)); E boolean FDECL(object_from_map, (int,int,int,struct obj **)); E int FDECL(do_screen_description, (coord, BOOLEAN_P, int, char *, - const char **)); + const char **, struct permonst **)); E int FDECL(do_look, (int, coord *)); E int NDECL(dowhatis); E int NDECL(doquickwhatis); diff --git a/include/hack.h b/include/hack.h index ed699a943..f65d2ddd1 100644 --- a/include/hack.h +++ b/include/hack.h @@ -270,6 +270,12 @@ typedef struct sortloot_item Loot; #define SHIFT_SEENMSG 0x01 /* put out a message if in sight */ #define SHIFT_MSG 0x02 /* always put out a message */ +/* flags for deliver_obj_to_mon */ +#define DF_NONE 0x00 +#define DF_RANDOM2 0x01 +#define DF_RANDOM3 0x02 +#define DF_ALL 0x04 + /* special mhpmax value when loading bones monster to flag as extinct or * genocided */ #define DEFUNCT_MONSTER (-100) diff --git a/src/decl.c b/src/decl.c index 2a9c28746..ffd9ef974 100644 --- a/src/decl.c +++ b/src/decl.c @@ -57,6 +57,7 @@ NEARDATA char pl_fruit[PL_FSIZ] = DUMMY; NEARDATA struct fruit *ffruit = (struct fruit *) 0; NEARDATA char tune[6] = DUMMY; +NEARDATA boolean ransacked = 0; const char *occtxt = DUMMY; const char quitchars[] = " \r\n\033"; diff --git a/src/do_name.c b/src/do_name.c index e4a874126..ef1870742 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -543,7 +543,7 @@ int cx, cy; cc.x = cx; cc.y = cy; - if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(cc, TRUE, sym, tmpbuf, &firstmatch, (struct permonst **)0)) { (void) coord_desc(cx, cy, tmpbuf, iflags.getpos_coords); custompline(SUPPRESS_HISTORY, "%s%s%s%s%s", firstmatch, *tmpbuf ? " " : "", tmpbuf, @@ -593,7 +593,8 @@ int gloc; any.a_int = i + 1; tmpcc.x = garr[i].x; tmpcc.y = garr[i].y; - if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, &firstmatch)) { + if (do_screen_description(tmpcc, TRUE, sym, tmpbuf, + &firstmatch, (struct permonst **)0)) { (void) coord_desc(garr[i].x, garr[i].y, tmpbuf, iflags.getpos_coords); Sprintf(fullbuf, "%s%s%s", firstmatch, @@ -2067,6 +2068,47 @@ char *buf; return buf; } +char * +rndorcname(s) +char *s; +{ + int i; + const char *v[] = {"a", "ai", "og", "u"}; + const char *snd[] = {"gor", "gris", "un", "bane", "ruk", + "oth","ul", "z", "thos","akh","hai"}; + int vstart = rn2(2); + + if (s) { + *s = '\0'; + for (i = 0; i < rn2(2) + 3; ++i) { + vstart = 1 - vstart; /* 0 -> 1, 1 -> 0 */ + if (!rn2(30) && i > 0) + (void) strcat(s, "-"); + (void) sprintf(eos(s), "%s", vstart ? v[rn2(SIZE(v))] : + snd[rn2(SIZE(snd))]); + } + } + return s; +} + +struct monst * +christen_orc(mtmp, gang) +struct monst *mtmp; +char *gang; +{ + size_t sz = 0; + char buf[BUFSZ], buf2[BUFSZ], *orcname; + + orcname = rndorcname(buf2); + sz = strlen(gang) + strlen(orcname) + strlen(" of "); + if (buf && gang && orcname && (sz < (BUFSZ - 1))) { + Sprintf(buf, "%s of %s", + upstart(orcname), upstart(gang)); + mtmp = christen_monst(mtmp, buf); + } + return mtmp; +} + /* make sure "The Colour of Magic" remains the first entry in here */ static const char *const sir_Terry_novels[] = { "The Colour of Magic", "The Light Fantastic", "Equal Rites", "Mort", diff --git a/src/dog.c b/src/dog.c index 4bcdd7722..46cd832ef 100644 --- a/src/dog.c +++ b/src/dog.c @@ -407,6 +407,12 @@ boolean with_you; break; } + if ((mtmp->mspare1 & MIGR_LEFTOVERS) != 0L) { + /* Pick up the rest of the MIGR_TO_SPECIES objects */ + if (migrating_objs) + deliver_obj_to_mon(mtmp, DF_ALL); + } + if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ diff --git a/src/dokick.c b/src/dokick.c index 874db822a..b2d36de70 100644 --- a/src/dokick.c +++ b/src/dokick.c @@ -1612,6 +1612,9 @@ boolean near_hero; continue; where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) != 0) + continue; + nobreak = (where & MIGR_NOBREAK) != 0; noscatter = (where & MIGR_WITH_HERO) != 0; where &= ~(MIGR_NOBREAK | MIGR_NOSCATTER); @@ -1667,6 +1670,48 @@ boolean near_hero; } } +void +deliver_obj_to_mon(mtmp, deliverflags) +struct monst *mtmp; +unsigned long deliverflags; +{ + struct obj *otmp, *otmp2; + int where, cnt = 0, maxobj = 0; + + if (deliverflags & DF_RANDOM3) + maxobj = rn2(3) + 1; + else if (deliverflags & DF_RANDOM2) + maxobj = rn2(2) + 1; + else if (deliverflags == DF_NONE) + maxobj = 1; + + for (otmp = migrating_objs; otmp; otmp = otmp2) { + otmp2 = otmp->nobj; + where = (int) (otmp->owornmask & 0x7fffL); /* destination code */ + if ((where & MIGR_TO_SPECIES) == 0) + continue; + + if ((mtmp->data->mflags2 & otmp->corpsenm) != 0) { + obj_extract_self(otmp); + otmp->owornmask = 0L; + otmp->ox = otmp->oy = 0; + + /* special treatment for orcs and their kind */ + if ((otmp->corpsenm & M2_ORC) != 0 && has_oname(otmp)) { + if (!has_mname(mtmp)) + mtmp = christen_orc(mtmp, ONAME(otmp)); + free_oname(otmp); + } + otmp->corpsenm = 0; + (void) add_to_minv(mtmp, otmp); + cnt++; + if (maxobj && cnt >= maxobj) + break; + /* getting here implies DF_ALL */ + } + } +} + STATIC_OVL void otransit_msg(otmp, nodrop, num) register struct obj *otmp; diff --git a/src/makemon.c b/src/makemon.c index 0d38383dc..e4cece72d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1390,6 +1390,9 @@ int mmflags; mtmp->mstrategy |= STRAT_APPEARMSG; } + if (allow_minvent && migrating_objs) + deliver_obj_to_mon(mtmp, DF_RANDOM3); /* in case there's waiting items */ + if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 22fb42d03..2e2646647 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -25,6 +25,10 @@ STATIC_DCL boolean FDECL(put_lregion_here, (XCHAR_P, XCHAR_P, XCHAR_P, STATIC_DCL void NDECL(baalz_fixup); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); +STATIC_DCL void FDECL(check_ransacked, (char *)); +STATIC_DCL void FDECL(migr_booty_item, (int, const char *)); +STATIC_DCL void FDECL(migrate_orc, (struct monst *, unsigned long)); +STATIC_DCL void NDECL(stolen_booty); /* adjust a coordinate one step in the specified direction */ #define mz_move(X, Y, dir) \ @@ -610,6 +614,8 @@ fixup_special() } else if (on_level(&u.uz, &baalzebub_level)) { /* custom wallify the "beetle" potion of the level */ baalz_fixup(); + } else if (u.uz.dnum == mines_dnum && ransacked) { + stolen_booty(); } if (lregions) @@ -617,6 +623,141 @@ fixup_special() num_lregions = 0; } +void +check_ransacked(s) +char *s; +{ + /* this kludge only works as long as orctown is minetn-1 */ + if (dungeons[u.uz.dnum].dname + && !strcmp(dungeons[u.uz.dnum].dname, "The Gnomish Mines") + && !strcmp(s, "minetn-1")) + ransacked = 1; + else + ransacked = 0; +} + +#define ORC_LEADER 1 + +void +migrate_orc(mtmp, flags) +struct monst *mtmp; +unsigned long flags; +{ + int nlev, max_depth, cur_depth; + d_level dest; + + cur_depth = (int) depth(&u.uz); + max_depth = dunlevs_in_dungeon(&u.uz) + + (dungeons[u.uz.dnum].depth_start - 1); + if (flags == ORC_LEADER) { + /* Note that the orc leader will take possession of any + * remaining stuff not already delivered to other + * orcs between here and the bottom of the mines. + */ + nlev = max_depth; + mtmp->mspare1 = MIGR_LEFTOVERS; + } else { + nlev = rn2(max_depth - cur_depth) + cur_depth + 1; + if (nlev == cur_depth) + nlev++; + if (nlev > max_depth) + nlev = max_depth; + mtmp->mspare1 = 0L; + } + get_level(&dest, nlev); + migrate_to_level(mtmp, ledger_no(&dest), MIGR_RANDOM, (coord *) 0); +} + +void +migr_booty_item(otyp, gang) +int otyp; +const char *gang; +{ + struct obj *otmp; + otmp = mksobj_migr_to_species(otyp, (unsigned long) M2_ORC, FALSE, FALSE); + if (otmp && gang) { + new_oname(otmp, strlen(gang) + 1); /* removes old name if one is present */ + Strcpy(ONAME(otmp), gang); + } +} + +void +stolen_booty(VOID_ARGS) +{ + char *gang, gang_name[BUFSZ]; + struct monst *mtmp; + int cnt, i, otyp; + + /* + * -------------------------------------------------------- + * Mythos: + * + * A tragic accident has occurred in Frontier Town... + * It has been overrun by orcs. + * + * The booty that the orcs took from the town is now + * in the possession of the orcs that did this and + * have long since fled the level. + * -------------------------------------------------------- + */ + + gang = rndorcname(gang_name); + /* create the leader of the orc gang */ + mtmp = makemon(&mons[PM_ORC_CAPTAIN], 0, 0, MM_NONAME); + if (mtmp) { + mtmp = christen_monst(mtmp, upstart(gang)); + mtmp->mpeaceful = 0; + migrate_orc(mtmp, ORC_LEADER); + } + /* create the stuff that the rest of the gang took */ + cnt = rn2(3) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, gang); + cnt = rn2(2) + 1; + for (i = 0; i < cnt; ++i) + migr_booty_item(SKELETON_KEY, gang); + migr_booty_item(rn2(2) ? LONG_SWORD : SILVER_SABER, gang); + otyp = rn2((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1) + LEATHER_GLOVES; + migr_booty_item(otyp, gang); + cnt = rn2(9) + 1; + for (i = 0; i < cnt; ++i) { + /* Food items - but no lembas! (or some other weird things) */ + otyp = rn2((TIN - TRIPE_RATION) + 1) + TRIPE_RATION; + if (otyp != LEMBAS_WAFER && otyp != GLOB_OF_GRAY_OOZE && + otyp != GLOB_OF_BROWN_PUDDING && otyp != GLOB_OF_GREEN_SLIME && + otyp != GLOB_OF_BLACK_PUDDING && otyp != MEAT_STICK && + otyp != MEATBALL && otyp != MEAT_STICK && otyp != MEAT_RING && + otyp != HUGE_CHUNK_OF_MEAT && otyp != CORPSE) + migr_booty_item(otyp, gang); + } + /* Make most of the orcs on the level be part of the invading gang */ + for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + if (DEADMONSTER(mtmp)) + continue; + + if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) + mtmp = christen_orc(mtmp, upstart(gang)); + } + /* Lastly, ensure there's a few more orcs from the gang along the way + * The mechanics are such that they aren't actually identified as + * members of the invading gang until they get their spoils assigned + * to the inventory; handled during that assignment. + */ + cnt = rn2(6) + 1; + for (i = 0; i < cnt; ++i) { + int mtyp; + + mtyp = rn2((PM_ORC_SHAMAN - PM_ORC) + 1) + PM_ORC; + mtmp = makemon(&mons[mtyp], 0, 0, MM_NONAME); + if (mtmp) + migrate_orc(mtmp, 0L); + } + + ransacked = 0; +} + +#undef ORC_LEADER + boolean maze_inbounds(x, y) int x, y; @@ -819,6 +960,7 @@ const char *s; } if (*protofile) { + check_ransacked(protofile); Strcat(protofile, LEV_EXT); if (load_special(protofile)) { /* some levels can end up with monsters diff --git a/src/mkobj.c b/src/mkobj.c index cf7a77233..558be1dc6 100644 --- a/src/mkobj.c +++ b/src/mkobj.c @@ -224,6 +224,23 @@ boolean init, artif; return otmp; } +struct obj * +mksobj_migr_to_species(otyp, mflags2, init, artif) +int otyp; +unsigned mflags2; +boolean init, artif; +{ + struct obj *otmp; + + otmp = mksobj(otyp, init, artif); + if (otmp) { + add_to_migration(otmp); + otmp->owornmask = (long) MIGR_TO_SPECIES; + otmp->corpsenm = mflags2; + } + return otmp; +} + /* mkobj(): select a type of item from a class, use mksobj() to create it */ struct obj * mkobj(oclass, artif) diff --git a/src/pager.c b/src/pager.c index 9c2d74946..6ef7bf6ce 100644 --- a/src/pager.c +++ b/src/pager.c @@ -16,8 +16,9 @@ STATIC_DCL void FDECL(look_at_monster, (char *, char *, struct monst *, int, int)); STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *, struct permonst *, - BOOLEAN_P, BOOLEAN_P)); + BOOLEAN_P, BOOLEAN_P, char *)); STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); +STATIC_DCL void FDECL(do_supplemental_info, (char *, struct permonst *,BOOLEAN_P)); STATIC_DCL void NDECL(whatdoes_help); STATIC_DCL void NDECL(docontact); STATIC_DCL void NDECL(dispfile_help); @@ -509,10 +510,11 @@ char *buf, *monbuf; * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void -checkfile(inp, pm, user_typed_name, without_asking) +checkfile(inp, pm, user_typed_name, without_asking, supplemental_name) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; +char *supplemental_name; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ], givenname[BUFSZ]; @@ -619,7 +621,7 @@ boolean user_typed_name, without_asking; int chk_skip, pass = 1; boolean yes_to_moreinfo, found_in_file, pass1found_in_file, skipping_entry; - char *ap, *alt = 0; /* alternate description */ + char *sp, *ap, *alt = 0; /* alternate description */ /* adjust the input to remove "named " and "called " */ if ((ep = strstri(dbase_str, " named ")) != 0) { @@ -629,6 +631,8 @@ boolean user_typed_name, without_asking; } else if ((ep = strstri(dbase_str, " called ")) != 0) { copynchars(givenname, ep + 8, BUFSZ - 1); alt = givenname; + if (supplemental_name && (sp = strstri(inp, " called ")) != 0) + copynchars(supplemental_name, sp + 8, BUFSZ - 1); } else ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) @@ -760,12 +764,13 @@ boolean user_typed_name, without_asking; } int -do_screen_description(cc, looked, sym, out_str, firstmatch) +do_screen_description(cc, looked, sym, out_str, firstmatch, for_supplement) coord cc; boolean looked; int sym; char *out_str; const char **firstmatch; +struct permonst **for_supplement; { static const char mon_interior[] = "the interior of a monster", unreconnoitered[] = "unreconnoitered"; @@ -1008,11 +1013,15 @@ const char **firstmatch; didlook: if (looked) { + struct permonst *pm = (struct permonst *)0; + if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; - (void) lookat(cc.x, cc.y, look_buf, monbuf); + pm = lookat(cc.x, cc.y, look_buf, monbuf); + if (pm && for_supplement) + *for_supplement = pm; *firstmatch = look_buf; if (*(*firstmatch)) { Sprintf(temp_buf, " (%s)", *firstmatch); @@ -1043,7 +1052,7 @@ coord *click_cc; boolean clicklook = (mode == 2); /* right mouse-click method */ char out_str[BUFSZ] = DUMMY; const char *firstmatch = 0; - struct permonst *pm = 0; + struct permonst *pm = 0, *supplemental_pm = 0; int i = '\0', ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ @@ -1137,7 +1146,7 @@ coord *click_cc; break; } if (*out_str) - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } case '?': @@ -1151,7 +1160,7 @@ coord *click_cc; return 0; if (out_str[1]) { /* user typed in a complete string */ - checkfile(out_str, pm, TRUE, TRUE); + checkfile(out_str, pm, TRUE, TRUE, (char *) 0); return 0; } sym = out_str[0]; @@ -1204,7 +1213,7 @@ coord *click_cc; } found = do_screen_description(cc, (from_screen || clicklook), sym, - out_str, &firstmatch); + out_str, &firstmatch, &supplemental_pm); /* Finally, print out our explanation. */ if (found) { @@ -1215,16 +1224,18 @@ coord *click_cc; if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick)) && !clicklook) { - char temp_buf[BUFSZ]; + char temp_buf[BUFSZ], supplemental_name[BUFSZ]; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, - (boolean) (ans == LOOK_VERBOSE)); + (boolean) (ans == LOOK_VERBOSE), supplemental_name); + if (supplemental_pm && supplemental_name) + do_supplemental_info(supplemental_name, supplemental_pm, + (boolean) (ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } - } while (from_screen && !quick && ans != LOOK_ONCE && !clicklook); flags.verbose = save_verbose; @@ -1319,6 +1330,68 @@ boolean do_mons; /* True => monsters, False => objects */ destroy_nhwindow(win); } +void +do_supplemental_info(name, pm, without_asking) +char *name; +struct permonst *pm; +boolean without_asking; +{ + winid datawin = WIN_ERR; + char *entrytext = name, *bp; + char question[QBUFSZ]; + boolean yes_to_moreinfo = FALSE; + + /* + * Provide some info on some specific things + * meant to support in-game mythology, and not + * available from data.base or other sources. + */ + if (name && pm && is_orc(pm) && + (strlen(name) < (BUFSZ - 1)) && + (bp = strstri(name, " of ")) != 0) { + char fullname[BUFSZ]; + + Strcpy(fullname, name); + if (!without_asking) { + Strcpy(question, "More info about \""); + /* +2 => length of "\"?" */ + copynchars(eos(question), entrytext, + (int) (sizeof question - 1 - (strlen(question) + 2))); + Strcat(question, "\"?"); + if (yn(question) == 'y') + yes_to_moreinfo = TRUE; + } + if (yes_to_moreinfo) { + int i, subs = 0; + char *gang = bp + 4; + char *text[] = { + "%s is a member of a marauding horde of orcs", + "rumored to have brutally attacked and plundered the ordinarily", + "sheltered town that is located deep within The Gnomish Mines.", + "", + "The members of that vicious horde proudly and defiantly acclaim their", + "allegiance to their leader %s in their names.", + }; + + *bp = '\0'; + datawin = create_nhwindow(NHW_MENU); + for (i = 0; i < SIZE(text); i++) { + char buf[BUFSZ], *txt; + + if (strstri(text[i], "%s") != 0) { + Sprintf(buf, text[i], + subs++ ? gang : fullname); + txt = buf; + } else + txt = text[i]; + putstr(datawin, 0, txt); + } + display_nhwindow(datawin, FALSE); + destroy_nhwindow(datawin), datawin = WIN_ERR; + } + } +} + /* the '/' command */ int dowhatis() From 43364277458c26cef36766dc3d428fca1c03cc21 Mon Sep 17 00:00:00 2001 From: PatR Date: Tue, 18 Sep 2018 16:30:58 -0700 Subject: [PATCH 11/24] fix #H7396 - wishing for "orange" Wishing for "orange" might grant an orange, but it might give an orange gem, orange potion, or orange spellbook instead (but never orange dragon scales or orange dragon scale mail). Force the food object to be an exact match so wishing always produces an orange. --- doc/fixes36.2 | 1 + src/objnam.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 4a4fd0fc3..0dbef935b 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -127,6 +127,7 @@ cancelled shapeshifter is no longer able to change shape cancelled shapeshifter hit by polymorph magic will become uncancelled polymorph zap which creates a new long worm (or retains an old one via wizard mode monpolycontrol) can hit that worm multiple times (tail segments) +wishing for "orange" could yield orange or orange colored gem/potion/spellbook Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/src/objnam.c b/src/objnam.c index 0b68f73dc..6588b7f9a 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1533352036 2018/08/04 03:07:16 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.206 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1537313446 2018/09/18 23:30:46 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.208 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -3204,6 +3204,11 @@ struct obj *no_wish; typ = SPE_BLANK_PAPER; goto typfnd; } + /* specific food rather than color of gem/potion/spellbook[/scales] */ + if (!BSTRCMPI(bp, p - 6, "orange") && mntmp == NON_PM) { + typ = ORANGE; + goto typfnd; + } /* * NOTE: Gold pieces are handled as objects nowadays, and therefore * this section should probably be reconsidered as well as the entire From 1cef842786e150e089f998551ecf0e87d7659c28 Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 18 Sep 2018 20:15:13 -0400 Subject: [PATCH 12/24] some orctown tuning bits --- src/makemon.c | 2 +- src/mkmaze.c | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index e4cece72d..3fd910201 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1391,7 +1391,7 @@ int mmflags; } if (allow_minvent && migrating_objs) - deliver_obj_to_mon(mtmp, DF_RANDOM3); /* in case there's waiting items */ + deliver_obj_to_mon(mtmp, DF_RANDOM2); /* in case there's waiting items */ if (!in_mklev) newsym(mtmp->mx, mtmp->my); /* make sure the mon shows up */ diff --git a/src/mkmaze.c b/src/mkmaze.c index 2e2646647..539f380e0 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -678,6 +678,8 @@ const char *gang; if (otmp && gang) { new_oname(otmp, strlen(gang) + 1); /* removes old name if one is present */ Strcpy(ONAME(otmp), gang); + if (otyp >= TRIPE_RATION && otyp <= TIN) + otmp->quan += (long) rn2(3); } } @@ -710,13 +712,13 @@ stolen_booty(VOID_ARGS) migrate_orc(mtmp, ORC_LEADER); } /* create the stuff that the rest of the gang took */ + migr_booty_item(rn2(2) ? LONG_SWORD : SILVER_SABER, gang); cnt = rn2(3) + 1; for (i = 0; i < cnt; ++i) migr_booty_item(rn2(4) ? TALLOW_CANDLE : WAX_CANDLE, gang); cnt = rn2(2) + 1; for (i = 0; i < cnt; ++i) migr_booty_item(SKELETON_KEY, gang); - migr_booty_item(rn2(2) ? LONG_SWORD : SILVER_SABER, gang); otyp = rn2((GAUNTLETS_OF_DEXTERITY - LEATHER_GLOVES) + 1) + LEATHER_GLOVES; migr_booty_item(otyp, gang); cnt = rn2(9) + 1; @@ -735,22 +737,33 @@ stolen_booty(VOID_ARGS) if (DEADMONSTER(mtmp)) continue; - if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) - mtmp = christen_orc(mtmp, upstart(gang)); + if (is_orc(mtmp->data) && !has_mname(mtmp) && rn2(10)) { + /* + * We'll consider the orc captain from the level + * .des file to be the captain of a rival orc horde + * who is there to see what has transpired, and to + * contemplate future action. + * + * Don't christen the orc captain as a subordinate + * member of the main orc horde. + */ + if (mtmp->data != &mons[PM_ORC_CAPTAIN]) + mtmp = christen_orc(mtmp, upstart(gang)); + } } - /* Lastly, ensure there's a few more orcs from the gang along the way + /* Lastly, ensure there's several more orcs from the gang along the way. * The mechanics are such that they aren't actually identified as * members of the invading gang until they get their spoils assigned * to the inventory; handled during that assignment. */ - cnt = rn2(6) + 1; + cnt = rn2(7) + 5; for (i = 0; i < cnt; ++i) { int mtyp; mtyp = rn2((PM_ORC_SHAMAN - PM_ORC) + 1) + PM_ORC; mtmp = makemon(&mons[mtyp], 0, 0, MM_NONAME); if (mtmp) - migrate_orc(mtmp, 0L); + migrate_orc(mtmp, 0UL); } ransacked = 0; From 0a1c908503765322a0923a29191da1a93f3d7e3f Mon Sep 17 00:00:00 2001 From: nhmall Date: Tue, 18 Sep 2018 20:19:06 -0400 Subject: [PATCH 13/24] fixes36.2 entry for the orctown changes --- doc/fixes36.2 | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 0dbef935b..3014b1d10 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -198,6 +198,7 @@ wizard mode #wizidentify can now select individual items for permanent identification and don't display the selection to permanently identify everything if everything is already fully identified spiders will occasionally spin webs when moving around +make mine town "orctown" variation a multiple level feature of the mines Code Cleanup and Reorganization From 9a945ad07eafe315db4ed160dc5621969a3b5a1b Mon Sep 17 00:00:00 2001 From: Mak Kolybabi Date: Wed, 19 Sep 2018 15:49:07 -0500 Subject: [PATCH 14/24] Fix spelling mistake in README. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 677f3d300..e479737b9 100644 --- a/README +++ b/README @@ -127,7 +127,7 @@ filing a bug report from our "Contact Us" web page at: https://www.nethack.org/common/contact.html or http://www.nethack.org/common/contact.html Please include the version information from #version or the command line -option --version in the apropriate field. +option --version in the appropriate field. A public repository of the latest NetHack code that we've made available can be obtained via git here: From 0500040427a6f6671baf493ea4a2415fa5d2a3c6 Mon Sep 17 00:00:00 2001 From: Mak Kolybabi Date: Wed, 19 Sep 2018 16:55:43 -0500 Subject: [PATCH 15/24] Fix spelling and capitalization issues in `dat` and `DEVEL`. --- DEVEL/Developer.txt | 2 +- DEVEL/code_features.txt | 2 +- DEVEL/code_style.txt | 10 +++++----- dat/hh | 2 +- dat/opthelp | 4 ++-- dat/quest.txt | 6 +++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index adc326003..f7917dc2d 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -62,7 +62,7 @@ NOTE: The following instructions require perl. If you do not have perl on A. If you have never set up git on this machine before: (This assumes you will only be using git for NetHack. If you are going to use it for other projects as well, think before you type.) - Tell git what name (or nicname) and email address to use for you: + Tell git what name (or nickname) and email address to use for you: git config --global user.name "MY NAME" git config --global user.email USER@EXAMPLE.COM You probably want to set up a credential cache. diff --git a/DEVEL/code_features.txt b/DEVEL/code_features.txt index 1c60e024e..f54865602 100644 --- a/DEVEL/code_features.txt +++ b/DEVEL/code_features.txt @@ -75,7 +75,7 @@ There is a fqn_prefix[] entry for holding the path to each of the following: To recap, they are about enabling "different paths for different things", and separation of: - read-only stuff from read-write stuff. -- sysadmin stuff from user-writeable stuff. +- sysadmin stuff from user-writable stuff. etc. ============================================== diff --git a/DEVEL/code_style.txt b/DEVEL/code_style.txt index 4f16a8995..b17076823 100644 --- a/DEVEL/code_style.txt +++ b/DEVEL/code_style.txt @@ -16,7 +16,7 @@ declarations. Due to some incompatibilities, the patch is not publicly available and clang-format is not expected to be regularly used. Developers should do their best to adhere to the coding style to promote -legibile, easy-to-edit code. Legibility is paramount, so in some cases, it may +legible, easy-to-edit code. Legibility is paramount, so in some cases, it may be better not to fully adhere to the style guidelines. Recipes for common text editors can be found at the end of this file. @@ -30,7 +30,7 @@ characters, not tabs. Lines should be at most 78 characters wide. If a line would be longer than the limit, the line should be wrapped and the wrapped portion should be aligned with the parentheses or brackets containing the wrap. If there is no set of -parenthese or brackets, the line should be indented four spaces. Wrapping +parentheses or brackets, the line should be indented four spaces. Wrapping should normally occur after a comma or before a binary operator, when possible: @@ -43,7 +43,7 @@ possible: Single blank lines should be used wherever convenient to improve readability. -Functions and Control Satements +Functions and Control Statements ------------------------------- For a function definition, the return type, declarator, and opening brace @@ -183,10 +183,10 @@ many entries that reproducing them here is impractical. Fortunately, the options are in plain English, so walking through them with a copy of this Guide handy and making changes as required will suffice. -emacs Configuration +Emacs Configuration =================== -There are no doubt umpteen different ways to handle this in emacs. +There are no doubt umpteen different ways to handle this in Emacs. Putting the following in ~/.emacs.el is one (defun hook-c () diff --git a/dat/hh b/dat/hh index 4b9c4d9a1..d689f65ef 100644 --- a/dat/hh +++ b/dat/hh @@ -96,7 +96,7 @@ M-2 twoweapon toggle two-weapon combat (unless number_pad is enabled) M-a adjust adjust inventory letters M-A annotate add a one-line note to the current dungeon level (see M-O) M-c chat talk to someone -M-C conduct view optional challanges +M-C conduct view optional challenges M-d dip dip an object into something M-e enhance advance or check weapon and spell skills M-f force force a lock diff --git a/dat/opthelp b/dat/opthelp index 7d328d4a9..dd379be79 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -104,7 +104,7 @@ preload_tiles control whether tiles get pre-loaded into RAM at [TRUE] of the tile graphics, but uses more memory. Boolean option if TTY_TILES_ESCCODES was set at compile time (tty only): -vt_tiledata insert extra data escae code markers into output [FALSE] +vt_tiledata insert extra data escape code markers into output [FALSE] Any Boolean option can be negated by prefixing it with a '!' or 'no'. @@ -159,7 +159,7 @@ paranoid_confirmation space separated list [paranoid_confirmation:pray] pray -- y to confirm an attempt to pray; on by default Remove -- always pick from inventory for 'R' and 'T' even when wearing just one applicable item to remove or take off -pickup_burden when you pick up an item that exceeds this encumberance [S] +pickup_burden when you pick up an item that exceeds this encumbrance [S] level (Unencumbered, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. pickup_types a list of default symbols for kinds of objects to [] diff --git a/dat/quest.txt b/dat/quest.txt index 5f5aeeed2..083077958 100644 --- a/dat/quest.txt +++ b/dat/quest.txt @@ -1668,7 +1668,7 @@ to %ns lair. If you can manage to defeat %n and return undead that befoul the land. "Go with %d as your guide, %p." -%E [%nC invaded %H and captured %o. Defeat %ni and retrive %oh.] +%E [%nC invaded %H and captured %o. Defeat %ni and retrieve %oh.] %Cp Pri 00025 "You can prevail, if you rely on %d." %E @@ -2056,7 +2056,7 @@ the Amulet." %E [You have succeeded. Take %o with you as you go to find the Amulet.] # assumes The Longbow of Diana %Cc Ran 00082 -%l flexs %o reverently. +%l flexes %o reverently. "With this wondrous bow, one need never run out of arrows. You are its keeper now, and the time has come to resume your @@ -2967,7 +2967,7 @@ The ice and snow gives way to a valley floor. You %x ahead of you a huge round hill surrounded by pools of lava. This then is the entrance to %i. It looks like you're not going to get in without a fight though. -%E [This is the entrace to %i.] +%E [This is the entrance to %i.] %Cp Val 00036 Once again, you stand before the entrance to %i. %E From 60ea2874edb9af3c36aab2ac478a2df5b7e70add Mon Sep 17 00:00:00 2001 From: Mak Kolybabi Date: Wed, 19 Sep 2018 21:46:07 -0500 Subject: [PATCH 16/24] Fix other spelling issues. --- doc/Guidebook.mn | 16 ++++++++-------- doc/Guidebook.tex | 14 +++++++------- doc/Guidebook.txt | 14 +++++++------- doc/config.nh | 10 +++++----- doc/nethack.6 | 2 +- doc/nethack.txt | 2 +- doc/window.doc | 4 ++-- sys/wince/mswproc.c | 2 +- win/gnome/gnbind.c | 2 +- win/win32/mswproc.c | 2 +- 10 files changed, 34 insertions(+), 34 deletions(-) diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 151b25f5a..866857333 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -54,7 +54,7 @@ .in -\\n(PYu \" undo indent past label (etc) .sn \\n(pdu \" tmac.n: inter-paragraph space .. -.\" end of labeled paragrah +.\" end of labeled paragraph .\" .\" aligned single character key with SHORT definition (if it overflows one .\" line, all bets are off) @@ -1583,7 +1583,7 @@ debt or credit, if any. The `Iu' command lists unpaid items The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. .hn 3 -Shop idiosyncracies +Shop idiosyncrasies .pg Several aspects of shop behavior might be unexpected. .\" note: using * instead of \(bu is better for plain text output @@ -2463,19 +2463,19 @@ defaults to the location of the NetHack.exe or NetHackw.exe file so setting HACKDIR to override that is not usually necessary or recommended. .lp LEVELDIR The location that in-progress level files are stored. Defaults to HACKDIR, -must be writeable. +must be writable. .lp SAVEDIR The location where saved games are kept. Defaults to HACKDIR, must be -writeable. +writable. .lp BONESDIR The location that bones files are kept. Defaults to HACKDIR, must be -writeable. +writable. .lp LOCKDIR The location that file synchronization locks are stored. Defaults to -HACKDIR, must be writeable. +HACKDIR, must be writable. .lp TROUBLEDIR The location that a record of game aborts and self-diagnosed game problems -is kept. Defaults to HACKDIR, must be writeable. +is kept. Defaults to HACKDIR, must be writable. .lp AUTOCOMPLETE Enable or disable an extended command autocompletion. Autocompletion has no effect for the X11 windowport. @@ -4017,7 +4017,7 @@ m S_mimic (mimic) ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) -\. S_ndoor (doorway witout door) +\. S_ndoor (doorway without door) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 4d3352d84..d8ecc0705 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -1452,7 +1452,7 @@ be automatically turned off. \item[\tb{\#untrap}] Untrap something (trap, door, or chest). Default key is '{\tt M-u}', and '{\tt u}' if {\it number\verb+_+pad\/} is on. %.lp "" -In some circumstancs it can also be used to rescue trapped monsters. +In some circumstances it can also be used to rescue trapped monsters. %.lp \item[\tb{\#up}] Go up a staircase. Default key is '{\tt <}'. @@ -1830,7 +1830,7 @@ The {\tt Ix} command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. %.hn 3 -\subsubsection*{Shop idiosyncracies} +\subsubsection*{Shop idiosyncrasies} %.pg Several aspects of shop behavior might be unexpected. @@ -2848,23 +2848,23 @@ so setting HACKDIR to override that is not usually necessary or recommended. %.lp \item[\bb{LEVELDIR}] The location that in-progress level files are stored. Defaults to HACKDIR, -must be writeable. +must be writable. %.lp \item[\bb{SAVEDIR}] The location where saved games are kept. Defaults to HACKDIR, must be -writeable. +writable. %.lp \item[\bb{BONESDIR}] The location that bones files are kept. Defaults to HACKDIR, must be -writeable. +writable. %.lp \item[\bb{LOCKDIR}] The location that file synchronization locks are stored. Defaults to -HACKDIR, must be writeable. +HACKDIR, must be writable. %.lp \item[\bb{TROUBLEDIR}] The location that a record of game aborts and self-diagnosed game problems -is kept. Defaults to HACKDIR, must be writeable. +is kept. Defaults to HACKDIR, must be writable. %.lp \item[\bb{AUTOCOMPLETE}] Enable or disable an extended command autocompletion. diff --git a/doc/Guidebook.txt b/doc/Guidebook.txt index a53364f73..f43daba67 100644 --- a/doc/Guidebook.txt +++ b/doc/Guidebook.txt @@ -1926,7 +1926,7 @@ any unpaid items which have been used up, along with other shop fees, if any. - 5.4.1. Shop idiosyncracies + 5.4.1. Shop idiosyncrasies Several aspects of shop behavior might be unexpected. @@ -3015,19 +3015,19 @@ LEVELDIR The location that in-progress level files are stored. Defaults - to HACKDIR, must be writeable. + to HACKDIR, must be writable. SAVEDIR The location where saved games are kept. Defaults to HACKDIR, - must be writeable. + must be writable. BONESDIR The location that bones files are kept. Defaults to HACKDIR, - must be writeable. + must be writable. LOCKDIR The location that file synchronization locks are stored. - Defaults to HACKDIR, must be writeable. + Defaults to HACKDIR, must be writable. NetHack 3.6 May 27, 2018 @@ -3042,7 +3042,7 @@ TROUBLEDIR The location that a record of game aborts and self-diagnosed - game problems is kept. Defaults to HACKDIR, must be writeable. + game problems is kept. Defaults to HACKDIR, must be writable. AUTOCOMPLETE Enable or disable an extended command autocompletion. Autocom- @@ -5043,7 +5043,7 @@ ] S_mimic_def (mimic) M S_mummy (mummy) N S_naga (naga) - . S_ndoor (doorway witout door) + . S_ndoor (doorway without door) n S_nymph (nymph) O S_ogre (ogre) o S_orc (orc) diff --git a/doc/config.nh b/doc/config.nh index 4ceeca6a0..ce5410382 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -398,21 +398,21 @@ #HACKDIR=c:\games\nethack # The location that level files in progress are stored -# (default=HACKDIR, writeable) +# (default=HACKDIR, writable) #LEVELDIR=c:\nethack\levels -# The location where saved games are kept (default=HACKDIR, writeable) +# The location where saved games are kept (default=HACKDIR, writable) #SAVEDIR=c:\nethack\save -# The location that bones files are kept (default=HACKDIR, writeable) +# The location that bones files are kept (default=HACKDIR, writable) #BONESDIR=c:\nethack\save # The location that file synchronization locks are stored -# (default=HACKDIR, writeable) +# (default=HACKDIR, writable) #LOCKDIR=c:\nethack\levels # The location that a record of game aborts and self-diagnosed game problems -# is kept (default=HACKDIR, writeable) +# is kept (default=HACKDIR, writable) #TROUBLEDIR=c:\nethack\trouble # Finnish keyboards might need these modifications uncommented. Windows GUI. diff --git a/doc/nethack.6 b/doc/nethack.6 index 1bf53a63f..e9f4c72ff 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -93,7 +93,7 @@ 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 heros among heroes - and then they find ways of making the +in history as heroes among heroes - and then they find ways of making the game even harder. See the .I Guidebook section on Conduct if this game has gotten too easy for you. diff --git a/doc/nethack.txt b/doc/nethack.txt index 4c9986349..9cd48ce3d 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -26,7 +26,7 @@ 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 heros among + 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. diff --git a/doc/window.doc b/doc/window.doc index 59b90255d..a60ed689e 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -334,7 +334,7 @@ add_menu(windid window, int glyph, const anything identifier, outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the @@ -461,7 +461,7 @@ status_update(int fldindex, genericptr_t ptr, int chg, int percentage, int color For the user's chosen set of BL_MASK_ condition bits, They are stored internally in the cond_hilites[] array, - at the array offset aligned to the color those condtion + at the array offset aligned to the color those condition bits should display in. For example, if the user has chosen to display strngl diff --git a/sys/wince/mswproc.c b/sys/wince/mswproc.c index 7137a062a..d04c2156c 100644 --- a/sys/wince/mswproc.c +++ b/sys/wince/mswproc.c @@ -1048,7 +1048,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the diff --git a/win/gnome/gnbind.c b/win/gnome/gnbind.c index bc3521497..42152eeb9 100644 --- a/win/gnome/gnbind.c +++ b/win/gnome/gnbind.c @@ -702,7 +702,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 3512f2627..77432f751 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -1102,7 +1102,7 @@ identifier outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with - the menu command (or their user defined alises), it loses. + the menu command (or their user defined aliases), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the From 647b671c76a69a8c12d25bfff17ece741709c25b Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 19 Sep 2018 23:30:19 -0400 Subject: [PATCH 17/24] some data.base bits Take some of the entries from the github pull request. resolves #35 --- dat/data.base | 52 ++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/dat/data.base b/dat/data.base index 6dd001450..f10a9e581 100644 --- a/dat/data.base +++ b/dat/data.base @@ -534,6 +534,7 @@ ooze kind had swept so evilly free of all litter. [ At the Mountains of Madness, by H.P. Lovecraft ] blue jelly +spotted jelly I'd planned how to prevent the lock from sealing behind me; it required a temporary sacrifice, not cleverness. I used the door itself to help me cut off a portion of my body, after shunting all @@ -892,6 +893,20 @@ tiamat extremely vain. citrine* A pale yellow variety of crystalline quartz resembling topaz. +clay golem + It was a warm spring night when a fist knocked at the door so + hard that the hinges bent. + A man opened it and peered out into the street. There was + mist coming off the river and it was a cloudy night. He might + as well have tried to see through white velvet. + But he thought afterwards that there had been shapes out + there, just beyond the light spilling out into the road. A + lot of shapes, watching him carefully. He thought maybe + there'd been very faint points of light... + There was no mistaking the shape right in front of him, + though. It was big and dark red and looked like a child's + clay model of a man. Its eyes were two embers. + [ Feet of Clay, by Terry Pratchett ] cleaver Hither came Conan, the Cimmerian, black-haired, sullen-eyed, sword in hand, a thief, a reaver, a slayer, with gigantic @@ -1994,6 +2009,7 @@ gold golem ~gold golem ~straw golem ~wood golem +~clay golem *golem "The original story harks back, so they say, to the sixteenth century. Using long-lost formulas from the Kabbala, a rabbi is @@ -2305,7 +2321,8 @@ cornucopia And scatters corn and wine, and fruits and flowers. [ Os Lusiadas, by Luis Vaz de Camoes ] horned devil - Horned devils lack any real special abilities, though they +barbed devil + These devils lack any real special abilities, though they are quite difficult to kill. ~horsem* *horse @@ -4001,6 +4018,7 @@ pony continent and to and from our own world. The precise manner of their working is a Management secret. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] +trident poseido*n Poseido(o)n, lord of the seas and father of rivers and fountains, was the son of Chronos and Rhea, brother of Zeus, @@ -5152,6 +5170,7 @@ tripe ration often, alas, because the heat has not been kept low enough, it has the consistency of wet shoe leather. [ Joy of Cooking, by I Rombauer and M Becker ] +~water troll *troll The troll shambled closer. He was perhaps eight feet tall, perhaps more. His forward stoop, with arms dangling past @@ -5420,6 +5439,21 @@ water demon and drink, I will enjoy eating you, the biggest monkey, most of all!" He grinned, and saliva dripped down his hairy chin. [ Buddhist Tales for Young and Old, Vol. 1 ] +water troll + It wasn't that the troll was _horrifying_. Instead of the + rotting, betentacled monstrosity he had been expecting + Rincewind found himself looking at a rather squat but not + particularly ugly old man who would quite easily have passed + for normal on any city street, always provided that other + people on the street were used to seeing old men who were + apparently composed of water and very little else. It was as + if the ocean had decided to create life without going through + all that tedious business of evolution, and had simply formed + a part of itself into a biped and sent it walking squishily up + the beach. The troll was a pleasant translucent blue color. + As Rincewind stared a small shoal of silver fish flashed + across its chest. + [ The Colour of Magic, by Terry Pratchett ] weapon A weapon is a device for making your enemy change his mind. [ The Vor Game, by Lois McMaster Bujold ] @@ -5428,17 +5462,17 @@ web When first we practise to deceive! [ Marmion, by Sir Walter Scott ] whistle - There were legends both on the front and on the back of the + There were legends both on the front and on the back of the whistle. The one read thus: - FLA FUR BIS FLE The other: QUIS EST ISTE QUI VENIT - 'I ought to be able to make it out,' he thought; - 'but I suppose I am a little rusty in my Latin. - When I come to think of it, I don't believe I even - know the word for a whistle. The long one does seem - simple enough. It ought to mean, "Who is this who is coming?" + FLA FUR BIS FLE The other: QUIS EST ISTE QUI VENIT + 'I ought to be able to make it out,' he thought; + 'but I suppose I am a little rusty in my Latin. + When I come to think of it, I don't believe I even + know the word for a whistle. The long one does seem + simple enough. It ought to mean, "Who is this who is coming?" - Well, the best way to find out is evidently to whistle + Well, the best way to find out is evidently to whistle for him.' [Ghost Stories of an Antiquary, by Montague Rhodes James From 9c46a26af4efe0a2a57febbb685e770c6d51b287 Mon Sep 17 00:00:00 2001 From: Mak Kolybabi Date: Wed, 19 Sep 2018 22:48:43 -0500 Subject: [PATCH 18/24] Grammar and punctuation fixes. --- DEVEL/code_features.txt | 2 +- dat/quest.txt | 2 +- doc/tmac.n | 2 +- doc/window.doc | 8 ++++---- src/objects.c | 2 +- src/pray.c | 2 +- src/vision.c | 2 +- sys/wince/mhcmd.c | 2 +- sys/wince/mhmsgwnd.c | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/DEVEL/code_features.txt b/DEVEL/code_features.txt index 1c60e024e..c5eb3ce80 100644 --- a/DEVEL/code_features.txt +++ b/DEVEL/code_features.txt @@ -20,7 +20,7 @@ Here's how to do it: - The example above will alert the users for a new feature added in 3.6.0 via a one-liner via pline(), but you could get more elaborate (just make sure it is all done - in the 'if' code block.. + in the 'if' code block. Once the user finds the alert no longer useful, or becoming annoying, they can set the "suppress_alert" option. diff --git a/dat/quest.txt b/dat/quest.txt index 5f5aeeed2..52ca68d21 100644 --- a/dat/quest.txt +++ b/dat/quest.txt @@ -2707,7 +2707,7 @@ and you may be able to defeat him." "If you are %a at all times you may succeed, %p." %E %Cp Tou 00034 -"Let all who meet you on your journey know that you are on an quest for +"Let all who meet you on your journey know that you are on a quest for %l and grant safe passage." %E %Cc Tou 00035 diff --git a/doc/tmac.n b/doc/tmac.n index 270a78a06..0d445d34d 100644 --- a/doc/tmac.n +++ b/doc/tmac.n @@ -50,7 +50,7 @@ .\" Version 1.6 March 15, 1989 Matt.Bishop@dartmouth.edu .\" ..!bear.dartmouth.edu!bishop .\" Fixed a bug in footnote handling (again, sigh ...) This one -.\" occurred when the the "fo" trap position was reset just beneath +.\" occurred when the "fo" trap position was reset just beneath .\" the current line; the footnote overflow trap would kick in and .\" never be closed. .\" diff --git a/doc/window.doc b/doc/window.doc index 59b90255d..de6555fe3 100644 --- a/doc/window.doc +++ b/doc/window.doc @@ -177,7 +177,7 @@ int nhgetch() -- Returns a single character input from the user. changed and also return ASCII 033 in this case. int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a - a positioning event (perhaps from a mouse). If the + positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of @@ -602,7 +602,7 @@ getmsghistory(init) If init is TRUE, start over again from most recent message. putmsghistory(msg) - -- The is the counterpart to getmsghistory() for restores + -- This is the counterpart to getmsghistory() for restores used to reload the port's message recall buffer. The routine is called repeatedly from the core restore routine, starting with the oldest message first, and @@ -693,7 +693,7 @@ when processing options, either in the config file, or by the 'O' command. You may be wondering what values your window port will find in the iflags.wc_* and iflags.wc2_* fields for options that the user has not -specified in his/her config file. Put another way, how does you port code +specified in his/her config file. Put another way, how does your port code tell if an option has not been set? The next paragraph explains that. If the core does not set an option, it will still be initialized @@ -1068,7 +1068,7 @@ When writing a new window-port, you need to follow the following guidelines: WINOBJ (if you want the NetHack binary to include them, that is). 9) Look at your port's portmain.c (the file containing main()) and make - sure that all of the calls match the the requirements laid out in + sure that all of the calls match the requirements laid out in Section VII. Now, proceed with compilation and installation as usual. Don't forget diff --git a/src/objects.c b/src/objects.c index 0809ff41a..fcca3b0f7 100644 --- a/src/objects.c +++ b/src/objects.c @@ -368,7 +368,7 @@ HELM("helm of telepathy", "visored helmet", * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2). * (1) The dragon scale mails and the dragon scales are together. * (2) That the order of the dragon scale mail and dragon scales - * is the the same as order of dragons defined in monst.c. + * is the same as order of dragons defined in monst.c. */ #define DRGN_ARMR(name,mgc,power,cost,ac,color) \ ARMOR(name, None, 1, mgc, 1, power, 0, 5, 40, \ diff --git a/src/pray.c b/src/pray.c index 8d4c5003d..5d0d456fc 100644 --- a/src/pray.c +++ b/src/pray.c @@ -921,7 +921,7 @@ aligntyp g_align; * - fix all of your problems; * - do you a gratuitous favor. * - * If you make it to the the last category, you roll randomly again + * If you make it to the last category, you roll randomly again * to see what they do for you. * * If your luck is at least 0, then you are guaranteed rescued from diff --git a/src/vision.c b/src/vision.c index 2dcc85b8b..be87051d9 100644 --- a/src/vision.c +++ b/src/vision.c @@ -1916,7 +1916,7 @@ char *limits; /* points at range limit for current row, or NULL */ * shadow limit imposed by the far block (right) then use the far * wall as our new far block when we recurse. * - * If the limits are the the same, and the far block really exists + * If the limits are the same, and the far block really exists * (fb_row >= 0) then do the same as above. * * Normally, the check would be for the far wall being closer OR EQUAL diff --git a/sys/wince/mhcmd.c b/sys/wince/mhcmd.c index 98730dbce..c82bf7624 100644 --- a/sys/wince/mhcmd.c +++ b/sys/wince/mhcmd.c @@ -1161,7 +1161,7 @@ CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize) hdc = GetDC(hWnd); /* if windows size is specified - attempt ro stretch cells across - the the window size. If not - make default cell size based on + the window size. If not - make default cell size based on 10 points font. Make sure that cell cesize does not exceeds 20 points */ if (pWindowSize->cx > 0) diff --git a/sys/wince/mhmsgwnd.c b/sys/wince/mhmsgwnd.c index 818f72aed..1c8976564 100644 --- a/sys/wince/mhmsgwnd.c +++ b/sys/wince/mhmsgwnd.c @@ -34,7 +34,7 @@ typedef struct mswin_nethack_message_window { int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ int lines_last_turn; /* lines added during the last turn */ - int dont_care; /* flag the the user does not care if messages are lost */ + int dont_care; /* flag the user does not care if messages are lost */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); From 792eb64af5b86ede4f8945dd6e4775f398001b18 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 20 Sep 2018 14:06:17 -0700 Subject: [PATCH 19/24] build bits Eliminate a few warnings: array name used as boolean is always true, parameter 'flags' shadows (blocks access to) global struct 'flags', initializer discards 'const' (assigning string literal to 'char *'). Plus a couple of simplifications. --- src/do_name.c | 16 ++++++---------- src/mkmaze.c | 15 +++++---------- src/pager.c | 21 +++++++++++---------- 3 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/do_name.c b/src/do_name.c index ef1870742..4c7653776 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do_name.c $NHDT-Date: 1519420054 2018/02/23 21:07:34 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.128 $ */ +/* NetHack 3.6 do_name.c $NHDT-Date: 1537477563 2018/09/20 21:06:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.132 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1700,10 +1700,7 @@ boolean called; if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind && !Hallucination) Strcat(buf, "saddled "); - if (buf[0] != 0) - has_adjectives = TRUE; - else - has_adjectives = FALSE; + has_adjectives = (buf[0] != '\0'); /* Put the actual monster name or type into the buffer now */ /* Be sure to remember whether the buffer starts with a name */ @@ -2096,14 +2093,13 @@ christen_orc(mtmp, gang) struct monst *mtmp; char *gang; { - size_t sz = 0; + int sz = 0; char buf[BUFSZ], buf2[BUFSZ], *orcname; orcname = rndorcname(buf2); - sz = strlen(gang) + strlen(orcname) + strlen(" of "); - if (buf && gang && orcname && (sz < (BUFSZ - 1))) { - Sprintf(buf, "%s of %s", - upstart(orcname), upstart(gang)); + sz = (int) (strlen(gang) + strlen(orcname) + sizeof " of " - sizeof ""); + if (gang && orcname && sz < BUFSZ) { + Sprintf(buf, "%s of %s", upstart(orcname), upstart(gang)); mtmp = christen_monst(mtmp, buf); } return mtmp; diff --git a/src/mkmaze.c b/src/mkmaze.c index 539f380e0..8282205f8 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mkmaze.c $NHDT-Date: 1518718417 2018/02/15 18:13:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.55 $ */ +/* NetHack 3.6 mkmaze.c $NHDT-Date: 1537477570 2018/09/20 21:06:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.61 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Pasi Kallinen, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -628,20 +628,15 @@ check_ransacked(s) char *s; { /* this kludge only works as long as orctown is minetn-1 */ - if (dungeons[u.uz.dnum].dname - && !strcmp(dungeons[u.uz.dnum].dname, "The Gnomish Mines") - && !strcmp(s, "minetn-1")) - ransacked = 1; - else - ransacked = 0; + ransacked = (u.uz.dnum == mines_dnum && !strcmp(s, "minetn-1")); } #define ORC_LEADER 1 void -migrate_orc(mtmp, flags) +migrate_orc(mtmp, mflags) struct monst *mtmp; -unsigned long flags; +unsigned long mflags; { int nlev, max_depth, cur_depth; d_level dest; @@ -649,7 +644,7 @@ unsigned long flags; cur_depth = (int) depth(&u.uz); max_depth = dunlevs_in_dungeon(&u.uz) + (dungeons[u.uz.dnum].depth_start - 1); - if (flags == ORC_LEADER) { + if (mflags == ORC_LEADER) { /* Note that the orc leader will take possession of any * remaining stuff not already delivered to other * orcs between here and the bottom of the mines. diff --git a/src/pager.c b/src/pager.c index 6ef7bf6ce..d3163750c 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 pager.c $NHDT-Date: 1523142395 2018/04/07 23:06:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.123 $ */ +/* NetHack 3.6 pager.c $NHDT-Date: 1537477571 2018/09/20 21:06:11 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.129 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1229,7 +1229,7 @@ coord *click_cc; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, (boolean) (ans == LOOK_VERBOSE), supplemental_name); - if (supplemental_pm && supplemental_name) + if (supplemental_pm) do_supplemental_info(supplemental_name, supplemental_pm, (boolean) (ans == LOOK_VERBOSE)); } @@ -1364,19 +1364,20 @@ boolean without_asking; if (yes_to_moreinfo) { int i, subs = 0; char *gang = bp + 4; - char *text[] = { - "%s is a member of a marauding horde of orcs", - "rumored to have brutally attacked and plundered the ordinarily", - "sheltered town that is located deep within The Gnomish Mines.", - "", - "The members of that vicious horde proudly and defiantly acclaim their", - "allegiance to their leader %s in their names.", + static const char *text[] = { + "%s is a member of a marauding horde of orcs", + "rumored to have brutally attacked and plundered the ordinarily", + "sheltered town that is located deep within The Gnomish Mines.", + "", + "The members of that vicious horde proudly and defiantly acclaim", + "their allegiance to their leader %s in their names.", }; *bp = '\0'; datawin = create_nhwindow(NHW_MENU); for (i = 0; i < SIZE(text); i++) { - char buf[BUFSZ], *txt; + char buf[BUFSZ]; + const char *txt; if (strstri(text[i], "%s") != 0) { Sprintf(buf, text[i], From 450542a5020df928eefe2a13458972adca45c019 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 20 Sep 2018 14:09:25 -0700 Subject: [PATCH 20/24] grow-up of unnamed pet Change the phrasing when a pet grows up into another monster type: (old) "The pony grows up into a horse." (new) "Your pony grows up into a horse." No effect if it has been assigned a name: (before and after) "Foo grows up into a horse." --- src/makemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/makemon.c b/src/makemon.c index 3fd910201..55dc7b49d 100644 --- a/src/makemon.c +++ b/src/makemon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 makemon.c $NHDT-Date: 1495237801 2017/05/19 23:50:01 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.116 $ */ +/* NetHack 3.6 makemon.c $NHDT-Date: 1537477761 2018/09/20 21:09:21 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.124 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1837,7 +1837,7 @@ struct monst *mtmp, *victim; slightly less sexist if prepared for it...) */ : (fem && !mtmp->female) ? "female " : "", ptr->mname); - pline("%s %s %s.", Monnam(mtmp), + pline("%s %s %s.", upstart(y_monnam(mtmp)), (fem != mtmp->female) ? "changes into" : humanoid(ptr) ? "becomes" : "grows up into", From 4abaccfc34ebdb14bb5bb5bd73c2a75029a4c30c Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 20 Sep 2018 14:18:30 -0700 Subject: [PATCH 21/24] missile launching traps Factor some common code for missile launching traps into a seprate routine. Reorder the prototypes for static routines in trap.c into the same order as theose functions appear in the file. --- src/trap.c | 85 +++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 43 deletions(-) diff --git a/src/trap.c b/src/trap.c index bdf944b31..f7d1d0bc9 100644 --- a/src/trap.c +++ b/src/trap.c @@ -7,6 +7,15 @@ extern const char *const destroy_strings[][3]; /* from zap.c */ +STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, struct obj *, + struct obj *)); +STATIC_DCL struct obj *FDECL(t_missile, (int, struct trap *)); +STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); +STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); +STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); +STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, + SHORT_P, long)); +STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); STATIC_DCL boolean FDECL(emergency_disrobe, (boolean *)); @@ -18,26 +27,16 @@ STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); +STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); +STATIC_DCL boolean FDECL(adj_nonconjoined_pit, (struct trap *)); STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); -STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, - BOOLEAN_P)); -STATIC_DCL void FDECL(launch_drop_spot, (struct obj *, XCHAR_P, XCHAR_P)); -STATIC_DCL int FDECL(mkroll_launch, (struct trap *, XCHAR_P, XCHAR_P, - SHORT_P, long)); -STATIC_DCL boolean FDECL(isclearpath, (coord *, int, SCHAR_P, SCHAR_P)); -STATIC_DCL char *FDECL(trapnote, (struct trap *, BOOLEAN_P)); #if 0 STATIC_DCL void FDECL(join_adjacent_pits, (struct trap *)); #endif -STATIC_DCL void FDECL(clear_conjoined_pits, (struct trap *)); -STATIC_DCL boolean FDECL(adj_nonconjoined_pit, (struct trap *)); - -STATIC_DCL int FDECL(steedintrap, (struct trap *, struct obj *)); -STATIC_DCL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, - struct obj *, - struct obj *)); +STATIC_DCL boolean FDECL(thitm, (int, struct monst *, struct obj *, int, + BOOLEAN_P)); STATIC_DCL void NDECL(maybe_finish_sokoban); /* mintrap() should take a flags argument, but for time being we use this */ @@ -839,6 +838,21 @@ struct trap *trap; return FALSE; } +/* make a single arrow/dart/rock for a trap to shoot or drop */ +STATIC_OVL struct obj * +t_missile(otyp, trap) +int otyp; +struct trap *trap; +{ + struct obj *otmp = mksobj(otyp, TRUE, FALSE); + + otmp->quan = 1L; + otmp->owt = weight(otmp); + otmp->opoisoned = 0; + otmp->ox = trap->tx, otmp->oy = trap->ty; + return otmp; +} + void dotrap(trap, trflags) register struct trap *trap; @@ -911,12 +925,9 @@ unsigned trflags; trap->once = 1; seetrap(trap); pline("An arrow shoots out at you!"); - otmp = mksobj(ARROW, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); - otmp->opoisoned = 0; - if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ - ; + otmp = t_missile(ARROW, trap); + if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { + ; /* nothing */ } else if (thitu(8, dmgval(otmp, &youmonst), &otmp, "arrow")) { if (otmp) obfree(otmp, (struct obj *) 0); @@ -939,14 +950,12 @@ unsigned trflags; trap->once = 1; seetrap(trap); pline("A little dart shoots out at you!"); - otmp = mksobj(DART, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(DART, trap); if (!rn2(6)) otmp->opoisoned = 1; oldumort = u.umortality; - if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { /* nothing */ - ; + if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) { + ; /* nothing */ } else if (thitu(7, dmgval(otmp, &youmonst), &otmp, "little dart")) { if (otmp) { if (otmp->opoisoned) @@ -976,13 +985,11 @@ unsigned trflags; trap->once = 1; feeltrap(trap); - otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(ROCK, trap); + place_object(otmp, u.ux, u.uy); pline("A trap door in %s opens and %s falls on your %s!", the(ceiling(u.ux, u.uy)), an(xname(otmp)), body_part(HEAD)); - if (uarmh) { if (is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); @@ -991,7 +998,6 @@ unsigned trflags; pline("%s does not protect you.", Yname2(uarmh)); } } - if (!Blind) otmp->dknown = 1; stackobj(otmp); @@ -1639,7 +1645,7 @@ static struct { xchar x, y; } launchplace; -static void +STATIC_OVL void launch_drop_spot(obj, x, y) struct obj *obj; xchar x, y; @@ -2147,10 +2153,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(ARROW, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); - otmp->opoisoned = 0; + otmp = t_missile(ARROW, trap); if (in_sight) seetrap(trap); if (thitm(8, mtmp, otmp, 0, FALSE)) @@ -2166,9 +2169,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(DART, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(DART, trap); if (!rn2(6)) otmp->opoisoned = 1; if (in_sight) @@ -2187,9 +2188,7 @@ register struct monst *mtmp; break; } trap->once = 1; - otmp = mksobj(ROCK, TRUE, FALSE); - otmp->quan = 1L; - otmp->owt = weight(otmp); + otmp = t_missile(ROCK, trap); if (in_sight) seetrap(trap); if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) @@ -4889,7 +4888,7 @@ boolean u_entering_trap2; return FALSE; } -void +STATIC_OVL void clear_conjoined_pits(trap) struct trap *trap; { @@ -4913,7 +4912,7 @@ struct trap *trap; } } -boolean +STATIC_OVL boolean adj_nonconjoined_pit(adjtrap) struct trap *adjtrap; { From 9c6fe0b3770c627267a0b66f2187aece321f550a Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 20 Sep 2018 17:58:10 -0400 Subject: [PATCH 22/24] initialize a supplement buffer --- src/pager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pager.c b/src/pager.c index d3163750c..4515ea8e8 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1226,6 +1226,7 @@ coord *click_cc; && !clicklook) { char temp_buf[BUFSZ], supplemental_name[BUFSZ]; + supplemental_name[0] = '\0'; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, (boolean) (ans == LOOK_VERBOSE), supplemental_name); From de7121ea5d5496f73e275b5fac0f52f41cb35c33 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 20 Sep 2018 18:02:48 -0400 Subject: [PATCH 23/24] cannot alter doc/tmac.n --- doc/tmac.n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tmac.n b/doc/tmac.n index 0d445d34d..270a78a06 100644 --- a/doc/tmac.n +++ b/doc/tmac.n @@ -50,7 +50,7 @@ .\" Version 1.6 March 15, 1989 Matt.Bishop@dartmouth.edu .\" ..!bear.dartmouth.edu!bishop .\" Fixed a bug in footnote handling (again, sigh ...) This one -.\" occurred when the "fo" trap position was reset just beneath +.\" occurred when the the "fo" trap position was reset just beneath .\" the current line; the footnote overflow trap would kick in and .\" never be closed. .\" From 49e4330cb2fd706c45ee91d718f547aeb223c2e2 Mon Sep 17 00:00:00 2001 From: PatR Date: Thu, 20 Sep 2018 15:19:50 -0700 Subject: [PATCH 24/24] special levels 'grow selection' Fixes #132 This is based on the commit for github pull request #132, which indicates that the 'grow' pattern is reversed from what the .des file specifies. I don't understand how this is really supposed to work and the only place nethack uses it is on the Valkyrie Home level, which seems to be created roughly the same both before and after this change. --- src/sp_lev.c | 51 +++++++++++++++++++++------------------------------ 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/src/sp_lev.c b/src/sp_lev.c index 4f8df6b9c..1d6b0cd3a 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -3827,7 +3827,7 @@ selection_do_grow(ov, dir) struct opvar *ov; int dir; { - int x, y, c; + int x, y; char tmp[COLNO][ROWNO]; if (ov->spovartyp != SPOVAR_SEL) @@ -3835,40 +3835,31 @@ int dir; if (!ov) return; - (void) memset(tmp, 0, sizeof(tmp)); + (void) memset(tmp, 0, sizeof tmp); - for (x = 0; x < COLNO; x++) + for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { - c = 0; - if ((dir & W_WEST) && (x > 0) - && (selection_getpoint(x - 1, y, ov))) - c++; - if ((dir & (W_WEST | W_NORTH)) && (x > 0) && (y > 0) - && (selection_getpoint(x - 1, y - 1, ov))) - c++; - if ((dir & W_NORTH) && (y > 0) - && (selection_getpoint(x, y - 1, ov))) - c++; - if ((dir & (W_NORTH | W_EAST)) && (y > 0) && (x < COLNO - 1) - && (selection_getpoint(x + 1, y - 1, ov))) - c++; - if ((dir & W_EAST) && (x < COLNO - 1) - && (selection_getpoint(x + 1, y, ov))) - c++; - if ((dir & (W_EAST | W_SOUTH)) && (x < COLNO - 1) - && (y < ROWNO - 1) && (selection_getpoint(x + 1, y + 1, ov))) - c++; - if ((dir & W_SOUTH) && (y < ROWNO - 1) - && (selection_getpoint(x, y + 1, ov))) - c++; - if ((dir & (W_SOUTH | W_WEST)) && (y < ROWNO - 1) && (x > 0) - && (selection_getpoint(x - 1, y + 1, ov))) - c++; - if (c) + /* note: dir is a mask of multiple directions, but the only + way to specify diagonals is by including the two adjacent + orthogonal directions, which effectively specifies three- + way growth [WEST|NORTH => WEST plus WEST|NORTH plus NORTH] */ + if (((dir & W_WEST) && selection_getpoint(x + 1, y, ov)) + || (((dir & (W_WEST | W_NORTH)) == (W_WEST | W_NORTH)) + && selection_getpoint(x + 1, y + 1, ov)) + || ((dir & W_NORTH) && selection_getpoint(x, y + 1, ov)) + || (((dir & (W_NORTH | W_EAST)) == (W_NORTH | W_EAST)) + && selection_getpoint(x - 1, y + 1, ov)) + || ((dir & W_EAST) && selection_getpoint(x - 1, y, ov)) + || (((dir & (W_EAST | W_SOUTH)) == (W_EAST | W_SOUTH)) + && selection_getpoint(x - 1, y - 1, ov)) + || ((dir & W_SOUTH) && selection_getpoint(x, y - 1, ov)) + || (((dir & (W_SOUTH | W_WEST)) == (W_SOUTH | W_WEST)) + && selection_getpoint(x + 1, y - 1, ov))) { tmp[x][y] = 1; + } } - for (x = 0; x < COLNO; x++) + for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (tmp[x][y]) selection_setpoint(x, y, ov, 1);