diff -Naur include/dungeon.h include/dungeon.h --- include/dungeon.h 2003-12-07 18:39:14.000000000 -0500 +++ include/dungeon.h 2006-03-07 23:15:06.444579100 -0500 @@ -166,4 +166,68 @@ #endif /* MFLOPPY */ }; +/* types and structures for dungeon map recording + * + * It is designed to eliminate the need for an external notes file for some of + * the more mundane dungeon elements. "Where was the last altar I passed?" etc... + * Presumably the character can remember this sort of thing even if, months + * later in real time picking up an old save game, I can't. + * + * To be consistent, one can assume that this map is in the player's mind and + * has no physical correspondence (eliminating illiteracy/blind/hands/hands free + * concerns.) Therefore, this map is not exaustive nor detailed ("some fountains"). + * This makes it also subject to player conditions (amnesia). + */ + +/* Because clearly Nethack needs more ways to specify alignment */ +#define Amask2msa(x) ((x) == 4 ? 3 : (x) & AM_MASK) +#define Msa2amask(x) ((x) == 3 ? 4 : (x)) +#define MSA_NONE 0 /* unaligned or multiple alignments */ +#define MSA_LAWFUL 1 +#define MSA_NEUTRAL 2 +#define MSA_CHAOTIC 3 + +typedef struct mapseen_feat { + /* feature knowledge that must be calculated from levl array */ + Bitfield(nfount, 2); + Bitfield(nsink, 2); + Bitfield(naltar, 2); + Bitfield(msalign, 2); /* corresponds to MSA_* above */ + Bitfield(nthrone, 2); + Bitfield(ntree, 2); + /* water, lava, ice are too verbose so commented out for now */ + /* + Bitfield(water, 1); + Bitfield(lava, 1); + Bitfield(ice, 1); + */ + + /* calculated from rooms array */ + Bitfield(nshop, 2); + Bitfield(ntemple, 2); + Bitfield(shoptype, 5); + + Bitfield(forgot, 1); /* player has forgotten about this level? */ +} mapseen_feat; + +/* for mapseen->rooms */ +#define MSR_SEEN 1 + +/* what the player knows about a single dungeon level */ +/* initialized in mklev() */ +typedef struct mapseen { + struct mapseen *next; /* next map in the chain */ + branch *br; /* knows about branch via taking it in goto_level */ + d_level lev; /* corresponding dungeon level */ + + mapseen_feat feat; + + /* custom naming */ + char *custom; + unsigned custom_lth; + + /* maybe this should just be in struct mkroom? */ + schar rooms[(MAXNROFROOMS+1)*2]; +} mapseen; + #endif /* DUNGEON_H */ diff -Naur include/extern.h include/extern.h --- include/extern.h 2003-12-07 18:39:14.000000000 -0500 +++ include/extern.h 2006-03-05 18:14:40.484375000 -0500 @@ -507,6 +507,13 @@ #ifdef WIZARD E schar FDECL(print_dungeon, (BOOLEAN_P,schar *,xchar *)); #endif +E int NDECL(donamelevel); +E int NDECL(dooverview); +E void FDECL(forget_mapseen, (int)); +E void FDECL(init_mapseen, (d_level *)); +E void NDECL(recalc_mapseen); +E void FDECL(recbranch_mapseen, (d_level *, d_level *)); +E void FDECL(remdun_mapseen, (int)); /* ### eat.c ### */ diff -Naur include/rm.h include/rm.h --- include/rm.h 2003-12-07 18:39:14.000000000 -0500 +++ include/rm.h 2006-03-05 22:44:53.453125000 -0500 @@ -333,6 +333,7 @@ struct rm { int glyph; /* what the hero thinks is there */ schar typ; /* what is really there */ + Bitfield(styp, 6); /* last seen/touched dungeon typ */ uchar seenv; /* seen vector */ Bitfield(flags,5); /* extra information for typ */ Bitfield(horizontal,1); /* wall/door/etc is horiz. (more typ info) */ diff -Naur src/cmd.c src/cmd.c --- src/cmd.c 2003-12-07 18:39:14.000000000 -0500 +++ src/cmd.c 2006-03-09 21:05:32.453125000 -0500 @@ -107,6 +107,7 @@ STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); STATIC_PTR int NDECL(domonability); +STATIC_PTR int NDECL(dooverview_or_wiz_where); STATIC_PTR int NDECL(dotravel); # ifdef WIZARD STATIC_PTR int NDECL(wiz_wish); @@ -493,6 +494,17 @@ return 0; } +STATIC_PTR int +dooverview_or_wiz_where() +{ +#ifdef WIZARD + if (wizard) return wiz_where(); + else +#endif + dooverview(); + return 0; +} + #ifdef WIZARD /* ^W command - wish for something */ @@ -1364,9 +1376,8 @@ {C('i'), TRUE, wiz_identify}, #endif {C('l'), TRUE, doredraw}, /* if number_pad is set */ -#ifdef WIZARD - {C('o'), TRUE, wiz_where}, -#endif + {C('n'), TRUE, donamelevel}, /* if number_pad is set */ + {C('o'), TRUE, dooverview_or_wiz_where}, /* depending on wizard status */ {C('p'), TRUE, doprev_message}, {C('r'), TRUE, doredraw}, {C('t'), TRUE, dotele}, @@ -1476,6 +1487,7 @@ struct ext_func_tab extcmdlist[] = { {"adjust", "adjust inventory letters", doorganize, TRUE}, + {"annotate", "name current level", donamelevel, TRUE}, {"chat", "talk to someone", dotalk, TRUE}, /* converse? */ {"conduct", "list which challenges you have adhered to", doconduct, TRUE}, {"dip", "dip an object into something", dodip, FALSE}, @@ -1488,6 +1500,7 @@ {"monster", "use a monster's special ability", domonability, TRUE}, {"name", "name an item or type of object", ddocall, TRUE}, {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE}, + {"overview", "show an overview of the dungeon", dooverview, TRUE}, {"pray", "pray to the gods for help", dopray, TRUE}, {"quit", "exit without saving current game", done2, TRUE}, #ifdef STEED diff -Naur src/display.c src/display.c --- src/display.c 2003-12-07 18:39:14.000000000 -0500 +++ src/display.c 2006-03-01 21:44:53.687500000 -0500 @@ -186,6 +186,7 @@ if (level.flags.hero_memory) lev->glyph = glyph; if (show) show_glyph(x,y, glyph); + lev->styp = lev->typ; } /* diff -Naur src/do.c src/do.c --- src/do.c 2003-12-07 18:39:14.000000000 -0500 +++ src/do.c 2006-03-05 21:42:43.296875000 -0500 @@ -1041,6 +1041,7 @@ keepdogs(FALSE); if (u.uswallow) /* idem */ u.uswldtim = u.uswallow = 0; + recalc_mapseen(); /* recalculate map overview before we leave the level */ /* * We no longer see anything on the level. Make sure that this * follows u.uswallow set to null since uswallow overrides all @@ -1076,6 +1077,11 @@ #ifdef USE_TILES substitute_tiles(newlevel); #endif + /* record this level transition as a potential seen branch unless using + * some non-standard means of transportation (level teleport). + */ + if ((at_stairs || falling || portal) && (u.uz.dnum != newlevel->dnum)) + recbranch_mapseen(&u.uz, newlevel); assign_level(&u.uz0, &u.uz); assign_level(&u.uz, newlevel); assign_level(&u.utolev, newlevel); diff -Naur src/dungeon.c src/dungeon.c --- src/dungeon.c 2003-12-07 18:39:14.000000000 -0500 +++ src/dungeon.c 2006-03-11 08:18:41.906250000 -0500 @@ -5,6 +5,7 @@ #include "hack.h" #include "dgn_file.h" #include "dlb.h" +#include "display.h" #ifdef OVL1 @@ -55,6 +56,16 @@ STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *)); #endif +mapseen *mapseenchn = (struct mapseen *)0; +STATIC_DCL void FDECL(free_mapseen, (mapseen *)); +STATIC_DCL mapseen *FDECL(load_mapseen, (int)); +STATIC_DCL void FDECL(save_mapseen, (int, mapseen *)); +STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *)); +STATIC_DCL void FDECL(print_mapseen, (winid,mapseen *,boolean)); +STATIC_DCL boolean FDECL(interest_mapseen, (mapseen *)); +STATIC_DCL char *FDECL(seen_string, (xchar x, const char *)); +STATIC_DCL const char *FDECL(br_string2, (branch *)); + #ifdef DEBUG #define DD dungeons[i] STATIC_DCL void NDECL(dumpit); @@ -116,6 +127,7 @@ boolean perform_write, free_data; { branch *curr, *next; + mapseen *curr_ms, *next_ms; int count; if (perform_write) { @@ -136,6 +148,13 @@ bwrite(fd, (genericptr_t) level_info, (unsigned)count * sizeof (struct linfo)); bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos); + + for (count = 0, curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next) + count++; + bwrite(fd, (genericptr_t) &count, sizeof(count)); + + for (curr_ms = mapseenchn; curr_ms; curr_ms = curr_ms->next) + save_mapseen(fd, curr_ms); } if (free_data) { @@ -144,6 +163,13 @@ free((genericptr_t) curr); } branches = 0; + for (curr_ms = mapseenchn; curr_ms; curr_ms = next_ms) { + next_ms = curr_ms->next; + if (curr_ms->custom) + free((genericptr_t)curr_ms->custom); + free((genericptr_t) curr_ms); + } + mapseenchn = 0; } } @@ -153,6 +179,7 @@ int fd; { branch *curr, *last; + mapseen *curr_ms, *last_ms; int count, i; mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns)); @@ -179,6 +206,18 @@ panic("level information count larger (%d) than allocated size", count); mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo)); mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos); + + mread(fd, (genericptr_t) &count, sizeof(count)); + last_ms = (mapseen *) 0; + for (i = 0; i < count; i++) { + curr_ms = load_mapseen(fd); + curr_ms->next = (mapseen *) 0; + if (last_ms) + last_ms->next = curr_ms; + else + mapseenchn = curr_ms; + last_ms = curr_ms; + } } static void @@ -1741,4 +1780,606 @@ #endif /* OVL1 */ +/* Record that the player knows about a branch from a level. This function + * will determine whether or not it was a "real" branch that was taken. + * This function should not be called for a transition done via level + * teleport or via the Eye. + */ +void +recbranch_mapseen(source, dest) + d_level *source; + d_level *dest; +{ + mapseen *mptr; + branch* br; + + /* not a branch */ + if (source->dnum == dest->dnum) return; + + /* we only care about forward branches */ + for (br = branches; br; br = br->next) { + if (on_level(source, &br->end1) && on_level(dest, &br->end2)) break; + if (on_level(source, &br->end2) && on_level(dest, &br->end1)) return; + } + + /* branch not found, so not a real branch. */ + if (!br) return; + + if (mptr = find_mapseen(source)) { + if (mptr->br && br != mptr->br) + impossible("Two branches on the same level?"); + mptr->br = br; + } else { + impossible("Can't note branch for unseen level (%d, %d)", + source->dnum, source->dlevel); + } +} + +/* 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 */ + int len; + + if (!(mptr = find_mapseen(&u.uz))) return 0; + + Sprintf(qbuf,"What do you want to call this dungeon level? "); + getlin(qbuf, nbuf); + + if (index(nbuf, '\033')) return 0; + + len = strlen(nbuf) + 1; + if (mptr->custom) { + free((genericptr_t)mptr->custom); + mptr->custom = (char *)0; + mptr->custom_lth = 0; + } + + if (*nbuf) { + mptr->custom = (char *) alloc(sizeof(char) * len); + mptr->custom_lth = len; + strcpy(mptr->custom, nbuf); + } + + return 0; +} + +/* find the particular mapseen object in the chain */ +/* may return 0 */ +STATIC_OVL mapseen * +find_mapseen(lev) +d_level *lev; +{ + mapseen *mptr; + + for (mptr = mapseenchn; mptr; mptr = mptr->next) + if (on_level(&(mptr->lev), lev)) break; + + return mptr; +} + +void +forget_mapseen(ledger_no) +int ledger_no; +{ + mapseen *mptr; + + for (mptr = mapseenchn; mptr; mptr = mptr->next) + if (dungeons[mptr->lev.dnum].ledger_start + + mptr->lev.dlevel == ledger_no) break; + + /* if not found, then nothing to forget */ + if (mptr) { + mptr->feat.forgot = 1; + mptr->br = (branch *)0; + + /* custom names are erased, not forgotten until revisted */ + if (mptr->custom) { + mptr->custom_lth = 0; + free((genericptr_t)mptr->custom); + mptr->custom = (char *)0; + } + + memset((genericptr_t) mptr->rooms, 0, sizeof(mptr->rooms)); + } +} + +STATIC_OVL void +save_mapseen(fd, mptr) +int fd; +mapseen *mptr; +{ + branch *curr; + int count; + + count = 0; + for (curr = branches; curr; curr = curr->next) { + if (curr == mptr->br) break; + count++; + } + + bwrite(fd, (genericptr_t) &count, sizeof(int)); + bwrite(fd, (genericptr_t) &mptr->lev, sizeof(d_level)); + bwrite(fd, (genericptr_t) &mptr->feat, sizeof(mapseen_feat)); + bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof(unsigned)); + if (mptr->custom_lth) + bwrite(fd, (genericptr_t) mptr->custom, + sizeof(char) * mptr->custom_lth); + bwrite(fd, (genericptr_t) &mptr->rooms, sizeof(mptr->rooms)); +} + +STATIC_OVL mapseen * +load_mapseen(fd) +int fd; +{ + int branchnum, count; + mapseen *load; + branch *curr; + + load = (mapseen *) alloc(sizeof(mapseen)); + mread(fd, (genericptr_t) &branchnum, sizeof(int)); + + count = 0; + for (curr = branches; curr; curr = curr->next) { + if (count == branchnum) break; + count++; + } + load->br = curr; + + mread(fd, (genericptr_t) &load->lev, sizeof(d_level)); + mread(fd, (genericptr_t) &load->feat, sizeof(mapseen_feat)); + mread(fd, (genericptr_t) &load->custom_lth, sizeof(unsigned)); + if (load->custom_lth > 0) { + load->custom = (char *) alloc(sizeof(char) * load->custom_lth); + mread(fd, (genericptr_t) load->custom, + sizeof(char) * load->custom_lth); + } else load->custom = (char *) 0; + mread(fd, (genericptr_t) &load->rooms, sizeof(load->rooms)); + + return load; +} + +/* Remove all mapseen objects for a particular dnum. + * Useful during quest expulsion to remove quest levels. + */ +void +remdun_mapseen(dnum) +int dnum; +{ + mapseen *mptr, *prev; + + prev = mapseenchn; + if (!prev) return; + mptr = prev->next; + + for (; mptr; prev = mptr, mptr = mptr->next) { + if (mptr->lev.dnum == dnum) { + prev->next = mptr->next; + free((genericptr_t) mptr); + mptr = prev; + } + } +} + +void +init_mapseen(lev) +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; + mapseen *init; + mapseen *old; + + init = (mapseen *) alloc(sizeof(mapseen)); + (void) memset((genericptr_t)init, 0, sizeof(mapseen)); + init->lev.dnum = lev->dnum; + init->lev.dlevel = lev->dlevel; + + if (!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; + } + + old = mptr->next; + mptr->next = init; + init->next = old; +} + +#define INTEREST(feat) \ + ((feat).nfount) || \ + ((feat).nsink) || \ + ((feat).nthrone) || \ + ((feat).naltar) || \ + ((feat).nshop) || \ + ((feat).ntemple) || \ + ((feat).ntree) + /* + || ((feat).water) || \ + ((feat).ice) || \ + ((feat).lava) + */ + +/* returns true if this level has something interesting to print out */ +STATIC_OVL boolean +interest_mapseen(mptr) +mapseen *mptr; +{ + return (on_level(&u.uz, &mptr->lev) || (!mptr->feat.forgot) && ( + INTEREST(mptr->feat) || + (mptr->custom) || + (mptr->br) + )); +} + +/* recalculate mapseen for the current level */ +void +recalc_mapseen() +{ + mapseen *mptr; + struct monst *shkp; + int x, y, ridx; + + /* 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 + */ + if (!(mptr = find_mapseen(&u.uz))) return; + + /* reset all features */ + memset((genericptr_t) &mptr->feat, 0, sizeof(mapseen_feat)); + + /* track rooms the hero is in */ + for (x = 0; x < sizeof(u.urooms); x++) { + if (!u.urooms[x]) continue; + + ridx = u.urooms[x] - ROOMOFFSET; + if (rooms[ridx].rtype < SHOPBASE || + ((shkp = shop_keeper(u.urooms[x])) && inhishop(shkp))) + mptr->rooms[ridx] |= MSR_SEEN; + else + /* shops without shopkeepers are no shops at all */ + mptr->rooms[ridx] &= ~MSR_SEEN; + } + + /* recalculate room knowledge: for now, just shops and temples + * this could be extended to an array of 0..SHOPBASE + */ + for (x = 0; x < sizeof(mptr->rooms); x++) { + if (mptr->rooms[x] & MSR_SEEN) { + if (rooms[x].rtype >= SHOPBASE) { + if (!mptr->feat.nshop) + mptr->feat.shoptype = rooms[x].rtype; + else if (mptr->feat.shoptype != rooms[x].rtype) + mptr->feat.shoptype = 0; + mptr->feat.nshop = min(mptr->feat.nshop + 1, 3); + } else if (rooms[x].rtype == TEMPLE) + /* altar and temple alignment handled below */ + mptr->feat.ntemple = min(mptr->feat.ntemple + 1, 3); + } + } + + /* Update styp with typ if and only if it is in sight or the hero can + * feel it on their current location (i.e. not levitating). This *should* + * give the "last known typ" for each dungeon location. (At the very least, + * it's a better assumption than determining what the player knows from + * the glyph and the typ (which is isn't quite enough information in some + * cases). + * + * It was reluctantly added to struct rm to track. Alternatively + * we could track "features" and then update them all here, and keep + * track of when new features are created or destroyed, but this + * seemed the most elegant, despite adding more data to struct rm. + * + * Although no current windowing systems (can) do this, this would add the + * ability to have non-dungeon glyphs float above the last known dungeon + * glyph (i.e. items on fountains). + * + * (vision-related styp update done in loop below) + */ + if (!Levitation) + levl[u.ux][u.uy].styp = levl[u.ux][u.uy].typ; + + for (x = 0; x < COLNO; x++) { + for (y = 0; y < ROWNO; y++) { + /* update styp from viz_array */ + if (viz_array[y][x] & IN_SIGHT) + levl[x][y].styp = levl[x][y].typ; + + switch (levl[x][y].styp) { + /* + case ICE: + mptr->feat.ice = 1; + break; + case POOL: + case MOAT: + case WATER: + mptr->feat.water = 1; + break; + case LAVAPOOL: + mptr->feat.lava = 1; + break; + */ + case TREE: + mptr->feat.ntree = min(mptr->feat.ntree + 1, 3); + break; + case FOUNTAIN: + mptr->feat.nfount = min(mptr->feat.nfount + 1, 3); + break; + case THRONE: + mptr->feat.nthrone = min(mptr->feat.nthrone + 1, 3); + break; + case SINK: + mptr->feat.nsink = min(mptr->feat.nsink + 1, 3); + break; + case ALTAR: + if (!mptr->feat.naltar) + mptr->feat.msalign = Amask2msa(levl[x][y].altarmask); + else if (mptr->feat.msalign != Amask2msa(levl[x][y].altarmask)) + mptr->feat.msalign = MSA_NONE; + + mptr->feat.naltar = min(mptr->feat.naltar + 1, 3); + break; + } + } + } +} + +int +dooverview() +{ + winid win; + mapseen *mptr; + boolean first; + boolean printdun; + int lastdun; + + first = TRUE; + + /* lazy intialization */ + (void) recalc_mapseen(); + + win = create_nhwindow(NHW_MENU); + + for (mptr = mapseenchn; mptr; mptr = mptr->next) { + + /* only print out info for a level or a dungeon if interest */ + if (interest_mapseen(mptr)) { + printdun = (first || lastdun != mptr->lev.dnum); + /* if (!first) putstr(win, 0, ""); */ + print_mapseen(win, mptr, printdun); + + if (printdun) { + first = FALSE; + lastdun = mptr->lev.dnum; + } + } + } + + display_nhwindow(win, TRUE); + destroy_nhwindow(win); + + return 0; +} + +STATIC_OVL char * +seen_string(x, obj) +xchar x; +const char *obj; +{ + /* players are computer scientists: 0, 1, 2, n */ + switch(x) { + case 0: return "no"; + /* an() returns too much. index is ok in this case */ + case 1: return index(vowels, *obj) ? "an" : "a"; + case 2: return "some"; + case 3: return "many"; + } + + return "(unknown)"; +} + +/* better br_string */ +STATIC_OVL const char * +br_string2(br) +branch *br; +{ + /* Special case: quest portal says closed if kicked from quest */ + boolean closed_portal = + (br->end2.dnum == quest_dnum && u.uevent.qexpelled); + switch(br->type) + { + case BR_PORTAL: return closed_portal ? "Sealed portal" : "Portal"; + case BR_NO_END1: return "Connection"; + case BR_NO_END2: return (br->end1_up) ? "One way stairs up" : + "One way stairs down"; + case BR_STAIR: return (br->end1_up) ? "Stairs up" : "Stairs down"; + } + + return "(unknown)"; +} + +STATIC_OVL const char* +shop_string(rtype) +int rtype; +{ + /* Yuck, redundancy...but shclass.name doesn't cut it as a noun */ + switch(rtype) { + case SHOPBASE: + return "general store"; + case ARMORSHOP: + return "armor shop"; + case SCROLLSHOP: + return "scroll shop"; + case POTIONSHOP: + return "potion shop"; + case WEAPONSHOP: + return "weapon shop"; + case FOODSHOP: + return "delicatessen"; + case RINGSHOP: + return "jewelers"; + case WANDSHOP: + return "wand shop"; + case BOOKSHOP: + return "bookstore"; + case CANDLESHOP: + return "lighting shop"; + default: + /* In case another patch adds a shop type that doesn't exist, + * do something reasonable like "a shop". + */ + return "shop"; + } +} + +/* some utility macros for print_mapseen */ +#define TAB " " +#define BULLET "" +#define PREFIX TAB TAB BULLET +#define COMMA (i++ > 0 ? ", " : PREFIX) +#define ADDNTOBUF(nam, var) { if (var) \ + Sprintf(eos(buf), "%s%s " nam "%s", COMMA, seen_string((var), (nam)), \ + ((var) != 1 ? "s" : "")); } +#define ADDTOBUF(nam, var) { if (var) Sprintf(eos(buf), "%s " nam, COMMA); } + +STATIC_OVL void +print_mapseen(win, mptr, printdun) +winid win; +mapseen *mptr; +boolean printdun; +{ + char buf[BUFSZ]; + int i, depthstart; + + /* Damnable special cases */ + /* The quest and knox should appear to be level 1 to match + * other text. + */ + if (mptr->lev.dnum == quest_dnum || mptr->lev.dnum == knox_level.dnum) + depthstart = 1; + else + depthstart = dungeons[mptr->lev.dnum].depth_start; + + if (printdun) { + /* Sokoban lies about dunlev_ureached and we should + * suppress the negative numbers in the endgame. + */ + if (dungeons[mptr->lev.dnum].dunlev_ureached == 1 || + mptr->lev.dnum == sokoban_dnum || In_endgame(&mptr->lev)) + Sprintf(buf, "%s:", dungeons[mptr->lev.dnum].dname); + else + 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); + } + + /* calculate level number */ + i = depthstart + mptr->lev.dlevel - 1; + if (Is_astralevel(&mptr->lev)) + Sprintf(buf, TAB "Astral Plane:"); + 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 bizarre reason. + */ + Sprintf(buf, TAB "Plane %i:", -i); + else + Sprintf(buf, TAB "Level %d:", i); + +#ifdef WIZARD + /* wizmode prints out proto dungeon names for clarity */ + if (wizard) { + s_level *slev; + if (slev = Is_special(&mptr->lev)) + Sprintf(eos(buf), " [%s]", slev->proto); + } +#endif + + if (mptr->custom) + Sprintf(eos(buf), " (%s)", mptr->custom); + + /* print out glyph or something more interesting? */ + Sprintf(eos(buf), "%s", on_level(&u.uz, &mptr->lev) ? + " <- You are here" : ""); + putstr(win, ATR_BOLD, buf); + + if (mptr->feat.forgot) return; + + if (INTEREST(mptr->feat)) { + buf[0] = 0; + + i = 0; /* interest counter */ + + /* List interests in an order vaguely corresponding to + * how important they are. + */ + if (mptr->feat.nshop > 1) + ADDNTOBUF("shop", mptr->feat.nshop) + else if (mptr->feat.nshop == 1) + Sprintf(eos(buf), "%s%s", COMMA, + an(shop_string(mptr->feat.shoptype))); + + /* Temples + non-temple altars get munged into just "altars" */ + if (!mptr->feat.ntemple || mptr->feat.ntemple != mptr->feat.naltar) + ADDNTOBUF("altar", mptr->feat.naltar) + else + ADDNTOBUF("temple", mptr->feat.ntemple) + + /* only print out altar's god if they are all to your god */ + if (Amask2align(Msa2amask(mptr->feat.msalign)) == u.ualign.type) + Sprintf(eos(buf), " to %s", align_gname(u.ualign.type)); + + ADDNTOBUF("fountain", mptr->feat.nfount) + ADDNTOBUF("sink", mptr->feat.nsink) + ADDNTOBUF("throne", mptr->feat.nthrone) + ADDNTOBUF("tree", mptr->feat.ntree); + /* + ADDTOBUF("water", mptr->feat.water) + ADDTOBUF("lava", mptr->feat.lava) + ADDTOBUF("ice", mptr->feat.ice) + */ + + /* capitalize afterwards */ + i = strlen(PREFIX); + buf[i] = toupper(buf[i]); + + putstr(win, 0, buf); + } + + /* print out branches */ + if (mptr->br) { + Sprintf(buf, PREFIX "%s to %s", br_string2(mptr->br), + dungeons[mptr->br->end2.dnum].dname); + + /* since mapseen objects are printed out in increasing order + * of dlevel, clarify which level this branch is going to + * if the branch goes upwards. Unless it's the end game + */ + if (mptr->br->end1_up && !In_endgame(&(mptr->br->end2))) + Sprintf(eos(buf), ", level %d", depth(&(mptr->br->end2))); + putstr(win, 0, buf); + } +} + /*dungeon.c*/ diff -Naur src/mklev.c src/mklev.c --- src/mklev.c 2003-12-07 18:39:14.000000000 -0500 +++ src/mklev.c 2006-03-11 08:26:07.828125000 -0500 @@ -922,6 +922,7 @@ { struct mkroom *croom; + init_mapseen(&u.uz); if(getbones()) return; in_mklev = TRUE; makelevel(); diff -Naur src/quest.c src/quest.c --- src/quest.c 2003-12-07 18:39:14.000000000 -0500 +++ src/quest.c 2006-03-05 21:43:21.562500000 -0500 @@ -157,6 +157,7 @@ if (seal) { /* remove the portal to the quest - sealing it off */ int reexpelled = u.uevent.qexpelled; u.uevent.qexpelled = 1; + remdun_mapseen(quest_dnum); /* Delete the near portal now; the far (main dungeon side) portal will be deleted as part of arrival on that level. If monster movement is in progress, any who haven't moved diff -Naur src/read.c src/read.c --- src/read.c 2003-12-07 18:39:14.000000000 -0500 +++ src/read.c 2006-03-05 21:46:13.937500000 -0500 @@ -521,6 +521,7 @@ levl[zx][zy].seenv = 0; levl[zx][zy].waslit = 0; levl[zx][zy].glyph = cmap_to_glyph(S_stone); + levl[zx][zy].styp = STONE; } } @@ -581,6 +582,7 @@ count = ((count * percent) + 50) / 100; for (i = 0; i < count; i++) { level_info[indices[i]].flags |= FORGOTTEN; + forget_mapseen(indices[i]); } } diff -Naur src/vision.c src/vision.c --- src/vision.c 2003-12-07 18:39:14.000000000 -0500 +++ src/vision.c 2006-03-05 21:43:57.093750000 -0500 @@ -806,6 +806,8 @@ /* Set the new min and max pointers. */ viz_rmin = next_rmin; viz_rmax = next_rmax; + + recalc_mapseen(); } diff -Naur util/makedefs.c util/makedefs.c --- util/makedefs.c 2003-12-07 18:39:14.000000000 -0500 +++ util/makedefs.c 2006-03-05 21:44:17.687500000 -0500 @@ -652,6 +652,7 @@ #ifdef WIZARD "debug mode", #endif + "dungeon map overview patch", #ifdef ELBERETH "Elbereth", #endif