]> granicus.if.org Git - nethack/commitdiff
more #overview changes
authornethack.rankin <nethack.rankin>
Sat, 14 Apr 2012 08:31:05 +0000 (08:31 +0000)
committernethack.rankin <nethack.rankin>
Sat, 14 Apr 2012 08:31:05 +0000 (08:31 +0000)
     Change how overview data is handled if/when you get expelled from
the quest:  mark quest levels as unreachable rather than discarding their
overview data, so that it can be included in end of game disclosure (and
can be revived if you manage to return to your quest branch by invoking
the W quest artifact).

     Order of endgame levels was odd:  earth followed by astral, water,
fire, and air, because the code didn't know how to insert in front of the
first one visited.  Now it does.  Placement of endgame levels was sub-
optimal:  since that has the highest internal dungeon branch number, it
came out last.  Now it is forced to come out first, so that it appears
above the dungeon.  And use "Plane of Earth" for level name rather than
"Plane 1", and so on for the others, when in the endgame.

     Since I'm bumping EDITLEVEL due to adding mapseen.flags.unreachable,
I am also inserting u.uevent.uvibrated now so that it won't trigger another
EDITLEVEL increment.  At the moment it doesn't do anything except get set
when you receive the "you feel strange vibrations <under you>" message.
The level where that occurs will eventually have an automatic annotation
of some sort.

include/dungeon.h
include/patchlevel.h
include/you.h
src/do.c
src/dungeon.c
src/hack.c

index f92592ea99f07ffeb16e5a0fdf827d368cbe2567..707ac6cf7f9443c7371af454b17ea41904bb1cd1 100644 (file)
@@ -219,6 +219,7 @@ typedef struct mapseen  {
            Bitfield(shoptype, 5);
        } feat;
        struct mapseen_flags {
+           Bitfield(unreachable, 1); /* can't get back to this level */
            Bitfield(forgot, 1); /* player has forgotten about this level */
            Bitfield(knownbones, 1); /* player aware of bones */
            Bitfield(oracle, 1);
@@ -226,8 +227,8 @@ typedef struct mapseen  {
            Bitfield(bigroom, 1);
            Bitfield(castle, 1);
            Bitfield(castletune, 1); /* add tune hint to castle annotation */
-           Bitfield(valley, 1);
 
+           Bitfield(valley, 1);
            Bitfield(msanctum, 1);
            Bitfield(ludios, 1);
 # ifdef REINCARNATION
index 8712cf3c39b1d1adc24bb3e3e9958202318be6c6..bb398bd4f4eb0ab932b37a64c7d627112ed1dd8c 100644 (file)
@@ -13,7 +13,7 @@
  * Incrementing EDITLEVEL can be used to force invalidation of old bones
  * and save files.
  */
-#define EDITLEVEL      54
+#define EDITLEVEL      55
 
 #define COPYRIGHT_BANNER_A \
 "NetHack, Copyright 1985-2012"
index 55f0864a6f177522d5abbdbe9a421913b92e691d..4b79f7fc5553e834c455ab86060e670ba1ee2354 100644 (file)
@@ -50,6 +50,7 @@ struct u_event {
        Bitfield(uhand_of_elbereth,2);  /* became Hand of Elbereth */
 #endif
        Bitfield(udemigod,1);           /* killed the wiz */
+       Bitfield(uvibrated,1);          /* stepped on "vibrating square" */
        Bitfield(ascended,1);           /* has offered the Amulet */
 };
 
index 532e3e7c595f25a2b4b38eaf13c1ab9d3477d465..7818ec5798feda3946bb7176ea1135111646e235 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -20,6 +20,8 @@ STATIC_DCL int NDECL(currentlevel_rewrite);
 STATIC_DCL void NDECL(final_level);
 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
 
+extern int n_dgns;             /* number of dungeons, from dungeon.c */
+
 static NEARDATA const char drop_types[] =
        { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 };
 
@@ -1100,6 +1102,11 @@ boolean at_stairs, falling, portal;
            /* discard unreachable levels; keep #0 */
            for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
                delete_levelfile(l_idx);
+#ifdef DUNGEON_OVERVIEW
+           /* mark #overview data for all dungeon branches as uninteresting */
+           for (l_idx = 0; l_idx < n_dgns; ++l_idx)
+               remdun_mapseen(l_idx);
+#endif
        }
 
 #ifdef REINCARNATION
index 57fcacb6f96e98647fc2568d3f3ba63e42710425..e9b66e194e7a15bc1c7b28e6092c45a8558e84ab 100644 (file)
@@ -24,8 +24,8 @@ struct proto_dungeon {
        int     n_brs;  /* number of tmpbranch entries */
 };
 
-int n_dgns;                            /* number of dungeons (used here,  */
-                                       /*   and mklev.c)                  */
+int n_dgns;                            /* number of dungeons (also used   */
+                                       /*   in mklev.c and do.c)          */
 static branch *branches = (branch *) 0;        /* dungeon branch list             */
 
 struct lchoice {
@@ -65,8 +65,10 @@ STATIC_DCL void FDECL(save_mapseen, (int, mapseen *));
 STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *));
 STATIC_DCL void FDECL(print_mapseen, (winid,mapseen *,int,int,BOOLEAN_P));
 STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *));
