diff --git a/doc/fixes36.2 b/doc/fixes36.2 index fb2cf76b0..ff9594aa0 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -196,6 +196,10 @@ avoid potential buffer overflow if object with very long name knocks other #wizintrinsic for 'warn_of_mon' didn't set any type of monster (now grid bugs) clairvoyance would show trap instead of a monster on/in that trap, which was intentional, but when clairvoyance finished the monster wasn't shown +nurse corpse/tin chance to convey poison resistance when eaten was not honored +make tame vampires be more aggressive when shifted to bat/fog/wolf form +a stale gold symbol could be displayed on the status line following a switch + to a new symset, as observed and reported for Windows RogueEpyx symset Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository @@ -246,6 +250,10 @@ windows-tty: Fix memory leaks as reported in H5779 windows-tty: Use nhraykey by default if the players keyboard layout is non-english as reported in H4216 windows-tty: We now support changing altkeyhandler in game +windows-tty: augment codepage850-to-Unicode mappings that are not displayable + with codepage437-to-Unicode mappings that are, to help ensure + that rogue-level characters in the status line match their appearance + on the map windows: Added ntassert() mechanism for Windows based port use windows: heed OPTIONS=symset:default in config file if it is present tty: significant optimizations for performance and per field rendering @@ -258,6 +266,8 @@ unix: Makefile.src and Makefile.utl inadvertently relied on a 'gnu make' verbose so doesn't use '$<' for multi-prerequisite targets unless specifically requested; use 'make QUIETCC=1 ' to get the 3.6.1 behavior back +vms: data file processing and playground setup were missing post-3.4.3 files + engrave, epitaph, and bogusmon made from corresponding *.txt Qt: add Qt5 specific hints file for linux and Mac OS X (Ray Chason) Qt: enable compiling Qt5 on Windows (Ray Chason) Qt: entering extended commands, hide non-matching ones @@ -304,3 +314,5 @@ for ^X and enlightenment, display the information in a menu rather than a Code Cleanup and Reorganization ------------------------------- +generated source file monstr.c is no longer used + diff --git a/include/decl.h b/include/decl.h index e48cbe0f6..19c5060ee 100644 --- a/include/decl.h +++ b/include/decl.h @@ -428,7 +428,11 @@ E const char *ARGV0; E void NDECL((*dropleveltempsfn)); #endif -enum earlyarg {ARG_DEBUG, ARG_VERSION}; +enum earlyarg {ARG_DEBUG, ARG_VERSION +#ifdef WIN32 + ,ARG_WINDOWS +#endif +}; struct early_opt { enum earlyarg e; diff --git a/src/allmain.c b/src/allmain.c index 99a53e77f..9bad82dc5 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -763,8 +763,15 @@ const char *msg; static struct early_opt earlyopts[] = { {ARG_DEBUG, "debug", 5, TRUE}, {ARG_VERSION, "version", 4, TRUE}, +#ifdef WIN32 + {ARG_WINDOWS, "windows", 4, TRUE}, +#endif }; +#ifdef WIN32 +extern int FDECL(windows_early_options, (const char *)); +#endif + /* * Returns: * 0 = no match @@ -834,6 +841,14 @@ enum earlyarg e_arg; early_version_info(insert_into_pastebuf); return 2; } +#ifdef WIN32 + case ARG_WINDOWS: { + if (extended_opt) { + extended_opt++; + return windows_early_options(extended_opt); + } + } +#endif default: break; } diff --git a/src/botl.c b/src/botl.c index 5d1fe2bcb..b2462f50f 100644 --- a/src/botl.c +++ b/src/botl.c @@ -698,6 +698,7 @@ int fld, idx, idx_p; boolean *valsetlist; { static int oldrndencode = 0; + static nhsym oldgoldsym = 0; int pc, chg, color = NO_COLOR; unsigned anytype; boolean updated = FALSE, reset; @@ -719,10 +720,28 @@ boolean *valsetlist; * so $:0 has already been encoded and cached by the window * port. Without this hack, gold's \G sequence won't be * recognized and ends up being displayed as-is for 'update_all'. + * + * Also, even if context.rndencode hasn't changed and the + * gold amount itself hasn't changed, the glyph portion of the + * encoding may have changed if a new symset was put into + * effect. + * + * \GXXXXNNNN:25 + * XXXX = the context.rndencode portion + * NNNN = the glyph portion + * 25 = the gold amount + * */ - if (context.rndencode != oldrndencode && fld == BL_GOLD) { - chg = 2; - oldrndencode = context.rndencode; + + if (fld == BL_GOLD) { + if (context.rndencode != oldrndencode) { + chg = 2; + oldrndencode = context.rndencode; + } + if (oldgoldsym != showsyms[COIN_CLASS + SYM_OFF_O]) { + chg = 2; + oldgoldsym = showsyms[COIN_CLASS + SYM_OFF_O]; + } } reset = FALSE; diff --git a/src/dogmove.c b/src/dogmove.c index 2ec72551e..e21d4e3f5 100644 --- a/src/dogmove.c +++ b/src/dogmove.c @@ -721,6 +721,7 @@ struct monst *mtmp, *mtarg; /* Give 1 in 3 chance of safe breathing even if pet is confused or * if you're on the quest start level */ if (!mtmp->mconf || !rn2(3) || Is_qstart(&u.uz)) { + int mtmp_lev; aligntyp align1 = A_NONE, align2 = A_NONE; /* For priests, minions */ boolean faith1 = TRUE, faith2 = TRUE; @@ -774,10 +775,26 @@ struct monst *mtmp, *mtarg; || (mtmp->m_lev > 12 && mtarg->m_lev < mtmp->m_lev - 9 && u.ulevel > 8 && mtarg->m_lev < u.ulevel - 7)) score -= 25; + /* for strength purposes, a vampshifter in weak form (vampire bat, + fog cloud, maybe wolf) will attack as if in vampire form; + otherwise if won't do much and usually wouldn't suffer enough + damage (from counterattacks) to switch back to vampire form; + make it be more aggressive by behaving as if stronger */ + mtmp_lev = mtmp->m_lev; + if (is_vampshifter(mtmp) && mtmp->data->mlet != S_VAMPIRE) { + /* is_vampshifter() implies (mtmp->cham >= LOW_PM) */ + mtmp_lev = mons[mtmp->cham].mlevel; + /* actual vampire level would range from 1.0*mlvl to 1.5*mlvl */ + mtmp_lev += rn2(mtmp_lev / 2 + 1); + /* we don't expect actual level in weak form to exceed + base level of strong form, but handle that if it happens */ + if (mtmp->m_lev > mtmp_lev) + mtmp_lev = mtmp->m_lev; + } /* And pets will hesitate to attack vastly stronger foes. This penalty will be discarded if master's in trouble. */ - if (mtarg->m_lev > mtmp->m_lev + 4L) - score -= (mtarg->m_lev - mtmp->m_lev) * 20L; + if (mtarg->m_lev > mtmp_lev + 4L) + score -= (mtarg->m_lev - mtmp_lev) * 20L; /* All things being the same, go for the beefiest monster. This bonus should not be large enough to override the pet's aversion to attacking much stronger monsters. */ diff --git a/src/eat.c b/src/eat.c index 0d5e83ab2..0d9df6ce7 100644 --- a/src/eat.c +++ b/src/eat.c @@ -943,10 +943,11 @@ register struct permonst *ptr; /* called after completely consuming a corpse */ STATIC_OVL void cpostfx(pm) -register int pm; +int pm; { - register int tmp = 0; + int tmp = 0; int catch_lycanthropy = NON_PM; + boolean check_intrinsics = FALSE; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ @@ -958,6 +959,7 @@ register int pm; /* MRKR: "eye of newt" may give small magical energy boost */ if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) { int old_uen = u.uen; + u.uen += rnd(3); if (u.uen > u.uenmax) { if (!rn2(3)) @@ -989,6 +991,7 @@ register int pm; u.uhp = u.uhpmax; make_blinded(0L, !u.ucreamed); context.botl = 1; + check_intrinsics = TRUE; /* might also convey poison resistance */ break; case PM_STALKER: if (!Invis) { @@ -1090,7 +1093,13 @@ register int pm; pline("For some reason, that tasted bland."); } /*FALLTHRU*/ - default: { + default: + check_intrinsics = TRUE; + break; + } + + /* possibly convey an intrinsic */ + if (check_intrinsics) { struct permonst *ptr = &mons[pm]; boolean conveys_STR = is_giant(ptr); int i, count; @@ -1137,9 +1146,7 @@ register int pm; gainstr((struct obj *) 0, 0, TRUE); else if (tmp > 0) givit(tmp, ptr); - break; - } /* default case */ - } /* switch */ + } /* check_intrinsics */ if (catch_lycanthropy >= LOW_PM) { set_ulycn(catch_lycanthropy); diff --git a/src/rumors.c b/src/rumors.c index 5e9af00a0..a0f367952 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 rumors.c $NHDT-Date: 1446713640 2015/11/05 08:54:00 $ $NHDT-Branch: master $:$NHDT-Revision: 1.27 $ */ +/* NetHack 3.6 rumors.c $NHDT-Date: 1542422933 2018/11/17 02:48:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.30 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -43,6 +43,7 @@ STATIC_DCL void FDECL(init_rumors, (dlb *)); STATIC_DCL void FDECL(init_oracles, (dlb *)); +STATIC_DCL void FDECL(couldnt_open_file, (const char *)); /* rumor size variables are signed so that value -1 can be used as a flag */ static long true_rumor_size = 0L, false_rumor_size; @@ -155,7 +156,7 @@ boolean exclude_cookie; else if (!in_mklev) /* avoid exercizing wisdom for graffiti */ exercise(A_WIS, (adjtruth > 0)); } else { - pline("Can't open rumors file!"); + couldnt_open_file(RUMORFILE); true_rumor_size = -1; /* don't try to open it again */ } /* this is safe either way, so do it always since we can't get the definition @@ -272,7 +273,7 @@ rumor_check() display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } else { - impossible("Can't open rumors file!"); + couldnt_open_file(RUMORFILE); true_rumor_size = -1; /* don't try to open it again */ } } @@ -314,8 +315,10 @@ char *buf; *endp = 0; Strcat(buf, xcrypt(line, xbuf)); (void) dlb_fclose(fh); - } else - impossible("Can't open file %s!", fname); + } else { + couldnt_open_file(fname); + } + return buf; } @@ -469,7 +472,7 @@ boolean delphi; destroy_nhwindow(tmpwin); (void) dlb_fclose(oracles); } else { - pline("Can't open oracles file!"); + couldnt_open_file(ORACLEFILE); oracle_flg = -1; /* don't try to open it again */ } } @@ -547,4 +550,20 @@ struct monst *oracl; return 1; } +STATIC_OVL void +couldnt_open_file(filename) +const char *filename; +{ + int save_something = program_state.something_worth_saving; + + /* most likely the file is missing, so suppress impossible()'s + "saving and restoring might fix this" (unless the fuzzer, + which escalates impossible to panic, is running) */ + if (!iflags.debug_fuzzer) + program_state.something_worth_saving = 0; + + impossible("Can't open '%s' file.", filename); + program_state.something_worth_saving = save_something; +} + /*rumors.c*/ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index cc60b3b3c..393dd0d8d 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -345,6 +345,13 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ argv++; } +#ifdef WIN32 + if (argcheck(argc, argv, ARG_WINDOWS) == 1) { + argc--; + argv++; + } +#endif + if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/vms/Makefile.dat b/sys/vms/Makefile.dat index 755099c6d..e74eb95be 100644 --- a/sys/vms/Makefile.dat +++ b/sys/vms/Makefile.dat @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - data files: special levels and other data. -# NetHack 3.6 Makefile.dat $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.9 $ +# NetHack 3.6 Makefile.dat $NHDT-Date: 1542388601 2018/11/16 17:16:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.10 $ # Copyright (c) 2015 by Mike Stephenson # NetHack may be freely redistributed. See license for details. @@ -26,10 +26,11 @@ UTILMARKER = $(UTL)util.timestamp; # note: filespecs have enough punctuation to satisfy DELETE MARKERS = spec_levs.timestamp;,quest_levs.timestamp; -VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.; +VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.;,\ + engrave.;,epitaph.;,bogusmon.; DUNGEON = dungeon.; X11TILES= x11tiles.; -# note: the level lists need to be space separated +# note: the level lists need to be space separated for use as-is by $(LEVCOMP) QUESTLEVS = Arch.des Barb.des Caveman.des Healer.des Knight.des \ Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des \ Valkyrie.des Wizard.des @@ -54,6 +55,12 @@ quest.dat : quest.dat; @ $(NOOP) oracles : oracles.; @ $(NOOP) +engrave : engrave.; + @ $(NOOP) +epitaph : epitaph.; + @ $(NOOP) +bogusmon : bogusmon.; + @ $(NOOP) options : options.; @ $(NOOP) x11tiles : $(X11TILES) @@ -102,6 +109,9 @@ data.; : data.base $(MAKEDEFS) rumors.; : rumors.tru rumors.fal $(MAKEDEFS) $(RUN) $(MAKEDEFS) -r +engrave.; epitaph.; bogusmon.; : engrave.txt epitaph.txt bogusmon.txt + $(RUN) $(MAKEDEFS) -s + quest.dat; : quest.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -q diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index e3cabd5c7..d6e1a9a25 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for building nethack itself. -# NetHack 3.6 Makefile.src $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.29 $ +# NetHack 3.6 Makefile.src $NHDT-Date: 1542388601 2018/11/16 17:16:41 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.31 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -113,19 +113,22 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ - files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c \ - makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c \ + files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \ + mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \ + mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ - priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c \ - role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ - steal.c steed.c sys.c teleport.c timeout.c topten.c track.c trap.c \ - u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ + priest.c quest.c questpgr.c read.c rect.c region.c restore.c \ + rip.c rnd.c role.c \ + rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ + steal.c steed.c sys.c teleport.c timeout.c topten.c track.c \ + trap.c u_init.c \ + uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # generated source files (tile.c is handled separately via WINxxxSRC) -GENCSRC = monstr.c vis_tab.c #tile.c +GENCSRC = vis_tab.c #tile.c # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) @@ -159,7 +162,7 @@ HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ extralev.obj,files.obj,fountain.obj,hack.obj,hacklib.obj,invent.obj HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mapglyph.obj,mcastu.obj, \ mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \ - mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj,monstr.obj + mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj HOBJ4 = mplayer.obj,mthrowu.obj,muse.obj,music.obj,o_init.obj,objnam.obj, \ options.obj,pager.obj,pickup.obj,pline.obj,polyself.obj, \ potion.obj,pray.obj,priest.obj,quest.obj,questpgr.obj,read.obj @@ -260,10 +263,6 @@ $(INC)pm.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)pm.h @ $(CD) $(SRC) -monstr.c : $(MAKEDEFS) - $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) $(SRC)monstr.c - @ $(CD) $(SRC) # both vis_tab.h and vis_tab.c are made at the same time by makedefs $(INC)vis_tab.h : vis_tab.c $(TOUCH) $(INC)vis_tab.h @@ -290,19 +289,20 @@ $(INC)date.h : $(VERSOURCES) $(HACK_H) $(MAKE)$(MAKEFLAGS) $(INC)date.h @ $(CD) $(SRC) -# special targets +# special targets (monstr.c is an obsolete generated source file) clean : - if f$search("*.*;-2").nes."" then purge/Keep=2 - if f$search("$(INC)*.*;-2").nes."" then purge/Keep=2 $(INC) /Exclude=*conf*.h - if f$search("*.obj").nes."" then delete *.obj;* - if f$search("*.h-t").nes."" then delete *.h-t;* !$(HACK_H),$(CONFIG_H) + - if f$search("monstr.c").nes."" then delete monstr.c;* spotless : clean - if f$search("*.*;-1).nes."" then purge - if f$search("$(INC)*.*;-1").nes."" then purge $(INC) - if f$search("$(SYSTEM)").nes."" then delete $(SYSTEM) - if f$search("$(GAME)").nes."" then delete $(GAME) - - delete monstr.c;,vis_tab.c;,$(INC)vis_tab.h;,\ + - delete vis_tab.c;,$(INC)vis_tab.h;,\ $(INC)pm.h;,$(INC)onames.h;,$(INC)date.h; - if f$search("tile.c").nes."" then delete tile.c; - if f$search("tclib.c").nes."" then delete tclib.c; @@ -368,7 +368,6 @@ winstat.obj : $(X11)winstat.c $(HACK_H) $(INC)winX.h wintext.obj : $(X11)wintext.c $(HACK_H) $(INC)winX.h $(INC)xwindow.h winval.obj : $(X11)winval.c $(HACK_H) $(INC)winX.h tile.obj : $(SRC)tile.c $(HACK_H) -monstr.obj : monstr.c $(CONFIG_H) vis_tab.obj : vis_tab.c $(CONFIG_H) $(INC)vis_tab.h # general code allmain.obj : allmain.c $(HACK_H) diff --git a/sys/vms/Makefile.utl b/sys/vms/Makefile.utl index a581e9e40..88ff37c29 100644 --- a/sys/vms/Makefile.utl +++ b/sys/vms/Makefile.utl @@ -1,5 +1,5 @@ # NetHack Makefile (VMS) - for utility programs. -# NetHack 3.6 Makefile.utl $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ +# NetHack 3.6 Makefile.utl $NHDT-Date: 1542388602 2018/11/16 17:16:42 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.16 $ # Copyright (c) 2011 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. @@ -173,8 +173,6 @@ $(INC)onames.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -o $(INC)pm.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -p -$(SRC)monstr.c : $(MAKEDEFS) - $(RUN) $(MAKEDEFS) -m # both vis_tab.h and vis_tab.c are made at the same time by makedefs -z $(INC)vis_tab.h : $(SRC)vis_tab.c $(TOUCH) $(INC)vis_tab.h diff --git a/sys/vms/install.com b/sys/vms/install.com index cb8ae3276..eecbca319 100755 --- a/sys/vms/install.com +++ b/sys/vms/install.com @@ -1,9 +1,9 @@ $ ! vms/install.com -- set up nethack 'playground' -$! $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ +$! $NHDT-Date: 1542388600 2018/11/16 17:16:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ $! Copyright (c) 2016 by Robert Patrick Rankin $! NetHack may be freely redistributed. See license for details. $ ! -$ ! $NHDT-Date: 1524689428 2018/04/25 20:50:28 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.10 $ +$ ! $NHDT-Date: 1542388600 2018/11/16 17:16:40 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.11 $ $ ! $ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*. $ ! @@ -26,10 +26,11 @@ $ if p2.nes."" then gameuic := 'p2' $ $ ! note: all filespecs contain some punctuation, $ ! to avoid inadvertent logical name interaction -$ play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG." +$ play_files = "PERM.,RECORD.,LOGFILE.,XLOGFILE.,PANICLOG." $ help_files = "HELP.,HH.,CMDHELP.,KEYHELP.,WIZHELP.,OPTHELP.," - + "HISTORY.,LICENSE." -$ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE." +$ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT,TRIBUTE.," - + + "ENGRAVE.,EPITAPH.,BOGUSMON." $ sysconf_file = "[.sys.vms]sysconf" $ guidebook = "[.doc]Guidebook.txt" $ invoc_proc = "[.sys.vms]nethack.com" @@ -88,6 +89,8 @@ $ makedefs -r !rumors.tru + rumors.fal -> rumors $ milestone "(oracles)" $ makedefs -h !oracles.txt -> oracles $ milestone "(dungeon preprocess)" +$ makedefs -s +$ milestone "(engrave, epitaph, bogusmon)" $ makedefs -e !dungeon.def -> dungeon.pdf $ milestone "(quest text)" $ makedefs -q !quest.txt -> quest.dat diff --git a/sys/vms/vmsbuild.com b/sys/vms/vmsbuild.com index 42fd104f2..6d45bb444 100755 --- a/sys/vms/vmsbuild.com +++ b/sys/vms/vmsbuild.com @@ -1,6 +1,6 @@ $ ! vms/vmsbuild.com -- compile and link NetHack 3.6.* [pr] $ version_number = "3.6.2" -$ ! $NHDT-Date: 1524689429 2018/04/25 20:50:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.17 $ +$ ! $NHDT-Date: 1542411224 2018/11/16 23:33:44 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.19 $ # Copyright (c) 2018 by Robert Patrick Rankin # NetHack may be freely redistributed. See license for details. $ ! @@ -251,7 +251,6 @@ $ makedefs -p !pm.h $ makedefs -o !onames.h $ makedefs -v !date.h $ milestone " (*.h)" -$ makedefs -m !../src/monstr.c $ makedefs -z !../src/vis_tab.c, ../include/vis_tab.h $ milestone " (*.c)" $ set default [-.src] @@ -269,7 +268,7 @@ $ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,cmd,dbridge,detect" - $ gosub compile_list $ c_list = "hack,hacklib,invent,light,lock,mail,makemon,mapglyph,mcastu" - + ",mhitm,mhitu,minion,mklev,mkmap,mkmaze,mkobj,mkroom,mon,mondata" - - + ",monmove,monstr,mplayer,mthrowu,muse,music,o_init,objnam,options" - + + ",monmove,mplayer,mthrowu,muse,music,o_init,objnam,options" - + ",pager,pickup" $ gosub compile_list $ c_list = "pline,polyself,potion,pray,priest,quest,questpgr,read" - diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 31b618acc..177426ee1 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -571,8 +571,6 @@ char ch; break; default: - // Temporary fix. Tty putstatusfield() - inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse); console.attr = (inverse) ? ttycolors_inv[console.current_nhcolor] : @@ -1666,6 +1664,12 @@ void set_cp_map() int count = MultiByteToWideChar(codePage, 0, &c, 1, &console.cpMap[i], 1); nhassert(count == 1); + + // If a character was mapped to unicode control codes, + // remap to the appropriate unicode character per our + // code page 437 mappings. + if (console.cpMap[i] < 32) + console.cpMap[i] = cp437[console.cpMap[i]]; } } diff --git a/sys/winnt/win10.c b/sys/winnt/win10.c index bf2ed9d39..3ec62a943 100644 --- a/sys/winnt/win10.c +++ b/sys/winnt/win10.c @@ -44,3 +44,40 @@ void win10_init() } } + +void win10_monitor_size(HWND hWnd, int * width, int * height) +{ + HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); + MONITORINFO info; + info.cbSize = sizeof(MONITORINFO); + BOOL success = GetMonitorInfo(monitor, &info); + nhassert(success); + *width = info.rcMonitor.right - info.rcMonitor.left; + *height = info.rcMonitor.bottom - info.rcMonitor.top; +} + +int win10_monitor_dpi(HWND hWnd) +{ + UINT monitorDpi = 96; + + if (gWin10.Valid) { + monitorDpi = gWin10.GetDpiForWindow(hWnd); + if (monitorDpi == 0) + monitorDpi = 96; + } + + monitorDpi = max(96, monitorDpi); + + return monitorDpi; +} + +double win10_monitor_scale(HWND hWnd) +{ + return (double) win10_monitor_dpi(hWnd) / 96.0; +} + +void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo) +{ + monitorInfo->scale = win10_monitor_scale(hWnd); + win10_monitor_size(hWnd, &monitorInfo->width, &monitorInfo->height); +} diff --git a/sys/winnt/win10.h b/sys/winnt/win10.h index 02b943b56..1bf4fce33 100644 --- a/sys/winnt/win10.h +++ b/sys/winnt/win10.h @@ -19,8 +19,19 @@ typedef struct { GetDpiForWindowProc GetDpiForWindow; } Win10; +typedef struct { + double scale; // dpi of monitor / 96 + int width; // in pixels + int height; // in pixels +} MonitorInfo; + extern Win10 gWin10; void win10_init(); +int win10_monitor_dpi(HWND hWnd); +double win10_monitor_scale(HWND hWnd); +void win10_monitor_size(HWND hWnd, int * width, int * height); +void win10_monitor_info(HWND hWnd, MonitorInfo * monitorInfo); -#endif // WIN10_H \ No newline at end of file + +#endif // WIN10_H diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index e3aaf640e..5b0fd8bc8 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -37,9 +37,13 @@ * */ +/* runtime cursor display control switch */ +boolean win32_cursorblink; + /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; + typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); @@ -581,6 +585,25 @@ BOOL winos_font_support_cp437(HFONT hFont) return allFound; } +int +windows_early_options(window_opt) +const char *window_opt; +{ + /* + * If you return 2, the game will exit before it begins. + * Return 1, to say the option parsed okay. + * Return 0, to say the option was bad. + */ + + if (match_optname(window_opt, "cursorblink", 5, FALSE)) { + win32_cursorblink = TRUE; + return 1; + } else { + raw_printf( + "-%swindows:cursorblink is the only supported option.\n"); + } + return 0; +} #endif /* WIN32 */ -/*winnt.c*/ \ No newline at end of file +/*winnt.c*/ diff --git a/win/X11/NetHack.ad b/win/X11/NetHack.ad index 0e5ca8b1f..755fa58a7 100644 --- a/win/X11/NetHack.ad +++ b/win/X11/NetHack.ad @@ -1,4 +1,4 @@ -! $NHDT-Date: 1524689294 2018/04/25 20:48:14 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.15 $ +! $NHDT-Date: 1542244983 2018/11/15 01:23:03 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.20 $ ! Copyright (c) 2017 by Pasi Kallinen ! NetHack may be freely redistributed. See license for details. @@ -37,7 +37,7 @@ NetHack*text*borderWidth: 0 ! NetHack.tile_file: x11tiles !NetHack.double_tile_size: True -! + ! The annotation of pets. !NetHack.pet_mark_bitmap: pet_mark.xbm !NetHack.pet_mark_color: Red @@ -57,30 +57,25 @@ NetHack.tile_file: x11tiles ! The color to use for the text on the hero's tombstone NetHack*rip*foreground: black -! Translation tables. There are currently several actions in nethack, but -! the only one you should be using is "input()", which, with no parameters, -! uses XLookupString to translate your keypress into a command. You -! can optionally give it parameters to change the behavior, see the example -! below. Note that you have to specify the translations in every appropriate -! window. -NetHack*message*translations: : input() -! -! Example extra translations for the map window. -! -!NetHack*map*translations: #override \ -! !Left: input(h) \n\ -! !Right: input(l) \n\ -! !Up: input(k) \n\ -! !Down: input(j) -! ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the ! default. Some window managers may not support the larger icon sizes. ! It is not guaranteed that the window manager will honor the icon selection. !NetHack*icon: nh56 -! + ! If True, the default, a popup for single character prompts such as y/n -! questions is _not_ used. -NetHack*slow: True +! questions is _not_ used. Single-character prompts appear in a fixed +! position between the top of the map and the bottom of the messages. +! If False, popups appear near where the pointer is positioned so tend to +! meander around the screen depending upon where the last click ocurred. +! (The name 'slow' is misleading; this feature was originally necessitated +! by window managers which were slow putting up popup windows, but the +! fixed-position prompting can be just as useful for quick popups.) +!NetHack*slow: False + +! If True, force keyboard to attach to popup windows. Some window managers +! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack +! has a lot of popups and is almost unplayable without some kind of autofocus. +!NetHack*autofocus: True ! If 'slow' is True, setting 'highlight_prompt' to True will cause the line ! between map and message display that's used for prompting to be "hidden" @@ -91,19 +86,33 @@ NetHack*highlight_prompt: False ! The number of lines the message window will show without scrolling. !NetHack*message_lines: 12 -! + ! If True, the message window has a line that seperates old and new messages. !NetHack*message_line: True -! -! If True, force keyboard to attach to popup windows. Some window managers -! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack -! has a lot of popups and is almost unplayable without some kind of autofocus. -!NetHack*autofocus: True -! -! True, use a "fancy" style status area vs. TTY-style status lines +! If True, the default, use a "fancy" style status area below the map. +! Fancy status has some highlighting but does not honor HILITE_STATUS. +! If False, use TTY-style status lines (two text lines below the map). +! TTY status honors HILITE_STATUS thresholds and colors, but for +! attributes only supports inverse (not bold, dim, blink, or underline). +! (As of this writing, fancy status looks better with a tiles map and +! tty-style status looks good with a text map but not with a tiles one.) !NetHack*fancy_status: False +! Translation tables. There are currently several actions in nethack, but +! the only one you should be using is "input()", which, with no parameters, +! uses XLookupString to translate your keypress into a command. You can +! optionally give it parameters to change the behavior, see the example below. +! Note that you have to specify the translations in every appropriate window. +NetHack*message*translations: : input() +! +! Example extra translations for the map window. +!NetHack*map*translations: #override \ +! !Left: input(h) \n\ +! !Right: input(l) \n\ +! !Up: input(k) \n\ +! !Down: input(j) + ! Specify the number of rows and columns of the map window. The default ! is the standard 80x21 window. Note: this _does_not_ change nethack's ! level size, only what you see of it. diff --git a/win/X11/winmenu.c b/win/X11/winmenu.c index eaba350d4..04d75e77f 100644 --- a/win/X11/winmenu.c +++ b/win/X11/winmenu.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 winmenu.c $NHDT-Date: 1539812601 2018/10/17 21:43:21 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.28 $ */ +/* NetHack 3.6 winmenu.c $NHDT-Date: 1542245161 2018/11/15 01:26:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.33 $ */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ @@ -45,6 +45,7 @@ static void FDECL(menu_all, (Widget, XtPointer, XtPointer)); static void FDECL(menu_none, (Widget, XtPointer, XtPointer)); static void FDECL(menu_invert, (Widget, XtPointer, XtPointer)); static void FDECL(menu_search, (Widget, XtPointer, XtPointer)); +static void FDECL(search_menu, (struct xwindow *)); static void FDECL(select_all, (struct xwindow *)); static void FDECL(select_none, (struct xwindow *)); static void FDECL(select_match, (struct xwindow *, char *)); @@ -285,25 +286,9 @@ Cardinal *num_params; menu_info->counting = TRUE; return; } else if (ch == MENU_SEARCH) { /* search */ - if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { - char buf[BUFSZ + 2], tmpbuf[BUFSZ]; - - X11_getlin("Search for:", tmpbuf); - if (!*tmpbuf || *tmpbuf == '\033') - return; - /* convert "string" into "*string*" for use with pmatch() */ - Sprintf(buf, "*%s*", tmpbuf); - - if (menu_info->how == PICK_ANY) { - invert_match(wp, buf); - return; - } else { - select_match(wp, buf); - } - } else { - X11_nhbell(); + search_menu(wp); + if (menu_info->how == PICK_ANY) return; - } } else if (ch == MENU_SELECT_ALL || ch == MENU_SELECT_PAGE) { if (menu_info->how == PICK_ANY) select_all(wp); @@ -471,26 +456,49 @@ XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; struct menu_info_t *menu_info = wp->menu_information; - char buf[BUFSZ + 2], tmpbuf[BUFSZ]; nhUse(w); nhUse(call_data); - X11_getlin("Search for:", tmpbuf); - if (!*tmpbuf || *tmpbuf == '\033') - return; - /* convert "string" into "*string*" for use with pmatch() */ - Sprintf(buf, "*%s*", tmpbuf); - - if (menu_info->how == PICK_ANY) - invert_match(wp, buf); - else - select_match(wp, buf); - + search_menu(wp); if (menu_info->how == PICK_ONE) menu_popdown(wp); } +/* common to menu_search and menu_key */ +static void +search_menu(wp) +struct xwindow *wp; +{ + char *pat, buf[BUFSZ + 2]; /* room for '*' + BUFSZ-1 + '*' + '\0' */ + struct menu_info_t *menu_info = wp->menu_information; + + buf[0] = buf[1] = '\0'; + pat = &buf[1]; /* leave room to maybe insert '*' at front */ + if (menu_info->how != PICK_NONE) { + X11_getlin("Search for:", pat); + if (!*pat || *pat == '\033') + return; + /* convert "string" into "*string*" for use with pmatch() */ + if (*pat != '*') + *--pat = '*'; /* now points to &buf[0] */ + if (*(eos(pat) - 1) != '*') + Strcat(pat, "*"); + } + + switch (menu_info->how) { + case PICK_ANY: + invert_match(wp, pat); + break; + case PICK_ONE: + select_match(wp, pat); + break; + default: /* PICK_NONE */ + X11_nhbell(); + break; + } +} + static void select_all(wp) struct xwindow *wp; diff --git a/win/win32/mhfont.c b/win/win32/mhfont.c index 12edec439..e8296cc8d 100644 --- a/win/win32/mhfont.c +++ b/win/win32/mhfont.c @@ -4,6 +4,7 @@ /* font management and such */ +#include "win10.h" #include "winos.h" #include "mhfont.h" @@ -26,9 +27,10 @@ void mswin_init_splashfonts(HWND hWnd) { HDC hdc = GetDC(hWnd); + double scale = win10_monitor_scale(hWnd); LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -80; // height of font + lgfnt.lfHeight = -(int)(80 * scale); // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index ce9330e8e..8e61aea8c 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -15,10 +15,12 @@ #include "color.h" #include "patchlevel.h" -//#define NHMAP_FONT_NAME TEXT("Terminal") #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 +#define CURSOR_BLINK_INTERVAL 1000 // milliseconds +#define CURSOR_HEIGHT 2 // pixels + extern short glyph2tile[]; #define TILEBMP_X(ntile) \ @@ -28,8 +30,11 @@ extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { - int map[COLNO][ROWNO]; /* glyph map */ - int bkmap[COLNO][ROWNO]; /* backround glyph map */ + HWND hWnd; /* window */ + + int map[COLNO][ROWNO]; /* glyph map */ + int bkmap[COLNO][ROWNO]; /* backround glyph map */ + boolean mapDirty[COLNO][ROWNO]; /* dirty flag for map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ @@ -38,15 +43,31 @@ typedef struct mswin_nethack_map_window { int xPageSize, yPageSize; /* scroll page size */ int xMin, xMax, yMin, yMax; /* scroll range */ int xCur, yCur; /* position of the cursor */ - int xScrTile, yScrTile; /* size of tile on screen in pixels */ + int xFrontTile, yFrontTile; /* size of tile in front buffer in pixels */ + int xBackTile, yBackTile; /* size of tile in back buffer in pixels */ POINT map_orig; /* map origin point */ - HFONT hMapFont; /* font for ASCII mode */ - boolean bUnicodeFont; /* font supports unicode page 437 */ + HFONT hMapFont; /* font for ASCII mode */ + boolean bUnicodeFont; /* font supports unicode page 437 */ - int tileWidth; /* width of tile in pixels at 96 dpi */ - int tileHeight; /* height of tile in pixels at 96 dpi */ - double scale; /* scale factor */ + int tileWidth; /* width of tile in pixels at 96 dpi */ + int tileHeight; /* height of tile in pixels at 96 dpi */ + double backScale; /* scaling from source to back buffer */ + double frontScale; /* scaling from back to front */ + double monitorScale; /* from 96dpi to monitor dpi*/ + + boolean cursorOn; + int yNoBlinkCursor; /* non-blinking cursor height inback buffer + in pixels */ + int yBlinkCursor; /* blinking cursor height inback buffer + in pixels */ + + int backWidth; /* back buffer width */ + int backHeight; /* back buffer height */ + HBITMAP hBackBuffer; /* back buffe bitmap */ + HDC backBufferDC; /* back buffer drawing context */ + + HDC tileDC; /* tile drawing context */ } NHMapWindow, *PNHMapWindow; @@ -59,15 +80,22 @@ static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); +static void paint(PNHMapWindow data, int i, int j); +static void dirtyAll(PNHMapWindow data); +static void dirty(PNHMapWindow data, int i, int j); +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg); +static void clearAll(PNHMapWindow data); + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar *ch, int *color); #endif +extern boolean win32_cursorblink; /* from sys\winnt\winnt.c */ HWND mswin_init_map_window() { static int run_once = 0; - HWND ret; + HWND hWnd; RECT rt; if (!run_once) { @@ -83,7 +111,7 @@ mswin_init_map_window() } /* create map window object */ - ret = CreateWindow( + hWnd = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS @@ -96,16 +124,19 @@ mswin_init_map_window() NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL); /* window-creation data */ - if (!ret) { + if (!hWnd) { panic("Cannot create map window"); } /* Set window caption */ - SetWindowText(ret, "Map"); + SetWindowText(hWnd, "Map"); - mswin_apply_window_style(ret); + mswin_apply_window_style(hWnd); - return ret; + /* set cursor blink timer */ + SetTimer(hWnd, 0, CURSOR_BLINK_INTERVAL, NULL); + + return hWnd; } void @@ -126,115 +157,146 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; + // calculate back buffer scale + data->monitorScale = win10_monitor_scale(hWnd); + + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + data->backScale = data->monitorScale; + } else { + data->backScale = 1.0; + } + + /* set back buffer tile size */ + data->xBackTile = (int) (data->tileWidth * data->backScale); + data->yBackTile = (int) (data->tileHeight * data->backScale); + + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + LOGFONT lgfnt; + + ZeroMemory(&lgfnt, sizeof(lgfnt)); + 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_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 (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); + } + + TEXTMETRIC textMetrics; + HFONT font; + + while (1) { + font = CreateFontIndirect(&lgfnt); + + SelectObject(data->backBufferDC, font); + + GetTextMetrics(data->backBufferDC, &textMetrics); + + if (textMetrics.tmHeight > data->yBackTile) { + lgfnt.lfHeight++; + continue; + } + + if (textMetrics.tmAveCharWidth > data->xBackTile) { + lgfnt.lfWidth++; + continue; + } + + break; + } + + if (data->hMapFont) + DeleteObject(data->hMapFont); + + data->hMapFont = font; + + data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); + + // set tile size to match font metrics + + data->xBackTile = textMetrics.tmAveCharWidth; + data->yBackTile = textMetrics.tmHeight; + + } + + int backWidth = COLNO * data->xBackTile; + int backHeight = ROWNO * data->yBackTile; + + /* create back buffer */ + + if (data->backWidth != backWidth || data->backHeight != backHeight) { + + HDC frontBufferDC = GetDC(hWnd); + HBITMAP hBackBuffer = CreateCompatibleBitmap(frontBufferDC, backWidth, backHeight); + ReleaseDC(hWnd, frontBufferDC); + + if (data->hBackBuffer != NULL) { + SelectBitmap(data->backBufferDC, hBackBuffer); + DeleteObject(data->hBackBuffer); + } + + data->backWidth = backWidth; + data->backHeight = backHeight; + + SelectBitmap(data->backBufferDC, hBackBuffer); + data->hBackBuffer = hBackBuffer; + } + + /* calculate front buffer tile size */ + if (wnd_size.cx > 0 && wnd_size.cy > 0 && data->bFitToScreenMode) { double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; - UINT mapWidth = COLNO * data->tileWidth; - UINT mapHeight = ROWNO * data->tileHeight; - double mapAspectRatio = (double) mapWidth / (double) mapHeight; + double backAspectRatio = + (double) data->backWidth / (double) data->backHeight; - if (windowAspectRatio > mapAspectRatio) - data->scale = (double) wnd_size.cy / (double) mapHeight; + if (windowAspectRatio > backAspectRatio) + data->frontScale = (double) wnd_size.cy / (double) data->backHeight; else - data->scale = (double) wnd_size.cx / (double) mapWidth; + data->frontScale = (double) wnd_size.cx / (double) data->backWidth; } else { - // Auto size window - UINT windowDpi = 96; - - if (gWin10.Valid) { - windowDpi = gWin10.GetDpiForWindow(hWnd); - if (windowDpi == 0) - windowDpi = 96; + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + data->frontScale = 1.0; + } else { + data->frontScale = data->monitorScale; } - windowDpi = max(96, windowDpi); - data->scale = (double) windowDpi / 96.0; } - /* set new screen tile size */ - data->xScrTile = (int) (data->tileWidth * data->scale); - data->yScrTile = (int) (data->tileHeight * data->scale); + data->xFrontTile = (int) ((double) data->xBackTile * data->frontScale); + data->yFrontTile = (int) ((double) data->yBackTile * data->frontScale); - data->xScrTile = max(1, data->xScrTile); - data->yScrTile = max(1, data->yScrTile); - - /* create font */ - if (data->hMapFont) - DeleteObject(data->hMapFont); - - LOGFONT lgfnt; - - ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -data->yScrTile; // height of font - lgfnt.lfWidth = -data->xScrTile; // average character width - lgfnt.lfEscapement = 0; // angle of escapement - lgfnt.lfOrientation = 0; // base-line orientation angle - 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 (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); - } - - TEXTMETRIC textMetrics; - - while (1) { - data->hMapFont = CreateFontIndirect(&lgfnt); - - HDC hdc = GetDC(NULL); - HFONT savedFont = SelectObject(hdc, data->hMapFont); - - GetTextMetrics(hdc, &textMetrics); - - SelectObject(hdc, savedFont); - ReleaseDC(NULL, hdc); - - if (textMetrics.tmHeight > data->yScrTile) { - lgfnt.lfHeight++; - continue; - } - - if (textMetrics.tmAveCharWidth > data->xScrTile) { - lgfnt.lfWidth++; - continue; - } - - break; - } - - data->bUnicodeFont = winos_font_support_cp437(data->hMapFont); - - // set tile size to match font metrics - - if (data->bAsciiMode) { - data->xScrTile = textMetrics.tmAveCharWidth; - data->yScrTile = textMetrics.tmHeight; - } + /* calcuate ASCII cursor height */ + data->yBlinkCursor = (int) ((double) CURSOR_HEIGHT * data->backScale); + data->yNoBlinkCursor = data->yBackTile; /* set map origin point */ data->map_orig.x = - max(0, client_rt.left + (wnd_size.cx - data->xScrTile * COLNO) / 2); + max(0, client_rt.left + (wnd_size.cx - data->xFrontTile * COLNO) / 2); data->map_orig.y = - max(0, client_rt.top + (wnd_size.cy - data->yScrTile * ROWNO) / 2); + max(0, client_rt.top + (wnd_size.cy - data->yFrontTile * ROWNO) / 2); - data->map_orig.x -= data->map_orig.x % data->xScrTile; - data->map_orig.y -= data->map_orig.y % data->yScrTile; + data->map_orig.x -= data->map_orig.x % data->xFrontTile; + data->map_orig.y -= data->map_orig.y % data->yFrontTile; // Set horizontal scroll - data->xPageSize = min(COLNO, wnd_size.cx / data->xScrTile); + data->xPageSize = min(COLNO, wnd_size.cx / data->xFrontTile); GetNHApp()->bNoHScroll = (data->xPageSize == COLNO); @@ -252,7 +314,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); - data->yPageSize = min(ROWNO, wnd_size.cy / data->yScrTile); + data->yPageSize = min(ROWNO, wnd_size.cy / data->yFrontTile); GetNHApp()->bNoVScroll = (data->yPageSize == ROWNO); @@ -270,8 +332,10 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) mswin_cliparound(data->xCur, data->yCur); - if (redraw) + if (redraw) { + dirtyAll(data); InvalidateRect(hWnd, NULL, TRUE); + } } /* set map mode */ @@ -454,8 +518,8 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } else { /* mapping factor is unchaged we just need to adjust scroll bars */ - size.cx = data->xScrTile * COLNO; - size.cy = data->yScrTile * ROWNO; + size.cx = data->xFrontTile * COLNO; + size.cy = data->yFrontTile * ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); @@ -479,10 +543,10 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) NHEVENT_MS(CLICK_1, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) - / data->xScrTile)), + / data->xFrontTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) - / data->yScrTile))); + / data->yFrontTile))); return 0; case WM_LBUTTONDBLCLK: @@ -490,19 +554,29 @@ MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) NHEVENT_MS(CLICK_2, max(0, min(COLNO, data->xPos + (LOWORD(lParam) - data->map_orig.x) - / data->xScrTile)), + / data->xFrontTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam) - data->map_orig.y) - / data->yScrTile))); + / data->yFrontTile))); return 0; case WM_DESTROY: if (data->hMapFont) DeleteObject(data->hMapFont); + if (data->hBackBuffer) + DeleteBitmap(data->hBackBuffer); + if (data->backBufferDC) + DeleteDC(data->backBufferDC); free(data); SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0); break; + case WM_TIMER: + data->cursorOn = !data->cursorOn; + dirty(data, data->xCur, data->yCur); + break; + + default: return DefWindowProc(hWnd, message, wParam, lParam); } @@ -514,25 +588,13 @@ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - RECT rt; data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph) lParam; - if ((data->map[msg_data->x][msg_data->y] != msg_data->glyph) - || (data->bkmap[msg_data->x][msg_data->y] != msg_data->bkglyph)) { - data->map[msg_data->x][msg_data->y] = msg_data->glyph; - data->bkmap[msg_data->x][msg_data->y] = msg_data->bkglyph; - - /* invalidate the update area. Erase backround if there - is nothing to paint or we are in text mode */ - nhcoord2display(data, msg_data->x, msg_data->y, &rt); - InvalidateRect(hWnd, &rt, - (((msg_data->glyph == NO_GLYPH) - && (msg_data->bkglyph == NO_GLYPH)) - || data->bAsciiMode || Is_rogue_level(&u.uz))); - } + setGlyph(data, msg_data->x, msg_data->y, + msg_data->glyph, msg_data->bkglyph); } break; case MSNH_MSG_CLIPAROUND: { @@ -579,44 +641,22 @@ onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) } } break; - case MSNH_MSG_CLEAR_WINDOW: { - int i, j; - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } - InvalidateRect(hWnd, NULL, TRUE); - } break; + case MSNH_MSG_CLEAR_WINDOW: + clearAll(data); + break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor) lParam; - HDC hdc; - RECT rt; - /* move focus rectangle at the cursor postion */ - hdc = GetDC(hWnd); + if (data->xCur != msg_data->x || data->yCur != msg_data->y) { - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); + dirty(data, data->xCur, data->yCur); + dirty(data, msg_data->x, msg_data->y); + + data->xCur = msg_data->x; + data->yCur = msg_data->y; } - - data->xCur = msg_data->x; - data->yCur = msg_data->y; - - nhcoord2display(data, data->xCur, data->yCur, &rt); - if (data->bAsciiMode) { - PatBlt(hdc, rt.left, rt.top, rt.right - rt.left, - rt.bottom - rt.top, DSTINVERT); - } else { - DrawFocusRect(hdc, &rt); - } - - ReleaseDC(hWnd, hdc); + } break; case MSNH_MSG_GETTEXT: { @@ -656,7 +696,6 @@ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; - int i, j; UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); @@ -667,242 +706,293 @@ onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); - for (i = 0; i < COLNO; i++) - for (j = 0; j < ROWNO; j++) { - data->map[i][j] = NO_GLYPH; - data->bkmap[i][j] = NO_GLYPH; - } + + data->hWnd = hWnd; data->bAsciiMode = FALSE; + data->cursorOn = TRUE; - data->xScrTile = GetNHApp()->mapTile_X; - data->yScrTile = GetNHApp()->mapTile_Y; + data->xFrontTile = GetNHApp()->mapTile_X; + data->yFrontTile = GetNHApp()->mapTile_Y; data->tileWidth = GetNHApp()->mapTile_X; data->tileHeight = GetNHApp()->mapTile_Y; + HDC hDC = GetDC(hWnd); + data->backBufferDC = CreateCompatibleDC(hDC); + data->tileDC = CreateCompatibleDC(hDC); + ReleaseDC(hWnd, hDC); + + SelectObject(data->tileDC, GetNHApp()->bmpMapTiles); + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); + + clearAll(data); + } +static void +paintTile(PNHMapWindow data, int i, int j, RECT * rect) +{ + short ntile; + int t_x, t_y; + int glyph, bkglyph; + int layer; +#ifdef USE_PILEMARK + int color; + unsigned special; + int mgch; +#endif + layer = 0; + glyph = data->map[i][j]; + bkglyph = data->bkmap[i][j]; + + if (bkglyph != NO_GLYPH) { + ntile = glyph2tile[bkglyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + layer++; + } + + if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { + ntile = glyph2tile[glyph]; + t_x = TILEBMP_X(ntile); + t_y = TILEBMP_Y(ntile); + + if (layer > 0) { + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, t_x, + t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, TILE_BK_COLOR); + } else { + StretchBlt(data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, data->tileDC, + t_x, t_y, GetNHApp()->mapTile_X, + GetNHApp()->mapTile_Y, SRCCOPY); + } + + layer++; + } + +#ifdef USE_PILEMARK + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, &special, + i, j); + if ((glyph != NO_GLYPH) && (special & MG_PET) +#else + if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) +#endif + && iflags.wc_hilite_pet) { + /* apply pet mark transparently over + pet image */ + HDC hdcPetMark; + HBITMAP bmPetMarkOld; + + /* this is DC for petmark bitmap */ + hdcPetMark = CreateCompatibleDC(data->backBufferDC); + bmPetMarkOld = + SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPetMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPetMark, bmPetMarkOld); + DeleteDC(hdcPetMark); + } +#ifdef USE_PILEMARK + if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) + && iflags.hilite_pile) { + /* apply pilemark transparently over other image */ + HDC hdcPileMark; + HBITMAP bmPileMarkOld; + + /* this is DC for pilemark bitmap */ + hdcPileMark = CreateCompatibleDC(data->backBufferDC); + bmPileMarkOld = SelectObject(hdcPileMark, + GetNHApp()->bmpPileMark); + + (*GetNHApp()->lpfnTransparentBlt)( + data->backBufferDC, rect->left, rect->top, + data->xBackTile, data->yBackTile, hdcPileMark, 0, 0, + TILE_X, TILE_Y, TILE_BK_COLOR); + SelectObject(hdcPileMark, bmPileMarkOld); + DeleteDC(hdcPileMark); + } +#endif + + if (i == data->xCur && j == data->yCur && + (data->cursorOn || !win32_cursorblink)) + DrawFocusRect(data->backBufferDC, rect); +} + + +static void +paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) +{ + if (data->map[i][j] >= 0) { + + char ch; + WCHAR wch; + int color; + unsigned special; + int mgch; + HBRUSH back_brush; + COLORREF OldFg; + + SetBkMode(data->backBufferDC, TRANSPARENT); + + HBRUSH blackBrush = CreateSolidBrush(RGB(0, 0, 0)); + FillRect(data->backBufferDC, rect, blackBrush); + DeleteObject(blackBrush); + + #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) + nhglyph2charcolor(data->map[i][j], &ch, &color); + OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); + #else + /* rely on NetHack core helper routine */ + (void) mapglyph(data->map[i][j], &mgch, &color, + &special, i, j); + ch = (char) mgch; + if (((special & MG_PET) && iflags.hilite_pet) + || ((special & (MG_DETECT | MG_BW_LAVA)) + && iflags.use_inverse)) { + back_brush = + CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); + FillRect(data->backBufferDC, rect, back_brush); + DeleteObject(back_brush); + switch (color) { + case CLR_GRAY: + case CLR_WHITE: + OldFg = SetTextColor( + data->backBufferDC, nhcolor_to_RGB(CLR_BLACK)); + break; + default: + OldFg = + SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + } else { + OldFg = SetTextColor(data->backBufferDC, nhcolor_to_RGB(color)); + } + #endif + if (data->bUnicodeFont) { + wch = winos_ascii_to_wide(ch); + DrawTextW(data->backBufferDC, &wch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } else { + DrawTextA(data->backBufferDC, &ch, 1, rect, + DT_CENTER | DT_VCENTER | DT_NOPREFIX + | DT_SINGLELINE); + } + + SetTextColor(data->backBufferDC, OldFg); + } + + if (i == data->xCur && j == data->yCur && + (data->cursorOn || !win32_cursorblink)) { + int yCursor = (win32_cursorblink ? data->yBlinkCursor : + data->yNoBlinkCursor); + PatBlt(data->backBufferDC, + rect->left, rect->bottom - yCursor, + rect->right - rect->left, + yCursor, + DSTINVERT); + } +} + +static void setGlyph(PNHMapWindow data, int i, int j, int fg, int bg) +{ + if ((data->map[i][j] != fg) || (data->bkmap[i][j] != bg)) { + data->map[i][j] = fg; + data->bkmap[i][j] = bg; + data->mapDirty[i][j] = TRUE; + + RECT rect; + nhcoord2display(data, i, j, &rect); + InvalidateRect(data->hWnd, &rect, FALSE); + } +} + +static void clearAll(PNHMapWindow data) +{ + for (int x = 0; x < COLNO; x++) + for (int y = 0; y < ROWNO; y++) { + data->map[x][y] = NO_GLYPH; + data->bkmap[x][y] = NO_GLYPH; + data->mapDirty[x][y] = TRUE; + } + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirtyAll(PNHMapWindow data) +{ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + data->mapDirty[i][j] = TRUE; + + InvalidateRect(data->hWnd, NULL, FALSE); +} + +static void dirty(PNHMapWindow data, int x, int y) +{ + data->mapDirty[x][y] = TRUE; + + RECT rt; + nhcoord2display(data, data->xCur, data->yCur, &rt); + + InvalidateRect(data->hWnd, &rt, FALSE); +} + +static void +paint(PNHMapWindow data, int i, int j) +{ + RECT rect; + + rect.left = i * data->xBackTile; + rect.top = j * data->yBackTile; + rect.right = rect.left + data->xBackTile; + rect.bottom = rect.top + data->yBackTile; + + if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + paintGlyph(data, i, j, &rect); + } else { + paintTile(data, i, j, &rect); + } + + data->mapDirty[i][j] = FALSE; +} + + /* on WM_PAINT */ void onPaint(HWND hWnd) { - PNHMapWindow data; + PNHMapWindow data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + + /* update back buffer */ + for (int i = 0; i < COLNO; i++) + for (int j = 0; j < ROWNO; j++) + if (data->mapDirty[i][j]) + paint(data, i, j); + PAINTSTRUCT ps; - HDC hDC; - HDC tileDC; - HGDIOBJ saveBmp; - RECT paint_rt; - int i, j; + HDC hFrontBufferDC = BeginPaint(hWnd, &ps); - /* get window data */ - data = (PNHMapWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + /* stretch back buffer onto front buffer window */ + int frontWidth = COLNO * data->xFrontTile; + int frontHeight = ROWNO * data->yFrontTile; - hDC = BeginPaint(hWnd, &ps); + StretchBlt(hFrontBufferDC, + data->map_orig.x - (data->xPos * data->xFrontTile), + data->map_orig.y - (data->yPos * data->yFrontTile), frontWidth, frontHeight, + data->backBufferDC, 0, 0, data->backWidth, data->backHeight, SRCCOPY); - /* calculate paint rectangle */ - if (!IsRectEmpty(&ps.rcPaint)) { - /* calculate paint rectangle */ - paint_rt.left = - max(data->xPos - + (ps.rcPaint.left - data->map_orig.x) / data->xScrTile, - 0); - paint_rt.top = max( - data->yPos + (ps.rcPaint.top - data->map_orig.y) / data->yScrTile, - 0); - paint_rt.right = min( - data->xPos - + (ps.rcPaint.right - data->map_orig.x) / data->xScrTile + 1, - COLNO); - paint_rt.bottom = min( - data->yPos - + (ps.rcPaint.bottom - data->map_orig.y) / data->yScrTile + 1, - ROWNO); - - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { - /* You enter a VERY primitive world! */ - HGDIOBJ oldFont; - - oldFont = SelectObject(hDC, data->hMapFont); - SetBkMode(hDC, TRANSPARENT); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) - if (data->map[i][j] >= 0) { - char ch; - WCHAR wch; - RECT glyph_rect; - int color; - unsigned special; - int mgch; - HBRUSH back_brush; - COLORREF OldFg; - - nhcoord2display(data, i, j, &glyph_rect); - -#if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) - nhglyph2charcolor(data->map[i][j], &ch, &color); - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); -#else - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, - &special, i, j); - ch = (char) mgch; - if (((special & MG_PET) && iflags.hilite_pet) - || ((special & (MG_DETECT | MG_BW_LAVA)) - && iflags.use_inverse)) { - back_brush = - CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); - FillRect(hDC, &glyph_rect, back_brush); - DeleteObject(back_brush); - switch (color) { - case CLR_GRAY: - case CLR_WHITE: - OldFg = SetTextColor( - hDC, nhcolor_to_RGB(CLR_BLACK)); - break; - default: - OldFg = - SetTextColor(hDC, nhcolor_to_RGB(color)); - } - } else { - OldFg = SetTextColor(hDC, nhcolor_to_RGB(color)); - } -#endif - if (data->bUnicodeFont) { - wch = winos_ascii_to_wide(ch); - DrawTextW(hDC, &wch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } else { - DrawTextA(hDC, &ch, 1, &glyph_rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); - } - - SetTextColor(hDC, OldFg); - } - SelectObject(hDC, oldFont); - } else { - short ntile; - int t_x, t_y; - int glyph, bkglyph; - RECT glyph_rect; - int layer; -#ifdef USE_PILEMARK - int color; - unsigned special; - int mgch; -#endif - /* prepare tiles DC for mapping */ - tileDC = CreateCompatibleDC(hDC); - saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); - - /* draw the map */ - for (i = paint_rt.left; i < paint_rt.right; i++) - for (j = paint_rt.top; j < paint_rt.bottom; j++) { - layer = 0; - glyph = data->map[i][j]; - bkglyph = data->bkmap[i][j]; - - if (bkglyph != NO_GLYPH) { - ntile = glyph2tile[bkglyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - nhcoord2display(data, i, j, &glyph_rect); - - StretchBlt(hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - layer++; - } - - if ((glyph != NO_GLYPH) && (glyph != bkglyph)) { - ntile = glyph2tile[glyph]; - t_x = TILEBMP_X(ntile); - t_y = TILEBMP_Y(ntile); - nhcoord2display(data, i, j, &glyph_rect); - - if (layer > 0) { - (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, t_x, - t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, TILE_BK_COLOR); - } else { - StretchBlt(hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, tileDC, - t_x, t_y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, SRCCOPY); - } - - layer++; - } - -#ifdef USE_PILEMARK - /* rely on NetHack core helper routine */ - (void) mapglyph(data->map[i][j], &mgch, &color, &special, - i, j); - if ((glyph != NO_GLYPH) && (special & MG_PET) -#else - if ((glyph != NO_GLYPH) && glyph_is_pet(glyph) -#endif - && iflags.wc_hilite_pet) { - /* apply pet mark transparently over - pet image */ - HDC hdcPetMark; - HBITMAP bmPetMarkOld; - - /* this is DC for petmark bitmap */ - hdcPetMark = CreateCompatibleDC(hDC); - bmPetMarkOld = - SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPetMark, bmPetMarkOld); - DeleteDC(hdcPetMark); - } -#ifdef USE_PILEMARK - if ((glyph != NO_GLYPH) && (special & MG_OBJPILE) - && iflags.hilite_pile) { - /* apply pilemark transparently over other image */ - HDC hdcPileMark; - HBITMAP bmPileMarkOld; - - /* this is DC for pilemark bitmap */ - hdcPileMark = CreateCompatibleDC(hDC); - bmPileMarkOld = SelectObject(hdcPileMark, - GetNHApp()->bmpPileMark); - - (*GetNHApp()->lpfnTransparentBlt)( - hDC, glyph_rect.left, glyph_rect.top, - data->xScrTile, data->yScrTile, hdcPileMark, 0, 0, - TILE_X, TILE_Y, TILE_BK_COLOR); - SelectObject(hdcPileMark, bmPileMarkOld); - DeleteDC(hdcPileMark); - } -#endif - } - - SelectObject(tileDC, saveBmp); - DeleteDC(tileDC); - } - - /* draw focus rect */ - nhcoord2display(data, data->xCur, data->yCur, &paint_rt); - if (data->bAsciiMode) { - PatBlt(hDC, paint_rt.left, paint_rt.top, - paint_rt.right - paint_rt.left, - paint_rt.bottom - paint_rt.top, DSTINVERT); - } else { - DrawFocusRect(hDC, &paint_rt); - } - } EndPaint(hWnd, &ps); } @@ -957,7 +1047,7 @@ onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) yDelta = yNewPos - data->yPos; data->yPos = yNewPos; - ScrollWindowEx(hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, + ScrollWindowEx(hWnd, 0, -data->yFrontTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); @@ -1018,7 +1108,7 @@ onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) xDelta = xNewPos - data->xPos; data->xPos = xNewPos; - ScrollWindowEx(hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, + ScrollWindowEx(hWnd, -data->xFrontTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); @@ -1032,10 +1122,10 @@ onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { - lpOut->left = (x - data->xPos) * data->xScrTile + data->map_orig.x; - lpOut->top = (y - data->yPos) * data->yScrTile + data->map_orig.y; - lpOut->right = lpOut->left + data->xScrTile; - lpOut->bottom = lpOut->top + data->yScrTile; + lpOut->left = (x - data->xPos) * data->xFrontTile + data->map_orig.x; + lpOut->top = (y - data->yPos) * data->yFrontTile + data->map_orig.y; + lpOut->right = lpOut->left + data->xFrontTile; + lpOut->bottom = lpOut->top + data->yFrontTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) diff --git a/win/win32/mhmap.h b/win/win32/mhmap.h index cff8a7d5d..695749431 100644 --- a/win/win32/mhmap.h +++ b/win/win32/mhmap.h @@ -15,6 +15,7 @@ void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 +#define ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN MAP_MODE_ASCII_FIT_TO_SCREEN #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 diff --git a/win/win32/mhmenu.c b/win/win32/mhmenu.c index a298f3893..d35c5ef2e 100644 --- a/win/win32/mhmenu.c +++ b/win/win32/mhmenu.c @@ -2,6 +2,7 @@ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include #include "resource.h" @@ -22,6 +23,9 @@ #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT +#define CHECK_WIDTH 16 +#define CHECK_HEIGHT 16 + typedef struct mswin_menu_item { int glyph; ANY_P identifier; @@ -61,6 +65,7 @@ typedef struct mswin_nethack_menu_window { HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; + HDC bmpDC; BOOL is_active; } NHMenuWindow, *PNHMenuWindow; @@ -267,14 +272,14 @@ mswin_menu_window_select_menu(HWND hWnd, int how, MENU_ITEM_P **_selected, INT_PTR CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - PNHMenuWindow data; - HWND control; - HDC hdc; + PNHMenuWindow data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + HWND control = GetDlgItem(hWnd, IDC_MENU_TEXT); TCHAR title[MAX_LOADSTRING]; - data = (PNHMenuWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); switch (message) { - case WM_INITDIALOG: + case WM_INITDIALOG: { + + HDC hdc = GetDC(control); data = (PNHMenuWindow) malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; @@ -287,12 +292,11 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); + data->bmpDC = CreateCompatibleDC(hdc); data->is_active = FALSE; SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data); /* set font for the text cotrol */ - control = GetDlgItem(hWnd, IDC_MENU_TEXT); - hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM) mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM) 0); @@ -310,6 +314,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* set focus to text control for now */ SetFocus(control); + } return FALSE; case WM_MSNH_COMMAND: @@ -500,6 +505,7 @@ MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: if (data) { + DeleteDC(data->bmpDC); DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); @@ -862,9 +868,11 @@ SetMenuListType(HWND hWnd, int how) SendMessage(control, WM_SETFONT, (WPARAM) fnt, (LPARAM) 0); /* add column to the list view */ + MonitorInfo monitorInfo; + win10_monitor_info(hWnd, &monitorInfo); ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; - lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN); + lvcol.cx = monitorInfo.width; lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); @@ -975,6 +983,9 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) int color = NO_COLOR, attr; boolean menucolr = FALSE; + double monitorScale = win10_monitor_scale(hWnd); + int tileXScaled = (int) (TILE_X * monitorScale); + int tileYScaled = (int) (TILE_Y * monitorScale); UNREFERENCED_PARAMETER(wParam); @@ -1009,30 +1020,29 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) if (NHMENU_IS_SELECTABLE(*item)) { char buf[2]; if (data->how != PICK_NONE) { - HGDIOBJ saveBrush; - HBRUSH hbrCheckMark; + HBITMAP bmpCheck; + HBITMAP bmpSaved; switch (item->count) { case -1: - hbrCheckMark = CreatePatternBrush(data->bmpChecked); + bmpCheck = data->bmpChecked; break; case 0: - hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); + bmpCheck = data->bmpNotChecked; break; default: - hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); + bmpCheck = data->bmpCheckedCount; break; } - y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; - SetBrushOrgEx(lpdis->hDC, x, y, NULL); - saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); - PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); - SelectObject(lpdis->hDC, saveBrush); - DeleteObject(hbrCheckMark); + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; + bmpSaved = SelectBitmap(data->bmpDC, bmpCheck); + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + data->bmpDC, 0, 0, CHECK_WIDTH, CHECK_HEIGHT, SRCCOPY); + SelectObject(data->bmpDC, bmpSaved); } - x += TILE_X + spacing; + x += tileXScaled + spacing; if (item->accelerator != 0) { buf[0] = item->accelerator; @@ -1053,13 +1063,14 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) } x += tm.tmAveCharWidth + tm.tmOverhang + spacing; } else { - x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing; + x += tileXScaled + tm.tmAveCharWidth + tm.tmOverhang + 2 * spacing; } /* print glyph if present */ if (NHMENU_HAS_GLYPH(*item)) { if (!IS_MAP_ASCII(iflags.wc_map_mode)) { HGDIOBJ saveBmp; + double monitorScale = win10_monitor_scale(hWnd); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); ntile = glyph2tile[item->glyph]; @@ -1068,21 +1079,21 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) t_y = (ntile / GetNHApp()->mapTilesPerLine) * GetNHApp()->mapTile_Y; - y = (lpdis->rcItem.bottom + lpdis->rcItem.top - - GetNHApp()->mapTile_Y) / 2; + y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tileYScaled) / 2; if (GetNHApp()->bmpMapTiles == GetNHApp()->bmpTiles) { /* using original nethack tiles - apply image transparently */ - (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, TILE_X, TILE_Y, + (*GetNHApp()->lpfnTransparentBlt)(lpdis->hDC, x, y, + tileXScaled, tileYScaled, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR); } else { /* using custom tiles - simple blt */ - BitBlt(lpdis->hDC, x, y, GetNHApp()->mapTile_X, - GetNHApp()->mapTile_Y, tileDC, t_x, t_y, SRCCOPY); + StretchBlt(lpdis->hDC, x, y, tileXScaled, tileYScaled, + tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY); } SelectObject(tileDC, saveBmp); - x += GetNHApp()->mapTile_X; + x += tileXScaled; } else { const char *sel_ind; switch (item->count) { @@ -1106,7 +1117,7 @@ onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) } } else { /* no glyph - need to adjust so help window won't look to cramped */ - x += TILE_X; + x += tileXScaled; } x += spacing; diff --git a/win/win32/mhrip.c b/win/win32/mhrip.c index f8da73dae..ed826704b 100644 --- a/win/win32/mhrip.c +++ b/win/win32/mhrip.c @@ -2,6 +2,7 @@ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include "resource.h" #include "mhrip.h" @@ -25,6 +26,14 @@ typedef struct mswin_nethack_text_window { HANDLE rip_bmp; TCHAR *window_text; TCHAR *rip_text; + int x; + int y; + int width; + int height; + int graveX; + int graveY; + int graveHeight; + int graveWidth; } NHRIPWindow, *PNHRIPWindow; INT_PTR CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM); @@ -62,9 +71,21 @@ mswin_display_RIP_window(HWND hWnd) RECT textrect; HDC hdc; HFONT OldFont; + MonitorInfo monitorInfo; + + win10_monitor_info(hWnd, &monitorInfo); data = (PNHRIPWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA); + data->x = (int)(RIP_OFFSET_X * monitorInfo.scale); + data->y = (int)(RIP_OFFSET_Y * monitorInfo.scale); + data->width = (int)(RIP_WIDTH * monitorInfo.scale); + data->height = (int)(RIP_HEIGHT * monitorInfo.scale); + data->graveX = (int)(RIP_GRAVE_X * monitorInfo.scale); + data->graveY = (int)(RIP_GRAVE_Y * monitorInfo.scale); + data->graveWidth = (int)(RIP_GRAVE_WIDTH * monitorInfo.scale); + data->graveHeight = (int)(RIP_GRAVE_HEIGHT * monitorInfo.scale); + GetNHApp()->hPopupWnd = hWnd; mapWnd = mswin_hwnd_from_winid(WIN_MAP); if (!IsWindow(mapWnd)) @@ -73,9 +94,9 @@ mswin_display_RIP_window(HWND hWnd) GetWindowRect(hWnd, &riprt); GetClientRect(hWnd, &clientrect); textrect = clientrect; - textrect.top += RIP_OFFSET_Y; - textrect.left += RIP_OFFSET_X; - textrect.right -= RIP_OFFSET_X; + textrect.top += data->y; + textrect.left += data->x; + textrect.right -= data->x; if (data->window_text) { hdc = GetDC(hWnd); OldFont = SelectObject(hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); @@ -84,17 +105,17 @@ mswin_display_RIP_window(HWND hWnd) SelectObject(hdc, OldFont); ReleaseDC(hWnd, hdc); } - if (textrect.right - textrect.left > RIP_WIDTH) - clientrect.right = textrect.right + RIP_OFFSET_X - clientrect.right; + if (textrect.right - textrect.left > data->width) + clientrect.right = textrect.right + data->y - clientrect.right; else clientrect.right = - textrect.left + 2 * RIP_OFFSET_X + RIP_WIDTH - clientrect.right; + textrect.left + 2 * data->x + data->width - clientrect.right; clientrect.bottom = - textrect.bottom + RIP_HEIGHT + RIP_OFFSET_Y - clientrect.bottom; + textrect.bottom + data->height + data->y - clientrect.bottom; GetWindowRect(GetDlgItem(hWnd, IDOK), &textrect); textrect.right -= textrect.left; textrect.bottom -= textrect.top; - clientrect.bottom += textrect.bottom + RIP_OFFSET_Y; + clientrect.bottom += textrect.bottom + data->y; riprt.right -= riprt.left; riprt.bottom -= riprt.top; riprt.right += clientrect.right; @@ -106,7 +127,7 @@ mswin_display_RIP_window(HWND hWnd) GetClientRect(hWnd, &clientrect); MoveWindow(GetDlgItem(hWnd, IDOK), (clientrect.right - clientrect.left - textrect.right) / 2, - clientrect.bottom - textrect.bottom - RIP_OFFSET_Y, + clientrect.bottom - textrect.bottom - data->y, textrect.right, textrect.bottom, TRUE); ShowWindow(hWnd, SW_SHOW); @@ -158,9 +179,9 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) SetBkMode(hdc, TRANSPARENT); GetClientRect(hWnd, &clientrect); textrect = clientrect; - textrect.top += RIP_OFFSET_Y; - textrect.left += RIP_OFFSET_X; - textrect.right -= RIP_OFFSET_X; + textrect.top += data->y; + textrect.left += data->x; + textrect.right -= data->x; if (data->window_text) { DrawText(hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); @@ -169,15 +190,16 @@ NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpRip); SetBkMode(hdc, OPAQUE); - bitmap_offset = (textrect.right - textrect.left - RIP_WIDTH) / 2; - BitBlt(hdc, textrect.left + bitmap_offset, textrect.bottom, RIP_WIDTH, - RIP_HEIGHT, hdcBitmap, 0, 0, SRCCOPY); + bitmap_offset = (textrect.right - textrect.left - data->width) / 2; + StretchBlt(hdc, textrect.left + bitmap_offset, textrect.bottom, + data->width, data->height, + hdcBitmap, 0, 0, RIP_WIDTH, RIP_HEIGHT, SRCCOPY); SetBkMode(hdc, TRANSPARENT); if (data->rip_text) { - textrect.left += RIP_GRAVE_X + bitmap_offset; - textrect.top = textrect.bottom + RIP_GRAVE_Y; - textrect.right = textrect.left + RIP_GRAVE_WIDTH; - textrect.bottom = textrect.top + RIP_GRAVE_HEIGHT; + textrect.left += data->graveX + bitmap_offset; + textrect.top = textrect.bottom + data->graveY; + textrect.right = textrect.left + data->graveWidth; + textrect.bottom = textrect.top + data->graveHeight; DrawText(hdc, data->rip_text, strlen(data->rip_text), &textrect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK); } diff --git a/win/win32/mhsplash.c b/win/win32/mhsplash.c index d1bceaa07..0b0e313cd 100644 --- a/win/win32/mhsplash.c +++ b/win/win32/mhsplash.c @@ -2,6 +2,7 @@ /* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ +#include "win10.h" #include "winMS.h" #include "resource.h" #include "mhsplash.h" @@ -17,15 +18,24 @@ PNHWinApp GetNHApp(void); INT_PTR CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM); -#define SPLASH_WIDTH 440 -#define SPLASH_HEIGHT 322 -#define SPLASH_VERSION_X 290 -#define SPLASH_VERSION_Y 10 -#define SPLASH_OFFSET_X 10 -#define SPLASH_OFFSET_Y 10 +#define SPLASH_WIDTH_96DPI 440 +#define SPLASH_HEIGHT_96DPI 322 +#define SPLASH_OFFSET_X_96DPI 10 +#define SPLASH_OFFSET_Y_96DPI 10 +#define SPLASH_VERSION_X_96DPI 280 +#define SPLASH_VERSION_Y_96DPI 0 extern HFONT version_splash_font; +typedef struct { + int width; + int height; + int offsetX; + int offsetY; + int versionX; + int versionY; +} SplashData; + void mswin_display_splash_window(BOOL show_ver) { @@ -34,16 +44,30 @@ mswin_display_splash_window(BOOL show_ver) RECT splashrt; RECT clientrt; RECT controlrt; - HWND hWnd; int buttop; strbuf_t strbuf; strbuf_init(&strbuf); - hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), + HWND hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); if (!hWnd) panic("Cannot create Splash window"); + + MonitorInfo monitorInfo; + win10_monitor_info(hWnd, &monitorInfo); + + SplashData splashData; + + splashData.width = (int) (monitorInfo.scale * SPLASH_WIDTH_96DPI); + splashData.height = (int) (monitorInfo.scale * SPLASH_HEIGHT_96DPI); + splashData.offsetX = (int) (monitorInfo.scale * SPLASH_OFFSET_X_96DPI); + splashData.offsetY = (int) (monitorInfo.scale * SPLASH_OFFSET_Y_96DPI); + splashData.versionX = (int) (monitorInfo.scale * SPLASH_VERSION_X_96DPI); + splashData.versionY = (int) (monitorInfo.scale * SPLASH_VERSION_Y_96DPI); + + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) &splashData); + mswin_init_splashfonts(hWnd); GetNHApp()->hPopupWnd = hWnd; /* Get control size */ @@ -57,30 +81,32 @@ mswin_display_splash_window(BOOL show_ver) splashrt.right -= splashrt.left; splashrt.bottom -= splashrt.top; /* Get difference between requested client area and current value */ - splashrt.right += SPLASH_WIDTH + SPLASH_OFFSET_X * 2 - clientrt.right; - splashrt.bottom += SPLASH_HEIGHT + controlrt.bottom + SPLASH_OFFSET_Y * 3 - - clientrt.bottom; + splashrt.right += splashData.width + splashData.offsetX * 2 + - clientrt.right; + splashrt.bottom += splashData.height + controlrt.bottom + + splashData.offsetY * 3 + - clientrt.bottom; /* Place the window centered */ /* On the screen, not on the parent window */ - left = (GetSystemMetrics(SM_CXSCREEN) - splashrt.right) / 2; - top = (GetSystemMetrics(SM_CYSCREEN) - splashrt.bottom) / 2; + left = (monitorInfo.width - splashrt.right) / 2; + top = (monitorInfo.height - splashrt.bottom) / 2; MoveWindow(hWnd, left, top, splashrt.right, splashrt.bottom, TRUE); /* Place the OK control */ GetClientRect(hWnd, &clientrt); MoveWindow(GetDlgItem(hWnd, IDOK), (clientrt.right - clientrt.left - controlrt.right) / 2, - clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y, + clientrt.bottom - controlrt.bottom - splashData.offsetY, controlrt.right, controlrt.bottom, TRUE); - buttop = clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y; + buttop = clientrt.bottom - controlrt.bottom - splashData.offsetY; /* Place the text control */ GetWindowRect(GetDlgItem(hWnd, IDC_EXTRAINFO), &controlrt); controlrt.right -= controlrt.left; controlrt.bottom -= controlrt.top; GetClientRect(hWnd, &clientrt); MoveWindow(GetDlgItem(hWnd, IDC_EXTRAINFO), - clientrt.left + SPLASH_OFFSET_X, - buttop - controlrt.bottom - SPLASH_OFFSET_Y, - clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE); + clientrt.left + splashData.offsetX, + buttop - controlrt.bottom - splashData.offsetY, + clientrt.right - 2 * splashData.offsetX, controlrt.bottom, TRUE); /* Fill the text control */ strbuf_reserve(&strbuf, BUFSIZ); @@ -168,16 +194,19 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) HANDLE OldFont; PAINTSTRUCT ps; + SplashData *splashData = (SplashData *) GetWindowLongPtr(hWnd, GWLP_USERDATA); + hdc = BeginPaint(hWnd, &ps); /* Show splash graphic */ hdcBitmap = CreateCompatibleDC(hdc); SetBkMode(hdc, OPAQUE); OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash); - (*GetNHApp()->lpfnTransparentBlt)(hdc, SPLASH_OFFSET_X, SPLASH_OFFSET_Y, - SPLASH_WIDTH, SPLASH_HEIGHT, hdcBitmap, 0, - 0, SPLASH_WIDTH, SPLASH_HEIGHT, - TILE_BK_COLOR); + (*GetNHApp()->lpfnTransparentBlt)(hdc, + splashData->offsetX, splashData->offsetY, + splashData->width, splashData->height, hdcBitmap, + 0, 0, SPLASH_WIDTH_96DPI, SPLASH_HEIGHT_96DPI, + TILE_BK_COLOR); SelectObject(hdcBitmap, OldBitmap); DeleteDC(hdcBitmap); @@ -186,8 +215,8 @@ NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) /* Print version number */ SetTextColor(hdc, RGB(0, 0, 0)); - rt.right = rt.left = SPLASH_VERSION_X; - rt.bottom = rt.top = SPLASH_VERSION_Y; + rt.right = rt.left = splashData->offsetX + splashData->versionX; + rt.bottom = rt.top = splashData->offsetY + splashData->versionY; Sprintf(VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); OldFont = SelectObject(hdc, version_splash_font); diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index fea75b177..c6714bc15 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -813,8 +813,14 @@ mswin_clear_nhwindow(winid wid) && (GetNHApp()->windowlist[wid].win != NULL)) { if (GetNHApp()->windowlist[wid].type == NHW_MAP) { if (Is_rogue_level(&u.uz)) - mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), - ROGUE_LEVEL_MAP_MODE); + if (iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN || + iflags.wc_map_mode == MAP_MODE_TILES_FIT_TO_SCREEN) + + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE_FIT_TO_SCREEN); + else + mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), + ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode);