diff --git a/doc/fixes36.2 b/doc/fixes36.2 index 9e6b004bb..51e6bfa69 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -293,6 +293,7 @@ changing Sting's description to be "(weapon in hand) (light blue aura)" was fix bit-use collision between WC2_TERM_SIZE and WC2_RESET_STATUS in include/winprocs.h following a recent merge fix foxen pluralization again after underflow remedy reintroduced the problem +fix "placing monster over another?" warning for vault guards tty: turn off an optimization that is the suspected cause of Windows reported partial status lines following level changes tty: ensure that current status fields are always copied to prior status diff --git a/src/mon.c b/src/mon.c index a22db1a1a..de037e42b 100644 --- a/src/mon.c +++ b/src/mon.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 mon.c $NHDT-Date: 1543455827 2018/11/29 01:43:47 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.272 $ */ +/* NetHack 3.6 mon.c $NHDT-Date: 1544658160 2018/12/12 23:42:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.274 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -48,8 +48,6 @@ struct monst *mtmp; boolean chk_geno; const char *msg; { - if (DEADMONSTER(mtmp)) - return; if (mtmp->data < &mons[LOW_PM] || mtmp->data >= &mons[NUMMONS]) { impossible("illegal mon data %s; mnum=%d (%s)", fmt_ptr((genericptr_t) mtmp->data), mtmp->mnum, msg); @@ -61,6 +59,15 @@ const char *msg; mtmp->mnum, mndx, msg); mtmp->mnum = mndx; } + if (DEADMONSTER(mtmp)) { +#if 0 + /* bad if not fmons list or if not vault guard */ + if (strcmp(msg, "fmon") || !mtmp->isgd) + impossible("dead monster on %s; %s at <%d,%d>", + msg, mons[mndx].mname, mtmp->mx, mtmp->my); +#endif + return; + } if (chk_geno && (mvitals[mndx].mvflags & G_GENOD) != 0) impossible("genocided %s in play (%s)", mons[mndx].mname, msg); } @@ -84,9 +91,11 @@ mon_sanity_check() struct monst *mtmp, *m; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { + /* dead monsters should still have sane data */ sanity_check_single_mon(mtmp, TRUE, "fmon"); - if (DEADMONSTER(mtmp)) + if (DEADMONSTER(mtmp) && !mtmp->isgd) continue; + x = mtmp->mx, y = mtmp->my; if (!isok(x, y) && !(mtmp->isgd && x == 0 && y == 0)) { impossible("mon (%s) claims to be at <%d,%d>?", @@ -713,10 +722,20 @@ movemon() break; } nmtmp = mtmp->nmon; - /* one dead monster needs to perform a move after death: - vault guard whose temporary corridor is still on the map */ - if (mtmp->isgd && !mtmp->mx && DEADMONSTER(mtmp)) - (void) gd_move(mtmp); + /* one dead monster needs to perform a move after death: vault + guard whose temporary corridor is still on the map; live + guards who have led the hero back to civilization get moved + off the map too; gd_move() decides whether the temporary + corridor can be removed and guard discarded (via clearing + mon->isgd flag so that dmonsfree() will get rid of mon) */ + if (mtmp->isgd && !mtmp->mx) { + /* parked at <0,0>; eventually isgd should get set to false */ + if (monstermoves > mtmp->mlstmv) { + (void) gd_move(mtmp); + mtmp->mlstmv = monstermoves; + } + continue; + } if (DEADMONSTER(mtmp)) continue; @@ -1766,7 +1785,7 @@ struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ mtmp->mtrapped = 0; mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ relobj(mtmp, 0, FALSE); - if (onmap) { + if (onmap || mtmp == level.monsters[0][0]) { if (mtmp->wormno) remove_worm(mtmp); else diff --git a/src/objnam.c b/src/objnam.c index ce828c355..6a805852d 100644 --- a/src/objnam.c +++ b/src/objnam.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 objnam.c $NHDT-Date: 1544492043 2018/12/11 01:34:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.229 $ */ +/* NetHack 3.6 objnam.c $NHDT-Date: 1544520422 2018/12/11 09:27:02 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.230 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1220,7 +1220,7 @@ unsigned doname_flags; Strcpy(tmpbuf, prefix + 2); /* set prefix[] to "", "a ", or "an " */ (void) just_an(prefix, *tmpbuf ? tmpbuf : bp); - /* apprend remainder of original prefix */ + /* append remainder of original prefix */ Strcat(prefix, tmpbuf); } @@ -1629,7 +1629,7 @@ const char *str; impossible("Alphabet soup: 'an(%s)'.", str ? "\"\"" : ""); return strcpy(buf, "an []"); } - just_an(buf, str); + (void) just_an(buf, str); return strcat(buf, str); } diff --git a/src/steed.c b/src/steed.c index 65e5ebbae..9eaf8f4c0 100644 --- a/src/steed.c +++ b/src/steed.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 steed.c $NHDT-Date: 1543543362 2018/11/30 02:02:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.59 $ */ +/* NetHack 3.6 steed.c $NHDT-Date: 1544608468 2018/12/12 09:54:28 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ @@ -742,6 +742,12 @@ place_monster(mon, x, y) struct monst *mon; int x, y; { + /* normal map bounds are <1..COLNO-1,0..ROWNO-1> but sometimes + vault guards (either living or dead) are parked at <0,0> */ + if (!isok(x, y) && (x != 0 || y != 0 || !mon->isgd)) { + impossible("trying to place monster at <%d,%d>", x, y); + x = y = 0; + } if (mon == u.usteed /* special case is for convoluted vault guard handling */ || (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) { diff --git a/src/vault.c b/src/vault.c index 7e47577e2..0e811d117 100644 --- a/src/vault.c +++ b/src/vault.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 vault.c $NHDT-Date: 1542765368 2018/11/21 01:56:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.55 $ */ +/* NetHack 3.6 vault.c $NHDT-Date: 1544608469 2018/12/12 09:54:29 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.57 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -10,6 +10,7 @@ STATIC_DCL struct monst *NDECL(findgd); STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(blackout, (int, int)); STATIC_DCL void FDECL(restfakecorr, (struct monst *)); +STATIC_DCL void FDECL(parkguard, (struct monst *)); STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *, int, int)); STATIC_DCL void FDECL(move_gold, (struct obj *, int)); STATIC_DCL void FDECL(wallify_vault, (struct monst *)); @@ -22,8 +23,8 @@ struct monst *mtmp; if (!mtmp->mextra) mtmp->mextra = newmextra(); if (!EGD(mtmp)) { - EGD(mtmp) = (struct egd *) alloc(sizeof(struct egd)); - (void) memset((genericptr_t) EGD(mtmp), 0, sizeof(struct egd)); + EGD(mtmp) = (struct egd *) alloc(sizeof (struct egd)); + (void) memset((genericptr_t) EGD(mtmp), 0, sizeof (struct egd)); } } @@ -38,6 +39,9 @@ struct monst *mtmp; mtmp->isgd = 0; } +/* try to remove the temporary corridor (from vault to rest of map) being + maintained by guard 'grd'; if guard is still in it, removal will fail, + to be tried again later */ STATIC_OVL boolean clear_fcorr(grd, forceshow) struct monst *grd; @@ -53,10 +57,14 @@ boolean forceshow; if (!on_level(&egrd->gdlevel, &u.uz)) return TRUE; + /* note: guard remains on 'fmons' list (alive or dead, at off-map + coordinate <0,0>), until temporary corridor from vault back to + civilization has been removed */ while ((fcbeg = egrd->fcbeg) < egrd->fcend) { fcx = egrd->fakecorr[fcbeg].fx; fcy = egrd->fakecorr[fcbeg].fy; - if ((DEADMONSTER(grd) || !in_fcorridor(grd, u.ux, u.uy)) && egrd->gddone) + if ((DEADMONSTER(grd) || !in_fcorridor(grd, u.ux, u.uy)) + && egrd->gddone) forceshow = TRUE; if ((u.ux == fcx && u.uy == fcy && !DEADMONSTER(grd)) || (!forceshow && couldsee(fcx, fcy)) @@ -137,6 +145,26 @@ struct monst *grd; } } +/* move guard--dead to alive--to <0,0> until temporary corridor is removed */ +STATIC_OVL void +parkguard(grd) +struct monst *grd; +{ + /* either guard is dead or will now be treated as if so; + monster traversal loops should skip it */ + if (grd == context.polearm.hitmon) + context.polearm.hitmon = 0; + if (grd->mx) { + remove_monster(grd->mx, grd->my); + newsym(grd->mx, grd->my); + place_monster(grd, 0, 0); + /* [grd->mx,my just got set to 0,0 by place_monster(), so this + just sets EGD(grd)->ogx,ogy to 0,0 too; is that what we want?] */ + EGD(grd)->ogx = grd->mx; + EGD(grd)->ogy = grd->my; + } +} + /* called in mon.c */ boolean grddead(grd) @@ -147,16 +175,8 @@ struct monst *grd; if (!dispose) { /* destroy guard's gold; drop any other inventory */ relobj(grd, 0, FALSE); - /* guard is dead; monster traversal loops should skip it */ grd->mhp = 0; - if (grd == context.polearm.hitmon) - context.polearm.hitmon = 0; - /* see comment by newpos in gd_move() */ - remove_monster(grd->mx, grd->my); - newsym(grd->mx, grd->my); - place_monster(grd, 0, 0); - EGD(grd)->ogx = grd->mx; - EGD(grd)->ogy = grd->my; + parkguard(grd); dispose = clear_fcorr(grd, TRUE); } if (dispose) @@ -226,13 +246,12 @@ invault() u.uinvault = 0; return; } - vaultroom -= ROOMOFFSET; guard = findgd(); if (++u.uinvault % VAULT_GUARD_TIME == 0 && !guard) { /* if time ok and no guard now. */ - char buf[BUFSZ] = DUMMY; + char buf[BUFSZ]; register int x, y, dd, gx, gy; int lx = 0, ly = 0; long umoney; @@ -387,6 +406,7 @@ invault() nomul(0); unmul((char *) 0); } + buf[0] = '\0'; trycount = 5; do { getlin(Deaf ? "You are required to supply your name. -" @@ -401,7 +421,7 @@ invault() } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") - || !strcmpi(buf, "Creosote")) { + || !strcmpi(buf, "Creosote")) { /* Discworld */ if (!mvitals[PM_CROESUS].died) { if (Deaf) { if (!Blind) @@ -468,9 +488,9 @@ invault() EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; - if (IS_WALL(levl[x][y].typ)) + if (IS_WALL(levl[x][y].typ)) { EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ; - else { /* the initial guard location is a dug door */ + } else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; @@ -603,27 +623,29 @@ register struct monst *grd; int x, y, nx, ny, m, n; int dx, dy, gx, gy, fci; uchar typ; + struct rm *crm; struct fakecorridor *fcp; register struct egd *egrd = EGD(grd); - struct rm *crm; - boolean goldincorridor = FALSE, - u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE, - grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ? TRUE : FALSE; - boolean disappear_msg_seen = FALSE, semi_dead = (DEADMONSTER(grd)); - long umoney = money_cnt(invent); - register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); - boolean see_guard, newspot = FALSE; + long umoney = 0L; + boolean goldincorridor = FALSE, u_in_vault = FALSE, grd_in_vault = FALSE, + disappear_msg_seen = FALSE, semi_dead = DEADMONSTER(grd), + u_carry_gold = FALSE, newspot = FALSE, see_guard; if (!on_level(&(egrd->gdlevel), &u.uz)) return -1; nx = ny = m = n = 0; + if (semi_dead || !grd->mx || egrd->gddone) { + egrd->gddone = 1; + goto cleanup; + } + debugpline1("gd_move: %s guard", grd->mpeaceful ? "peaceful" : "hostile"); + + u_in_vault = vault_occupied(u.urooms) ? TRUE : FALSE; + grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT) ? TRUE : FALSE; if (!u_in_vault && !grd_in_vault) wallify_vault(grd); + if (!grd->mpeaceful) { - if (semi_dead) { - egrd->gddone = 1; - goto newpos; - } if (!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) { @@ -647,6 +669,9 @@ register struct monst *grd; grd->mpeaceful = 0; return -1; } + + umoney = money_cnt(invent); + u_carry_gold = umoney > 0L || hidden_gold() > 0L; if (egrd->fcend == 1) { if (u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if (egrd->warncnt == 3 && !Deaf) @@ -696,7 +721,6 @@ register struct monst *grd; } else { if (!Deaf) verbalize("Well, begone."); - wallify_vault(grd); egrd->gddone = 1; goto cleanup; } @@ -881,7 +905,7 @@ proceed: fcp->fy = ny; fcp->ftyp = typ; newpos: - gd_mv_monaway(grd, nx,ny); + gd_mv_monaway(grd, nx, ny); if (egrd->gddone) { /* The following is a kludge. We need to keep */ /* the guard around in order to be able to make */ @@ -893,17 +917,14 @@ newpos: /* At the end of the process, the guard is killed */ /* in restfakecorr(). */ cleanup: - x = grd->mx; - y = grd->my; - + x = grd->mx, y = grd->my; see_guard = canspotmon(grd); + parkguard(grd); /* move to <0,0> */ wallify_vault(grd); - remove_monster(grd->mx, grd->my); - newsym(grd->mx, grd->my); - place_monster(grd, 0, 0); - egrd->ogx = grd->mx; - egrd->ogy = grd->my; restfakecorr(grd); + debugpline2("gd_move: %scleanup%s", + grd->isgd ? "" : "final ", + grd->isgd ? " attempt" : ""); if (!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { if (!disappear_msg_seen && see_guard) pline("Suddenly, %s disappears.", noit_mon_nam(grd)); diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index 75155a73f..b883cd7bd 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -15,7 +15,8 @@ #include "color.h" #include "patchlevel.h" -#define NHMAP_FONT_NAME TEXT("Courier New") +#define NHMAP_FONT_NAME TEXT("Terminal") +#define NHMAP_TTFONT_NAME TEXT("Consolas") #define MAXWINDOWTEXT 255 #define CURSOR_BLINK_INTERVAL 1000 // milliseconds @@ -182,24 +183,38 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -data->yBackTile; // height of font - lgfnt.lfWidth = 0; // average character width + if (data->bFitToScreenMode) { + lgfnt.lfHeight = -data->yBackTile; // height of font + lgfnt.lfWidth = 0; // average character width + } else { + lgfnt.lfHeight = -data->yBackTile; // height of font + lgfnt.lfWidth = -data->xBackTile; // average character width + } lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle - lgfnt.lfWeight = FW_SEMIBOLD; // font weight + lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision - lgfnt.lfQuality = NONANTIALIASED_QUALITY; // output quality + if (data->bFitToScreenMode) { + lgfnt.lfQuality = ANTIALIASED_QUALITY; // output quality + } else { + lgfnt.lfQuality = NONANTIALIASED_QUALITY; // output quality + } if (iflags.wc_font_map && *iflags.wc_font_map) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); } else { - lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family - NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); + if (!data->bFitToScreenMode) { + lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family + NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); + } else { + lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family + NH_A2W(NHMAP_TTFONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); + } } TEXTMETRIC textMetrics; @@ -216,6 +231,9 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) GetTextMetrics(data->backBufferDC, &textMetrics); + if (!data->bFitToScreenMode) + break; + if ((textMetrics.tmHeight > data->yBackTile || textMetrics.tmAveCharWidth > data->xBackTile) && lgfnt.lfHeight < -MIN_FONT_HEIGHT) {