diff --git a/doc/fixes36.2 b/doc/fixes36.2 index ac5e5af87..9e6b004bb 100644 --- a/doc/fixes36.2 +++ b/doc/fixes36.2 @@ -252,12 +252,22 @@ hero hit by something that causes inventory items to be destroyed with loss of similar problem with more obvious symptom, an "object lost" panic when the unholy water was wielded; the fix for that wasn't general enough] add MM_ASLEEP makemon() flag and honor it when creating group for fill_zoo -at start of session (new game or restore), HILITE_STATUS for gold was ignored -if player creates any menu colors via 'O' while menucolors is off, issue a - reminder that it needs to be on in order for those to become effective add MM_NOGRP makemon() flag as a means of suppressing groups of monsters in a couple places that warrant it when a specific monster type isn't specified on the call to makemon() +at start of session (new game or restore), HILITE_STATUS for gold was ignored +if player creates any menu colors via 'O' while menucolors is off, issue a + reminder that it needs to be on in order for those to become effective +setting second or later named fruit to value beginning with two or more spaces + followed by non-space gave "singular of null?" warning +when blocking/unblocking of levitation or flying was updated due to walking + onto different terrain, the relevant status condition wasn't updated + on the screen until some other status update happened +if levitating hero poly'd into pass-wall creature jumped or teleported from + terrain that allowed levitation to terrain that didn't or vice versa, + blocking of levitation wasn't updated properly +clairvoyance revealing underwater or under-lava objects left object displayed + instead of restoring the water or lava Fixes to Post-3.6.1 Problems that Were Exposed Via git Repository diff --git a/include/decl.h b/include/decl.h index 19c5060ee..c3e3aa85c 100644 --- a/include/decl.h +++ b/include/decl.h @@ -25,6 +25,10 @@ E char SAVEF[]; E char SAVEP[]; #endif +/* max size of a windowtype option */ +#define WINTYPELEN 16 +E char chosen_windowtype[WINTYPELEN]; + E NEARDATA int bases[MAXOCLASSES]; E NEARDATA int multi; diff --git a/include/extern.h b/include/extern.h index 5d0ddd2ff..aea39b4f5 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1543892214 2018/12/04 02:56:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.665 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1544401264 2018/12/10 00:21:04 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.666 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -854,6 +854,7 @@ E boolean NDECL(u_rooted); E void NDECL(domove); E boolean NDECL(overexertion); E void NDECL(invocation_message); +E void NDECL(switch_terrain); E boolean FDECL(pooleffects, (BOOLEAN_P)); E void FDECL(spoteffects, (BOOLEAN_P)); E char *FDECL(in_rooms, (XCHAR_P, XCHAR_P, int)); diff --git a/include/flag.h b/include/flag.h index a459c5bb9..1306356c4 100644 --- a/include/flag.h +++ b/include/flag.h @@ -445,6 +445,9 @@ struct instance_flags { short soko_prize_type2; /* amulet of reflection */ struct debug_flags debug; boolean windowtype_locked; /* windowtype can't change from configfile */ + boolean windowtype_deferred; /* pick a windowport and store it in + chosen_windowport[], but do not switch to + it in the midst of options processing */ }; /* diff --git a/include/winprocs.h b/include/winprocs.h index ddfef409d..85ece4a7d 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -375,4 +375,77 @@ struct chain_procs { }; #endif /* WINCHAIN */ +#ifdef SAFEPROCS +/* + * window port routines available in sys/share/safeproc.c + */ +extern struct window_procs *FDECL(get_safe_procs, (int)); +extern void FDECL(safe_init_nhwindows, (int *, char **)); +extern void NDECL(safe_player_selection); +extern void NDECL(safe_askname); +extern void NDECL(safe_get_nh_event); +extern void FDECL(safe_exit_nhwindows, (const char *)); +extern void FDECL(safe_suspend_nhwindows, (const char *)); +extern void NDECL(safe_resume_nhwindows); +extern winid FDECL(safe_create_nhwindow, (int)); +extern void FDECL(safe_clear_nhwindow, (winid)); +extern void FDECL(safe_display_nhwindow, (winid, BOOLEAN_P)); +extern void FDECL(safe_destroy_nhwindow, (winid)); +extern void FDECL(safe_curs, (winid, int, int)); +extern void FDECL(safe_putstr, (winid, int, const char *)); +extern void FDECL(safe_putmixed, (winid, int, const char *)); +extern void FDECL(safe_display_file, (const char *, BOOLEAN_P)); +extern void FDECL(safe_start_menu, (winid)); +extern void FDECL(safe_add_menu, (winid, int, const ANY_P *, CHAR_P, CHAR_P, + int, const char *, BOOLEAN_P)); +extern void FDECL(safe_end_menu, (winid, const char *)); +extern int FDECL(safe_select_menu, (winid, int, MENU_ITEM_P **)); +extern char FDECL(safe_message_menu, (CHAR_P, int, const char *)); +extern void NDECL(safe_update_inventory); +extern void NDECL(safe_mark_synch); +extern void NDECL(safe_wait_synch); +#ifdef CLIPPING +extern void FDECL(safe_cliparound, (int, int)); +#endif +#ifdef POSITIONBAR +extern void FDECL(safe_update_positionbar, (char *)); +#endif +extern void FDECL(safe_print_glyph, (winid, XCHAR_P, XCHAR_P, int, int)); +extern void FDECL(safe_raw_print, (const char *)); +extern void FDECL(safe_raw_print_bold, (const char *)); +extern int NDECL(safe_nhgetch); +extern int FDECL(safe_nh_poskey, (int *, int *, int *)); +extern void NDECL(safe_nhbell); +extern int NDECL(safe_doprev_message); +extern char FDECL(safe_yn_function, (const char *, const char *, CHAR_P)); +extern void FDECL(safe_getlin, (const char *, char *)); +extern int NDECL(safe_get_ext_cmd); +extern void FDECL(safe_number_pad, (int)); +extern void NDECL(safe_delay_output); +#ifdef CHANGE_COLOR +extern void FDECL(safe_change_color, (int, long, int)); +#ifdef MAC +extern void FDECL(safe_change_background, (int)); +extern short FDECL(safe_set_font_name, (winid, char *)); +#endif +extern char *NDECL(safe_get_color_string); +#endif +extern void NDECL(safe_start_screen); +extern void NDECL(safe_end_screen); +extern void FDECL(safe_outrip, (winid, int, time_t)); +extern void FDECL(safe_preference_update, (const char *)); +extern char *FDECL(safe_getmsghistory, (BOOLEAN_P)); +extern void FDECL(safe_putmsghistory, (const char *, BOOLEAN_P)); +extern void NDECL(safe_status_init); +extern void NDECL(safe_status_finish); +extern void FDECL(safe_status_enablefield, + (int, const char *, const char *, BOOLEAN_P)); +extern void FDECL(safe_status_update, (int, genericptr_t, int, int, int, unsigned long *)); +extern boolean NDECL(safe_can_suspend); +extern void FDECL(stdio_raw_print, (const char *)); +extern void FDECL(stdio_raw_print_bold, (const char *)); +extern void NDECL(stdio_wait_synch); +extern int NDECL(stdio_nhgetch); +#endif /* SAFEPROCS */ #endif /* WINPROCS_H */ + diff --git a/src/apply.c b/src/apply.c index d202acc77..edb3940e6 100644 --- a/src/apply.c +++ b/src/apply.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 apply.c $NHDT-Date: 1542765339 2018/11/21 01:55:39 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.254 $ */ +/* NetHack 3.6 apply.c $NHDT-Date: 1544442708 2018/12/10 11:51:48 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.269 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -418,7 +418,7 @@ register struct obj *obj; return res; case SCORR: You_hear(hollow_str, "passage"); - lev->typ = CORR; + lev->typ = CORR, lev->flags = 0; unblock_point(rx, ry); feel_newsym(rx, ry); return res; @@ -3394,7 +3394,7 @@ struct obj *obj; */ typ = fillholetyp(x, y, FALSE); if (typ != ROOM) { - levl[x][y].typ = typ; + levl[x][y].typ = typ, levl[x][y].flags = 0; liquid_flow(x, y, typ, t_at(x, y), fillmsg ? (char *) 0 diff --git a/src/botl.c b/src/botl.c index 2fa84afe0..db96c160b 100644 --- a/src/botl.c +++ b/src/botl.c @@ -234,7 +234,8 @@ do_statusline2() void bot() { - if (youmonst.data && iflags.status_updates) { + /* dosave() flags completion by setting u.uhp to -1 */ + if ((u.uhp != -1) && youmonst.data && iflags.status_updates) { #ifdef STATUS_HILITES bot_via_windowport(); #else diff --git a/src/decl.c b/src/decl.c index 1750a5bd4..7ce723644 100644 --- a/src/decl.c +++ b/src/decl.c @@ -17,6 +17,7 @@ int locknum = 0; /* max num of simultaneous users */ #ifdef DEF_PAGER char *catmore = 0; /* default pager */ #endif +char chosen_windowtype[WINTYPELEN]; NEARDATA int bases[MAXOCLASSES] = DUMMY; diff --git a/src/detect.c b/src/detect.c index 416c2611f..e6c5778af 100644 --- a/src/detect.c +++ b/src/detect.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 detect.c $NHDT-Date: 1542853884 2018/11/22 02:31:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.87 $ */ +/* NetHack 3.6 detect.c $NHDT-Date: 1544437284 2018/12/10 10:21:24 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.91 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2018. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1308,7 +1308,8 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */ struct obj *otmp; long save_EDetect_mons; char save_viz_uyux; - boolean unconstrained, refresh = FALSE, mdetected = FALSE, + boolean unconstrained, refresh = FALSE, + mdetected = FALSE, odetected = FALSE, /* fake spellbook 'sobj' implies hero has cast the spell; when book is blessed, casting is skilled or expert level; if already clairvoyant, non-skilled spell acts like skilled */ @@ -1363,6 +1364,10 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */ if (extended) otmp->dknown = 1; map_object(otmp, TRUE); + newglyph = glyph_at(zx, zy); + /* if otmp is underwater, we'll need to redisplay the water */ + if (newglyph != oldglyph && covers_objects(zx, zy)) + odetected = TRUE; } /* if there is a monster here, see or detect it, possibly as "remembered, unseen monster" */ @@ -1385,7 +1390,7 @@ struct obj *sobj; /* scroll--actually fake spellbook--object */ } } - if (!level.flags.hero_memory || unconstrained || mdetected) { + if (!level.flags.hero_memory || unconstrained || mdetected || odetected) { flush_screen(1); /* flush temp screen */ /* the getpos() prompt from browse_map() is only shown when flags.verbose is set, but make this unconditional so that diff --git a/src/dig.c b/src/dig.c index 3f5e74bc0..29d0941d4 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dig.c $NHDT-Date: 1542765354 2018/11/21 01:55:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.115 $ */ +/* NetHack 3.6 dig.c $NHDT-Date: 1544442710 2018/12/10 11:51:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.116 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -81,7 +81,7 @@ boolean waslit, rockit; lev->horizontal = FALSE; /* short-circuit vision recalc */ viz_array[y][x] = (dist < 3) ? (IN_SIGHT | COULD_SEE) : COULD_SEE; - lev->typ = (rockit ? STONE : ROOM); + lev->typ = (rockit ? STONE : ROOM); /* flags set via doormask above */ if (dist >= 3) impossible("mkcavepos called with dist %d", dist); feel_newsym(x, y); @@ -129,7 +129,7 @@ register boolean rockit; } if (!rockit && levl[u.ux][u.uy].typ == CORR) { - levl[u.ux][u.uy].typ = ROOM; + levl[u.ux][u.uy].typ = ROOM; /* flags for CORR already 0 */ if (waslit) levl[u.ux][u.uy].waslit = TRUE; newsym(u.ux, u.uy); /* in case player is invisible */ @@ -361,9 +361,9 @@ dig(VOID_ARGS) } if (context.digging.effort > 100) { - register const char *digtxt, *dmgtxt = (const char *) 0; - register struct obj *obj; - register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); + const char *digtxt, *dmgtxt = (const char *) 0; + struct obj *obj; + boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) { if (break_statue(obj)) @@ -397,12 +397,12 @@ dig(VOID_ARGS) } if (IS_TREE(lev->typ)) { digtxt = "You cut down the tree."; - lev->typ = ROOM; + lev->typ = ROOM, lev->flags = 0; if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy); } else { digtxt = "You succeed in cutting away some rock."; - lev->typ = CORR; + lev->typ = CORR, lev->flags = 0; } } else if (IS_WALL(lev->typ)) { if (shopedge) { @@ -410,12 +410,11 @@ dig(VOID_ARGS) dmgtxt = "damage"; } if (level.flags.is_maze_lev) { - lev->typ = ROOM; + lev->typ = ROOM, lev->flags = 0; } else if (level.flags.is_cavernous_lev && !in_town(dpx, dpy)) { - lev->typ = CORR; + lev->typ = CORR, lev->flags = 0; } else { - lev->typ = DOOR; - lev->doormask = D_NODOOR; + lev->typ = DOOR, lev->doormask = D_NODOOR; } digtxt = "You make an opening in the wall."; } else if (lev->typ == SDOOR) { @@ -573,6 +572,7 @@ int ttyp; } else if (lev->typ == DRAWBRIDGE_DOWN || (is_drawbridge_wall(x, y) >= 0)) { int bx = x, by = y; + /* if under the portcullis, the bridge is adjacent */ (void) find_drawbridge(&bx, &by); destroy_drawbridge(bx, by); @@ -853,6 +853,7 @@ coord *cc; } else { typ = fillholetyp(dig_x, dig_y, FALSE); + lev->flags = 0; if (typ != ROOM) { lev->typ = typ; liquid_flow(dig_x, dig_y, typ, ttmp, @@ -935,7 +936,7 @@ coord *cc; pline_The("grave seems unused. Strange...."); break; } - levl[dig_x][dig_y].typ = ROOM; + levl[dig_x][dig_y].typ = ROOM, levl[dig_x][dig_y].flags = 0; del_engr_at(dig_x, dig_y); newsym(dig_x, dig_y); return; @@ -1272,7 +1273,7 @@ register struct monst *mtmp; newsym(mtmp->mx, mtmp->my); return FALSE; } else if (here->typ == SCORR) { - here->typ = CORR; + here->typ = CORR, here->flags = 0; unblock_point(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); draft_message(FALSE); /* "You feel a draft." */ @@ -1297,20 +1298,19 @@ register struct monst *mtmp; if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); if (level.flags.is_maze_lev) { - here->typ = ROOM; + here->typ = ROOM, here->flags = 0; } else if (level.flags.is_cavernous_lev && !in_town(mtmp->mx, mtmp->my)) { - here->typ = CORR; + here->typ = CORR, here->flags = 0; } else { - here->typ = DOOR; - here->doormask = D_NODOOR; + here->typ = DOOR, here->doormask = D_NODOOR; } } else if (IS_TREE(here->typ)) { - here->typ = ROOM; + here->typ = ROOM, here->flags = 0; if (pile && pile < 5) (void) rnd_treefruit_at(mtmp->mx, mtmp->my); } else { - here->typ = CORR; + here->typ = CORR, here->flags = 0; if (pile && pile < 5) (void) mksobj_at((pile == 1) ? BOULDER : ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); @@ -1495,7 +1495,7 @@ zap_dig() shopdoor = TRUE; } if (room->typ == SDOOR) - room->typ = DOOR; + room->typ = DOOR; /* doormask set below */ else if (cansee(zx, zy)) pline_The("door is razed!"); watch_dig((struct monst *) 0, zx, zy, TRUE); @@ -1511,21 +1511,21 @@ zap_dig() add_damage(zx, zy, SHOP_WALL_COST); shopwall = TRUE; } - room->typ = ROOM; + room->typ = ROOM, room->flags = 0; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("wall glows then fades."); break; } else if (IS_TREE(room->typ)) { /* check trees before stone */ if (!(room->wall_info & W_NONDIGGABLE)) { - room->typ = ROOM; + room->typ = ROOM, room->flags = 0; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("tree shudders but is unharmed."); break; } else if (room->typ == STONE || room->typ == SCORR) { if (!(room->wall_info & W_NONDIGGABLE)) { - room->typ = CORR; + room->typ = CORR, room->flags = 0; unblock_point(zx, zy); /* vision */ } else if (!Blind) pline_The("rock glows then fades."); @@ -1541,17 +1541,16 @@ zap_dig() } watch_dig((struct monst *) 0, zx, zy, TRUE); if (level.flags.is_cavernous_lev && !in_town(zx, zy)) { - room->typ = CORR; + room->typ = CORR, room->flags = 0; } else { - room->typ = DOOR; - room->doormask = D_NODOOR; + room->typ = DOOR, room->doormask = D_NODOOR; } digdepth -= 2; } else if (IS_TREE(room->typ)) { - room->typ = ROOM; + room->typ = ROOM, room->flags = 0; digdepth -= 2; } else { /* IS_ROCK but not IS_WALL or SDOOR */ - room->typ = CORR; + room->typ = CORR, room->flags = 0; digdepth--; } unblock_point(zx, zy); /* vision */ @@ -1563,8 +1562,10 @@ zap_dig() if (pitflow && isok(flow_x, flow_y)) { struct trap *ttmp = t_at(flow_x, flow_y); + if (ttmp && is_pit(ttmp->ttyp)) { schar filltyp = fillholetyp(ttmp->tx, ttmp->ty, TRUE); + if (filltyp != ROOM) pit_flow(ttmp, filltyp); } @@ -1589,7 +1590,7 @@ char *msg; int ltyp; struct rm *room; const char *foundation_msg = - "The foundation is too hard to dig through from this angle."; + "The foundation is too hard to dig through from this angle."; if (!cc) return FALSE; @@ -1597,7 +1598,7 @@ char *msg; return FALSE; *msg = '\0'; room = &levl[cc->x][cc->y]; - ltyp = room->typ; + ltyp = room->typ, room->flags = 0; if (is_pool(cc->x, cc->y) || is_lava(cc->x, cc->y)) { /* this is handled by the caller after we return FALSE */ @@ -1677,15 +1678,14 @@ pit_flow(trap, filltyp) struct trap *trap; schar filltyp; { - if (trap && (filltyp != ROOM) - && is_pit(trap->ttyp)) { + if (trap && filltyp != ROOM && is_pit(trap->ttyp)) { struct trap t; int idx; t = *trap; - levl[trap->tx][trap->ty].typ = filltyp; - liquid_flow(trap->tx, trap->ty, filltyp, trap, - (trap->tx == u.ux && trap->ty == u.uy) + levl[t.tx][t.ty].typ = filltyp, levl[t.tx][t.ty].flags = 0; + liquid_flow(t.tx, t.ty, filltyp, trap, + (t.tx == u.ux && t.ty == u.uy) ? "Suddenly %s flows in from the adjacent pit!" : (char *) 0); for (idx = 0; idx < 8; ++idx) { diff --git a/src/do.c b/src/do.c index 2dbe2b5cb..a3f7800b4 100644 --- a/src/do.c +++ b/src/do.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 do.c $NHDT-Date: 1543972190 2018/12/05 01:09:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.176 $ */ +/* NetHack 3.6 do.c $NHDT-Date: 1544442710 2018/12/10 11:51:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.177 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -67,7 +67,7 @@ boolean pushing; levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else - levl[rx][ry].typ = ROOM; + levl[rx][ry].typ = ROOM, levl[rx][ry].flags = 0; if (ttmp) (void) delfloortrap(ttmp); @@ -276,22 +276,29 @@ STATIC_DCL void polymorph_sink() { uchar sym = S_sink; + boolean sinklooted; if (levl[u.ux][u.uy].typ != SINK) return; + sinklooted = levl[u.ux][u.uy].looted != 0; level.flags.nsinks--; - levl[u.ux][u.uy].doormask = 0; + levl[u.ux][u.uy].doormask = 0; /* levl[][].flags */ switch (rn2(4)) { default: case 0: sym = S_fountain; levl[u.ux][u.uy].typ = FOUNTAIN; + levl[u.ux][u.uy].blessedftn = 0; + if (sinklooted) + SET_FOUNTAIN_LOOTED(u.ux, u.uy); level.flags.nfountains++; break; case 1: sym = S_throne; levl[u.ux][u.uy].typ = THRONE; + if (sinklooted) + levl[u.ux][u.uy].looted = T_LOOTED; break; case 2: sym = S_altar; diff --git a/src/dothrow.c b/src/dothrow.c index e55c9b7d6..48220a4fb 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 dothrow.c $NHDT-Date: 1543892215 2018/12/04 02:56:55 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.152 $ */ +/* NetHack 3.6 dothrow.c $NHDT-Date: 1544401268 2018/12/10 00:21:08 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.153 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -707,6 +707,11 @@ int x, y; newsym(ox, oy); /* update old position */ vision_recalc(1); /* update for new position */ flush_screen(1); + /* if terrain type changes, levitation or flying might become blocked + or unblocked; might issue message, so do this after map+vision has + been updated for new location instead of right after u_on_newpos() */ + if (levl[u.ux][u.uy].typ != levl[ox][oy].typ) + switch_terrain(); if (is_pool(x, y) && !u.uinwater) { if ((Is_waterlevel(&u.uz) && levl[x][y].typ == WATER) diff --git a/src/fountain.c b/src/fountain.c index 616d42b47..57e914559 100644 --- a/src/fountain.c +++ b/src/fountain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 fountain.c $NHDT-Date: 1455402364 2016/02/13 22:26:04 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.56 $ */ +/* NetHack 3.6 fountain.c $NHDT-Date: 1544442711 2018/12/10 11:51:51 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.60 $ */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ @@ -137,7 +137,7 @@ genericptr_t poolcnt; pline("Water gushes forth from the overflowing fountain!"); /* Put a pool at x, y */ - levl[x][y].typ = POOL; + levl[x][y].typ = POOL, levl[x][y].flags = 0; /* No kelp! */ del_engr_at(x, y); water_damage_chain(level.objects[x][y], TRUE); @@ -205,8 +205,7 @@ boolean isyou; return; } /* replace the fountain with ordinary floor */ - levl[x][y].typ = ROOM; - levl[x][y].looted = 0; + levl[x][y].typ = ROOM, levl[x][y].flags = 0; levl[x][y].blessedftn = 0; if (cansee(x, y)) pline_The("fountain dries up!"); @@ -397,8 +396,7 @@ register struct obj *obj; exercise(A_WIS, TRUE); } update_inventory(); - levl[u.ux][u.uy].typ = ROOM; - levl[u.ux][u.uy].looted = 0; + levl[u.ux][u.uy].typ = ROOM, levl[u.ux][u.uy].flags = 0; newsym(u.ux, u.uy); level.flags.nfountains--; if (in_town(u.ux, u.uy)) @@ -511,8 +509,9 @@ int x, y; if (cansee(x, y) || (x == u.ux && y == u.uy)) pline_The("pipes break! Water spurts out!"); level.flags.nsinks--; - levl[x][y].doormask = 0; - levl[x][y].typ = FOUNTAIN; + levl[x][y].typ = FOUNTAIN, levl[x][y].looted = 0; + levl[x][y].blessedftn = 0; + SET_FOUNTAIN_LOOTED(x, y); level.flags.nfountains++; newsym(x, y); } diff --git a/src/hack.c b/src/hack.c index c0c0313f2..362a4c78a 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 hack.c $NHDT-Date: 1543972190 2018/12/05 01:09:50 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.200 $ */ +/* NetHack 3.6 hack.c $NHDT-Date: 1544401269 2018/12/10 00:21:09 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.201 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -13,7 +13,6 @@ STATIC_DCL int FDECL(still_chewing, (XCHAR_P, XCHAR_P)); STATIC_DCL void NDECL(dosinkfall); STATIC_DCL boolean FDECL(findtravelpath, (int)); STATIC_DCL boolean FDECL(trapmove, (int, int, struct trap *)); -STATIC_DCL void NDECL(switch_terrain); STATIC_DCL struct monst *FDECL(monstinroom, (struct permonst *, int)); STATIC_DCL boolean FDECL(doorless_door, (int, int)); STATIC_DCL void FDECL(move_update, (BOOLEAN_P)); @@ -1935,12 +1934,13 @@ invocation_message() /* moving onto different terrain; might be going into solid rock, inhibiting levitation or flight, or coming back out of such, reinstating levitation/flying */ -STATIC_OVL void +void switch_terrain() { struct rm *lev = &levl[u.ux][u.uy]; boolean blocklev = (IS_ROCK(lev->typ) || closed_door(u.ux, u.uy) - || (Is_waterlevel(&u.uz) && lev->typ == WATER)); + || (Is_waterlevel(&u.uz) && lev->typ == WATER)), + was_levitating = !!Levitation, was_flying = !!Flying; if (blocklev) { /* called from spoteffects(), stop levitating but skip float_down() */ @@ -1968,6 +1968,8 @@ switch_terrain() if (Flying) You("start flying."); } + if ((!Levitation ^ was_levitating) || (!Flying ^ was_flying)) + context.botl = TRUE; /* update Lev/Fly status condition */ } /* extracted from spoteffects; called by spoteffects to check for entering or @@ -2828,12 +2830,13 @@ const char *msg_override; else if (!nomovemsg) nomovemsg = You_can_move_again; if (*nomovemsg) - pline1(nomovemsg); + pline("%s", nomovemsg); nomovemsg = 0; u.usleep = 0; multi_reason = NULL; if (afternmv) { int NDECL((*f)) = afternmv; + /* clear afternmv before calling it (to override the encumbrance hack for levitation--see weight_cap()) */ afternmv = (int NDECL((*))) 0; diff --git a/src/lock.c b/src/lock.c index 067eb6c99..5c52532b9 100644 --- a/src/lock.c +++ b/src/lock.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 lock.c $NHDT-Date: 1521499715 2018/03/19 22:48:35 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.80 $ */ +/* NetHack 3.6 lock.c $NHDT-Date: 1544442712 2018/12/10 11:51:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.82 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -950,7 +950,7 @@ int x, y; return FALSE; } block_point(x, y); - door->typ = SDOOR; + door->typ = SDOOR, door->doormask = D_NODOOR; if (vis) pline_The("doorway vanishes!"); newsym(x, y); diff --git a/src/monmove.c b/src/monmove.c index c501cf421..fbc2d419d 100644 --- a/src/monmove.c +++ b/src/monmove.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 monmove.c $NHDT-Date: 1517877380 2018/02/06 00:36:20 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.96 $ */ +/* NetHack 3.6 monmove.c $NHDT-Date: 1544442712 2018/12/10 11:51:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.109 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1474,6 +1474,7 @@ dissolve_bars(x, y) register int x, y; { levl[x][y].typ = (Is_special(&u.uz) || *in_rooms(x, y, 0)) ? ROOM : CORR; + levl[x][y].flags = 0; newsym(x, y); } diff --git a/src/music.c b/src/music.c index 6b5d3330f..bcaae3f83 100644 --- a/src/music.c +++ b/src/music.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 music.c $NHDT-Date: 1542765361 2018/11/21 01:56:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.56 $ */ +/* NetHack 3.6 music.c $NHDT-Date: 1544442713 2018/12/10 11:51:53 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.57 $ */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ @@ -320,7 +320,7 @@ int force; */ filltype = fillholetyp(x, y, FALSE); if (filltype != ROOM) { - levl[x][y].typ = filltype; + levl[x][y].typ = filltype; /* flags set via doormask */ liquid_flow(x, y, filltype, chasm, (char *) 0); } diff --git a/src/options.c b/src/options.c index b3595a6ad..3a190b9c1 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 options.c $NHDT-Date: 1544174413 2018/12/07 09:20:13 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.339 $ */ +/* NetHack 3.6 options.c $NHDT-Date: 1544396581 2018/12/09 23:03:01 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.340 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -20,7 +20,6 @@ NEARDATA struct instance_flags iflags; /* provide linkage */ #endif #define BACKWARD_COMPAT -#define WINTYPELEN 16 #ifdef DEFAULT_WC_TILED_MAP #define PREFER_TILED TRUE @@ -873,16 +872,23 @@ initoptions_finish() * A multi-interface binary might only support status highlighting * for some of the interfaces; check whether we asked for it but are * using one which doesn't. + * + * Option processing can take place before a user-decided WindowPort + * is even initialized, so check for that too. */ - if (iflags.hilite_delta && !wc2_supported("statushilites")) { - raw_printf("Status highlighting not supported for %s interface.", - windowprocs.name); - iflags.hilite_delta = 0; + if (!WINDOWPORT("safe-startup")) { + if (iflags.hilite_delta && !wc2_supported("statushilites")) { + raw_printf("Status highlighting not supported for %s interface.", + windowprocs.name); + iflags.hilite_delta = 0; + } } #endif return; } +/* copy up to maxlen-1 characters; 'dest' must be able to hold maxlen; + treat comma as alternate end of 'src' */ STATIC_OVL void nmcpy(dest, src, maxlen) char *dest; @@ -896,7 +902,7 @@ int maxlen; break; /*exit on \0 terminator*/ *dest++ = *src++; } - *dest = 0; + *dest = '\0'; } /* @@ -2583,7 +2589,7 @@ boolean tinitial, tfrom_file; if (duplicate) complain_about_duplicate(opts, 1); - op = string_for_opt(opts, negated); + op = string_for_opt(opts, negated || !initial); if (negated) { if (op) { bad_negation("fruit", TRUE); @@ -2594,6 +2600,8 @@ boolean tinitial, tfrom_file; } if (!op) return FALSE; + /* 3.6.2: strip leading and trailing spaces, condense internal ones */ + mungspaces(op); if (!initial) { struct fruit *f; int fnum = 0; @@ -3514,10 +3522,14 @@ boolean tinitial, tfrom_file; bad_negation(fullname, FALSE); return FALSE; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { - char buf[WINTYPELEN]; + if (!iflags.windowtype_deferred) { + char buf[WINTYPELEN]; - nmcpy(buf, op, WINTYPELEN); - choose_windows(buf); + nmcpy(buf, op, WINTYPELEN); + choose_windows(buf); + } else { + nmcpy(chosen_windowtype, op, WINTYPELEN); + } } else return FALSE; return retval; @@ -4465,7 +4477,7 @@ doset() /* changing options via menu by Per Liboriussen */ /* boolean option */ Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", boolopt[opt_indx].name); - parseoptions(buf, setinitial, fromfile); + (void) parseoptions(buf, setinitial, fromfile); if (wc_supported(boolopt[opt_indx].name) || wc2_supported(boolopt[opt_indx].name)) preference_update(boolopt[opt_indx].name); @@ -4481,7 +4493,7 @@ doset() /* changing options via menu by Per Liboriussen */ continue; Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); /* pass the buck */ - parseoptions(buf, setinitial, fromfile); + (void) parseoptions(buf, setinitial, fromfile); } if (wc_supported(compopt[opt_indx].name) || wc2_supported(compopt[opt_indx].name)) @@ -4639,7 +4651,8 @@ boolean setinitial, setfromfile; destroy_nhwindow(tmpwin); } else if (!strcmp("pickup_types", optname)) { /* parseoptions will prompt for the list of types */ - parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile); + (void) parseoptions(strcpy(buf, "pickup_types"), + setinitial, setfromfile); } else if (!strcmp("disclose", optname)) { /* order of disclose_names[] must correspond to disclosure_options in decl.c */ diff --git a/src/sit.c b/src/sit.c index 1aa8085bf..5f85bb13e 100644 --- a/src/sit.c +++ b/src/sit.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sit.c $NHDT-Date: 1458341129 2016/03/18 22:45:29 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.53 $ */ +/* NetHack 3.6 sit.c $NHDT-Date: 1544442714 2018/12/10 11:51:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.59 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2012. */ /* NetHack may be freely redistributed. See license for details. */ @@ -281,7 +281,7 @@ dosit() if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ - levl[u.ux][u.uy].typ = ROOM; + levl[u.ux][u.uy].typ = ROOM, levl[u.ux][u.uy].flags = 0; pline_The("throne vanishes in a puff of logic."); newsym(u.ux, u.uy); } diff --git a/src/teleport.c b/src/teleport.c index a7901e3d9..9aedc0c3e 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 teleport.c $NHDT-Date: 1523306912 2018/04/09 20:48:32 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.73 $ */ +/* NetHack 3.6 teleport.c $NHDT-Date: 1544401270 2018/12/10 00:21:10 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.81 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2011. */ /* NetHack may be freely redistributed. See license for details. */ @@ -340,6 +340,11 @@ boolean allow_drag; vision_full_recalc = 1; nomul(0); vision_recalc(0); /* vision before effects */ + /* if terrain type changes, levitation or flying might become blocked + or unblocked; might issue message, so do this after map+vision has + been updated for new location instead of right after u_on_newpos() */ + if (levl[u.ux][u.uy].typ != levl[u.ux0][u.uy0].typ) + switch_terrain(); if (telescroll) { /* when teleporting by scroll, we need to handle discovery now before getting feedback about any objects at our diff --git a/src/zap.c b/src/zap.c index 1e6e3b1b3..6907880e4 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 zap.c $NHDT-Date: 1544230271 2018/12/08 00:51:11 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.301 $ */ +/* NetHack 3.6 zap.c $NHDT-Date: 1544442714 2018/12/10 11:51:54 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.302 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Robert Patrick Rankin, 2013. */ /* NetHack may be freely redistributed. See license for details. */ @@ -4374,7 +4374,7 @@ short exploding_wand_typ; msgtxt = "Some water evaporates."; } else { rangemod -= 3; - lev->typ = ROOM; + lev->typ = ROOM, lev->flags = 0; t = maketrap(x, y, PIT); if (t) t->tseen = 1; @@ -4413,9 +4413,9 @@ short exploding_wand_typ; lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); } else { - if (!lava) - lev->icedpool = (lev->typ == POOL) ? ICED_POOL - : ICED_MOAT; + lev->icedpool = lava ? 0 + : (lev->typ == POOL) ? ICED_POOL + : ICED_MOAT; lev->typ = lava ? ROOM : ICE; } bury_objs(x, y); @@ -4490,15 +4490,14 @@ short exploding_wand_typ; Norep("The %s melt.", defsyms[S_bars].explanation); if (*in_rooms(x, y, SHOPBASE)) { /* in case we ever have a shop bounded by bars */ - lev->typ = ROOM; + lev->typ = ROOM, lev->flags = 0; if (see_it) newsym(x, y); add_damage(x, y, (type >= 0) ? SHOP_BARS_COST : 0L); if (type >= 0) *shopdamage = TRUE; } else { - lev->typ = DOOR; - lev->doormask = D_NODOOR; + lev->typ = DOOR, lev->doormask = D_NODOOR; if (see_it) newsym(x, y); } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index 8651ae8fe..1f67b0efb 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -3,11 +3,7 @@ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ -/* main.c - MSDOS, OS/2, ST, Amiga, and Windows NetHack */ - -#ifdef WIN32 -#include "win32api.h" /* for GetModuleFileName */ -#endif +/* main.c - MSDOS, OS/2, ST, Amiga NetHack */ #include "hack.h" #include "dlb.h" @@ -47,29 +43,12 @@ void NDECL(preserve_icon); STATIC_DCL void FDECL(process_options, (int argc, char **argv)); STATIC_DCL void NDECL(nhusage); -#if defined(MICRO) || defined(WIN32) || defined(OS2) +#if defined(MICRO) || defined(OS2) extern void FDECL(nethack_exit, (int)); #else #define nethack_exit exit #endif -#ifdef WIN32 -extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ -extern int redirect_stdout; /* from sys/share/pcsys.c */ -extern int GUILaunched; -char *NDECL(exename); -char default_window_sys[] = "mswin"; -#ifndef WIN32CON -HANDLE hStdOut; -boolean NDECL(fakeconsole); -void NDECL(freefakeconsole); -#endif -#endif - -#if defined(MSWIN_GRAPHICS) -extern void NDECL(mswin_destroy_reg); -#endif - #ifdef EXEPATH STATIC_DCL char *FDECL(exepath, (char *)); #endif @@ -78,7 +57,7 @@ int FDECL(main, (int, char **)); extern boolean FDECL(pcmain, (int, char **)); -#if defined(__BORLANDC__) && !defined(_WIN32) +#if defined(__BORLANDC__) void NDECL(startup); unsigned _stklen = STKSIZ; #endif @@ -98,21 +77,8 @@ char *argv[]; { boolean resuming; - nethack_enter(argc, argv); - sys_early_init(); -#if defined(WIN32) && defined(TTY_GRAPHICS) - Strcpy(default_window_sys, "tty"); -#else -#if defined(CURSES_GRAPHICS) - Strcpy(default_window_sys, "curses"); -#endif -#endif - resuming = pcmain(argc, argv); -#ifdef LAN_FEATURES - init_lan_features(); -#endif moveloop(resuming); nethack_exit(EXIT_SUCCESS); /*NOTREACHED*/ @@ -126,14 +92,10 @@ char *argv[]; { register int fd; register char *dir; -#if defined(WIN32) || defined(MSDOS) +#if defined(MSDOS) char *envp = NULL; char *sptr = NULL; #endif -#if defined(WIN32) - char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; - boolean save_getreturn_status = getreturn_enabled; -#endif #ifdef NOCWD_ASSUMPTIONS char failbuf[BUFSZ]; #endif @@ -162,7 +124,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ # endif #endif -#if defined(__BORLANDC__) && !defined(_WIN32) +#if defined(__BORLANDC__) startup(); #endif @@ -175,15 +137,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ #endif hname = "NetHack"; /* used for syntax messages */ -#ifndef WIN32 choose_windows(DEFAULT_WINDOW_SYS); -#else - choose_windows(default_window_sys); - if (argc >= 1 - && !strcmpi(default_window_sys, "mswin") - && strstri(argv[0], "nethackw.exe")) - iflags.windowtype_locked = TRUE; -#endif #if !defined(AMIGA) && !defined(GNUDOS) /* Save current directory and make sure it gets restored when @@ -243,7 +197,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) fqn_prefix[prefcnt] = fqn_prefix[0]; -#if defined(WIN32) || defined(MSDOS) +#if defined(MSDOS) /* sysconf should be searched for in this location */ envp = nh_getenv("COMMONPROGRAMFILES"); if (envp) { @@ -317,14 +271,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ chdirx(HACKDIR, 1); #endif ami_wininit_data(); -#endif -#ifdef WIN32 - save_getreturn_status = getreturn_enabled; -#ifdef TTY_GRAPHICS - raw_clear_screen(); -#endif - getreturn_enabled = TRUE; - check_recordfile((char *) 0); #endif initoptions(); @@ -355,13 +301,6 @@ _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 @@ -381,36 +320,11 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, dir); } if (argc > 1) { -#if defined(WIN32) && !defined(WIN32CON) - int sfd = 0; - boolean tmpconsole = FALSE; - hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); -#endif /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { -#if defined(WIN32) && !defined(WIN32CON) - -#if 0 - if (!hStdOut) { - tmpconsole = fakeconsole(); - } -#endif - /* - * Check to see if we're redirecting to a file. - */ - sfd = (int) _fileno(stdout); - redirect_stdout = (sfd >= 0) ? !isatty(sfd) : 0; - - if (!redirect_stdout && !hStdOut) { - raw_printf( - "-s is not supported for the Graphical Interface\n"); - nethack_exit(EXIT_SUCCESS); - } -#endif - #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir, 0); #endif @@ -418,47 +332,16 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ initoptions(); #endif prscore(argc, argv); -#if defined(WIN32) && !defined(WIN32CON) - if (tmpconsole) { - getreturn("to exit"); - freefakeconsole(); - tmpconsole = FALSE; - } -#endif nethack_exit(EXIT_SUCCESS); } -#ifdef MSWIN_GRAPHICS - if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ - mswin_destroy_reg(); - nethack_exit(EXIT_SUCCESS); - } -#endif /* Don't initialize the window system just to print usage */ if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { -#if 0 - if (!hStdOut) { - GUILaunched = 0; - tmpconsole = fakeconsole(); - } -#endif nhusage(); - -#if defined(WIN32) && !defined(WIN32CON) - if (tmpconsole) { - getreturn("to exit"); - freefakeconsole(); - tmpconsole = FALSE; - } -#endif nethack_exit(EXIT_SUCCESS); } } } - -#ifdef WIN32 - getreturn_enabled = save_getreturn_status; -#endif /* * It seems you really want to play. */ @@ -472,11 +355,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ "\"%s\".%s", copyright_banner_line(1), copyright_banner_line(2), copyright_banner_line(3), copyright_banner_line(4), DLBFILE, -#ifdef WIN32 - "\nAre you perhaps trying to run NetHack within a zip utility?"); -#else ""); -#endif error("dlb_init failure."); } @@ -490,41 +369,22 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ chdirx(hackdir, 1); #endif -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) /* In 3.6.0, several ports process options before they init * the window port. This allows settings that impact window * ports to be specified or read from the sys or user config files. */ process_options(argc, argv); -#ifdef WIN32 - /* - if (WINDOWPORT("mswin")) - NHWinMainInit(); - else - */ -#ifdef TTY_GRAPHICS - if (WINDOWPORT("tty")) { - iflags.use_background_glyph = FALSE; - nttty_open(1); - } else { - iflags.use_background_glyph = TRUE; - } -#endif /* TTY_GRAPHICS */ -#endif /* WIN32 */ -#endif /* MSDOS || WIN32 */ +#endif /* MSDOS */ -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) init_nhwindows(&argc, argv); #else init_nhwindows(&argc, argv); process_options(argc, argv); #endif -#if defined(WIN32) && defined(TTY_GRAPHICS) - toggle_mouse_support(); /* must come after process_options */ -#endif - #ifdef MFLOPPY set_lock_and_bones(); #ifndef AMIGA @@ -561,19 +421,8 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ * overwritten without confirmation when a user starts up * another game with the same player name. */ -#if defined(WIN32) - /* Obtain the name of the logged on user and incorporate - * it into the name. */ - Sprintf(fnamebuf, "%s-%s", get_username(0), plname); - (void) fname_encode( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', - fnamebuf, encodedfnamebuf, BUFSZ); - Sprintf(lock, "%s", encodedfnamebuf); - /* regularize(lock); */ /* we encode now, rather than substitute */ -#else Strcpy(lock, plname); regularize(lock); -#endif getlock(); #else /* What follows is !PC_LOCKING */ #ifdef AMIGA /* We'll put the bones & levels in the user specified directory \ @@ -599,11 +448,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (fd < 0) { raw_print("Cannot create lock file"); } else { -#ifdef WIN32 - hackpid = GetCurrentProcessId(); -#else hackpid = 1; -#endif write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); nhclose(fd); } @@ -618,10 +463,6 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ vision_init(); display_gamewindows(); -#ifdef WIN32 - getreturn_enabled = TRUE; -#endif - /* * First, try to find and restore a save file for specified character. * We'll return here if new game player_selection() renames the hero. @@ -799,18 +640,6 @@ char *argv[]; case 'l': bigscreen = -1; break; -#endif -#ifdef WIN32 - case 'w': /* windowtype */ -#ifdef TTY_GRAPHICS - if (strncmpi(&argv[0][2], "tty", 3)) { - nttty_open(1); - } -#endif - config_error_init(FALSE, "command line", FALSE); - choose_windows(&argv[0][2]); - config_error_done(); - break; #endif case '@': flags.randomall = 1; @@ -904,14 +733,14 @@ boolean wr; #endif /* CHDIR */ #ifdef PORT_HELP -#if defined(MSDOS) || defined(WIN32) +#if defined(MSDOS) void port_help() { /* display port specific help file */ display_file(PORT_HELP, 1); } -#endif /* MSDOS || WIN32 */ +#endif /* MSDOS */ #endif /* PORT_HELP */ /* validate wizard mode if player has requested access to it */ @@ -930,71 +759,6 @@ authorize_wizard_mode() #define PATH_SEPARATOR '\\' #endif -#if defined(WIN32) && !defined(WIN32CON) -static char exenamebuf[PATHLEN]; -extern HANDLE hConIn; -extern HANDLE hConOut; -boolean has_fakeconsole; - -char * -exename() -{ - int bsize = PATHLEN; - char *tmp = exenamebuf, *tmp2; - -#ifdef UNICODE - { - TCHAR wbuf[PATHLEN * 4]; - GetModuleFileName((HANDLE) 0, wbuf, PATHLEN * 4); - WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); - } -#else - *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; -#endif - tmp2 = strrchr(tmp, PATH_SEPARATOR); - if (tmp2) - *tmp2 = '\0'; - tmp2++; - return tmp2; -} - -boolean -fakeconsole(void) -{ - if (!hStdOut) { - HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); - HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); - - if (!hStdOut && !hStdIn) { - /* Bool rval; */ - AllocConsole(); - AttachConsole(GetCurrentProcessId()); - /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ - freopen("CON", "w", stdout); - freopen("CON", "r", stdin); - } - has_fakeconsole = TRUE; - } - - /* Obtain handles for the standard Console I/O devices */ - hConIn = GetStdHandle(STD_INPUT_HANDLE); - hConOut = GetStdHandle(STD_OUTPUT_HANDLE); -#if 0 - if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { - /* Unable to set control handler */ - cmode = 0; /* just to have a statement to break on for debugger */ - } -#endif - return has_fakeconsole; -} -void freefakeconsole() -{ - if (has_fakeconsole) { - FreeConsole(); - } -} -#endif - #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; @@ -1009,19 +773,7 @@ char *str; return (char *) 0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; -#ifndef WIN32 Strcpy(tmp, str); -#else -#ifdef UNICODE - { - TCHAR wbuf[BUFSZ]; - GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); - WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); - } -#else - *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; -#endif -#endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; diff --git a/sys/share/pcsys.c b/sys/share/pcsys.c index 0286ad50b..8a99b181e 100644 --- a/sys/share/pcsys.c +++ b/sys/share/pcsys.c @@ -391,19 +391,11 @@ char *name; return; } -#ifdef WIN32 -boolean getreturn_enabled; -int redirect_stdout; -#endif - +#ifndef WIN32 void getreturn(str) const char *str; { -#ifdef WIN32 - if (!getreturn_enabled) - return; -#endif #ifdef TOS msmsg("Hit %s.", str); #else @@ -414,7 +406,6 @@ const char *str; return; } -#ifndef WIN32 void msmsg VA_DECL(const char *, fmt) { @@ -492,7 +483,7 @@ const char *name, *mode; return (FILE *) 0; } -#if defined(MICRO) || defined(WIN32) || defined(OS2) +#if defined(MICRO) || defined(OS2) void nethack_exit(code) int code; @@ -551,4 +542,4 @@ msexit() wait_synch(); return; } -#endif /* MICRO || WIN32 || OS2 */ +#endif /* MICRO || OS2 */ diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 4b8e4f6f1..dba200d97 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -215,7 +215,7 @@ VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o -VOBJ10 = $(O)mail.o $(O)pcmain.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o +VOBJ10 = $(O)mail.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o @@ -233,7 +233,7 @@ VOBJ24 = $(O)track.o $(O)trap.o $(O)u_init.o $(O)uhitm.o VOBJ25 = $(O)vault.o $(O)vis_tab.o $(O)vision.o $(O)weapon.o VOBJ26 = $(O)were.o $(O)wield.o $(O)windows.o $(O)wizard.o VOBJ27 = $(O)worm.o $(O)worn.o $(O)write.o $(O)zap.o -VOBJ28 = $(O)win10.o +VOBJ28 = $(O)win10.o $(O)safeproc.o $(O)windmain.o DLBOBJ = $(O)dlb.o @@ -535,7 +535,7 @@ INCLDIR= /I..\include /I..\sys\winnt # Util builds #========================================== -cflagsBuild = $(cflags) $(INCLDIR) $(WINPFLAG) $(DLBFLG) +cflagsBuild = $(cflags) $(INCLDIR) $(WINPFLAG) $(DLBFLG) -DSAFEPROCS lflagsBuild = $(lflags) $(conlibs) $(MACHINE) #========================================== @@ -1503,7 +1503,6 @@ $(O)\curswins.c: $(WCURSES)\curswins.c $(WCURSES)\curswins.h $(INCL)\wincurs.h # * $(CFLAGS) replaced with $(cflagsBuild) # * $(CC) replaced with @$(CC) # * targets prefixed with $(O) -# * the single win32api.h reference uncommented # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. @@ -1511,8 +1510,7 @@ $(O)\curswins.c: $(WCURSES)\curswins.c $(WCURSES)\curswins.h $(INCL)\wincurs.h $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\atari\tos.c -$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ - $(MSWSYS)\win32api.h +$(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pcsys.c diff --git a/sys/winnt/defaults.nh b/sys/winnt/defaults.nh index 8c9994284..39b7924cf 100644 --- a/sys/winnt/defaults.nh +++ b/sys/winnt/defaults.nh @@ -108,16 +108,16 @@ OPTIONS=suppress_alert:3.3.1 OPTIONS=map_mode:tiles,scroll_margin:10 # Message window settings -OPTIONS=font_message:Arial,font_size_message:9,align_message:top +OPTIONS=font_message:Arial,font_size_message:14,align_message:top # Menu settings -OPTIONS=font_menu:Arial,font_size_menu:9 +OPTIONS=font_menu:Arial,font_size_menu:14 # Text settings -OPTIONS=font_text:Courier New,font_size_text:9 +OPTIONS=font_text:Courier New,font_size_text:14 # Status window settings -OPTIONS=font_status:Courier New,font_size_status:9 +OPTIONS=font_status:Courier New,font_size_status:14 # Other OPTIONS=hilite_pet,!toptenwin @@ -136,7 +136,7 @@ OPTIONS=hilite_pet,!toptenwin # "Nethack mode" colors OPTIONS=windowcolors:status white/#000000 message white/#000000 text white/#000000 menu white/#000000 menutext white/#000000 -OPTIONS=vary_msgcount:1 +OPTIONS=vary_msgcount:4 # *** LOCATIONS *** # IMPORTANT: If you change any of these locations, the directories they diff --git a/sys/winnt/stubs.c b/sys/winnt/stubs.c index 3e7fa4c20..af10a7fc0 100644 --- a/sys/winnt/stubs.c +++ b/sys/winnt/stubs.c @@ -96,13 +96,11 @@ clear_screen() return; } -#ifdef TTY_GRAPHICS void backsp() { return; } -#endif int has_color(int color) diff --git a/sys/winnt/windmain.c b/sys/winnt/windmain.c new file mode 100644 index 000000000..d8b7c8056 --- /dev/null +++ b/sys/winnt/windmain.c @@ -0,0 +1,724 @@ +/* NetHack 3.6 windmain.c $NHDT-Date: 1543465755 2018/11/29 04:29:15 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.101 $ */ +/* Copyright (c) Derek S. Ray, 2015. */ +/* NetHack may be freely redistributed. See license for details. */ + +/* main.c - Windows */ + +#include "win32api.h" /* for GetModuleFileName */ +#include "hack.h" +#include "dlb.h" +#include +#include + +#if !defined(SAFEPROCS) +#error You must #define SAFEPROCS to build windmain.c +#endif + +#define E extern +static void FDECL(process_options, (int argc, char **argv)); +static void NDECL(nhusage); +static char *FDECL(exepath, (char *)); +char *NDECL(exename); +boolean NDECL(fakeconsole); +void NDECL(freefakeconsole); +E void FDECL(nethack_exit, (int)); +E char chosen_windowtype[WINTYPELEN]; /* flag.h */ +#if defined(MSWIN_GRAPHICS) +E void NDECL(mswin_destroy_reg); +#endif +#undef E + +int NDECL(windows_nhgetch); +void NDECL(windows_nhbell); +int FDECL(windows_nh_poskey, (int *, int *, int *)); +void FDECL(windows_raw_print, (const char *)); +char FDECL(windows_yn_function, (const char *, const char *, CHAR_P)); +void FDECL(windows_getlin, (const char *, char *)); +extern int NDECL(windows_console_custom_nhgetch); + +char orgdir[PATHLEN]; +char *dir; +boolean getreturn_enabled; +extern int redirect_stdout; /* from sys/share/pcsys.c */ +extern int GUILaunched; +HANDLE hStdOut; +#if defined(MSWIN_GRAPHICS) +char default_window_sys[] = "mswin"; +#endif + +/* + * __MINGW32__ Note + * If the graphics version is built, we don't need a main; it is skipped + * to help MinGW decide which entry point to choose. If both main and + * WinMain exist, the resulting executable won't work correctly. + */ +int +#ifndef __MINGW32__ +main(argc, argv) +#else +mingw_main(argc, argv) +#endif +int argc; +char *argv[]; +{ + boolean resuming = FALSE; /* assume new game */ + int fd; + char *windowtype = NULL; + char *envp = NULL; + char *sptr = NULL; + char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; + char failbuf[BUFSZ]; + + /* + * Get a set of valid safe windowport function + * pointers during early startup initialization. + */ + if (!WINDOWPORT("safe-startup")) + windowprocs = *get_safe_procs(1); + if (!GUILaunched) + windowprocs.win_nhgetch = windows_console_custom_nhgetch; + + sys_early_init(); +#ifdef _MSC_VER +# ifdef DEBUG + /* set these appropriately for VS debugging */ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); + _CrtSetReportMode(_CRT_ERROR, + _CRTDBG_MODE_DEBUG); /* | _CRTDBG_MODE_FILE);*/ + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); +/*| _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW);*/ +/* use STDERR by default +_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); +_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ +/* Heap Debugging + _CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) + | _CRTDBG_ALLOC_MEM_DF + | _CRTDBG_CHECK_ALWAYS_DF + | _CRTDBG_CHECK_CRT_DF + | _CRTDBG_DELAY_FREE_MEM_DF + | _CRTDBG_LEAK_CHECK_DF); + _CrtSetBreakAlloc(1423); +*/ +# endif +#endif + + hname = "NetHack"; /* used for syntax messages */ + /* Save current directory and make sure it gets restored when + * the game is exited. + */ + if (getcwd(orgdir, sizeof orgdir) == (char *) 0) + error("NetHack: current directory path too long"); + dir = nh_getenv("NETHACKDIR"); + if (dir == (char *) 0) + dir = nh_getenv("HACKDIR"); + if (dir == (char *) 0) + dir = exepath(argv[0]); +#ifdef _MSC_VER + if (IsDebuggerPresent()) { + static char exepath[_MAX_PATH]; + /* check if we're running under the debugger so we can get to the right folder anyway */ + if (dir != (char *)0) { + char *top = (char *)0; + + if (strlen(dir) < (_MAX_PATH - 1)) + strcpy(exepath, dir); + top = strstr(exepath, "\\build\\.\\Debug"); + if (!top) top = strstr(exepath, "\\build\\.\\Release"); + if (top) { + *top = '\0'; + if (strlen(exepath) < (_MAX_PATH - (strlen("\\binary\\") + 1))) { + Strcat(exepath, "\\binary\\"); + if (strlen(exepath) < (PATHLEN - 1)) { + dir = exepath; + } + } + } + } + } +#endif + if (dir != (char *)0) { + int prefcnt; + int fd; + boolean have_syscf = FALSE; + + (void) strncpy(hackdir, dir, PATHLEN - 1); + hackdir[PATHLEN - 1] = '\0'; + fqn_prefix[0] = (char *) alloc(strlen(hackdir) + 2); + Strcpy(fqn_prefix[0], hackdir); + append_slash(fqn_prefix[0]); + for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) + fqn_prefix[prefcnt] = fqn_prefix[0]; + /* sysconf should be searched for in this location */ + envp = nh_getenv("COMMONPROGRAMFILES"); + if (envp) { + if ((sptr = index(envp, ';')) != 0) + *sptr = '\0'; + if (strlen(envp) > 0) { + fqn_prefix[SYSCONFPREFIX] = + (char *) alloc(strlen(envp) + 10); + Strcpy(fqn_prefix[SYSCONFPREFIX], envp); + append_slash(fqn_prefix[SYSCONFPREFIX]); + Strcat(fqn_prefix[SYSCONFPREFIX], "NetHack\\"); + } + } + + /* okay so we have the overriding and definitive locaton + for sysconf, but only in the event that there is not a + sysconf file there (for whatever reason), check a secondary + location rather than abort. */ + + /* Is there a SYSCF_FILE there? */ + fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); + if (fd >= 0) { + /* readable */ + close(fd); + have_syscf = TRUE; + } + + if (!have_syscf) { + /* No SYSCF_FILE where there should be one, and + without an installer, a user may not be able + to place one there. So, let's try somewhere else... */ + fqn_prefix[SYSCONFPREFIX] = fqn_prefix[0]; + + /* Is there a SYSCF_FILE there? */ + fd = open(fqname(SYSCF_FILE, SYSCONFPREFIX, 0), O_RDONLY); + if (fd >= 0) { + /* readable */ + close(fd); + have_syscf = TRUE; + } + } + + /* user's home directory should default to this - unless + * overridden */ + envp = nh_getenv("USERPROFILE"); + if (envp) { + if ((sptr = index(envp, ';')) != 0) + *sptr = '\0'; + if (strlen(envp) > 0) { + fqn_prefix[CONFIGPREFIX] = + (char *) alloc(strlen(envp) + 2); + Strcpy(fqn_prefix[CONFIGPREFIX], envp); + append_slash(fqn_prefix[CONFIGPREFIX]); + } + } + } + if (GUILaunched || IsDebuggerPresent()) { + getreturn_enabled = TRUE; + } + + check_recordfile((char *) 0); + iflags.windowtype_deferred = TRUE; + initoptions(); + if (!validate_prefix_locations(failbuf)) { + raw_printf("Some invalid directory locations were specified:\n\t%s\n", + failbuf); + nethack_exit(EXIT_FAILURE); + } + if (!hackdir[0]) + Strcpy(hackdir, orgdir); + process_options(argc, argv); + +/* + * It seems you really want to play. + */ + + if (argc >= 1 + && !strcmpi(default_window_sys, "mswin") + && (strstri(argv[0], "nethackw.exe") || GUILaunched)) + iflags.windowtype_locked = TRUE; + + windowtype = default_window_sys; + if (!iflags.windowtype_locked) { +#if defined(TTY_GRAPHICS) + Strcpy(default_window_sys, "tty"); +#else +#if defined(CURSES_GRAPHICS) + Strcpy(default_window_sys, "curses"); +#endif /* CURSES */ +#endif /* TTY */ + if (iflags.windowtype_deferred && chosen_windowtype[0]) + windowtype = chosen_windowtype; + } + choose_windows(windowtype); + + if (!dlb_init()) { + pline( + "%s\n%s\n%s\n%s\n\nNetHack was unable to open the required file " + "\"%s\".%s", + copyright_banner_line(1), copyright_banner_line(2), + copyright_banner_line(3), copyright_banner_line(4), DLBFILE, + "\nAre you perhaps trying to run NetHack within a zip utility?"); + error("dlb_init failure."); + } + + u.uhp = 1; /* prevent RIP on early quits */ + u.ux = 0; /* prevent flush_screen() */ + + nethack_enter(argc, argv); + iflags.use_background_glyph = FALSE; + if (WINDOWPORT("mswin")) + iflags.use_background_glyph = TRUE; + if (WINDOWPORT("tty")) + nttty_open(1); + + init_nhwindows(&argc, argv); + + if (WINDOWPORT("tty")) + toggle_mouse_support(); + + /* strip role,race,&c suffix; calls askname() if plname[] is empty + or holds a generic user name like "player" or "games" */ + plnamesuffix(); + set_playmode(); /* sets plname to "wizard" for wizard mode */ + /* until the getlock code is resolved, override askname()'s + setting of renameallowed; when False, player_selection() + won't resent renaming as an option */ + iflags.renameallowed = FALSE; + /* Obtain the name of the logged on user and incorporate + * it into the name. */ + Sprintf(fnamebuf, "%s-%s", get_username(0), plname); + (void) fname_encode( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', + fnamebuf, encodedfnamebuf, BUFSZ); + Sprintf(lock, "%s", encodedfnamebuf); + /* regularize(lock); */ /* we encode now, rather than substitute */ + getlock(); + + /* Set up level 0 file to keep the game state. + */ + fd = create_levelfile(0, (char *) 0); + if (fd < 0) { + raw_print("Cannot create lock file"); + } else { + hackpid = GetCurrentProcessId(); + write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); + nhclose(fd); + } + /* + * Initialize the vision system. This must be before mklev() on a + * new game or before a level restore on a saved game. + */ + vision_init(); + display_gamewindows(); + /* + * First, try to find and restore a save file for specified character. + * We'll return here if new game player_selection() renames the hero. + */ +attempt_restore: + if ((fd = restore_saved_game()) >= 0) { +#ifdef NEWS + if (iflags.news) { + display_file(NEWS, FALSE); + iflags.news = FALSE; + } +#endif + pline("Restoring save file..."); + mark_synch(); /* flush output */ + if (dorecover(fd)) { + resuming = TRUE; /* not starting new game */ + if (discover) + You("are in non-scoring discovery mode."); + if (discover || wizard) { + if (yn("Do you want to keep the save file?") == 'n') + (void) delete_savefile(); + else { + nh_compress(fqname(SAVEF, SAVEPREFIX, 0)); + } + } + } + } + + if (!resuming) { + /* new game: start by choosing role, race, etc; + player might change the hero's name while doing that, + in which case we try to restore under the new name + and skip selection this time if that didn't succeed */ + if (!iflags.renameinprogress) { + player_selection(); + if (iflags.renameinprogress) { + /* player has renamed the hero while selecting role; + discard current lock file and create another for + the new character name */ + goto attempt_restore; + } + } + newgame(); + if (discover) + You("are in non-scoring discovery mode."); + } + moveloop(resuming); + nethack_exit(EXIT_SUCCESS); + /*NOTREACHED*/ + return 0; +} + +STATIC_OVL void +process_options(argc, argv) +int argc; +char *argv[]; +{ + int i; + + /* + * Process options. + */ + if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION) == 2) + nethack_exit(EXIT_SUCCESS); + + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (argcheck(argc, argv, ARG_WINDOWS) == 1) { + argc--; + argv++; + } + 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 + */ + argc--; + argv++; + dir = argv[0] + 2; + if (*dir == '=' || *dir == ':') + dir++; + if (!*dir && argc > 1) { + argc--; + argv++; + dir = argv[0]; + } + if (!*dir) + error("Flag -d must be followed by a directory name."); + Strcpy(hackdir, dir); + } + + if (argc > 1) { + /* + * Now we know the directory containing 'record' and + * may do a prscore(). + */ + if (!strncmp(argv[1], "-s", 2)) { +#ifdef SYSCF + initoptions(); +#endif + prscore(argc, argv); + + nethack_exit(EXIT_SUCCESS); + } + if (GUILaunched) { + if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ + mswin_destroy_reg(); + nethack_exit(EXIT_SUCCESS); + } + } + /* Don't initialize the full window system just to print usage */ + if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { + nhusage(); + nethack_exit(EXIT_SUCCESS); + } + } + } + while (argc > 1 && argv[1][0] == '-') { + argv++; + argc--; + switch (argv[0][1]) { + case 'a': + if (argv[0][2]) { + if ((i = str2align(&argv[0][2])) >= 0) + flags.initalign = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2align(argv[0])) >= 0) + flags.initalign = i; + } + break; + case 'D': + wizard = TRUE, discover = FALSE; + break; + case 'X': + discover = TRUE, wizard = FALSE; + break; +#ifdef NEWS + case 'n': + iflags.news = FALSE; + break; +#endif + case 'u': + if (argv[0][2]) + (void) strncpy(plname, argv[0] + 2, sizeof(plname) - 1); + else if (argc > 1) { + argc--; + argv++; + (void) strncpy(plname, argv[0], sizeof(plname) - 1); + } else + raw_print("Player name expected after -u"); + break; + case 'g': + if (argv[0][2]) { + if ((i = str2gend(&argv[0][2])) >= 0) + flags.initgend = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2gend(argv[0])) >= 0) + flags.initgend = i; + } + break; + case 'p': /* profession (role) */ + if (argv[0][2]) { + if ((i = str2role(&argv[0][2])) >= 0) + flags.initrole = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2role(argv[0])) >= 0) + flags.initrole = i; + } + break; + case 'r': /* race */ + if (argv[0][2]) { + if ((i = str2race(&argv[0][2])) >= 0) + flags.initrace = i; + } else if (argc > 1) { + argc--; + argv++; + if ((i = str2race(argv[0])) >= 0) + flags.initrace = i; + } + break; + case 'w': /* windowtype */ + config_error_init(FALSE, "command line", FALSE); + if (strlen(&argv[0][2]) < (WINTYPELEN - 1)) + Strcpy(chosen_windowtype, &argv[0][2]); + config_error_done(); + break; + case '@': + flags.randomall = 1; + break; + default: + if ((i = str2role(&argv[0][1])) >= 0) { + flags.initrole = i; + break; + } else + raw_printf("\nUnknown switch: %s", argv[0]); + /* FALL THROUGH */ + case '?': + nhusage(); + nethack_exit(EXIT_SUCCESS); + } + } +} + +STATIC_OVL void +nhusage() +{ + char buf1[BUFSZ], buf2[BUFSZ], *bufptr; + + buf1[0] = '\0'; + bufptr = buf1; + +#define ADD_USAGE(s) \ + if ((strlen(buf1) + strlen(s)) < (BUFSZ - 1)) \ + Strcat(bufptr, s); + + /* -role still works for those cases which aren't already taken, but + * is deprecated and will not be listed here. + */ + (void) Sprintf(buf2, "\nUsage:\n%s [-d dir] -s [-r race] [-p profession] " + "[maxrank] [name]...\n or", + hname); + ADD_USAGE(buf2); + + (void) Sprintf( + buf2, "\n%s [-d dir] [-u name] [-r race] [-p profession] [-[DX]]", + hname); + ADD_USAGE(buf2); +#ifdef NEWS + ADD_USAGE(" [-n]"); +#endif + if (!iflags.window_inited) + raw_printf("%s\n", buf1); + else + (void) printf("%s\n", buf1); +#undef ADD_USAGE +} + +#ifdef PORT_HELP +void +port_help() +{ + /* display port specific help file */ + display_file(PORT_HELP, 1); +} +#endif /* PORT_HELP */ + +/* validate wizard mode if player has requested access to it */ +boolean +authorize_wizard_mode() +{ + if (!strcmp(plname, WIZARD_NAME)) + return TRUE; + return FALSE; +} + +#define PATH_SEPARATOR '\\' + +#if defined(WIN32) && !defined(WIN32CON) +static char exenamebuf[PATHLEN]; +extern HANDLE hConIn; +extern HANDLE hConOut; +boolean has_fakeconsole; + +char * +exename() +{ + int bsize = PATHLEN; + char *tmp = exenamebuf, *tmp2; + +#ifdef UNICODE + { + TCHAR wbuf[PATHLEN * 4]; + GetModuleFileName((HANDLE) 0, wbuf, PATHLEN * 4); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); + } +#else + *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; +#endif + tmp2 = strrchr(tmp, PATH_SEPARATOR); + if (tmp2) + *tmp2 = '\0'; + tmp2++; + return tmp2; +} + +boolean +fakeconsole(void) +{ + if (!hStdOut) { + HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + + if (!hStdOut && !hStdIn) { + /* Bool rval; */ + AllocConsole(); + AttachConsole(GetCurrentProcessId()); + /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */ + freopen("CON", "w", stdout); + freopen("CON", "r", stdin); + } + has_fakeconsole = TRUE; + } + + /* Obtain handles for the standard Console I/O devices */ + hConIn = GetStdHandle(STD_INPUT_HANDLE); + hConOut = GetStdHandle(STD_OUTPUT_HANDLE); +#if 0 + if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) { + /* Unable to set control handler */ + cmode = 0; /* just to have a statement to break on for debugger */ + } +#endif + return has_fakeconsole; +} +void freefakeconsole() +{ + if (has_fakeconsole) { + FreeConsole(); + } +} +#endif + +#define EXEPATHBUFSZ 256 +char exepathbuf[EXEPATHBUFSZ]; + +char * +exepath(str) +char *str; +{ + char *tmp, *tmp2; + int bsize; + + if (!str) + return (char *) 0; + bsize = EXEPATHBUFSZ; + tmp = exepathbuf; +#ifdef UNICODE + { + TCHAR wbuf[BUFSZ]; + GetModuleFileName((HANDLE) 0, wbuf, BUFSZ); + WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); + } +#else + *(tmp + GetModuleFileName((HANDLE) 0, tmp, bsize)) = '\0'; +#endif + tmp2 = strrchr(tmp, PATH_SEPARATOR); + if (tmp2) + *tmp2 = '\0'; + return tmp; +} + +/*ARGSUSED*/ +void +windows_raw_print(str) +const char *str; +{ + if (str) + fprintf(stdout, "%s\n", str); + windows_nhgetch(); + return; +} + +/*ARGSUSED*/ +void +windows_raw_print_bold(str) +const char *str; +{ + windows_raw_print(str); + return; +} + +int +windows_nhgetch() +{ + return getchar(); +} + + +void +windows_nhbell() +{ + return; +} + +/*ARGSUSED*/ +int +windows_nh_poskey(x, y, mod) +int *x, *y, *mod; +{ + return '\033'; +} + +/*ARGSUSED*/ +char +windows_yn_function(query, resp, def) +const char *query; +const char *resp; +char def; +{ + return '\033'; +} + +/*ARGSUSED*/ +static void +windows_getlin(prompt, outbuf) +const char *prompt UNUSED; +char *outbuf; +{ + Strcpy(outbuf, "\033"); +} + +/*pcmain.c*/ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 0be1da094..c75e53c47 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -43,10 +43,17 @@ boolean win32_cursorblink; /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; +extern int GUILaunched; +boolean getreturn_enabled; +int redirect_stdout; typedef HWND(WINAPI *GETCONSOLEWINDOW)(); static HWND GetConsoleHandle(void); static HWND GetConsoleHwnd(void); +#if !defined(TTY_GRAPHICS) +extern void NDECL(backsp); +#endif +int NDECL(windows_console_custom_nhgetch); /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. @@ -492,12 +499,58 @@ void nhassert_failed(const char * exp, const char * file, int line) error(message); } -/* nethack_enter_winnt() is the first thing called from main */ +void +nethack_exit(code) +int code; +{ + /* Only if we started from the GUI, not the command prompt, + * we need to get one last return, so the score board does + * not vanish instantly after being created. + * GUILaunched is defined and set in nttty.c. + */ + + + if (!GUILaunched) { + windowprocs = *get_safe_procs(1); + /* use our custom version which works + a little cleaner than the stdio one */ + windowprocs.win_nhgetch = windows_console_custom_nhgetch; + } + if (getreturn_enabled) + wait_synch(); + exit(code); +} + +#undef kbhit +#include + +int +windows_console_custom_nhgetch(VOID_ARGS) +{ + return _getch(); +} + + +void +getreturn(str) +const char *str; +{ + char buf[BUFSZ]; + + if (!getreturn_enabled) + return; + Sprintf(buf,"Hit %s.", str); + raw_print(buf); + wait_synch(); + return; +} + +/* nethack_enter_winnt() is called from main immediately after + initializing the window port */ void nethack_enter_winnt() { -#ifdef TTY_GRAPHICS - nethack_enter_nttty(); -#endif + if (WINDOWPORT("tty")) + nethack_enter_nttty(); } /* CP437 to Unicode mapping according to the Unicode Consortium */ diff --git a/win/share/safeproc.c b/win/share/safeproc.c new file mode 100644 index 000000000..671ee1822 --- /dev/null +++ b/win/share/safeproc.c @@ -0,0 +1,561 @@ +/* NetHack 3.6 safeproc.c */ +/* Copyright (c) Michael Allison, 2018 */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include + +/* + * *********************************************************** + * This is a complete WindowPort implementation that can be + * assigned to the windowproc function pointers very early + * in the startup initialization, perhaps immediately even. + * It requires only the following call: + * windowprocs = *get_safe_procs(0); + * + * The game startup can trigger functions in other modules + * that make assumptions on a WindowPort being available + * and bad things can happen if any function pointers are + * null at that time. + * + * Some ports prior to 3.6.2 made attempts to early init + * various pieces of one of their WindowPorts, but that + * caused conflicts if that particular WindowPort wasn't + * the one that the user ended up selecting in their + * config file later. The WindowPort interfaced was designed + * to allow multiple WindowPorts to be linked into the same + * game binary. + * + * The base functions established by a call to get_safe_procs() + * accomplish the goal of preventing crashes, but not much + * else. + * + * There are also a few additional functions provided in here + * that can be selected optionally to provide some startup + * functionality for getting messages out to the user about + * issues that are being experienced during startup in + * general or during options parsing. The ones in here are + * deliberately free from any platforms or OS specific code. + * Please leave them using stdio C routines as much as + * possible. That isn't to say you can't do fancier functions + * prior to initialization of the primary WindowPort, but you + * can provide those platform-specific functions elsewhere, + * and assign them the same way that these more generic versions + * are assigned. + * + * The additional platform-independent, but more functional + * routines provided in here should be assigned after the + * windowprocs = *get_safe_procs(n) + * call. + * + * Usage: + * + * windowprocs = *get_safe_procs(0); + * initializes a set of winprocs function pointers that ensure + * none of the function pointers are left null, but that's all + * it does. + * + * windowprocs = *get_safe_procs(1); + * initializes a set of winprocs functions pointers that ensure + * none of the function pointers are left null, but also + * provides some basic output and input functionality using + * nothing other than C stdio routines (no platform-specific + * or OS-specific code). + * + * *********************************************************** + */ + +struct window_procs safe_procs = { + "safe-startup", 0L, 0L, + safe_init_nhwindows, safe_player_selection, safe_askname, safe_get_nh_event, + safe_exit_nhwindows, safe_suspend_nhwindows, safe_resume_nhwindows, + safe_create_nhwindow, safe_clear_nhwindow, safe_display_nhwindow, + safe_destroy_nhwindow, safe_curs, safe_putstr, genl_putmixed, + safe_display_file, safe_start_menu, safe_add_menu, safe_end_menu, + safe_select_menu, safe_message_menu, safe_update_inventory, safe_mark_synch, + safe_wait_synch, +#ifdef CLIPPING + safe_cliparound, +#endif +#ifdef POSITIONBAR + safe_update_positionbar, +#endif + safe_print_glyph, safe_raw_print, safe_raw_print_bold, safe_nhgetch, + safe_nh_poskey, safe_nhbell, safe_doprev_message, safe_yn_function, + safe_getlin, safe_get_ext_cmd, safe_number_pad, safe_delay_output, +#ifdef CHANGE_COLOR /* the Mac uses a palette device */ + safe_change_color, +#ifdef MAC + safe_change_background, set_safe_font_name, +#endif + safe_get_color_string, +#endif + safe_start_screen, safe_end_screen, genl_outrip, + safe_preference_update, + safe_getmsghistory, safe_putmsghistory, + safe_status_init, + safe_status_finish, safe_status_enablefield, +#ifdef STATUS_HILITES + safe_status_update, +#else + safe_status_update, +#endif + safe_can_suspend, +}; + +struct window_procs * +get_safe_procs(optn) +int optn; +{ + if (optn) { + /* include the slightly more functional stdc versions */ + safe_procs.win_raw_print = stdio_raw_print; + safe_procs.win_raw_print_bold = stdio_raw_print_bold; + safe_procs.win_nhgetch = stdio_nhgetch; + safe_procs.win_wait_synch = stdio_wait_synch; + } + return &safe_procs; +} + +/*ARGSUSED*/ +void +safe_init_nhwindows(argcp, argv) +int *argcp UNUSED; +char **argv UNUSED; +{ + return; +} + +void +safe_player_selection() +{ + return; +} + +void +safe_askname() +{ + return; +} + +void +safe_get_nh_event() +{ + return; +} + +void +safe_suspend_nhwindows(str) +const char *str; +{ + return; +} + +void +safe_resume_nhwindows() +{ + return; +} + +void +safe_exit_nhwindows(str) +const char *str; +{ + return; +} + +winid +safe_create_nhwindow(type) +int type; +{ + return WIN_ERR; +} + +void +safe_clear_nhwindow(window) +winid window; +{ + return; +} + +/*ARGSUSED*/ +void +safe_display_nhwindow(window, blocking) +winid window; +boolean blocking; +{ + return; +} + +void +safe_dismiss_nhwindow(window) +winid window; +{ + return; +} + +void +safe_destroy_nhwindow(window) +winid window; +{ + return; +} + +void +safe_curs(window, x, y) +winid window; +int x, y; +{ + return; +} + +void +safe_putstr(window, attr, str) +winid window; +int attr; +const char *str; +{ + return; +} + +void +safe_display_file(fname, complain) +const char *fname; +boolean complain; +{ + return; +} + +void +safe_start_menu(window) +winid window; +{ + return; +} + +/*ARGSUSED*/ +/* + * Add a menu item to the beginning of the menu list. This list is reversed + * later. + */ +void +safe_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) +winid window; /* window to use, must be of type NHW_MENU */ +int glyph UNUSED; /* glyph to display with item (not used) */ +const anything *identifier; /* what to return if selected */ +char ch; /* keyboard accelerator (0 = pick our own) */ +char gch; /* group accelerator (0 = no group) */ +int attr; /* attribute for string (like safe_putstr()) */ +const char *str; /* menu string */ +boolean preselected; /* item is marked as selected */ +{ + return; +} + +/* + * End a menu in this window, window must a type NHW_MENU. + */ +void +safe_end_menu(window, prompt) +winid window; /* menu to use */ +const char *prompt; /* prompt to for menu */ +{ + return; +} + +int +safe_select_menu(window, how, menu_list) +winid window; +int how; +menu_item **menu_list; +{ + return 0; +} + +/* special hack for treating top line --More-- as a one item menu */ +char +safe_message_menu(let, how, mesg) +char let; +int how; +const char *mesg; +{ + return '\033'; +} + +void +safe_update_inventory() +{ + return; +} + +void +safe_mark_synch() +{ +} + +void +safe_wait_synch() +{ +} + +#ifdef CLIPPING +void +safe_cliparound(x, y) +int x, y; +{ +} +#endif /* CLIPPING */ + +/* + * safe_print_glyph + * + * Print the glyph to the output device. Don't flush the output device. + */ +void +safe_print_glyph(window, x, y, glyph, bkglyph) +winid window; +xchar x, y; +int glyph; +int bkglyph UNUSED; +{ + return; +} + +void +safe_raw_print(str) +const char *str; +{ + return; +} + +void +safe_raw_print_bold(str) +const char *str; +{ + return; +} + +int +safe_nhgetch() +{ + return '\033'; +} + +/* + * return a key, or 0, in which case a mouse button was pressed + * mouse events should be returned as character postitions in the map window. + * Since normal tty's don't have mice, just return a key. + */ +/*ARGSUSED*/ +int +safe_nh_poskey(x, y, mod) +int *x, *y, *mod; +{ + return '\033'; +} + +void +win_safe_init(dir) +int dir; +{ + return; +} + +#ifdef POSITIONBAR +void +safe_update_positionbar(posbar) +char *posbar; +{ + return; +} +#endif /* POSITIONBAR */ + +/* + * safe_status_init() + * -- initialize the port-specific data structures. + */ +void +safe_status_init() +{ + return; +} + +void +safe_can_suspend() +{ + return; +} + +void +safe_nhbell() +{ + return; +} + +int +safe_doprev_message() +{ + return 0; +} + +char +safe_yn_function(query, resp, def) +const char *query; +const char *resp; +char def; +{ + return '\033'; +} + +/*ARGSUSED*/ +static void +safe_getlin(prompt, outbuf) +const char *prompt UNUSED; +char *outbuf; +{ + Strcpy(outbuf, "\033"); +} + +int +safe_get_ext_cmd() +{ + return '\033'; +} + +void +safe_number_pad(mode) +int mode; +{ + return; +} + +void +safe_delay_output() +{ + return; +} + +void +safe_start_screen() +{ + return; +} + +void +safe_end_screen() +{ + return; +} + +void +safe_outrip(tmpwin, how, when) +winid tmpwin; +int how; +time_t when; +{ + return; +} + +/*ARGSUSED*/ +void +safe_preference_update(pref) +const char *pref UNUSED; +{ + return; +} + +char * +safe_getmsghistory(init) +boolean init UNUSED; +{ + return (char *) 0; +} + +void +safe_putmsghistory(msg, is_restoring) +const char *msg; +boolean is_restoring; +{ +} + +void +safe_status_finish() +{ +} + +void +safe_status_enablefield(fieldidx, nm, fmt, enable) +int fieldidx; +const char *nm; +const char *fmt; +boolean enable; +{ +} + +#ifdef STATUS_HILITES +/* call once for each field, then call with BL_FLUSH to output the result */ +void +safe_status_update(idx, ptr, chg, percent, color, colormasks) +int idx; +genericptr_t ptr; +int chg UNUSED, percent UNUSED, color UNUSED; +unsigned long *colormasks UNUSED; +{ +} +#endif /* STATUS_HILITES */ + +/************************************************************** + * These are some optionally selectable routines that add + * some base functionality over the safe_* versions above. + * The safe_* versions are primarily designed to ensure that + * there are no null function pointers remaining at early + * game startup/initialization time. + * + * The slightly more functional versions in here should be kept + * free of platform-specific code or OS-specific code. If you + * want to use versions that involve platform-specific or + * OS-specific code, go right ahead but use your own replacement + * version of the functions in a platform-specific or + * OS-specific source file, not in here. + ***************************************************************/ + +/* Add to your code: windowprocs.win_raw_print = stdio_wait_synch; */ +void +stdio_wait_synch() +{ + char valid[] = {' ', '\n', '\r', '\033', '\0'}; + + fprintf(stdout, "--More--"); + (void) fflush(stdout); + while (!index(valid, nhgetch())) + ; +} + +/* Add to your code: windowprocs.win_raw_print = stdio_raw_print; */ +void +stdio_raw_print(str) +const char *str; +{ + if (str) + fprintf(stdout, "%s\n", str); + return; +} + +/* Add to your code: windowprocs.win_raw_print_bold = stdio_raw_print_bold; */ +void +stdio_raw_print_bold(str) +const char *str; +{ + stdio_raw_print(str); + return; +} + +/* Add to your code: windowprocs.win_nhgetch = stdio_nhgetch; */ +int +stdio_nhgetch() +{ + return getchar(); +} + + +/* safeprocs.c */ diff --git a/win/win32/mhfont.h b/win/win32/mhfont.h index 20b5d1400..9402d54a9 100644 --- a/win/win32/mhfont.h +++ b/win/win32/mhfont.h @@ -9,6 +9,9 @@ #include "winMS.h" +#define MIN_FONT_WIDTH 9 +#define MIN_FONT_HEIGHT 12 + typedef struct cached_font { int code; HFONT hFont; diff --git a/win/win32/mhmap.c b/win/win32/mhmap.c index d401c4c3c..75155a73f 100644 --- a/win/win32/mhmap.c +++ b/win/win32/mhmap.c @@ -15,7 +15,7 @@ #include "color.h" #include "patchlevel.h" -#define NHMAP_FONT_NAME TEXT("Terminal") +#define NHMAP_FONT_NAME TEXT("Courier New") #define MAXWINDOWTEXT 255 #define CURSOR_BLINK_INTERVAL 1000 // milliseconds @@ -160,25 +160,33 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) // calculate back buffer scale data->monitorScale = win10_monitor_scale(hWnd); - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + boolean bText = data->bAsciiMode || + (u.uz.dlevel != 0 && Is_rogue_level(&u.uz)); + + if (bText && !data->bFitToScreenMode) data->backScale = data->monitorScale; - } else { + 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 (bText && data->bFitToScreenMode) { + data->xBackTile = wnd_size.cx / COLNO; + data->yBackTile = wnd_size.cy / ROWNO; + data->yBackTile = max(data->yBackTile, 12); + } else { + data->xBackTile = (int)(data->tileWidth * data->backScale); + data->yBackTile = (int)(data->tileHeight * data->backScale); + } - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + if (bText) { LOGFONT lgfnt; ZeroMemory(&lgfnt, sizeof(lgfnt)); - lgfnt.lfHeight = -data->yBackTile; // height of font - lgfnt.lfWidth = -data->xBackTile; // average character width + lgfnt.lfHeight = -data->yBackTile; // height of font + lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle - lgfnt.lfWeight = FW_NORMAL; // font weight + lgfnt.lfWeight = FW_SEMIBOLD; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option @@ -195,25 +203,26 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } TEXTMETRIC textMetrics; - HFONT font; + HFONT font = NULL; while (1) { + + if (font != NULL) + DeleteObject(font); + font = CreateFontIndirect(&lgfnt); SelectObject(data->backBufferDC, font); GetTextMetrics(data->backBufferDC, &textMetrics); - if (textMetrics.tmHeight > data->yBackTile) { + if ((textMetrics.tmHeight > data->yBackTile || + textMetrics.tmAveCharWidth > data->xBackTile) && + lgfnt.lfHeight < -MIN_FONT_HEIGHT) { lgfnt.lfHeight++; continue; } - if (textMetrics.tmAveCharWidth > data->xBackTile) { - lgfnt.lfWidth++; - continue; - } - break; } @@ -256,7 +265,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) /* calculate front buffer tile size */ - if (wnd_size.cx > 0 && wnd_size.cy > 0 && data->bFitToScreenMode) { + if (wnd_size.cx > 0 && wnd_size.cy > 0 && !bText && data->bFitToScreenMode) { double windowAspectRatio = (double) wnd_size.cx / (double) wnd_size.cy; @@ -270,7 +279,7 @@ mswin_map_stretch(HWND hWnd, LPSIZE map_size, BOOL redraw) } else { - if (data->bAsciiMode || Is_rogue_level(&u.uz)) { + if (bText) { data->frontScale = 1.0; } else { data->frontScale = data->monitorScale; @@ -893,9 +902,22 @@ paintGlyph(PNHMapWindow data, int i, int j, RECT * rect) #endif if (data->bUnicodeFont) { wch = winos_ascii_to_wide(ch); - DrawTextW(data->backBufferDC, &wch, 1, rect, - DT_CENTER | DT_VCENTER | DT_NOPREFIX - | DT_SINGLELINE); + if (wch == 0x2591 || wch == 0x2592) { + int level = 80; + HBRUSH brush = CreateSolidBrush(RGB(level, level, level)); + FillRect(data->backBufferDC, rect, brush); + DeleteObject(brush); + level = (wch == 0x2591 ? 100 : 200); + brush = CreateSolidBrush(RGB(level, level, level)); + RECT smallRect = { rect->left + 1, rect->top + 1, + rect->right - 1, rect->bottom - 1 }; + FillRect(data->backBufferDC, &smallRect, brush); + DeleteObject(brush); + } else { + 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 diff --git a/win/win32/mswproc.c b/win/win32/mswproc.c index 3cfcc95bf..85f427725 100644 --- a/win/win32/mswproc.c +++ b/win/win32/mswproc.c @@ -718,6 +718,13 @@ mswin_exit_nhwindows(const char *str) /* Write Window settings to the registry */ mswin_write_reg(); + /* set things back to failsafes */ + windowprocs = *get_safe_procs(0); + + /* and make sure there is still a way to communicate something */ + windowprocs.win_raw_print = mswin_raw_print; + windowprocs.win_raw_print_bold = mswin_raw_print_bold; + windowprocs.win_wait_synch = mswin_wait_synch; } /* Prepare the window to be suspended. */ diff --git a/win/win32/vs2017/NetHack.vcxproj b/win/win32/vs2017/NetHack.vcxproj index e51474a65..9f193832a 100644 --- a/win/win32/vs2017/NetHack.vcxproj +++ b/win/win32/vs2017/NetHack.vcxproj @@ -34,7 +34,7 @@ Speed true $(WinWin32Dir);$(IncDir);$(SysWinntDir);$(SysShareDir);$(WinShareDir);%(AdditionalIncludeDirectories) - TILES;WIN32CON;DLB;MSWIN_GRAPHICS;_LIB;%(PreprocessorDefinitions) + TILES;WIN32CON;DLB;MSWIN_GRAPHICS;SAFEPROCS;_LIB;%(PreprocessorDefinitions) kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;%(AdditionalDependencies) @@ -151,7 +151,6 @@ - @@ -160,7 +159,9 @@ GUISTUB;%(PreprocessorDefinitions) + + @@ -254,4 +255,4 @@ - \ No newline at end of file + diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs2017/NetHackW.vcxproj index af28761da..d1ede9f0a 100644 --- a/win/win32/vs2017/NetHackW.vcxproj +++ b/win/win32/vs2017/NetHackW.vcxproj @@ -20,7 +20,7 @@ Disabled true $(WinWin32Dir);$(IncDir);$(SysWinntDir);$(SysShareDir);$(WinShareDir);%(AdditionalIncludeDirectories) - TILES;_WINDOWS;DLB;MSWIN_GRAPHICS;NOTTYGRAPHICS;%(PreprocessorDefinitions) + TILES;_WINDOWS;DLB;MSWIN_GRAPHICS;SAFEPROCS;NOTTYGRAPHICS;%(PreprocessorDefinitions) NDEBUG;%(PreprocessorDefinitions) @@ -146,7 +146,6 @@ - @@ -154,8 +153,10 @@ TTYSTUB; + + @@ -200,4 +201,4 @@ - \ No newline at end of file + diff --git a/win/win32/winhack.c b/win/win32/winhack.c index 9dcbb4e4b..c6941d7c0 100644 --- a/win/win32/winhack.c +++ b/win/win32/winhack.c @@ -15,6 +15,10 @@ #include "mhmain.h" #include "mhmap.h" +#if !defined(SAFEPROCS) +#error You must #define SAFEPROCS to build winhack.c +#endif + /* Borland and MinGW redefine "boolean" in shlwapi.h, so just use the little bit we need */ typedef struct _DLLVERSIONINFO { @@ -59,6 +63,8 @@ _nhapply_image_transparent(HDC hDC, int x, int y, int width, int height, // Global Variables: NHWinApp _nethack_app; +extern int GUILaunched; /* We tell shared startup code in windmain.c + that the GUI was launched via this */ #ifdef __BORLANDC__ #define _stricmp(s1, s2) stricmp(s1, s2) @@ -66,7 +72,7 @@ NHWinApp _nethack_app; #endif // Foward declarations of functions included in this code module: -extern boolean FDECL(pcmain, (int, char **)); +extern boolean FDECL(main, (int, char **)); static void __cdecl mswin_moveloop(void *); #define MAX_CMDLINE_PARAM 255 @@ -82,24 +88,44 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, TCHAR *p; TCHAR wbuf[BUFSZ]; char buf[BUFSZ]; + DWORD major, minor; - boolean resuming; /* OSVERSIONINFO osvi; */ UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); UNREFERENCED_PARAMETER(nCmdShow); - /* We must initialize state sufficiently to support calls to panic */ + /* + * Get a set of valid safe windowport function + * pointers during early startup initialization. + * + * When get_safe_procs is called with 0 as the param, + * non-functional, but safe function pointers are set + * for all windowport routines. + * + * When get_safe_procs is called with 1 as the param, + * raw_print, raw_print_bold, and wait_synch, and nhgetch + * are set to use C stdio routines via stdio_raw_print, + * stdio_raw_print_bold, stdio_wait_synch, and + * stdio_nhgetch. + */ + windowprocs = *get_safe_procs(0); + + /* + * Now we are going to override a couple + * of the windowprocs functions so that + * error messages are handled in a suitable + * way for the graphical version. + */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; windowprocs.win_wait_synch = mswin_wait_synch; win10_init(); - sys_early_init(); - /* init applicatio structure */ + /* init application structure */ _nethack_app.hApp = hInstance; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR) IDC_NETHACKW); @@ -209,10 +235,9 @@ WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, } free(savefile); } - resuming = pcmain(argc, argv); - - moveloop(resuming); - + GUILaunched = 1; + /* let main do the argument processing */ + (void) main(argc, argv); return 0; }