From a453215a0675f68736001722299522cf34711f45 Mon Sep 17 00:00:00 2001 From: PatR Date: Fri, 24 Jan 2020 17:00:49 -0800 Subject: [PATCH] disclose achievements When disclosing conduct at end of game (but not during except in wizard mode), display achievements too. They're also included in dumplog if it's enabled. Previously they were only output as an extra field in xlogfile. --- doc/fixes37.0 | 4 +- src/cmd.c | 209 +++++++++++++++++++------------------------------- src/invent.c | 6 +- src/topten.c | 41 +++++++++- 4 files changed, 125 insertions(+), 135 deletions(-) diff --git a/doc/fixes37.0 b/doc/fixes37.0 index dfd769792..0ab5454a3 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 ----------------------------------- @@ -121,6 +121,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 34c43e536..53545429f 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)