+STATIC_DCL void FDECL(traverse_mapseenchn, (BOOLEAN_P,winid,int,int,int *));
 STATIC_DCL const char *FDECL(seen_string, (XCHAR_P,const char *));
 STATIC_DCL const char *FDECL(br_string2, (branch *));
+STATIC_DCL const char *FDECL(endgamelevelname, (char *,int));
 STATIC_DCL const char *FDECL(shop_string, (int));
 STATIC_DCL char *FDECL(tunesuffix, (mapseen *,char *));
 #endif /* DUNGEON_OVERVIEW */
@@ -1872,18 +1874,16 @@ d_level *dest;
     }
 }
 
-/* add a custom name to the current level */
+/* #annotate command - add a custom name to the current level */
 int
 donamelevel()
 {
     mapseen *mptr;
-    char qbuf[QBUFSZ];         /* Buffer for query text */
     char nbuf[BUFSZ];          /* Buffer for response */
 
     if (!(mptr = find_mapseen(&u.uz))) return 0;
 
-    Sprintf(qbuf,"What do you want to call this dungeon level? ");
-    getlin(qbuf, nbuf);
+    getlin("What do you want to call this dungeon level?", nbuf);
     if (index(nbuf, '\033')) return 0;
 
     /* discard old annotation, if any */
@@ -1997,6 +1997,8 @@ int fd;
 
 /* Remove all mapseen objects for a particular dnum.
  * Useful during quest expulsion to remove quest levels.
+ * [No longer deleted, just marked as unreachable.  #overview will
+ * ignore such levels, end of game disclosure will include them.]
  */
 void
 remdun_mapseen(dnum)
@@ -2007,6 +2009,10 @@ int dnum;
     mptraddr = &mapseenchn;
     while ((mptr = *mptraddr) != 0) {
        if (mptr->lev.dnum == dnum) {
+#if 1      /* use this... */
+           mptr->flags.unreachable = 1;
+       }
+#else      /* old deletion code */
            *mptraddr = mptr->next;
            if (mptr->custom)
                free((genericptr_t) mptr->custom);
@@ -2014,6 +2020,7 @@ int dnum;
                savecemetery(-1, FREE_SAVE, &mptr->final_resting_place);
            free((genericptr_t) mptr);
        } else
+#endif
            mptraddr = &mptr->next;
     }
 }
@@ -2025,7 +2032,7 @@ d_level *lev;
     /* Create a level and insert in "sorted" order.  This is an insertion
      * sort first by dungeon (in order of discovery) and then by level number.
      */
-    mapseen *mptr, *init, *old;
+    mapseen *mptr, *init, *prev;
 
     init = (mapseen *) alloc(sizeof *init);
     (void) memset((genericptr_t)init, 0, sizeof *init);
@@ -2040,25 +2047,20 @@ d_level *lev;
     init->lev.dnum = lev->dnum;
     init->lev.dlevel = lev->dlevel;
 
-    if (!mapseenchn) {
+    /* walk until we get to the place where we should insert init */
+    for (mptr = mapseenchn, prev = 0; mptr; prev = mptr, mptr = mptr->next)
+       if (mptr->lev.dnum > init->lev.dnum ||
+               (mptr->lev.dnum == init->lev.dnum &&
+                   mptr->lev.dlevel > init->lev.dlevel))
+           break;
+    if (!prev) {
+       init->next = mapseenchn;
        mapseenchn = init;
-       return;
-    }
-
-    /* walk until we get to the place where we should
-     * insert init between mptr and mptr->next
-     */
-    for (mptr = mapseenchn; mptr->next; mptr = mptr->next) {
-       if (mptr->next->lev.dnum == init->lev.dnum) break;
-    }
-    for (; mptr->next; mptr = mptr->next) {
-       if ((mptr->next->lev.dnum != init->lev.dnum) ||
-           (mptr->next->lev.dlevel > init->lev.dlevel)) break;
+    } else {
+       mptr = prev->next;
+       prev->next = init;
+       init->next = mptr;
     }
-
-    old = mptr->next;
-    mptr->next = init;
-    init->next = old;
 }
 
 #define INTEREST(feat) \
