]> granicus.if.org Git - nethack/commitdiff
redo achievement tracking
authorPatR <rankin@nethack.org>
Mon, 10 Feb 2020 08:17:54 +0000 (00:17 -0800)
committerPatR <rankin@nethack.org>
Mon, 10 Feb 2020 08:17:54 +0000 (00:17 -0800)
Instead of an assortment of bits, assign numeric indices to the
potential achievements and keep an array of those in the order they
were attained.  So disclosure might show the same subset occurring
differently in different games depending on the player's actions.
The encoded field in xlogfile doesn't care about that and remains
the same.

Modifies 'struct u', so EDITLEVEL has been incremented and existing
save files are invalidated.

12 files changed:
include/extern.h
include/patchlevel.h
include/you.h
src/cmd.c
src/do.c
src/end.c
src/insight.c
src/invent.c
src/mon.c
src/pray.c
src/spell.c
src/topten.c

index 4ad7d6a59769e5cb37e16cb30499e75ed70837a9..b5e8d46e526e280486151654f29e74d7fe43b262 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 extern.h        $NHDT-Date: 1580633720 2020/02/02 08:55:20 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.787 $ */
+/* NetHack 3.6 extern.h        $NHDT-Date: 1581322657 2020/02/10 08:17:37 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.795 $ */
 /* Copyright (c) Steve Creps, 1988.                              */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -994,7 +994,9 @@ E void FDECL(youhiding, (BOOLEAN_P, int));
 E char *FDECL(trap_predicament, (char *, int, BOOLEAN_P));
 E int NDECL(doconduct);
 E void FDECL(show_conduct, (int));
-E int NDECL(count_uachieve);
+E void FDECL(record_achievement, (XCHAR_P));
+E boolean FDECL(remove_achievement, (XCHAR_P));
+E int NDECL(count_achievements);
 E int NDECL(dovanquished);
 E void FDECL(list_vanquished, (CHAR_P, BOOLEAN_P));
 E int NDECL(num_genocides);
index f0be248515bdde5fa933e7862e856b6b0c3293bc..acc3b457ed32a02a6d977fb67e851e281bf28d3a 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 patchlevel.h    $NHDT-Date: 1580437691 2020/01/31 02:28:11 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.155 $ */
+/* NetHack 3.7 patchlevel.h    $NHDT-Date: 1581322658 2020/02/10 08:17:38 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.156 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Michael Allison, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -14,7 +14,7 @@
  * Incrementing EDITLEVEL can be used to force invalidation of old bones
  * and save files.
  */
-#define EDITLEVEL 13
+#define EDITLEVEL 14
 
 #define COPYRIGHT_BANNER_A "NetHack, Copyright 1985-2020"
 #define COPYRIGHT_BANNER_B \
index 611fcf3b17acd9fbd0b20de965ecf0fa47133ed5..f017f0e0ccaf1bba6b80f717696774922324bc3b 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 you.h   $NHDT-Date: 1574648937 2019/11/25 02:28:57 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.41 $ */
+/* NetHack 3.6 you.h   $NHDT-Date: 1581322658 2020/02/10 08:17:38 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.42 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2016. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -54,17 +54,25 @@ struct u_event {
     Bitfield(ascended, 1);          /* has offered the Amulet */
 };
 
