diff --git a/doc/fixes37.0 b/doc/fixes37.0 index b2b555a40..1f822bc9d 100644 --- a/doc/fixes37.0 +++ b/doc/fixes37.0 @@ -1,4 +1,4 @@ -$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.72 $ $NHDT-Date: 1579899144 2020/01/24 20:52:24 $ +$NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.74 $ $NHDT-Date: 1579914040 2020/01/25 01:00:40 $ General Fixes and Modified Features ----------------------------------- @@ -119,6 +119,8 @@ tiny chance for randomly created spellbooks to be Discworld novels instead 'goldX', 'implicit_uncursed', and 'mention_walls' options changed to be persistent across save/restore wearing a wet towel confers "half damage from poison gas" attribute +for end of game disclosure and dumplog, show 'achievements' (previously only + available as an encoded value in xlogfile) along with 'conduct' Platform- and/or Interface-Specific New Features diff --git a/src/cmd.c b/src/cmd.c index 46f210f19..df02c6e4f 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 cmd.c $NHDT-Date: 1579655026 2020/01/22 01:03:46 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.392 $ */ +/* NetHack 3.6 cmd.c $NHDT-Date: 1579914040 2020/01/25 01:00:40 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.394 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -194,6 +194,7 @@ static void FDECL(characteristics_enlightenment, (int, int)); static void FDECL(one_characteristic, (int, int, int)); static void FDECL(status_enlightenment, (int, int)); static void FDECL(attributes_enlightenment, (int, int)); +static void FDECL(show_achievements, (int)); static void FDECL(add_herecmd_menuitem, (winid, int NDECL((*)), const char *)); @@ -3185,135 +3186,6 @@ int final; } } -#if 0 /* no longer used */ -static boolean NDECL(minimal_enlightenment); - -/* - * Courtesy function for non-debug, non-explorer mode players - * to help refresh them about who/what they are. - * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise. - */ -static boolean -minimal_enlightenment() -{ - winid tmpwin; - menu_item *selected; - anything any; - int genidx, n; - char buf[BUFSZ], buf2[BUFSZ]; - static const char untabbed_fmtstr[] = "%-15s: %-12s"; - static const char untabbed_deity_fmtstr[] = "%-17s%s"; - static const char tabbed_fmtstr[] = "%s:\t%-12s"; - static const char tabbed_deity_fmtstr[] = "%s\t%s"; - static const char *fmtstr; - static const char *deity_fmtstr; - - fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr; - deity_fmtstr = iflags.menu_tab_sep ? tabbed_deity_fmtstr - : untabbed_deity_fmtstr; - any = cg.zeroany; - buf[0] = buf2[0] = '\0'; - tmpwin = create_nhwindow(NHW_MENU); - start_menu(tmpwin); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - "Starting", MENU_ITEMFLAGS_NONE); - - /* Starting name, race, role, gender */ - Sprintf(buf, fmtstr, "name", g.plname); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - Sprintf(buf, fmtstr, "race", g.urace.noun); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - Sprintf(buf, fmtstr, "role", - (flags.initgend && g.urole.name.f) ? g.urole.name.f : g.urole.name.m); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - /* Starting alignment */ - Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL])); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - /* Current name, race, role, gender */ - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_ITEMFLAGS_NONE); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - "Current", MENU_ITEMFLAGS_NONE); - Sprintf(buf, fmtstr, "race", Upolyd ? g.youmonst.data->mname : g.urace.noun); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - if (Upolyd) { - Sprintf(buf, fmtstr, "role (base)", - (u.mfemale && g.urole.name.f) ? g.urole.name.f - : g.urole.name.m); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - } else { - Sprintf(buf, fmtstr, "role", - (flags.female && g.urole.name.f) ? g.urole.name.f - : g.urole.name.m); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - } - /* don't want poly_gender() here; it forces `2' for non-humanoids */ - genidx = is_neuter(g.youmonst.data) ? 2 : flags.female; - Sprintf(buf, fmtstr, "gender", genders[genidx].adj); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - if (Upolyd && (int) u.mfemale != genidx) { - Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - } - - /* Current alignment */ - Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type)); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - /* Deity list */ - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", - MENU_ITEMFLAGS_NONE); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, - "Deities", MENU_ITEMFLAGS_NONE); - Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC), - (u.ualignbase[A_ORIGINAL] == u.ualign.type - && u.ualign.type == A_CHAOTIC) ? " (s,c)" - : (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" - : (u.ualign.type == A_CHAOTIC) ? " (c)" : ""); - Sprintf(buf, fmtstr, "Chaotic", buf2); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL), - (u.ualignbase[A_ORIGINAL] == u.ualign.type - && u.ualign.type == A_NEUTRAL) ? " (s,c)" - : (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" - : (u.ualign.type == A_NEUTRAL) ? " (c)" : ""); - Sprintf(buf, fmtstr, "Neutral", buf2); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL), - (u.ualignbase[A_ORIGINAL] == u.ualign.type - && u.ualign.type == A_LAWFUL) ? " (s,c)" - : (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" - : (u.ualign.type == A_LAWFUL) ? " (c)" : ""); - Sprintf(buf, fmtstr, "Lawful", buf2); - add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, - MENU_ITEMFLAGS_NONE); - - end_menu(tmpwin, "Base Attributes"); - n = select_menu(tmpwin, PICK_NONE, &selected); - destroy_nhwindow(tmpwin); - return (boolean) (n != -1); -} -#endif /*0*/ - /* ^X command */ static int doattributes(VOID_ARGS) @@ -3499,12 +3371,89 @@ int final; " for any artifacts", ""); } + show_achievements(final); + /* Pop up the window and wait for a key */ display_nhwindow(g.en_win, TRUE); destroy_nhwindow(g.en_win); g.en_win = WIN_ERR; } +static void +show_achievements(final) +int final; +{ + winid awin = WIN_ERR; + int acnt = 0; + + /* unfortunately we can't show the achievements (at least not all of + them) while the game is in progress because it would give away the + ID of luckstone (at Mine's End) and of real Amulet of Yendor */ + if (!final && !wizard) + return; + + if (g.en_win != WIN_ERR) { + awin = g.en_win; + putstr(awin, 0, ""); + } else { + awin = create_nhwindow(NHW_MENU); + } + putstr(awin, 0, "Achievements:"); + /* arranged in approximate order of difficulty */ + if (u.uachieve.mines_luckstone) + enl_msg(You_, "have ", "", + "completed the Gnomish Mines", ""), ++acnt; + if (u.uachieve.finish_sokoban) + enl_msg(You_, "have ", "", + "completed Sokoban", ""), ++acnt; + if (u.uachieve.killed_medusa) + enl_msg(You_, "have ", "", + "defeated Medusa", ""), ++acnt; + if (u.uachieve.bell) + enl_msg(You_, "have ", "", + "handled the Bell of Opening", ""), ++acnt; + if (u.uachieve.enter_gehennom) + enl_msg(You_, "have ", "", + "passed the Valley of the Dead", ""), ++acnt; + if (u.uachieve.menorah) + enl_msg(You_, "have ", "", + "handled the Candelabrum of Invocation", ""), ++acnt; + if (u.uachieve.book) + enl_msg(You_, "have ", "", + "handled the Book of the Dead", ""), ++acnt; + if (u.uevent.invoked) + enl_msg(You_, "have ", "", + "gained access to Moloch's Sanctum", ""), ++acnt; + if (u.uachieve.amulet) + enl_msg(You_, "have ", "", + "obtained the Amulet of Yendor", ""), ++acnt; + if (In_endgame(&u.uz)) + enl_msg(You_, "have ", "", + "reached the Elemental Planes", ""), ++acnt; + if (Is_astralevel(&u.uz)) + enl_msg(You_, "have ", "", + "reached the Astral Plane", ""), ++acnt; + if (u.uachieve.ascended) + enlght_out(" You ascended!"), ++acnt; + if (u.uroleplay.blind || u.uroleplay.nudist) { + if (acnt) + putstr(awin, 0, ""); + if (u.uroleplay.blind) + enl_msg(You_, "are exploring", "explored", + " without being able to see", ""), ++acnt; + if (u.uroleplay.nudist) + enl_msg(You_, "have gone", "went", + " without any armor", ""), ++acnt; + } + if (!acnt) + enlght_out(" []"); + + if (awin != g.en_win) { + display_nhwindow(awin, TRUE); + destroy_nhwindow(awin); + } +} + /* ordered by command name */ struct ext_func_tab extcmdlist[] = { { '#', "#", "perform an extended command", diff --git a/src/invent.c b/src/invent.c index 88d6fb1d3..e014e481b 100644 --- a/src/invent.c +++ b/src/invent.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 invent.c $NHDT-Date: 1575245062 2019/12/02 00:04:22 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.267 $ */ +/* NetHack 3.7 invent.c $NHDT-Date: 1579914042 2020/01/25 01:00:42 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.286 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -834,8 +834,8 @@ struct obj *obj; set_artifact_intrinsic(obj, 1, W_ART); } - /* "special achievements" aren't discoverable during play, they - end up being recorded in XLOGFILE at end of game, nowhere else */ + /* "special achievements"; revealed in end of game disclosure and + dumplog, originally just recorded in XLOGFILE */ if (is_mines_prize(obj)) { u.uachieve.mines_luckstone = 1; g.context.achieveo.mines_prize_oid = 0; diff --git a/src/topten.c b/src/topten.c index 4ca879a98..b2c163d69 100644 --- a/src/topten.c +++ b/src/topten.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 topten.c $NHDT-Date: 1450451497 2015/12/18 15:11:37 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.6 topten.c $NHDT-Date: 1579914041 2020/01/25 01:00:41 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.62 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -430,6 +430,45 @@ encodeachieve() { long r = 0L; + /* + * Other potential achievements to track (some already recorded + * for other purposes such as automatic level annotations or + * quest progress): + * entered mines branch, + * chatted with the Oracle, + * read a Discworld novel, + * entered Sokoban's first level, + * entered Bigroom level, + * got quest summons, + * entered quest branch, + * chatted with leader, + * entered second quest level, + * entered last quest level, + * defeated nemesis (not same as acquiring Bell or artifact), + * completed quest (again, not the same as getting the items), + * entered rogue level, + * entered Fort Ludios level/branch, + * entered Medusa level, + * entered castle level, + * opened castle drawbridge, + * obtained castle wand, + * entered valley level, + * [assorted demon lairs?], + * entered Vlad's tower branch, + * defeated Vlad (not same as acquiring Candelabrum), + * entered Wizard's tower area within relevant level, + * defeated Wizard, + * found vibrating square, + * entered sanctum level, + * [defeated Riders], + * located the correct high altar (for initial alignment or current + * one or both?) on the astral level. + * Too many to include them all in a 32-bit mask, but that could + * handle a lot of them. Defeated can be seen via the vanquished + * monsters list and many or all of the entered can be seen via + * the dungeon overview but both of those things go away as soon as + * the program exits. + */ if (u.uachieve.bell) r |= 1L << 0; if (u.uachieve.enter_gehennom)