@@ -2082,8 +2084,8 @@ interest_mapseen(mptr)
 mapseen *mptr;
 {
     if (on_level(&u.uz, &mptr->lev)) return TRUE;
-    if (mptr->flags.forgot) return FALSE;
-    if (In_endgame(&u.uz) && !In_endgame(&mptr->lev)) return FALSE;
+    if (mptr->flags.unreachable || mptr->flags.forgot) return FALSE;
+    /* level is of interest if it has an auto-generated annotation */
     if (mptr->flags.oracle || mptr->flags.bigroom ||
 # ifdef REINCARNATION
        mptr->flags.roguelevel ||
@@ -2095,6 +2097,12 @@ mapseen *mptr;
        be furthest one reached, unless level teleporting in wizard mode) */
     if (In_sokoban(&mptr->lev) &&
        (In_sokoban(&u.uz) || !mptr->flags.sokosolved)) return TRUE;
+    /* when in the endgame, list all endgame levels visited, whether they
+       have annotations or not, so that #overview doesn't become extremely
+       sparse once the rest of the dungeon has been flagged as unreachable */
+    if (In_endgame(&u.uz)) return In_endgame(&mptr->lev);
+    /* level is of interest if it has non-zero feature count or known bones
+       or user annotation or known connection to another dungeon brancth */
     return (INTEREST(mptr->feat) ||
            (mptr->final_resting_place &&
                (mptr->flags.knownbones || wizard)) ||
@@ -2109,17 +2117,34 @@ recalc_mapseen()
     struct monst *mtmp;
     struct cemetery *bp, **bonesaddr;
     unsigned i, ridx;
-    int x, y, count, atmp;
+    int x, y, ltyp, count, atmp;
 
     /* Should not happen in general, but possible if in the process
      * of being booted from the quest.  The mapseen object gets
      * removed during the expulsion but prior to leaving the level
+     * [Since quest explusion no longer deletes quest mapseen data,
+     * null return from find_mapseen() should now be impossible.]
      */
     if (!(mptr = find_mapseen(&u.uz))) return;
 
     /* reset all features; mptr->feat.* = 0; */
     (void) memset((genericptr_t) &mptr->feat, 0, sizeof mptr->feat);
     /* reset most flags; some level-specific ones are left as-is */
+    if (mptr->flags.unreachable) {
+       mptr->flags.unreachable = 0; /* reached it; Eye of the Aethiopica? */
+       if (In_quest(&u.uz)) {
+           mapseen *mptrtmp = mapseenchn;
+
+           /* when quest was unreachable due to ejection and portal removal,
+              getting back to it via arti-invoke should revive annotation
+              data for all quest levels, not just the one we're on now */
+           do {
+               if (mptrtmp->lev.dnum == mptr->lev.dnum)
+                   mptrtmp->flags.unreachable = 0;
+               mptrtmp = mptrtmp->next;
+           } while (mptrtmp);
+       }
+    }
     mptr->flags.knownbones = 0;
     mptr->flags.sokosolved = In_sokoban(&u.uz) && !Sokoban;
     /* mptr->flags.bigroom retains previous value when hero can't see */
@@ -2190,17 +2215,21 @@ recalc_mapseen()
      * the ability to have non-dungeon glyphs float above the last known
      * dungeon glyph (i.e. items on fountains).
      */
-    if (!Levitation)
-       lastseentyp[u.ux][u.uy] = levl[u.ux][u.uy].typ;
-
     for (x = 1; x < COLNO; x++) {
        for (y = 0; y < ROWNO; y++) {
-           if (cansee(x, y)) {
-               mtmp = m_at(x, y);
-               lastseentyp[x][y] =
-             (mtmp && mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp)) ?
-                                   cmap_to_type(mtmp->mappearance) :
-                                   levl[x][y].typ;
+           if (cansee(x, y) || (x == u.ux && y == u.uy && !Levitation)) {
+               ltyp = levl[x][y].typ;
+               if (ltyp == DRAWBRIDGE_UP)
+                   switch (levl[x][y].drawbridgemask & DB_UNDER) {
+                       case DB_ICE:  ltyp = ICE; break;
+                       case DB_LAVA: ltyp = LAVAPOOL; break;
+                       case DB_MOAT: ltyp = MOAT; break;
+                       default:      ltyp = STONE; break;
+                   }
+               if ((mtmp = m_at(x, y)) != 0 &&
+                       mtmp->m_ap_type == M_AP_FURNITURE && canseemon(mtmp))
+                   ltyp = cmap_to_type(mtmp->mappearance);
+               lastseentyp[x][y] = ltyp;
            }
 
            switch (lastseentyp[x][y]) {
@@ -2323,6 +2352,7 @@ int roomno;
     mptr->msrooms[roomno].seen = 1;
 }
 
+/* #overview command */
 int
 dooverview()
 {
@@ -2330,30 +2360,51 @@ dooverview()
     return 0;
 }
 
+/* called for #overview or for end of game disclosure */
 void
 show_overview(why, reason)
 int why;       /* 0 => #overview command,
-                  1 or 2 => end of game disclosure (1: alive, 2: dead) */
+                  1 or 2 => final disclosure (1: hero lived, 2: hero died) */
 int reason;    /* how hero died; used when disclosing end-of-game level */
 {
     winid win;
-    mapseen *mptr;
     int lastdun = -1;
 
     /* lazy intialization */
     (void) recalc_mapseen();
 
     win = create_nhwindow(NHW_MENU);
+    /* show the endgame levels before the rest of the dungeon,
+       so that the Planes (dnum 5-ish) come out above main dungeon (dnum 0) */
+    if (In_endgame(&u.uz))
+       traverse_mapseenchn(TRUE, win, why, reason, &lastdun);
+    /* if game is over or we're not in the endgame yet, show the dungeon */
+    if (why > 0 || !In_endgame(&u.uz))
+       traverse_mapseenchn(FALSE, win, why, reason, &lastdun);
+    display_nhwindow(win, TRUE);
+    destroy_nhwindow(win);
+}
+
+/* display endgame levels or non-endgame levels, not both */
+STATIC_OVL void
+traverse_mapseenchn(viewendgame, win, why, reason, lastdun_p)
+boolean viewendgame;
+winid win;
+int why, reason, *lastdun_p;
+{
+    mapseen *mptr;
+    boolean showheader;
+
     for (mptr = mapseenchn; mptr; mptr = mptr->next) {
+       if (viewendgame ^ In_endgame(&mptr->lev)) continue;
+
        /* only print out info for a level or a dungeon if interest */
        if (why > 0 || interest_mapseen(mptr)) {
-           print_mapseen(win, mptr, why, reason,
-                         (boolean)(mptr->lev.dnum != lastdun));
-           lastdun = mptr->lev.dnum;
+           showheader = (boolean)(mptr->lev.dnum != *lastdun_p);
+           print_mapseen(win, mptr, why, reason, showheader);
+           *lastdun_p = mptr->lev.dnum;
        }
     }
-    display_nhwindow(win, TRUE);
-    destroy_nhwindow(win);
 }
 
 STATIC_OVL const char *
@@ -2393,6 +2444,29 @@ branch *br;
     return "(unknown)";
 }
 
+/* get the name of an endgame level; topten.c does something similar */
+STATIC_OVL const char *
+endgamelevelname(outbuf, indx)
+char *outbuf;
+int indx;
+{
+    const char *planename = 0;
+
+    *outbuf = '\0';
+    switch (indx) {
+    case -5: Strcpy(outbuf, "Astral Plane"); break;
+    case -4: planename = "Water"; break;
+    case -3: planename = "Fire"; break;
+    case -2: planename = "Air"; break;
+    case -1: planename = "Earth"; break;
+    }
+    if (planename)
+       Sprintf(outbuf, "Plane of %s", planename);
+    else if (!*outbuf)
+       Sprintf(outbuf, "unknown plane #%d", indx);
+    return outbuf;
+}
+
 STATIC_OVL const char *
 shop_string(rtype)
 int rtype;
@@ -2461,11 +2535,11 @@ char *outbuf;
                            } while (0)
 
 STATIC_OVL void
-print_mapseen(win, mptr, final, reason, printdun)
+print_mapseen(win, mptr, final, how, printdun)
 winid win;
 mapseen *mptr;
 int final;     /* 0: not final; 1: game over, alive; 2: game over, dead */
-int reason;    /* cause of death; only used if final==2 and mptr->lev==u.uz */
+int how;       /* cause of death; only used if final==2 and mptr->lev==u.uz */
 boolean printdun;
 {
     char buf[BUFSZ], tmpbuf[BUFSZ];
@@ -2492,24 +2566,13 @@ boolean printdun;
            Sprintf(buf, "%s: levels %d to %d", 
                    dungeons[mptr->lev.dnum].dname, depthstart,
                    depthstart + dungeons[mptr->lev.dnum].dunlev_ureached - 1);
-       putstr(win, ATR_INVERSE, buf);
+       putstr(win, !final ? ATR_INVERSE : 0, buf);
     }
 
     /* calculate level number */
     i = depthstart + mptr->lev.dlevel - 1;
-    if (Is_astralevel(&mptr->lev))
-       Sprintf(buf, "%sAstral Plane:", TAB);
-    else if (In_endgame(&mptr->lev))
-       /* Negative numbers are mildly confusing, since they are never
-        * shown to the player, except in wizard mode.  We could show
-        * "Level -1" for the earth plane, for example.  Instead,
-        * show "Plane 1" for the earth plane to differentiate from
-        * level 1.  There's not much to show, but maybe the player
-        * wants to #annotate them for some reason such as keeping
-        * track of encounters with the Wizard.
-        * [TODO: change this to be "Plane of <element-name>:"]
-        */
-       Sprintf(buf, "%sPlane %i:", TAB, -i);
+    if (In_endgame(&mptr->lev))
+       Sprintf(buf, "%s%s:", TAB, endgamelevelname(tmpbuf, i));
     else
        /* FIXME: when this branch has only one level (Ft.Ludios),
         * listing "Level 1:" for it might confuse inexperienced
@@ -2530,7 +2593,8 @@ boolean printdun;
     if (mptr->custom)
        Sprintf(eos(buf), " (%s)", mptr->custom);
     if (on_level(&u.uz, &mptr->lev))
-       Sprintf(eos(buf), " <- You %s here", !final ? "are" : "were");
+       Sprintf(eos(buf), " <- You %s here.",
+               (!final || (final == 1 && how == ASCENDED)) ? "are" : "were");
     putstr(win, !final ? ATR_BOLD : 0, buf);
 
     if (mptr->flags.forgot) return;
@@ -2539,7 +2603,6 @@ boolean printdun;
        buf[0] = 0;
                
        i = 0;  /* interest counter */
-
        /* List interests in an order vaguely corresponding to
         * how important they are.
         */
@@ -2592,6 +2655,9 @@ boolean printdun;
     } else if (mptr->flags.roguelevel) {
        Sprintf(buf, "%sA primitive area.", PREFIX);
 # endif
+    } else if (on_level(&mptr->lev, &qstart_level)) {
+       Sprintf(buf, "%sHome%s.", PREFIX,
+               mptr->flags.unreachable ? " (no way back...)" : "");
     } else if (mptr->flags.ludios) {
        /* presence of the ludios branch in #overview output indicates that
           the player has made it onto the level; presence of this annotation
@@ -2634,7 +2700,7 @@ boolean printdun;
            if (died_here) {
                /* disclosure occurs before bones creation, so listing dead
                   hero here doesn't give away whether bones are produced */
-               formatkiller(tmpbuf, sizeof tmpbuf, reason);
+               formatkiller(tmpbuf, sizeof tmpbuf, how);
                /* rephrase a few death reasons to work with "you" */
                (void) strsubst(tmpbuf, " himself", " yourself");
                (void) strsubst(tmpbuf, " herself", " yourself");
index 0f9082e403f346cc9031d486882ae1572ffeb97f..ed56ac9eef8b393dceae419c38e22ad314830e8e 100644 (file)
@@ -1638,6 +1638,7 @@ invocation_message()
            else Sprintf(buf, "under your %s", makeplural(body_part(FOOT)));
 
            You_feel("a strange vibration %s.", buf);
+           u.uevent.uvibrated = 1;
            if (otmp && otmp->spe == 7 && otmp->lamplit)
                pline("%s %s!", The(xname(otmp)),
                    Blind ? "throbs palpably" : "glows with a strange light");