-struct u_achieve {
-    Bitfield(amulet, 1);  /* touched Amulet */
-    Bitfield(bell, 1);    /* touched Bell */
-    Bitfield(book, 1);    /* touched Book */
-    Bitfield(menorah, 1); /* touched Candelabrum */
-    Bitfield(enter_gehennom,1); /* entered Gehennom (or Valley) by any means */
-    Bitfield(ascended, 1); /* not quite the same as u.uevent.ascended */
-    Bitfield(mines_luckstone, 1); /* got a luckstone at end of mines */
-    Bitfield(finish_sokoban, 1);  /* obtained the sokoban prize */
-
-    Bitfield(killed_medusa, 1);
+/* numerical order of these matters because they've been encoded in a
+   bitmask in xlogfile; reordering would break decoding that; during play
+   the number doesn't matter--they're recorded in the order achieved */
+enum achivements {
+    ACH_BELL =  1, /* acquired Bell of Opening */
+    ACH_HELL =  2, /* entered Gehennom */
+    ACH_CNDL =  3, /* acquired Candelabrum of Invocation */
+    ACH_BOOK =  4, /* acquired Book of the Dead */
+    ACH_INVK =  5, /* performed invocation to gain access to Sanctum */
+    ACH_AMUL =  6, /* acuired The Amulet */
+    ACH_ENDG =  7, /* entered end game */
+    ACH_ASTR =  8, /* entered Astral Plane */
+    ACH_UWIN =  9, /* ascended */
+    ACH_LUCK = 10, /* acquired Mines' End luckstone */
+    ACH_SOKO = 11, /* acquired Sokoban bag of holding or amu of reflection */
+    ACH_MEDU = 12, /* killed Medusa */
+    ACH_BLND = 13, /* hero was always blond, no, blind */
+    ACH_NUDE = 14, /* hero never wore armor */
+    N_ACH
 };
 
 struct u_realtime {
@@ -346,7 +354,6 @@ struct you {
     /* 1 free bit! */
 
     unsigned udg_cnt;           /* how long you have been demigod */
-    struct u_achieve uachieve;  /* achievements */
     struct u_event uevent;      /* certain events have happened */
     struct u_have uhave;        /* you're carrying special objects */
     struct u_conduct uconduct;  /* KMH, conduct */
@@ -399,7 +406,7 @@ struct you {
     struct skills weapon_skills[P_NUM_SKILLS];
     boolean twoweap;         /* KMH -- Using two-weapon combat */
     short mcham;             /* vampire mndx if shapeshifted to bat/cloud */
-
+    xchar uachieved[N_ACH];  /* list of achievements in the order attained */
 }; /* end of `struct you' */
 
 #define Upolyd (u.umonnum != u.umonster)
index 4264e1e28e0440cb829cefb969e99e7a23f040b9..94d5e245b6fefe5991b8f5200c17c335e18fd4ab 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 cmd.c   $NHDT-Date: 1579914040 2020/01/25 01:00:40 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.394 $ */
+/* NetHack 3.6 cmd.c   $NHDT-Date: 1581322659 2020/02/10 08:17:39 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.398 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2013. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -792,16 +792,12 @@ boolean pre, wiztower;
                 static const char Unachieve[] = "%s achievement revoked.";
 
                 if (Is_mineend_level(&u.uz)) {
-                    if (u.uachieve.mines_luckstone) {
+                    if (remove_achievement(ACH_LUCK))
                         pline(Unachieve, "Mine's end");
-                        u.uachieve.mines_luckstone = 0;
-                    }
                     g.context.achieveo.mines_prize_oid = 0;
                 } else if (Is_sokoend_level(&u.uz)) {
-                    if (u.uachieve.finish_sokoban) {
+                    if (remove_achievement(ACH_SOKO))
                         pline(Unachieve, "Sokoban end");
-                        u.uachieve.finish_sokoban = 0;
-                    }
                     g.context.achieveo.soko_prize_oid = 0;
                 }
             }
index 2a58939f20bd290d7b2f8948a45a698f19a3ea6d..70d51f8dacbd609e4f1b2189f67612f9c711cd27 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 do.c    $NHDT-Date: 1580608377 2020/02/02 01:52:57 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.222 $ */
+/* NetHack 3.6 do.c    $NHDT-Date: 1581322660 2020/02/10 08:17:40 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.224 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -1039,8 +1039,7 @@ dodown()
         pline("Unspeakable cruelty and harm lurk down there.");
         if (yn("Are you sure you want to enter?") != 'y')
             return 0;
-        else
-            pline("So be it.");
+        pline("So be it.");
         u.uevent.gehennom_entered = 1; /* don't ask again */
     }
 
@@ -1642,7 +1641,8 @@ boolean at_stairs, falling, portal;
             You_hear("groans and moans everywhere.");
         } else
             pline("It is hot here.  You smell smoke...");
-        u.uachieve.enter_gehennom = 1;
+
+        record_achievement(ACH_HELL); /* reached Gehennom */
     }
     /* in case we've managed to bypass the Valley's stairway down */
     if (Inhell && !Is_valley(&u.uz))
