The g? structs had a mix of variables that were written to
the savefile, and those that were not.
For better clarity and to distinguish those that end up in
the savefile, relocate some g? variables that get written
directly to the savefile into different structs.
This updates EDITLEVEL, although technically it probably
didn't need to, since savefile contents are not changing.
Details:
gb.bases -> svb.bases
gb.bbubbles -> svb.bbubbles
gb.branches -> svb.branches
gc.context -> svc.context
gd.disco -> svd.disco
gd.dndest -> svd.dndest
gd.doors -> svd.doors
gd.doors_alloc -> svd.doors_alloc
gd.dungeon_topology -> svd.dungeon_topology
gd.dungeons -> svd.dungeons
ge.exclusion_zones -> sve.exclusion_zones
gh.hackpid -> svh.hackpid
gi.inv_pos -> svi.inv_pos
gk.killer -> svk.killer
gl.lastseentyp -> svl.lastseentyp
gl.level -> svl.level
gl.level_info -> svl.level_info
gm.mapseenchn -> svm.mapseenchn
gm.moves -> svm.moves
gm.mvitals -> svm.mvitals
gn.n_dgns -> svn.n_dgns
gn.n_regions -> svn.n_regions
gn.nroom -> svn.nroom
go.oracle_cnt -> svo.oracle_cnt
gp.pl_character -> svp.pl_character
gp.pl_fruit -> svp.pl_fruit
gp.plname -> svp.plname
gp.program_state -> svp.program_state
gq.quest_status -> svq.quest_status
gr.rooms -> svr.rooms
gs.sp_levchn -> svs.sp_levchn
gs.spl_book -> svs.spl_book
gt.timer_id -> svt.timer_id
gt.tune -> svt.tune
gu.updest -> svu.updest
gx.xmax -> svx.xmax
gx.xmin -> svx.xmin
gy.ymax -> svy.ymax
gy.ymin -> svy.ymin
Related note:
There are some pointer variables that are heads of chains that were not
moved from 'g?' to 'sv?', because they are not actually written to the
savefile directly, but the objects/monst/trap/lightsource/timer in the
chains they point to are. That can be changed, if desired.
Examples: gi.invent, gm.migrating_objs, gb.billobjs, gm.migrating_mons,
gf.ftrap, gl.light_base, gt.timer_base
1402 lines
44 KiB
C
1402 lines
44 KiB
C
/* NetHack 3.7 mhmain.c $NHDT-Date: 1596498352 2020/08/03 23:45:52 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.76 $ */
|
|
/* Copyright (C) 2001 by Alex Kompel */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "winMS.h"
|
|
#include <commdlg.h>
|
|
#include "config.h"
|
|
#if !defined(PATCHLEVEL_H)
|
|
#include "patchlevel.h"
|
|
#endif
|
|
#include "resource.h"
|
|
#include "mhmsg.h"
|
|
#include "mhinput.h"
|
|
#include "mhmain.h"
|
|
#include "mhmenu.h"
|
|
#include "mhstatus.h"
|
|
#include "mhmsgwnd.h"
|
|
#include "mhmap.h"
|
|
|
|
typedef struct mswin_nethack_main_window {
|
|
int mapAcsiiModeSave;
|
|
} NHMainWindow, *PNHMainWindow;
|
|
|
|
extern winid WIN_STATUS;
|
|
|
|
static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass");
|
|
static TCHAR szTitle[MAX_LOADSTRING];
|
|
extern void mswin_display_splash_window(BOOL);
|
|
|
|
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
|
static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
|
|
static void register_main_window_class(void);
|
|
static int menuid2mapmode(int menuid);
|
|
static int mapmode2menuid(int map_mode);
|
|
static void nhlock_windows(BOOL lock);
|
|
static char *nh_compose_ascii_screenshot(void);
|
|
#ifdef ENHANCED_SYMBOLS
|
|
static WCHAR *nh_compose_unicode_screenshot(void);
|
|
#endif
|
|
static void mswin_apply_window_style_all(void);
|
|
// returns strdup() created pointer - callee assumes the ownership
|
|
|
|
HWND
|
|
mswin_init_main_window(void)
|
|
{
|
|
static int run_once = 0;
|
|
HWND ret;
|
|
WINDOWPLACEMENT wp;
|
|
|
|
/* register window class */
|
|
if (!run_once) {
|
|
LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
|
register_main_window_class();
|
|
run_once = 1;
|
|
}
|
|
|
|
/* create the main window */
|
|
ret =
|
|
CreateWindow(szMainWindowClass, /* registered class name */
|
|
szTitle, /* window name */
|
|
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */
|
|
CW_USEDEFAULT, /* horizontal position of window */
|
|
CW_USEDEFAULT, /* vertical position of window */
|
|
CW_USEDEFAULT, /* window width */
|
|
CW_USEDEFAULT, /* window height */
|
|
NULL, /* handle to parent or owner window */
|
|
NULL, /* menu handle or child identifier */
|
|
GetNHApp()->hApp, /* handle to application instance */
|
|
NULL /* window-creation data */
|
|
);
|
|
|
|
if (!ret)
|
|
panic("Cannot create main window");
|
|
|
|
if (GetNHApp()->regMainMinX != CW_USEDEFAULT) {
|
|
wp.length = sizeof(wp);
|
|
wp.showCmd = GetNHApp()->regMainShowState;
|
|
|
|
wp.ptMinPosition.x = GetNHApp()->regMainMinX;
|
|
wp.ptMinPosition.y = GetNHApp()->regMainMinY;
|
|
|
|
wp.ptMaxPosition.x = GetNHApp()->regMainMaxX;
|
|
wp.ptMaxPosition.y = GetNHApp()->regMainMaxY;
|
|
|
|
wp.rcNormalPosition.left = GetNHApp()->regMainLeft;
|
|
wp.rcNormalPosition.top = GetNHApp()->regMainTop;
|
|
wp.rcNormalPosition.right = GetNHApp()->regMainRight;
|
|
wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom;
|
|
SetWindowPlacement(ret, &wp);
|
|
} else
|
|
ShowWindow(ret, SW_SHOWDEFAULT);
|
|
|
|
UpdateWindow(ret);
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
register_main_window_class(void)
|
|
{
|
|
WNDCLASS wcex;
|
|
|
|
ZeroMemory(&wcex, sizeof(wcex));
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = (WNDPROC) MainWndProc;
|
|
wcex.cbClsExtra = 0;
|
|
wcex.cbWndExtra = 0;
|
|
wcex.hInstance = GetNHApp()->hApp;
|
|
wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR) IDI_NETHACKW);
|
|
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
|
|
wcex.lpszMenuName = (TCHAR *) IDC_NETHACKW;
|
|
wcex.lpszClassName = szMainWindowClass;
|
|
|
|
RegisterClass(&wcex);
|
|
}
|
|
|
|
/*
|
|
* Keypad keys are translated to the normal values below.
|
|
* Shifted keypad keys are translated to the
|
|
* shift values below.
|
|
*/
|
|
|
|
enum KEY_INDEXES {
|
|
KEY_NW,
|
|
KEY_N,
|
|
KEY_NE,
|
|
KEY_MINUS,
|
|
KEY_W,
|
|
KEY_GOINTERESTING,
|
|
KEY_E,
|
|
KEY_PLUS,
|
|
KEY_SW,
|
|
KEY_S,
|
|
KEY_SE,
|
|
KEY_INV,
|
|
KEY_WAITLOOK,
|
|
KEY_LAST
|
|
};
|
|
|
|
static const unsigned char
|
|
/* normal, shift, control */
|
|
keypad[KEY_LAST][3] =
|
|
{
|
|
{ 'y', 'Y', C('y') }, /* 7 */
|
|
{ 'k', 'K', C('k') }, /* 8 */
|
|
{ 'u', 'U', C('u') }, /* 9 */
|
|
{ 'm', C('p'), C('p') }, /* - */
|
|
{ 'h', 'H', C('h') }, /* 4 */
|
|
{ 'g', 'G', 'g' }, /* 5 */
|
|
{ 'l', 'L', C('l') }, /* 6 */
|
|
{ '+', 'P', C('p') }, /* + */
|
|
{ 'b', 'B', C('b') }, /* 1 */
|
|
{ 'j', 'J', C('j') }, /* 2 */
|
|
{ 'n', 'N', C('n') }, /* 3 */
|
|
{ 'i', 'I', C('i') }, /* Ins */
|
|
{ '.', ':', ':' } /* Del */
|
|
},
|
|
numpad[KEY_LAST][3] = {
|
|
{ '7', M('7'), '7' }, /* 7 */
|
|
{ '8', M('8'), '8' }, /* 8 */
|
|
{ '9', M('9'), '9' }, /* 9 */
|
|
{ 'm', C('p'), C('p') }, /* - */
|
|
{ '4', M('4'), '4' }, /* 4 */
|
|
{ '5', M('5'), '5' }, /* 5 */
|
|
{ '6', M('6'), '6' }, /* 6 */
|
|
{ '+', 'P', C('p') }, /* + */
|
|
{ '1', M('1'), '1' }, /* 1 */
|
|
{ '2', M('2'), '2' }, /* 2 */
|
|
{ '3', M('3'), '3' }, /* 3 */
|
|
{ '0', M('0'), '0' }, /* Ins */
|
|
{ '.', ':', ':' } /* Del */
|
|
};
|
|
|
|
#define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0)
|
|
#define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0])
|
|
#define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1])
|
|
#define KEYTABLE(x) \
|
|
(STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x))
|
|
|
|
static const char *extendedlist = "acdefijlmnopqrstuvw?2";
|
|
|
|
#define SCANLO 0x02
|
|
static const char scanmap[] = {
|
|
/* ... */
|
|
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, 0, 'q', 'w',
|
|
'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd',
|
|
'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v',
|
|
'b', 'n', 'm', ',', '.', '?' /* ... */
|
|
};
|
|
|
|
#define IDT_FUZZ_TIMER 100
|
|
|
|
/*
|
|
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
|
|
//
|
|
// PURPOSE: Processes messages for the main window.
|
|
*/
|
|
LRESULT CALLBACK
|
|
MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
PNHMainWindow data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
|
|
switch (message) {
|
|
case WM_CREATE:
|
|
/* set window data */
|
|
data = (PNHMainWindow) malloc(sizeof(NHMainWindow));
|
|
if (!data)
|
|
panic("out of memory");
|
|
ZeroMemory(data, sizeof(NHMainWindow));
|
|
data->mapAcsiiModeSave = MAP_MODE_ASCII12x16;
|
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) data);
|
|
|
|
/* update menu items */
|
|
CheckMenuItem(
|
|
GetMenu(hWnd), IDM_SETTING_LOCKWINDOWS,
|
|
MF_BYCOMMAND
|
|
| (GetNHApp()->bWindowsLocked ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
CheckMenuItem(GetMenu(hWnd), IDM_SETTING_AUTOLAYOUT,
|
|
GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
/* store handle to the mane menu in the application record */
|
|
GetNHApp()->hMainWnd = hWnd;
|
|
break;
|
|
|
|
case WM_MSNH_COMMAND:
|
|
onMSNHCommand(hWnd, wParam, lParam);
|
|
break;
|
|
|
|
case WM_KEYDOWN: {
|
|
|
|
/* translate arrow keys into nethack commands */
|
|
switch (wParam) {
|
|
case VK_LEFT:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one line left */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
|
|
MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_W));
|
|
}
|
|
return 0;
|
|
|
|
case VK_RIGHT:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one line right */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
|
|
MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_E));
|
|
}
|
|
return 0;
|
|
|
|
case VK_UP:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one line up */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_LINEUP, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_N));
|
|
}
|
|
return 0;
|
|
|
|
case VK_DOWN:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one line down */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_S));
|
|
}
|
|
return 0;
|
|
|
|
case VK_HOME:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window to upper left corner */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
|
|
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
|
|
MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_NW));
|
|
}
|
|
return 0;
|
|
|
|
case VK_END:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window to lower right corner */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM) NULL);
|
|
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL,
|
|
MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_SW));
|
|
}
|
|
return 0;
|
|
|
|
case VK_PRIOR:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one page up */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_PAGEUP, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_NE));
|
|
}
|
|
return 0;
|
|
|
|
case VK_NEXT:
|
|
if (STATEON(VK_CONTROL)) {
|
|
/* scroll map window one page down */
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL,
|
|
MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM) NULL);
|
|
} else {
|
|
NHEVENT_KBD(KEYTABLE(KEY_SE));
|
|
}
|
|
return 0;
|
|
|
|
case VK_DECIMAL:
|
|
case VK_DELETE:
|
|
NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK));
|
|
return 0;
|
|
|
|
case VK_INSERT:
|
|
NHEVENT_KBD(KEYTABLE(KEY_INV));
|
|
return 0;
|
|
|
|
case VK_SUBTRACT:
|
|
NHEVENT_KBD(KEYTABLE(KEY_MINUS));
|
|
return 0;
|
|
|
|
case VK_ADD:
|
|
NHEVENT_KBD(KEYTABLE(KEY_PLUS));
|
|
return 0;
|
|
|
|
#if defined(DEBUG) && defined(_MSC_VER)
|
|
case VK_PAUSE:
|
|
if (IsDebuggerPresent()) {
|
|
iflags.debug_fuzzer = !iflags.debug_fuzzer;
|
|
return 0;
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
case VK_CLEAR: /* This is the '5' key */
|
|
NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING));
|
|
return 0;
|
|
|
|
case VK_F4:
|
|
if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
|
|
mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
|
|
? data->mapAcsiiModeSave
|
|
: MAP_MODE_TILES);
|
|
} else {
|
|
mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
|
|
? MAP_MODE_ASCII_FIT_TO_SCREEN
|
|
: MAP_MODE_TILES_FIT_TO_SCREEN);
|
|
}
|
|
return 0;
|
|
|
|
case VK_F5:
|
|
if (IS_MAP_ASCII(iflags.wc_map_mode)) {
|
|
if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
|
|
mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN);
|
|
} else {
|
|
mswin_select_map_mode(MAP_MODE_TILES);
|
|
}
|
|
} else {
|
|
if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
|
|
mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN);
|
|
} else {
|
|
mswin_select_map_mode(data->mapAcsiiModeSave);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
default: {
|
|
WORD c;
|
|
BYTE kbd_state[256];
|
|
|
|
c = 0;
|
|
ZeroMemory(kbd_state, sizeof(kbd_state));
|
|
(void) GetKeyboardState(kbd_state);
|
|
|
|
if (ToAscii((UINT) wParam, (lParam >> 16) & 0xFF, kbd_state, &c, 0)) {
|
|
NHEVENT_KBD(c & 0xFF);
|
|
return 0;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
} /* end switch */
|
|
} break;
|
|
|
|
case WM_SYSCHAR: /* Alt-char pressed */
|
|
{
|
|
/*
|
|
If not nethackmode, don't handle Alt-keys here.
|
|
If no Alt-key pressed it can never be an extended command
|
|
*/
|
|
if (GetNHApp()->regNetHackMode && ((lParam & 1 << 29) != 0)) {
|
|
unsigned char c = (unsigned char) (wParam & 0xFF);
|
|
unsigned char scancode = (lParam >> 16) & 0xFF;
|
|
if (strchr(extendedlist, tolower(c)) != 0) {
|
|
NHEVENT_KBD(M(tolower(c)));
|
|
} else if (scancode == (SCANLO + SIZE(scanmap)) - 1) {
|
|
NHEVENT_KBD(M('?'));
|
|
}
|
|
return 0;
|
|
}
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
} break;
|
|
|
|
case WM_COMMAND:
|
|
/* process commands - menu commands mostly */
|
|
if (onWMCommand(hWnd, wParam, lParam))
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
else
|
|
return 0;
|
|
|
|
case WM_MOVE:
|
|
case WM_SIZE: {
|
|
WINDOWPLACEMENT wp;
|
|
|
|
mswin_layout_main_window(NULL);
|
|
|
|
wp.length = sizeof(wp);
|
|
if (GetWindowPlacement(hWnd, &wp)) {
|
|
GetNHApp()->regMainShowState =
|
|
(wp.showCmd == SW_SHOWMAXIMIZED ? SW_SHOWMAXIMIZED
|
|
: SW_SHOWNORMAL);
|
|
|
|
GetNHApp()->regMainMinX = wp.ptMinPosition.x;
|
|
GetNHApp()->regMainMinY = wp.ptMinPosition.y;
|
|
|
|
GetNHApp()->regMainMaxX = wp.ptMaxPosition.x;
|
|
GetNHApp()->regMainMaxY = wp.ptMaxPosition.y;
|
|
|
|
GetNHApp()->regMainLeft = wp.rcNormalPosition.left;
|
|
GetNHApp()->regMainTop = wp.rcNormalPosition.top;
|
|
GetNHApp()->regMainRight = wp.rcNormalPosition.right;
|
|
GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom;
|
|
}
|
|
break;
|
|
}
|
|
case WM_SETFOCUS:
|
|
/* if there is a menu window out there -
|
|
transfer input focus to it */
|
|
if (IsWindow(GetNHApp()->hPopupWnd)) {
|
|
SetFocus(GetNHApp()->hPopupWnd);
|
|
}
|
|
break;
|
|
|
|
case WM_CLOSE: {
|
|
/* exit gracefully */
|
|
if (svp.program_state.gameover) {
|
|
/* assume the user really meant this, as the game is already
|
|
* over... */
|
|
/* to make sure we still save bones, just set stop printing flag
|
|
*/
|
|
svp.program_state.stopprint++;
|
|
NHEVENT_KBD(
|
|
'\033'); /* and send keyboard input as if user pressed ESC */
|
|
/* additional code for this is done in menu and rip windows */
|
|
} else if (!svp.program_state.something_worth_saving) {
|
|
/* User exited before the game started, e.g. during splash display
|
|
*/
|
|
/* Just get out. */
|
|
bail((char *) 0);
|
|
} else {
|
|
/* prompt user for action */
|
|
switch (NHMessageBox(hWnd, TEXT("Save?"),
|
|
MB_YESNOCANCEL | MB_ICONQUESTION)) {
|
|
case IDYES:
|
|
#ifdef SAFERHANGUP
|
|
/* destroy popup window - it has its own loop and we need to
|
|
return control to NetHack core at this point */
|
|
if (IsWindow(GetNHApp()->hPopupWnd))
|
|
SendMessage(GetNHApp()->hPopupWnd, WM_COMMAND, IDCANCEL,
|
|
0);
|
|
|
|
/* tell NetHack core that "hangup" is requested */
|
|
hangup(1);
|
|
#else
|
|
NHEVENT_KBD('y');
|
|
dosave();
|
|
#endif
|
|
break;
|
|
case IDNO:
|
|
NHEVENT_KBD('q');
|
|
done(QUIT);
|
|
break;
|
|
case IDCANCEL:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case WM_DESTROY:
|
|
/* apparently we never get here
|
|
TODO: work on exit routines - need to send
|
|
WM_QUIT somehow */
|
|
|
|
/* clean up */
|
|
free((PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
|
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) 0);
|
|
|
|
// PostQuitMessage(0);
|
|
exit(1);
|
|
break;
|
|
|
|
case WM_DPICHANGED: {
|
|
mswin_layout_main_window(NULL);
|
|
} break;
|
|
|
|
default:
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
UNREFERENCED_PARAMETER(hWnd);
|
|
UNREFERENCED_PARAMETER(wParam);
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
switch (wParam) {
|
|
/* new window was just added */
|
|
case MSNH_MSG_ADDWND: {
|
|
PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd) lParam;
|
|
HWND child;
|
|
|
|
if (GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP)
|
|
mswin_select_map_mode(iflags.wc_map_mode);
|
|
|
|
child = GetNHApp()->windowlist[msg_param->wid].win;
|
|
} break;
|
|
|
|
case MSNH_MSG_RANDOM_INPUT: {
|
|
nhassert(iflags.debug_fuzzer);
|
|
NHEVENT_KBD(randomkey());
|
|
} break;
|
|
|
|
}
|
|
}
|
|
|
|
/* adjust windows to fit main window layout
|
|
---------------------------
|
|
| Status |
|
|
+-------------------------+
|
|
| |
|
|
| |
|
|
| MAP |
|
|
| |
|
|
| |
|
|
+-------------------------+
|
|
| Messages |
|
|
---------------------------
|
|
*/
|
|
void
|
|
mswin_layout_main_window(HWND changed_child)
|
|
{
|
|
winid i;
|
|
RECT client_rt, wnd_rect;
|
|
POINT status_org;
|
|
SIZE status_size;
|
|
POINT msg_org;
|
|
SIZE msg_size;
|
|
POINT map_org;
|
|
SIZE map_size;
|
|
SIZE menu_size;
|
|
HWND wnd_status, wnd_msg;
|
|
PNHMainWindow data;
|
|
|
|
if (GetNHApp()->bAutoLayout) {
|
|
GetClientRect(GetNHApp()->hMainWnd, &client_rt);
|
|
data = (PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd,
|
|
GWLP_USERDATA);
|
|
|
|
/* get sizes of child windows */
|
|
wnd_status = mswin_hwnd_from_winid(WIN_STATUS);
|
|
if (IsWindow(wnd_status)) {
|
|
mswin_status_window_size(wnd_status, &status_size);
|
|
} else {
|
|
status_size.cx = status_size.cy = 0;
|
|
}
|
|
|
|
wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE);
|
|
if (IsWindow(wnd_msg)) {
|
|
mswin_message_window_size(wnd_msg, &msg_size);
|
|
} else {
|
|
msg_size.cx = msg_size.cy = 0;
|
|
}
|
|
|
|
/* find all menu windows and calculate the size */
|
|
menu_size.cx = menu_size.cy = 0;
|
|
for (i = 0; i < MAXWINDOWS; i++) {
|
|
SIZE tmp_size;
|
|
if (GetNHApp()->windowlist[i].win
|
|
&& !GetNHApp()->windowlist[i].dead
|
|
&& GetNHApp()->windowlist[i].type == NHW_MENU) {
|
|
mswin_menu_window_size(GetNHApp()->windowlist[i].win,
|
|
&tmp_size);
|
|
menu_size.cx = max(menu_size.cx, tmp_size.cx);
|
|
menu_size.cy = max(menu_size.cy, tmp_size.cy);
|
|
}
|
|
}
|
|
|
|
/* set window positions */
|
|
SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right,
|
|
client_rt.bottom);
|
|
switch (iflags.wc_align_status) {
|
|
case ALIGN_LEFT:
|
|
status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
|
|
status_size.cy =
|
|
(wnd_rect.bottom - wnd_rect.top); // that won't look good
|
|
status_org.x = wnd_rect.left;
|
|
status_org.y = wnd_rect.top;
|
|
wnd_rect.left += status_size.cx;
|
|
break;
|
|
|
|
case ALIGN_RIGHT:
|
|
status_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
|
|
status_size.cy =
|
|
(wnd_rect.bottom - wnd_rect.top); // that won't look good
|
|
status_org.x = wnd_rect.right - status_size.cx;
|
|
status_org.y = wnd_rect.top;
|
|
wnd_rect.right -= status_size.cx;
|
|
break;
|
|
|
|
case ALIGN_TOP:
|
|
status_size.cx = (wnd_rect.right - wnd_rect.left);
|
|
status_org.x = wnd_rect.left;
|
|
status_org.y = wnd_rect.top;
|
|
wnd_rect.top += status_size.cy;
|
|
break;
|
|
|
|
case ALIGN_BOTTOM:
|
|
default:
|
|
status_size.cx = (wnd_rect.right - wnd_rect.left);
|
|
status_org.x = wnd_rect.left;
|
|
status_org.y = wnd_rect.bottom - status_size.cy;
|
|
wnd_rect.bottom -= status_size.cy;
|
|
break;
|
|
}
|
|
|
|
switch (iflags.wc_align_message) {
|
|
case ALIGN_LEFT:
|
|
msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
|
|
msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
|
|
msg_org.x = wnd_rect.left;
|
|
msg_org.y = wnd_rect.top;
|
|
wnd_rect.left += msg_size.cx;
|
|
break;
|
|
|
|
case ALIGN_RIGHT:
|
|
msg_size.cx = (wnd_rect.right - wnd_rect.left) / 4;
|
|
msg_size.cy = (wnd_rect.bottom - wnd_rect.top);
|
|
msg_org.x = wnd_rect.right - msg_size.cx;
|
|
msg_org.y = wnd_rect.top;
|
|
wnd_rect.right -= msg_size.cx;
|
|
break;
|
|
|
|
case ALIGN_TOP:
|
|
msg_size.cx = (wnd_rect.right - wnd_rect.left);
|
|
msg_org.x = wnd_rect.left;
|
|
msg_org.y = wnd_rect.top;
|
|
wnd_rect.top += msg_size.cy;
|
|
break;
|
|
|
|
case ALIGN_BOTTOM:
|
|
default:
|
|
msg_size.cx = (wnd_rect.right - wnd_rect.left);
|
|
msg_org.x = wnd_rect.left;
|
|
msg_org.y = wnd_rect.bottom - msg_size.cy;
|
|
wnd_rect.bottom -= msg_size.cy;
|
|
break;
|
|
}
|
|
|
|
/* map window */
|
|
map_org.x = wnd_rect.left;
|
|
map_org.y = wnd_rect.top;
|
|
map_size.cx = wnd_rect.right - wnd_rect.left;
|
|
map_size.cy = wnd_rect.bottom - wnd_rect.top;
|
|
|
|
GetNHApp()->rtStatusWindow.left = status_org.x;
|
|
GetNHApp()->rtStatusWindow.top = status_org.y;
|
|
GetNHApp()->rtStatusWindow.right = status_org.x + status_size.cx;
|
|
GetNHApp()->rtStatusWindow.bottom = status_org.y + status_size.cy;
|
|
|
|
GetNHApp()->rtTextWindow.left = map_org.x;
|
|
GetNHApp()->rtTextWindow.top = map_org.y;
|
|
GetNHApp()->rtTextWindow.right =
|
|
map_org.x + (wnd_rect.right - wnd_rect.left);
|
|
GetNHApp()->rtTextWindow.bottom = map_org.y + map_size.cy;
|
|
|
|
GetNHApp()->rtMapWindow.left = map_org.x;
|
|
GetNHApp()->rtMapWindow.top = map_org.y;
|
|
GetNHApp()->rtMapWindow.right = map_org.x + map_size.cx;
|
|
GetNHApp()->rtMapWindow.bottom = map_org.y + map_size.cy;
|
|
|
|
GetNHApp()->rtMsgWindow.left = msg_org.x;
|
|
GetNHApp()->rtMsgWindow.top = msg_org.y;
|
|
GetNHApp()->rtMsgWindow.right = msg_org.x + msg_size.cx;
|
|
GetNHApp()->rtMsgWindow.bottom = msg_org.y + msg_size.cy;
|
|
|
|
/* map_width/4 < menu_width < map_width*2/3 */
|
|
GetNHApp()->rtMenuWindow.left =
|
|
GetNHApp()->rtMapWindow.right
|
|
- min(map_size.cx * 2 / 3, max(map_size.cx / 4, menu_size.cx));
|
|
GetNHApp()->rtMenuWindow.top = GetNHApp()->rtMapWindow.top;
|
|
GetNHApp()->rtMenuWindow.right = GetNHApp()->rtMapWindow.right;
|
|
GetNHApp()->rtMenuWindow.bottom = GetNHApp()->rtMapWindow.bottom;
|
|
|
|
GetNHApp()->rtInvenWindow.left = GetNHApp()->rtMenuWindow.left;
|
|
GetNHApp()->rtInvenWindow.top = GetNHApp()->rtMenuWindow.top;
|
|
GetNHApp()->rtInvenWindow.right = GetNHApp()->rtMenuWindow.right;
|
|
GetNHApp()->rtInvenWindow.bottom = GetNHApp()->rtMenuWindow.bottom;
|
|
|
|
/* adjust map window size only if perm_invent is set */
|
|
if (iflags.perm_invent)
|
|
GetNHApp()->rtMapWindow.right = GetNHApp()->rtMenuWindow.left;
|
|
}
|
|
|
|
/* go through the windows list and adjust sizes */
|
|
for (i = 0; i < MAXWINDOWS; i++) {
|
|
if (GetNHApp()->windowlist[i].win
|
|
&& !GetNHApp()->windowlist[i].dead) {
|
|
RECT rt;
|
|
/* kludge - inventory window should have its own type (same as
|
|
menu-text
|
|
as a matter of fact) */
|
|
if (iflags.perm_invent && i == WIN_INVEN) {
|
|
mswin_get_window_placement(NHW_INVEN, &rt);
|
|
} else {
|
|
mswin_get_window_placement(GetNHApp()->windowlist[i].type,
|
|
&rt);
|
|
}
|
|
|
|
MoveWindow(GetNHApp()->windowlist[i].win, rt.left, rt.top,
|
|
rt.right - rt.left, rt.bottom - rt.top, TRUE);
|
|
}
|
|
}
|
|
if (IsWindow(changed_child))
|
|
SetForegroundWindow(changed_child);
|
|
}
|
|
|
|
VOID CALLBACK FuzzTimerProc(
|
|
_In_ HWND hwnd,
|
|
_In_ UINT uMsg,
|
|
_In_ UINT_PTR idEvent,
|
|
_In_ DWORD dwTime
|
|
)
|
|
{
|
|
INPUT input[16];
|
|
int i_pos = 0;
|
|
int c = randomkey();
|
|
SHORT k = VkKeyScanA(c);
|
|
BOOL gen_alt = (rn2(50) == 0) && isalpha(c);
|
|
|
|
if (!iflags.debug_fuzzer) {
|
|
KillTimer(hwnd, IDT_FUZZ_TIMER);
|
|
return;
|
|
}
|
|
|
|
if (!GetFocus())
|
|
return;
|
|
|
|
ZeroMemory(input, sizeof(input));
|
|
if (gen_alt) {
|
|
input[i_pos].type = INPUT_KEYBOARD;
|
|
input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
|
|
input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
|
|
i_pos++;
|
|
}
|
|
|
|
if (HIBYTE(k) & 1) {
|
|
input[i_pos].type = INPUT_KEYBOARD;
|
|
input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
|
|
input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
|
|
i_pos++;
|
|
}
|
|
|
|
input[i_pos].type = INPUT_KEYBOARD;
|
|
input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE;
|
|
input[i_pos].ki.wScan = MapVirtualKey(LOBYTE(k), 0);
|
|
i_pos++;
|
|
|
|
if (HIBYTE(k) & 1) {
|
|
input[i_pos].type = INPUT_KEYBOARD;
|
|
input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
|
|
input[i_pos].ki.wScan = MapVirtualKey(VK_LSHIFT, 0);
|
|
i_pos++;
|
|
}
|
|
if (gen_alt) {
|
|
input[i_pos].type = INPUT_KEYBOARD;
|
|
input[i_pos].ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
|
|
input[i_pos].ki.wScan = MapVirtualKey(VK_MENU, 0);
|
|
i_pos++;
|
|
}
|
|
SendInput(i_pos, input, sizeof(input[0]));
|
|
}
|
|
|
|
LRESULT
|
|
onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int wmId, wmEvent;
|
|
PNHMainWindow data;
|
|
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
data = (PNHMainWindow) GetWindowLongPtr(hWnd, GWLP_USERDATA);
|
|
wmId = LOWORD(wParam);
|
|
wmEvent = HIWORD(wParam);
|
|
|
|
// Parse the menu selections:
|
|
switch (wmId) {
|
|
case IDM_ABOUT:
|
|
mswin_display_splash_window(TRUE);
|
|
break;
|
|
|
|
case IDM_FUZZ:
|
|
if (iflags.debug_fuzzer)
|
|
KillTimer(hWnd, IDT_FUZZ_TIMER);
|
|
else
|
|
SetTimer(hWnd, IDT_FUZZ_TIMER, 10, FuzzTimerProc);
|
|
iflags.debug_fuzzer = !iflags.debug_fuzzer;
|
|
break;
|
|
case IDM_EXIT:
|
|
if (iflags.debug_fuzzer)
|
|
break;
|
|
done2();
|
|
break;
|
|
|
|
case IDM_SAVE:
|
|
if (iflags.debug_fuzzer)
|
|
break;
|
|
if (!svp.program_state.gameover && !svp.program_state.done_hup)
|
|
dosave();
|
|
else
|
|
MessageBeep(0);
|
|
break;
|
|
|
|
case IDM_MAP_TILES:
|
|
case IDM_MAP_ASCII4X6:
|
|
case IDM_MAP_ASCII6X8:
|
|
case IDM_MAP_ASCII8X8:
|
|
case IDM_MAP_ASCII16X8:
|
|
case IDM_MAP_ASCII7X12:
|
|
case IDM_MAP_ASCII8X12:
|
|
case IDM_MAP_ASCII12X16:
|
|
case IDM_MAP_ASCII16X12:
|
|
case IDM_MAP_ASCII10X18:
|
|
mswin_select_map_mode(menuid2mapmode(wmId));
|
|
break;
|
|
|
|
case IDM_MAP_FIT_TO_SCREEN:
|
|
if (IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
|
|
mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
|
|
? data->mapAcsiiModeSave
|
|
: MAP_MODE_TILES);
|
|
} else {
|
|
mswin_select_map_mode(IS_MAP_ASCII(iflags.wc_map_mode)
|
|
? MAP_MODE_ASCII_FIT_TO_SCREEN
|
|
: MAP_MODE_TILES_FIT_TO_SCREEN);
|
|
}
|
|
break;
|
|
|
|
case IDM_SETTING_SCREEN_TO_CLIPBOARD: {
|
|
char *p = NULL;
|
|
#ifdef ENHANCED_SYMBOLS
|
|
WCHAR *wp = NULL;
|
|
#endif
|
|
unsigned chr_size = 1;
|
|
size_t len;
|
|
HANDLE hglbCopy;
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8)) {
|
|
wp = nh_compose_unicode_screenshot();
|
|
if (!wp)
|
|
return 0;
|
|
len = wcslen(wp);
|
|
chr_size = sizeof(WCHAR);
|
|
} else
|
|
#endif
|
|
{
|
|
p = nh_compose_ascii_screenshot();
|
|
if (!p)
|
|
return 0;
|
|
len = strlen(p);
|
|
}
|
|
|
|
if (!OpenClipboard(hWnd)) {
|
|
NHMessageBox(hWnd, TEXT("Cannot open clipboard"),
|
|
MB_OK | MB_ICONERROR);
|
|
free(p);
|
|
#ifdef ENHANCED_SYMBOLS
|
|
free(wp);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
EmptyClipboard();
|
|
|
|
hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * chr_size);
|
|
if (hglbCopy == NULL) {
|
|
CloseClipboard();
|
|
free(p);
|
|
#ifdef ENHANCED_SYMBOLS
|
|
free(wp);
|
|
#endif
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8)) {
|
|
WCHAR *p_copy;
|
|
|
|
if ((p_copy = (WCHAR *) GlobalLock(hglbCopy)) != 0) {
|
|
wcsncpy(p_copy, wp, len);
|
|
p_copy[len] = 0; // null character
|
|
}
|
|
} else {
|
|
#endif
|
|
char *p_copy;
|
|
|
|
if ((p_copy = (char *) GlobalLock(hglbCopy)) != 0) {
|
|
strncpy(p_copy, p, len);
|
|
p_copy[len] = 0; // null character
|
|
}
|
|
#ifdef ENHANCED_SYMBOLS
|
|
}
|
|
#endif
|
|
GlobalUnlock(hglbCopy);
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8))
|
|
SetClipboardData(CF_UNICODETEXT, hglbCopy);
|
|
else
|
|
#endif
|
|
SetClipboardData(SYMHANDLING(H_IBM) ? CF_OEMTEXT : CF_TEXT, hglbCopy);
|
|
|
|
CloseClipboard();
|
|
|
|
free(p);
|
|
#ifdef ENHANCED_SYMBOLS
|
|
free(wp);
|
|
#endif
|
|
} break;
|
|
|
|
case IDM_SETTING_SCREEN_TO_FILE: {
|
|
OPENFILENAME ofn;
|
|
TCHAR filename[1024];
|
|
TCHAR whackdir[MAX_PATH];
|
|
FILE *pFile;
|
|
char *text;
|
|
wchar_t *wtext;
|
|
int tlen = 0;
|
|
|
|
if (iflags.debug_fuzzer)
|
|
break;
|
|
|
|
ZeroMemory(filename, sizeof(filename));
|
|
ZeroMemory(&ofn, sizeof(ofn));
|
|
ofn.lStructSize = sizeof(OPENFILENAME);
|
|
ofn.hwndOwner = hWnd;
|
|
ofn.hInstance = GetNHApp()->hApp;
|
|
ofn.lpstrFilter = TEXT("Text Files (*.txt)\x0*.txt\x0")
|
|
TEXT("All Files (*.*)\x0*.*\x0") TEXT("\x0\x0");
|
|
ofn.lpstrCustomFilter = NULL;
|
|
ofn.nMaxCustFilter = 0;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = filename;
|
|
ofn.nMaxFile = SIZE(filename);
|
|
ofn.lpstrFileTitle = NULL;
|
|
ofn.nMaxFileTitle = 0;
|
|
ofn.lpstrInitialDir = NH_A2W(gh.hackdir, whackdir, MAX_PATH);
|
|
ofn.lpstrTitle = NULL;
|
|
ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
|
|
ofn.nFileOffset = 0;
|
|
ofn.nFileExtension = 0;
|
|
ofn.lpstrDefExt = TEXT("txt");
|
|
ofn.lCustData = 0;
|
|
ofn.lpfnHook = 0;
|
|
ofn.lpTemplateName = 0;
|
|
|
|
if (!GetSaveFileName(&ofn))
|
|
return FALSE;
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
if (SYMHANDLING(H_UTF8)) {
|
|
text = NULL;
|
|
wtext = nh_compose_unicode_screenshot();
|
|
if (!wtext)
|
|
return FALSE;
|
|
tlen = wcslen(wtext);
|
|
} else
|
|
#endif
|
|
{
|
|
text = nh_compose_ascii_screenshot();
|
|
if (!text)
|
|
return FALSE;
|
|
tlen = strlen(text);
|
|
wtext = (wchar_t *) malloc(tlen * sizeof(wchar_t));
|
|
if (wtext) {
|
|
MultiByteToWideChar(NH_CODEPAGE, 0, text, -1, wtext, tlen);
|
|
}
|
|
}
|
|
|
|
filename[SIZE(filename) - 1] = '\0';
|
|
pFile = _tfopen(filename, TEXT("wt+,ccs=UTF-8"));
|
|
if (!pFile) {
|
|
TCHAR buf[4096];
|
|
_stprintf(buf, TEXT("Cannot open %s for writing!"), filename);
|
|
NHMessageBox(hWnd, buf, MB_OK | MB_ICONERROR);
|
|
if (text)
|
|
free(text);
|
|
if (wtext)
|
|
free(wtext);
|
|
return FALSE;
|
|
}
|
|
|
|
if (wtext) {
|
|
fwrite(wtext, tlen * sizeof(wchar_t), 1, pFile);
|
|
fclose(pFile);
|
|
free(wtext);
|
|
}
|
|
if (text)
|
|
free(text);
|
|
} break;
|
|
|
|
case IDM_NHMODE: {
|
|
GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1;
|
|
mswin_menu_check_intf_mode();
|
|
mswin_apply_window_style_all();
|
|
break;
|
|
}
|
|
case IDM_CLEARSETTINGS: {
|
|
mswin_destroy_reg();
|
|
/* Notify the user that windows settings will not be saved this time.
|
|
*/
|
|
NHMessageBox(GetNHApp()->hMainWnd,
|
|
TEXT("Your Windows Settings will not be stored when you "
|
|
"exit this time."),
|
|
MB_OK | MB_ICONINFORMATION);
|
|
break;
|
|
}
|
|
|
|
case IDM_SETTING_AUTOLAYOUT:
|
|
GetNHApp()->bAutoLayout = !GetNHApp()->bAutoLayout;
|
|
mswin_layout_main_window(NULL);
|
|
|
|
/* Update menu item check-mark */
|
|
CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_AUTOLAYOUT,
|
|
GetNHApp()->bAutoLayout ? MF_CHECKED : MF_UNCHECKED);
|
|
break;
|
|
|
|
case IDM_SETTING_LOCKWINDOWS:
|
|
nhlock_windows(!GetNHApp()->bWindowsLocked);
|
|
break;
|
|
|
|
case IDM_HELP_LONG:
|
|
display_file(HELP, TRUE);
|
|
break;
|
|
|
|
case IDM_HELP_COMMANDS:
|
|
display_file(SHELP, TRUE);
|
|
break;
|
|
|
|
case IDM_HELP_HISTORY:
|
|
(void) dohistory();
|
|
break;
|
|
|
|
case IDM_HELP_INFO_CHAR:
|
|
(void) dowhatis();
|
|
break;
|
|
|
|
case IDM_HELP_INFO_KEY:
|
|
(void) dowhatdoes();
|
|
break;
|
|
|
|
case IDM_HELP_OPTIONS:
|
|
option_help();
|
|
break;
|
|
|
|
case IDM_HELP_OPTIONS_LONG:
|
|
display_file(OPTIONFILE, TRUE);
|
|
break;
|
|
|
|
case IDM_HELP_EXTCMD:
|
|
(void) doextlist();
|
|
break;
|
|
|
|
case IDM_HELP_LICENSE:
|
|
display_file(LICENSE, TRUE);
|
|
break;
|
|
|
|
case IDM_HELP_PORTHELP:
|
|
display_file(PORT_HELP, TRUE);
|
|
break;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// Message handler for about box.
|
|
LRESULT CALLBACK
|
|
About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
char buf[BUFSZ];
|
|
TCHAR wbuf[BUFSZ];
|
|
RECT main_rt, dlg_rt;
|
|
SIZE dlg_sz;
|
|
|
|
UNREFERENCED_PARAMETER(lParam);
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
getversionstring(buf, sizeof buf);
|
|
SetDlgItemText(hDlg, IDC_ABOUT_VERSION,
|
|
NH_A2W(buf, wbuf, sizeof(wbuf)));
|
|
|
|
Sprintf(buf, "%s\n%s\n%s\n%s",
|
|
COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B,
|
|
nomakedefs.copyright_banner_c, COPYRIGHT_BANNER_D);
|
|
SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT,
|
|
NH_A2W(buf, wbuf, sizeof(wbuf)));
|
|
|
|
/* center dialog in the main window */
|
|
GetWindowRect(GetNHApp()->hMainWnd, &main_rt);
|
|
GetWindowRect(hDlg, &dlg_rt);
|
|
dlg_sz.cx = dlg_rt.right - dlg_rt.left;
|
|
dlg_sz.cy = dlg_rt.bottom - dlg_rt.top;
|
|
|
|
dlg_rt.left = (main_rt.left + main_rt.right - dlg_sz.cx) / 2;
|
|
dlg_rt.right = dlg_rt.left + dlg_sz.cx;
|
|
dlg_rt.top = (main_rt.top + main_rt.bottom - dlg_sz.cy) / 2;
|
|
dlg_rt.bottom = dlg_rt.top + dlg_sz.cy;
|
|
MoveWindow(hDlg, (main_rt.left + main_rt.right - dlg_sz.cx) / 2,
|
|
(main_rt.top + main_rt.bottom - dlg_sz.cy) / 2, dlg_sz.cx,
|
|
dlg_sz.cy, TRUE);
|
|
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
mswin_menu_check_intf_mode(void)
|
|
{
|
|
HMENU hMenu = GetMenu(GetNHApp()->hMainWnd);
|
|
|
|
if (GetNHApp()->regNetHackMode)
|
|
CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED);
|
|
else
|
|
CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED);
|
|
}
|
|
|
|
void
|
|
mswin_select_map_mode(int mode)
|
|
{
|
|
PNHMainWindow data;
|
|
winid map_id;
|
|
|
|
map_id = WIN_MAP;
|
|
data =
|
|
(PNHMainWindow) GetWindowLongPtr(GetNHApp()->hMainWnd, GWLP_USERDATA);
|
|
|
|
/* override for Rogue level */
|
|
if (Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode))
|
|
return;
|
|
|
|
/* set map mode menu mark */
|
|
if (IS_MAP_ASCII(mode)) {
|
|
CheckMenuRadioItem(
|
|
GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18,
|
|
mapmode2menuid(IS_MAP_FIT_TO_SCREEN(mode) ? data->mapAcsiiModeSave
|
|
: mode),
|
|
MF_BYCOMMAND);
|
|
} else {
|
|
CheckMenuRadioItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES,
|
|
IDM_MAP_ASCII10X18, mapmode2menuid(MAP_MODE_TILES),
|
|
MF_BYCOMMAND);
|
|
}
|
|
|
|
/* set fit-to-screen mode mark */
|
|
CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_MAP_FIT_TO_SCREEN,
|
|
MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode) ? MF_CHECKED
|
|
: MF_UNCHECKED));
|
|
|
|
if (IS_MAP_ASCII(iflags.wc_map_mode)
|
|
&& !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) {
|
|
data->mapAcsiiModeSave = iflags.wc_map_mode;
|
|
}
|
|
|
|
iflags.wc_map_mode = mode;
|
|
|
|
/*
|
|
** first, check if WIN_MAP has been initialized.
|
|
** If not - attempt to retrieve it by type, then check it again
|
|
*/
|
|
if (map_id == WIN_ERR)
|
|
map_id = mswin_winid_from_type(NHW_MAP);
|
|
if (map_id != WIN_ERR)
|
|
mswin_map_mode(mswin_hwnd_from_winid(map_id), mode);
|
|
}
|
|
|
|
static struct t_menu2mapmode {
|
|
int menuID;
|
|
int mapMode;
|
|
} _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES },
|
|
{ IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 },
|
|
{ IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 },
|
|
{ IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 },
|
|
{ IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 },
|
|
{ IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 },
|
|
{ IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 },
|
|
{ IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 },
|
|
{ IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 },
|
|
{ IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 },
|
|
{ IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN },
|
|
{ -1, -1 } };
|
|
|
|
int
|
|
menuid2mapmode(int menuid)
|
|
{
|
|
struct t_menu2mapmode *p;
|
|
for (p = _menu2mapmode; p->mapMode != -1; p++)
|
|
if (p->menuID == menuid)
|
|
return p->mapMode;
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
mapmode2menuid(int map_mode)
|
|
{
|
|
struct t_menu2mapmode *p;
|
|
for (p = _menu2mapmode; p->mapMode != -1; p++)
|
|
if (p->mapMode == map_mode)
|
|
return p->menuID;
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
nhlock_windows(BOOL lock)
|
|
{
|
|
/* update menu */
|
|
GetNHApp()->bWindowsLocked = lock;
|
|
CheckMenuItem(GetMenu(GetNHApp()->hMainWnd), IDM_SETTING_LOCKWINDOWS,
|
|
MF_BYCOMMAND | (lock ? MF_CHECKED : MF_UNCHECKED));
|
|
|
|
/* restyle windows */
|
|
mswin_apply_window_style_all();
|
|
}
|
|
|
|
void
|
|
mswin_apply_window_style(HWND hwnd) {
|
|
DWORD style = 0, exstyle = 0;
|
|
|
|
style = GetWindowLong(hwnd, GWL_STYLE);
|
|
exstyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
|
|
|
if( !GetNHApp()->bWindowsLocked ) {
|
|
style = WS_CHILD|WS_CLIPSIBLINGS|WS_CAPTION|WS_SIZEBOX|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
|
|
exstyle = WS_EX_WINDOWEDGE;
|
|
} else if (GetNHApp()->regNetHackMode) {
|
|
/* do away borders */
|
|
style = WS_CHILD|WS_CLIPSIBLINGS|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
|
|
exstyle = 0;
|
|
} else {
|
|
style = WS_CHILD|WS_CLIPSIBLINGS|WS_THICKFRAME|(style & (WS_VISIBLE|WS_VSCROLL|WS_HSCROLL));
|
|
exstyle = WS_EX_WINDOWEDGE;
|
|
}
|
|
|
|
SetWindowLong(hwnd, GWL_STYLE, style);
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, exstyle);
|
|
SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_NOCOPYBITS);
|
|
}
|
|
|
|
void
|
|
mswin_apply_window_style_all(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAXWINDOWS; i++) {
|
|
if (IsWindow(GetNHApp()->windowlist[i].win)
|
|
&& !GetNHApp()->windowlist[i].dead) {
|
|
mswin_apply_window_style(GetNHApp()->windowlist[i].win);
|
|
}
|
|
}
|
|
mswin_layout_main_window(NULL);
|
|
}
|
|
|
|
// returns strdup() created pointer - callee assumes the ownership
|
|
char *
|
|
nh_compose_ascii_screenshot(void)
|
|
{
|
|
char *retval;
|
|
PMSNHMsgGetText text;
|
|
|
|
retval = (char *) malloc(3 * TEXT_BUFFER_SIZE);
|
|
|
|
text =
|
|
(PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE);
|
|
if (text && retval) {
|
|
text->max_size =
|
|
TEXT_BUFFER_SIZE
|
|
- 1; /* make sure we always have 0 at the end of the buffer */
|
|
|
|
ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
|
|
strcpy(retval, text->buffer);
|
|
|
|
ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
|
|
strcat(retval, text->buffer);
|
|
|
|
ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
|
|
SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
|
|
strcat(retval, text->buffer);
|
|
|
|
free(text);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
#ifdef ENHANCED_SYMBOLS
|
|
// returns malloc() created pointer - callee assumes the ownership
|
|
static WCHAR *
|
|
nh_compose_unicode_screenshot(void)
|
|
{
|
|
WCHAR *retval;
|
|
PMSNHMsgGetText text;
|
|
PMSNHMsgGetWideText wtext;
|
|
size_t retsize;
|
|
const size_t max_size = 3 * TEXT_BUFFER_SIZE;
|
|
|
|
retval = (WCHAR *) malloc(max_size * sizeof(WCHAR));
|
|
retsize = 0;
|
|
|
|
text =
|
|
(PMSNHMsgGetText) malloc(sizeof(MSNHMsgGetText) + TEXT_BUFFER_SIZE);
|
|
if (text && retval) {
|
|
text->max_size =
|
|
TEXT_BUFFER_SIZE
|
|
- 1; /* make sure we always have 0 at the end of the buffer */
|
|
|
|
wtext = (PMSNHMsgGetWideText) malloc(
|
|
sizeof(MSNHMsgGetWideText) + TEXT_BUFFER_SIZE * sizeof(WCHAR));
|
|
if (wtext) {
|
|
wtext->max_size =
|
|
TEXT_BUFFER_SIZE
|
|
- 1; /* make sure we always have 0 at the end of the buffer */
|
|
|
|
ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
|
|
retsize += MultiByteToWideChar(
|
|
CP_ACP, 0, text->buffer, strlen(text->buffer),
|
|
retval + retsize, max_size - retsize);
|
|
|
|
ZeroMemory(wtext->buffer, TEXT_BUFFER_SIZE * sizeof(WCHAR));
|
|
SendMessage(mswin_hwnd_from_winid(WIN_MAP), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETWIDETEXT, (LPARAM) wtext);
|
|
wcsncpy(retval + retsize, wtext->buffer, max_size - retsize - 1);
|
|
retsize += wcslen(retval + retsize);
|
|
|
|
ZeroMemory(text->buffer, TEXT_BUFFER_SIZE);
|
|
SendMessage(mswin_hwnd_from_winid(WIN_STATUS), WM_MSNH_COMMAND,
|
|
(WPARAM) MSNH_MSG_GETTEXT, (LPARAM) text);
|
|
retsize += MultiByteToWideChar(
|
|
CP_ACP, 0, text->buffer, strlen(text->buffer),
|
|
retval + retsize, max_size - retsize);
|
|
retval[retsize] = L'\0';
|
|
free(wtext);
|
|
}
|
|
free(text);
|
|
}
|
|
return retval;
|
|
}
|
|
#endif
|