@@ -1677,10 +1677,14 @@ boolean at_stairs, falling, portal;
 
     /* special location arrival messages/events */
     if (In_endgame(&u.uz)) {
-        if (new &&on_level(&u.uz, &astral_level))
+        if (newdungeon)
+            record_achievement(ACH_ENDG); /* reached endgame */
+        if (new && on_level(&u.uz, &astral_level)) {
             final_level(); /* guardian angel,&c */
-        else if (newdungeon && u.uhave.amulet)
+            record_achievement(ACH_ASTR); /* reached Astral level */
+        } else if (newdungeon && u.uhave.amulet) {
             resurrect(); /* force confrontation with Wizard */
+        }
     } else if (In_quest(&u.uz)) {
         onquest(); /* might be reaching locate|goal level */
     } else if (In_V_tower(&u.uz)) {
index f10e0f42452d42ff287b0b0d06b1c041b071cfff..cc328e6eb20d1726b3eba33a73abcd77c40dbb24 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 end.c   $NHDT-Date: 1575245059 2019/12/02 00:04:19 $  $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.181 $ */
+/* NetHack 3.6 end.c   $NHDT-Date: 1581322661 2020/02/10 08:17:41 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.206 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -812,7 +812,7 @@ boolean taken;
 
     if (!done_stopprint) {
         if (should_query_disclose_option('c', &defquery)) {
-            int acnt = count_uachieve();
+            int acnt = count_achievements();
 
             Sprintf(qbuf, "Do you want to see your conduct%s%s?",
                     (acnt > 0) ? " and achievement" : "",
@@ -1222,6 +1222,17 @@ int how;
     iflags.at_night = night();
     iflags.at_midnight = midnight();
 
+    /* final achievement tracking; only show blind and nudist if some
+       tangible progress has been made; always show ascension last */
+    if (u.uachieved[0] || !flags.beginner) {
+        if (u.uroleplay.blind)
+            record_achievement(ACH_BLND); /* blind the whole game */
+        if (u.uroleplay.nudist)
+            record_achievement(ACH_NUDE); /* never wore armor */
+    }
+    if (how == ASCENDED)
+        record_achievement(ACH_UWIN);
+
     dump_open_log(endtime);
     /* Sometimes you die on the first move.  Life's not fair.
      * On those rare occasions you get hosed immediately, go out
@@ -1592,6 +1603,7 @@ int how;
      * score list?" */
     if (have_windows && !iflags.toptenwin)
         exit_nhwindows((char *) 0), have_windows = FALSE;
+    /* update 'logfile' and 'xlogfile', if enabled, and maybe 'record' */
     topten(how, endtime);
     if (have_windows)
         exit_nhwindows((char *) 0);
index 62ee93607a309a65553e37d55a44f9c345d4e122..153f4df07bde28105a447acede888313e6a5ae99 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 insight.c       $NHDT-Date: 1580577249 2020/02/01 17:14:09 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.0 $ */
+/* NetHack 3.7 insight.c       $NHDT-Date: 1581322662 2020/02/10 08:17:42 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1698,51 +1698,17 @@ int final;
     g.en_win = WIN_ERR;
 }
 
-/* uses to decide whether there are any achievements to display */
-int
-count_uachieve()
-{
-    int acnt = 0;
-
-    /* these tests must be kept in sync with show_achievements() */
-    if (u.uroleplay.blind)
-        ++acnt;
-    if (u.uroleplay.nudist)
-        ++acnt;
-    if (u.uachieve.mines_luckstone)
-        ++acnt;
-    if (u.uachieve.finish_sokoban)
-        ++acnt;
-    if (u.uachieve.killed_medusa)
-        ++acnt;
-    if (u.uachieve.bell)
-        ++acnt;
-    if (u.uachieve.enter_gehennom)
-        ++acnt;
-    if (u.uachieve.menorah)
-        ++acnt;
-    if (u.uachieve.book)
-        ++acnt;
-    if (u.uevent.invoked)
-        ++acnt;
-    if (u.uachieve.amulet)
-        ++acnt;
-    if (In_endgame(&u.uz))
-        ++acnt;
-    if (Is_astralevel(&u.uz))
-        ++acnt;
-    if (u.uachieve.ascended)
-        ++acnt;
-
-    return acnt;
-}
+/*
+ *      Achievements (see 'enum achievements' in you.h).
+ */
 
 static void
 show_achievements(final)
-int final;
+int final; /* used "behind the curtain" by enl_foo() macros */
 {
-    int acnt;
+    int i, achidx, acnt;
     char title[BUFSZ];
+    boolean ach_amulet = FALSE;
     winid awin = WIN_ERR;
 
     /* unfortunately we can't show the achievements (at least not all of
@@ -1754,7 +1720,7 @@ int final;
     /* first, figure whether any achievements have been accomplished
        so that we don't show the header for them if the resulting list
        below it would be empty */
-    if ((acnt = count_uachieve()) == 0)
+    if ((acnt = count_achievements()) == 0)
         return;
 
     if (g.en_win != WIN_ERR) {
@@ -1765,67 +1731,105 @@ int final;
     }
     Sprintf(title, "Achievement%s:", plur(acnt));
     putstr(awin, 0, title);
-    /* after 'blind' and 'nudist', which are the easiest if you die but
-       the hardest if you ascend, they're arranged in approximate order
-       of difficulty */
-    if (u.uroleplay.blind)
-        enl_msg(You_, "are exploring", "explored",
-                " without being able to see", "");
-    if (u.uroleplay.nudist)
-        enl_msg(You_, "have gone", "went", " without any armor", "");
-
-    if (u.uachieve.mines_luckstone)
-        enl_msg(You_, "have ", "", "completed the Gnomish Mines", "");
-    if (u.uachieve.finish_sokoban)
-        enl_msg(You_, "have ", "", "completed Sokoban", "");
-    if (u.uachieve.killed_medusa)
-        enl_msg(You_, "have ", "", "defeated Medusa", "");
-    if (u.uachieve.bell) {
-        /* alternate phrasing for present vs past and also for possessing
-           the item vs once held it */
-        enl_msg(You_,
-                u.uhave.bell ? "have" : "have handled",
-                u.uhave.bell ? "had" : "handled",
-                " the Bell of Opening", "");
-    }
-    /* wording is clumsy but the game is inconsistent about "entering
-       Gehennom"; the Valley is part of Gehennom but the message about
-       entering Gehennom is given when descending from the Valley to the
-       level below and that's also when the flag about entering gets set */
-    if (u.uachieve.enter_gehennom)
-        enl_msg(You_, "have ", "", "passed the Valley of the Dead", "");
-    if (u.uachieve.menorah) {
-        enl_msg(You_,
-                u.uhave.menorah ? "have" : "have handled",
-                u.uhave.menorah ? "had" : "handled",
-                " the Candelabrum of Invocation", "");
-    }
-    if (u.uachieve.book) {
-        enl_msg(You_,
-                u.uhave.book ? "have" : "have handled",
-                u.uhave.book ? "had" : "handled",
-                " the Book of the Dead", "");
-    }
-    if (u.uevent.invoked)
-        enl_msg(You_, "have ", "", "gained access to Moloch's Sanctum", "");
-    if (u.uachieve.amulet) {
-        /* extra alternate wording for past tense because ascension
-           requires giving up the Amulet */
-        enl_msg(You_,
-                u.uhave.amulet ? "have" : "have obtained",
-                u.uachieve.ascended ? "delivered"
-                 : u.uhave.amulet ? "had" : "had obtained",
-                " the Amulet of Yendor", "");
-    }
-
-    /* reaching Astral makes feedback about reaching the Planes be redundant
-       and asceding makes both be redundant, but we display all that apply */
-    if (In_endgame(&u.uz))
-        enl_msg(You_, "have ", "", "reached the Elemental Planes", "");
-    if (Is_astralevel(&u.uz))
-        enl_msg(You_, "have ", "", "reached the Astral Plane", "");
-    if (u.uachieve.ascended)
-        enlght_out(" You ascended!");
+
+    /* display achievements in the order in which they were recorded;
+       lone exception is to defer the Amulet (by taking it out of list)
+       if we just ascended; it warrants alternate wording when given
+       away during ascension, but the Amulet achievement is always
+       attained before entering endgame and the alternate wording looks
+       strange if shown before "reached endgame" and "reached Astral" */
+    if (remove_achievement(ACH_UWIN)) { /* UWIN == Ascended! */
+        ach_amulet = remove_achievement(ACH_AMUL);
+        record_achievement(ACH_UWIN); /* put back; always last when present */
+        acnt = count_achievements();
+    }
+    for (i = 0; i < acnt; ++i) {
+        achidx = u.uachieved[i];
+
+        switch (achidx) {
+        case ACH_BLND:
+            enl_msg(You_, "are exploring", "explored",
+                    " without being able to see", "");
+            break;
+        case ACH_NUDE:
+            enl_msg(You_, "have gone", "went", " without any armor", "");
+            break;
+        case ACH_LUCK:
+            enl_msg(You_, "have ", "", "completed the Gnomish Mines", "");
+            break;
+        case ACH_SOKO:
+            enl_msg(You_, "have ", "", "completed Sokoban", "");
+            break;
+        case ACH_MEDU:
+            enl_msg(You_, "have ", "", "defeated Medusa", "");
+            break;
+        case ACH_BELL:
+            /* alternate phrasing for present vs past and also for
+               possessing the item vs once held it */
+            enl_msg(You_,
+                    u.uhave.bell ? "have" : "have handled",
+                    u.uhave.bell ? "had" : "handled",
+                    " the Bell of Opening", "");
+            break;
+        case ACH_HELL:
+            enl_msg(You_, "have ", "", "entered Gehennom", "");
+            break;
+        case ACH_CNDL:
+            enl_msg(You_,
+                    u.uhave.menorah ? "have" : "have handled",
+                    u.uhave.menorah ? "had" : "handled",
+                    " the Candelabrum of Invocation", "");
+            break;
+        case ACH_BOOK:
+            enl_msg(You_,
+                    u.uhave.book ? "have" : "have handled",
+                    u.uhave.book ? "had" : "handled",
+                    " the Book of the Dead", "");
+            break;
+        case ACH_INVK:
+            enl_msg(You_, "have ", "",
+                    "gained access to Moloch's Sanctum", "");
+            break;
+        case ACH_AMUL:
+            /* note: we won't get here if ACH_UWIN is going to be shown */
+            enl_msg(You_,
+                    u.uhave.amulet ? "have" : "have obtained",
+                    u.uhave.amulet ? "had" : "had obtained",
+                    " the Amulet of Yendor", "");
+            break;
+
+        /* reaching Astral makes feedback about reaching the Planes
+           be redundant and ascending makes both be redundant, but
+           we display all that apply */
+        case ACH_ENDG:
+            enl_msg(You_, "have ", "", "reached the Elemental Planes", "");
+            break;
+        case ACH_ASTR:
+            enl_msg(You_, "have ", "", "reached the Astral Plane", "");
+            break;
+        case ACH_UWIN:
+            /* if we took Amulet achievement out of the list, show it now;
+               always uses past tense here since game ends upon ascension */
+            if (ach_amulet)
+                enl_msg(You_, "?", "delivered", " the Amulet of Yendor", "");
+            /* the ultimate achievement... */
+            enlght_out(" You ascended!");
+            break;
+        default:
+            /* title[] has served its purpose, reuse it as a scratch buffer */
+            Sprintf(title, " [Unexpected achievement #%d.]", achidx);
+            enlght_out(title);
+            break;
+        } /* switch */
+    } /* for */
+#ifdef XLOGFILE
+    /* if we removed the Amulet achievement because of ascension, put it
+       back for encoding in the achievements field of xlogfile; it will
+       change position from the original ordering but that doesn't matter
+       to the bitmask which is going to be constructed and logged */
+    if (ach_amulet)
+        record_achievement(ACH_AMUL);
+#endif
 
     if (awin != g.en_win) {
         display_nhwindow(awin, TRUE);
@@ -1833,6 +1837,65 @@ int final;
     }
 }
 
+/* record an achievement (add at end of list unless already present) */
+void
+record_achievement(achidx)
+xchar achidx;
+{
+    int i;
+
+    /* valid achievements range from 1 to N_ACH-1 */
+    if (achidx < 1 || achidx >= N_ACH) {
+        impossible("Achievement #%d is out of range.", achidx);
+        return;
+    }
+
+    /* the list has an extra slot so there is always at least one 0 at
+       its end (more than one unless all N_ACH-1 possible achievements
+       have been recorded); find first empty slot or achievement #achidx;
+       an attempt to duplicate an achievement can happen if any of Bell,
+       Candelabrum, Book, or Amulet is dropped then picked up again */
+    for (i = 0; u.uachieved[i]; ++i)
+        if (u.uachieved[i] == achidx)
+            return; /* already recorded, don't duplicate it */
+    u.uachieved[i] = achidx;
+    return;
+}
+
+/* discard a recorded achievement; return True if removed, False otherwise */
+boolean
+remove_achievement(achidx)
+xchar achidx;
+{
+    int i;
+
+    for (i = 0; u.uachieved[i]; ++i)
+        if (u.uachieved[i] == achidx)
+            break; /* stop when found */
+    if (!u.uachieved[i]) /* not found */
+        return FALSE;
+    /* list is 0 terminated so any beyond the removed one move up a slot */
+    do {
+        u.uachieved[i] = u.uachieved[i + 1];
+    } while (u.uachieved[++i]);
+    return TRUE;
+}
+
+/* used to decide whether there are any achievements to display */
+int
+count_achievements()
+{
+    int i, acnt = 0;
+
+    for (i = 0; u.uachieved[i]; ++i)
+        ++acnt;
+    return acnt;
+}
+
+/*
+ *      Vanquished monsters.
+ */
+
 static const char *vanqorders[NUM_VANQ_ORDER_MODES] = {
     "traditional: by monster level, by internal monster index",
     "by monster toughness, by internal monster index",
index 084cd472e4aca55bae5b6e11c79de181b5fab5ac..51568945e35095196d911735a4341fc020ebd378 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 invent.c        $NHDT-Date: 1580476196 2020/01/31 13:09:56 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ */
+/* NetHack 3.7 invent.c        $NHDT-Date: 1581322662 2020/02/10 08:17:42 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.290 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -810,22 +810,22 @@ struct obj *obj;
         if (u.uhave.amulet)
             impossible("already have amulet?");
         u.uhave.amulet = 1;
-        u.uachieve.amulet = 1;
+        record_achievement(ACH_AMUL);
     } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) {
         if (u.uhave.menorah)
             impossible("already have candelabrum?");
         u.uhave.menorah = 1;
-        u.uachieve.menorah = 1;
+        record_achievement(ACH_CNDL);
     } else if (obj->otyp == BELL_OF_OPENING) {
         if (u.uhave.bell)
             impossible("already have silver bell?");
         u.uhave.bell = 1;
-        u.uachieve.bell = 1;
+        record_achievement(ACH_BELL);
     } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) {
         if (u.uhave.book)
             impossible("already have the book?");
         u.uhave.book = 1;
-        u.uachieve.book = 1;
+        record_achievement(ACH_BOOK);
     } else if (obj->oartifact) {
         if (is_quest_artifact(obj)) {
             if (u.uhave.questart)
@@ -839,12 +839,12 @@ struct obj *obj;
     /* "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;
+        record_achievement(ACH_LUCK);
+        g.context.achieveo.mines_prize_oid = 0; /* done with luckstone o_id */
         obj->nomerge = 0;
     } else if (is_soko_prize(obj)) {
-        u.uachieve.finish_sokoban = 1;
-        g.context.achieveo.soko_prize_oid = 0;
+        record_achievement(ACH_SOKO);
+        g.context.achieveo.soko_prize_oid = 0; /* done with bag/amulet o_id */
         obj->nomerge = 0;
     }
 }
index e2d571f5e9a9d21bed1793995096a68dbe54b04f..d528a911cc70c29e510339b9068f2836af7ad189 100644 (file)
--- a/src/mon.c
+++ b/src/mon.c
@@ -1,4 +1,4 @@
-/* NetHack 3.6 mon.c   $NHDT-Date: 1580044343 2020/01/26 13:12:23 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.320 $ */
+/* NetHack 3.6 mon.c   $NHDT-Date: 1581322664 2020/02/10 08:17:44 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.321 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -2065,7 +2065,7 @@ register struct monst *mtmp;
     if (mtmp->data->msound == MS_NEMESIS)
         nemdead();
     if (mtmp->data == &mons[PM_MEDUSA])
-        u.uachieve.killed_medusa = 1;
+        record_achievement(ACH_MEDU);
     if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph))
         unmap_object(mtmp->mx, mtmp->my);
     m_detach(mtmp, mptr);
index 3d4045141ee271cabe7d47b7d9b85c4db1f0e73e..b098311d4ea2cac8ddfb7ccc581fcc715611a52a 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 pray.c  $NHDT-Date: 1579401997 2020/01/19 02:46:37 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.139 $ */
+/* NetHack 3.6 pray.c  $NHDT-Date: 1581322665 2020/02/10 08:17:45 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.140 $ */
 /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -1516,7 +1516,6 @@ dosacrifice()
             /* The final Test.  Did you win? */
             if (uamul == otmp)
                 Amulet_off();
-            u.uevent.ascended = 1;
             if (carried(otmp))
                 useup(otmp); /* well, it's gone now */
             else
@@ -1552,8 +1551,8 @@ dosacrifice()
                 pline(cloud_of_smoke, hcolor(NH_ORANGE));
                 done(ESCAPED);
             } else { /* super big win */
+                u.uevent.ascended = 1;
                 adjalign(10);
-                u.uachieve.ascended = 1;
                 pline(
                "An invisible choir sings, and you are bathed in radiance...");
                 godvoice(altaralign, "Mortal, thou hast done well!");
@@ -1564,6 +1563,7 @@ dosacrifice()
                     flags.female ? "dess" : "");
                 done(ASCENDED);
             }
+            /*NOTREACHED*/
         }
     } /* real Amulet */
 
index 4b5e035943fab9f0d56f5c52efd2bb9a454589fd..11718e3c007cb6085ba405dc0db0330c021752f1 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 spell.c $NHDT-Date: 1546565814 2019/01/04 01:36:54 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.88 $ */
+/* NetHack 3.6 spell.c $NHDT-Date: 1581322667 2020/02/10 08:17:47 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.102 $ */
 /*      Copyright (c) M. Stephenson 1988                          */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -259,6 +259,7 @@ struct obj *book2;
             /* successful invocation */
             mkinvokearea();
             u.uevent.invoked = 1;
+            record_achievement(ACH_INVK);
             /* in case you haven't killed the Wizard yet, behave as if
                you just did */
             u.uevent.udemigod = 1; /* wizdead() */
index b2c163d695d43bd36fed145489c48809dca6e530..1581cd4dc18fa93ae7661e60035e2bf917b07fb1 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 topten.c        $NHDT-Date: 1579914041 2020/01/25 01:00:41 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.62 $ */
+/* NetHack 3.6 topten.c        $NHDT-Date: 1581322668 2020/02/10 08:17:48 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.64 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2012. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -428,6 +428,7 @@ encodeconduct()
 static long
 encodeachieve()
 {
+    int i, ilimit;
     long r = 0L;
 
     /*
@@ -469,34 +470,9 @@ encodeachieve()
      * 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)
-        r |= 1L << 1;
-    if (u.uachieve.menorah)
-        r |= 1L << 2;
-    if (u.uachieve.book)
-        r |= 1L << 3;
-    if (u.uevent.invoked)
-        r |= 1L << 4;
-    if (u.uachieve.amulet)
-        r |= 1L << 5;
-    if (In_endgame(&u.uz))
-        r |= 1L << 6;
-    if (Is_astralevel(&u.uz))
-        r |= 1L << 7;
-    if (u.uachieve.ascended)
-        r |= 1L << 8;
-    if (u.uachieve.mines_luckstone)
-        r |= 1L << 9;
-    if (u.uachieve.finish_sokoban)
-        r |= 1L << 10;
-    if (u.uachieve.killed_medusa)
-        r |= 1L << 11;
-    if (u.uroleplay.blind)
-        r |= 1L << 12;
-    if (u.uroleplay.nudist)
-        r |= 1L << 13;
+    ilimit = min(N_ACH, 32 - 1); /* 32: portable limit for 'long' */
+    for (i = 0; i < ilimit && u.uachieved[i]; ++i)
+        r |= 1L << (u.uachieved[i] - 1);
 
     return r;
 }