X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/5dda68e8cf413ef970e2aed330c01af2aeae856a..aa27d4932844e6aa590afba411b1503217f1602d:/windows.c diff --git a/windows.c b/windows.c index 494caae..383b742 100644 --- a/windows.c +++ b/windows.c @@ -1,5 +1,14 @@ /* * windows.c: Windows front end for my puzzle collection. + * + * TODO: + * + * - Figure out what to do if a puzzle requests a size bigger than + * the screen will take. In principle we could put scrollbars in + * the window, although that would be pretty horrid. Another + * option is to detect in advance that this will be a problem - + * we can probably tell this using midend_size() before actually + * generating the puzzle - and simply refuse to do it. */ #include @@ -18,11 +27,15 @@ #define IDM_RESTART 0x0020 #define IDM_UNDO 0x0030 #define IDM_REDO 0x0040 -#define IDM_QUIT 0x0050 -#define IDM_CONFIG 0x0060 -#define IDM_SEED 0x0070 -#define IDM_HELPC 0x0080 -#define IDM_GAMEHELP 0x0090 +#define IDM_COPY 0x0050 +#define IDM_SOLVE 0x0060 +#define IDM_QUIT 0x0070 +#define IDM_CONFIG 0x0080 +#define IDM_DESC 0x0090 +#define IDM_SEED 0x00A0 +#define IDM_HELPC 0x00B0 +#define IDM_GAMEHELP 0x00C0 +#define IDM_ABOUT 0x00D0 #define IDM_PRESETS 0x0100 #define HELP_FILE_NAME "puzzles.hlp" @@ -101,7 +114,7 @@ struct frontend { int nfonts, fontsize; config_item *cfg; struct cfg_aux *cfgaux; - int cfg_which, cfg_done; + int cfg_which, dlg_done; HFONT cfgfont; char *help_path; int help_has_contents; @@ -121,6 +134,14 @@ void fatal(char *fmt, ...) exit(1); } +void get_random_seed(void **randseed, int *randseedsize) +{ + time_t *tp = snew(time_t); + time(tp); + *randseed = (void *)tp; + *randseedsize = sizeof(time_t); +} + void status_bar(frontend *fe, char *text) { SetWindowText(fe->statusbar, text); @@ -137,18 +158,12 @@ void frontend_default_colour(frontend *fe, float *output) void clip(frontend *fe, int x, int y, int w, int h) { - if (!fe->clip) { - fe->clip = CreateRectRgn(0, 0, 1, 1); - GetClipRgn(fe->hdc_bm, fe->clip); - } - IntersectClipRect(fe->hdc_bm, x, y, x+w, y+h); } void unclip(frontend *fe) { - assert(fe->clip); - SelectClipRgn(fe->hdc_bm, fe->clip); + SelectClipRgn(fe->hdc_bm, NULL); } void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize, @@ -174,11 +189,7 @@ void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize, fe->fonts[i].type = fonttype; fe->fonts[i].size = fontsize; - /* - * FIXME: Really I should make at least _some_ effort to - * pick the correct font. - */ - fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0, 0, + fe->fonts[i].font = CreateFont(-fontsize, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, @@ -210,6 +221,7 @@ void draw_text(frontend *fe, int x, int y, int fonttype, int fontsize, x -= size.cx; } SetBkMode(fe->hdc_bm, TRANSPARENT); + SetTextColor(fe->hdc_bm, fe->colours[colour]); TextOut(fe->hdc_bm, x, y, text, strlen(text)); SelectObject(fe->hdc_bm, oldfont); } @@ -317,6 +329,53 @@ void activate_timer(frontend *fe) } } +void write_clip(HWND hwnd, char *data) +{ + HGLOBAL clipdata; + int len, i, j; + char *data2; + void *lock; + + /* + * Windows expects CRLF in the clipboard, so we must convert + * any \n that has come out of the puzzle backend. + */ + len = 0; + for (i = 0; data[i]; i++) { + if (data[i] == '\n') + len++; + len++; + } + data2 = snewn(len+1, char); + j = 0; + for (i = 0; data[i]; i++) { + if (data[i] == '\n') + data2[j++] = '\r'; + data2[j++] = data[i]; + } + assert(j == len); + data2[j] = '\0'; + + clipdata = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len + 1); + if (!clipdata) + return; + lock = GlobalLock(clipdata); + if (!lock) + return; + memcpy(lock, data2, len); + ((unsigned char *) lock)[len] = 0; + GlobalUnlock(clipdata); + + if (OpenClipboard(hwnd)) { + EmptyClipboard(); + SetClipboardData(CF_TEXT, clipdata); + CloseClipboard(); + } else + GlobalFree(clipdata); + + sfree(data2); +} + /* * See if we can find a help file. */ @@ -352,15 +411,13 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) int x, y; RECT r, sr; HDC hdc; - time_t t; fe = snew(frontend); - time(&t); - fe->me = midend_new(fe, &t, sizeof(t)); + fe->me = midend_new(fe, &thegame); if (game_id) { - *error = midend_game_id(fe->me, game_id, FALSE); + *error = midend_game_id(fe->me, game_id); if (*error) { midend_free(fe->me); sfree(fe); @@ -406,7 +463,7 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) (WS_THICKFRAME | WS_MAXIMIZEBOX | WS_OVERLAPPED), TRUE, 0); - fe->hwnd = CreateWindowEx(0, game_name, game_name, + fe->hwnd = CreateWindowEx(0, thegame.name, thegame.name, WS_OVERLAPPEDWINDOW &~ (WS_THICKFRAME | WS_MAXIMIZEBOX), CW_USEDEFAULT, CW_USEDEFAULT, @@ -420,10 +477,11 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Game"); AppendMenu(menu, MF_ENABLED, IDM_NEW, "New"); AppendMenu(menu, MF_ENABLED, IDM_RESTART, "Restart"); - AppendMenu(menu, MF_ENABLED, IDM_SEED, "Specific..."); + AppendMenu(menu, MF_ENABLED, IDM_DESC, "Specific..."); + AppendMenu(menu, MF_ENABLED, IDM_SEED, "Random Seed..."); if ((fe->npresets = midend_num_presets(fe->me)) > 0 || - game_can_configure) { + thegame.can_configure) { HMENU sub = CreateMenu(); int i; @@ -444,7 +502,7 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) AppendMenu(sub, MF_ENABLED, IDM_PRESETS + 0x10 * i, name); } - if (game_can_configure) { + if (thegame.can_configure) { AppendMenu(sub, MF_ENABLED, IDM_CONFIG, "Custom..."); } } @@ -452,18 +510,28 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED, IDM_UNDO, "Undo"); AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo"); + if (thegame.can_format_as_text) { + AppendMenu(menu, MF_SEPARATOR, 0, 0); + AppendMenu(menu, MF_ENABLED, IDM_COPY, "Copy"); + } + if (thegame.can_solve) { + AppendMenu(menu, MF_SEPARATOR, 0, 0); + AppendMenu(menu, MF_ENABLED, IDM_SOLVE, "Solve"); + } AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit"); + menu = CreateMenu(); + AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "Help"); + AppendMenu(menu, MF_ENABLED, IDM_ABOUT, "About"); if (fe->help_path) { - HMENU hmenu = CreateMenu(); - AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)hmenu, "Help"); - AppendMenu(hmenu, MF_ENABLED, IDM_HELPC, "Contents"); - if (game_winhelp_topic) { + AppendMenu(menu, MF_SEPARATOR, 0, 0); + AppendMenu(menu, MF_ENABLED, IDM_HELPC, "Contents"); + if (thegame.winhelp_topic) { char *item; - assert(game_name); - item = snewn(9+strlen(game_name), char); /*ick*/ - sprintf(item, "Help on %s", game_name); - AppendMenu(hmenu, MF_ENABLED, IDM_GAMEHELP, item); + assert(thegame.name); + item = snewn(9+strlen(thegame.name), char); /*ick*/ + sprintf(item, "Help on %s", thegame.name); + AppendMenu(menu, MF_ENABLED, IDM_GAMEHELP, item); sfree(item); } } @@ -499,6 +567,30 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error) return fe; } +static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA); + + switch (msg) { + case WM_INITDIALOG: + return 0; + + case WM_COMMAND: + if ((HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) && + LOWORD(wParam) == IDOK) + fe->dlg_done = 1; + return 0; + + case WM_CLOSE: + fe->dlg_done = 1; + return 0; + } + + return 0; +} + static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -524,10 +616,10 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, MessageBox(hwnd, err, "Validation error", MB_ICONERROR | MB_OK); } else { - fe->cfg_done = 2; + fe->dlg_done = 2; } } else { - fe->cfg_done = 1; + fe->dlg_done = 1; } return 0; } @@ -561,7 +653,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, return 0; case WM_CLOSE: - fe->cfg_done = 1; + fe->dlg_done = 1; return 0; } @@ -570,7 +662,7 @@ static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, char *wclass, int wstyle, - int exstyle, char *wtext, int wid) + int exstyle, const char *wtext, int wid) { HWND ret; ret = CreateWindowEx(exstyle, wclass, wtext, @@ -580,6 +672,158 @@ HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, return ret; } +static void about(frontend *fe) +{ + int i; + WNDCLASS wc; + MSG msg; + TEXTMETRIC tm; + HDC hdc; + HFONT oldfont; + SIZE size; + int gm, id; + int winwidth, winheight, y; + int height, width, maxwid; + const char *strings[16]; + int lengths[16]; + int nstrings = 0; + char titlebuf[512]; + + sprintf(titlebuf, "About %.250s", thegame.name); + + strings[nstrings++] = thegame.name; + strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection"; + strings[nstrings++] = ver; + + wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW; + wc.lpfnWndProc = DefDlgProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA + 8; + wc.hInstance = fe->inst; + wc.hIcon = NULL; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1); + wc.lpszMenuName = NULL; + wc.lpszClassName = "GameAboutBox"; + RegisterClass(&wc); + + hdc = GetDC(fe->hwnd); + SetMapMode(hdc, MM_TEXT); + + fe->dlg_done = FALSE; + + fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), + 0, 0, 0, 0, + FALSE, FALSE, FALSE, DEFAULT_CHARSET, + OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, + DEFAULT_QUALITY, + FF_SWISS, + "MS Shell Dlg"); + + oldfont = SelectObject(hdc, fe->cfgfont); + if (GetTextMetrics(hdc, &tm)) { + height = tm.tmAscent + tm.tmDescent; + width = tm.tmAveCharWidth; + } else { + height = width = 30; + } + + /* + * Figure out the layout of the About box by measuring the + * length of each piece of text. + */ + maxwid = 0; + winheight = height/2; + + for (i = 0; i < nstrings; i++) { + if (GetTextExtentPoint32(hdc, strings[i], strlen(strings[i]), &size)) + lengths[i] = size.cx; + else + lengths[i] = 0; /* *shrug* */ + if (maxwid < lengths[i]) + maxwid = lengths[i]; + winheight += height * 3 / 2 + (height / 2); + } + + winheight += height + height * 7 / 4; /* OK button */ + winwidth = maxwid + 4*width; + + SelectObject(hdc, oldfont); + ReleaseDC(fe->hwnd, hdc); + + /* + * Create the dialog, now that we know its size. + */ + { + RECT r, r2; + + r.left = r.top = 0; + r.right = winwidth; + r.bottom = winheight; + + AdjustWindowRectEx(&r, (WS_OVERLAPPEDWINDOW /*| + DS_MODALFRAME | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU*/) &~ + (WS_MAXIMIZEBOX | WS_OVERLAPPED), + FALSE, 0); + + /* + * Centre the dialog on its parent window. + */ + r.right -= r.left; + r.bottom -= r.top; + GetWindowRect(fe->hwnd, &r2); + r.left = (r2.left + r2.right - r.right) / 2; + r.top = (r2.top + r2.bottom - r.bottom) / 2; + r.right += r.left; + r.bottom += r.top; + + fe->cfgbox = CreateWindowEx(0, wc.lpszClassName, titlebuf, + DS_MODALFRAME | WS_POPUP | WS_VISIBLE | + WS_CAPTION | WS_SYSMENU, + r.left, r.top, + r.right-r.left, r.bottom-r.top, + fe->hwnd, NULL, fe->inst, NULL); + } + + SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE); + + SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe); + SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)AboutDlgProc); + + id = 1000; + y = height/2; + for (i = 0; i < nstrings; i++) { + int border = width*2 + (maxwid - lengths[i]) / 2; + mkctrl(fe, border, border+lengths[i], y+height*1/8, y+height*9/8, + "Static", 0, 0, strings[i], id++); + y += height*3/2; + + assert(y < winheight); + y += height/2; + } + + y += height/2; /* extra space before OK */ + mkctrl(fe, width*2, maxwid+width*2, y, y+height*7/4, "BUTTON", + BS_PUSHBUTTON | BS_NOTIFY | WS_TABSTOP | BS_DEFPUSHBUTTON, 0, + "OK", IDOK); + + SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0); + + EnableWindow(fe->hwnd, FALSE); + ShowWindow(fe->cfgbox, SW_NORMAL); + while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { + if (!IsDialogMessage(fe->cfgbox, &msg)) + DispatchMessage(&msg); + if (fe->dlg_done) + break; + } + EnableWindow(fe->hwnd, TRUE); + SetForegroundWindow(fe->hwnd); + DestroyWindow(fe->cfgbox); + DeleteObject(fe->cfgfont); +} + static int get_config(frontend *fe, int which) { config_item *i; @@ -611,7 +855,7 @@ static int get_config(frontend *fe, int which) hdc = GetDC(fe->hwnd); SetMapMode(hdc, MM_TEXT); - fe->cfg_done = FALSE; + fe->dlg_done = FALSE; fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, @@ -675,6 +919,7 @@ static int get_config(frontend *fe, int which) col2r = col1l+2*height+maxcheckbox; winwidth = col2r + 2*width; + SelectObject(hdc, oldfont); ReleaseDC(fe->hwnd, hdc); /* @@ -806,7 +1051,7 @@ static int get_config(frontend *fe, int which) while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { if (!IsDialogMessage(fe->cfgbox, &msg)) DispatchMessage(&msg); - if (fe->cfg_done) + if (fe->dlg_done) break; } EnableWindow(fe->hwnd, TRUE); @@ -817,7 +1062,7 @@ static int get_config(frontend *fe, int which) free_cfg(fe->cfg); sfree(fe->cfgaux); - return (fe->cfg_done == 2); + return (fe->dlg_done == 2); } static void new_game_type(frontend *fe) @@ -875,8 +1120,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, PostQuitMessage(0); break; case IDM_RESTART: - if (!midend_process_key(fe->me, 0, 0, 'r')) - PostQuitMessage(0); + midend_restart_game(fe->me); break; case IDM_UNDO: if (!midend_process_key(fe->me, 0, 0, 'u')) @@ -886,6 +1130,24 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!midend_process_key(fe->me, 0, 0, '\x12')) PostQuitMessage(0); break; + case IDM_COPY: + { + char *text = midend_text_format(fe->me); + if (text) + write_clip(hwnd, text); + else + MessageBeep(MB_ICONWARNING); + sfree(text); + } + break; + case IDM_SOLVE: + { + char *msg = midend_solve(fe->me); + if (msg) + MessageBox(hwnd, msg, "Unable to solve", + MB_ICONERROR | MB_OK); + } + break; case IDM_QUIT: if (!midend_process_key(fe->me, 0, 0, 'q')) PostQuitMessage(0); @@ -898,6 +1160,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (get_config(fe, CFG_SEED)) new_game_type(fe); break; + case IDM_DESC: + if (get_config(fe, CFG_DESC)) + new_game_type(fe); + break; + case IDM_ABOUT: + about(fe); + break; case IDM_HELPC: assert(fe->help_path); WinHelp(hwnd, fe->help_path, @@ -905,10 +1174,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_GAMEHELP: assert(fe->help_path); - assert(game_winhelp_topic); + assert(thegame.winhelp_topic); { - char *cmd = snewn(10+strlen(game_winhelp_topic), char); /*ick*/ - sprintf(cmd, "JI(`',`%s')", game_winhelp_topic); + char *cmd = snewn(10+strlen(thegame.winhelp_topic), char); + sprintf(cmd, "JI(`',`%s')", thegame.winhelp_topic); WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd); sfree(cmd); } @@ -952,38 +1221,70 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_KEYDOWN: { int key = -1; + BYTE keystate[256]; + int r = GetKeyboardState(keystate); + int shift = (r && (keystate[VK_SHIFT] & 0x80)) ? MOD_SHFT : 0; + int ctrl = (r && (keystate[VK_CONTROL] & 0x80)) ? MOD_CTRL : 0; switch (wParam) { - case VK_LEFT: key = CURSOR_LEFT; break; - case VK_RIGHT: key = CURSOR_RIGHT; break; - case VK_UP: key = CURSOR_UP; break; - case VK_DOWN: key = CURSOR_DOWN; break; + case VK_LEFT: + if (!(lParam & 0x01000000)) + key = MOD_NUM_KEYPAD | '4'; + else + key = shift | ctrl | CURSOR_LEFT; + break; + case VK_RIGHT: + if (!(lParam & 0x01000000)) + key = MOD_NUM_KEYPAD | '6'; + else + key = shift | ctrl | CURSOR_RIGHT; + break; + case VK_UP: + if (!(lParam & 0x01000000)) + key = MOD_NUM_KEYPAD | '8'; + else + key = shift | ctrl | CURSOR_UP; + break; + case VK_DOWN: + if (!(lParam & 0x01000000)) + key = MOD_NUM_KEYPAD | '2'; + else + key = shift | ctrl | CURSOR_DOWN; + break; /* * Diagonal keys on the numeric keypad. */ case VK_PRIOR: - if (!(lParam & 0x01000000)) key = CURSOR_UP_RIGHT; + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '9'; break; case VK_NEXT: - if (!(lParam & 0x01000000)) key = CURSOR_DOWN_RIGHT; + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '3'; break; case VK_HOME: - if (!(lParam & 0x01000000)) key = CURSOR_UP_LEFT; + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '7'; break; case VK_END: - if (!(lParam & 0x01000000)) key = CURSOR_DOWN_LEFT; + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '1'; + break; + case VK_INSERT: + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '0'; + break; + case VK_CLEAR: + if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '5'; break; /* * Numeric keypad keys with Num Lock on. */ - case VK_NUMPAD4: key = CURSOR_LEFT; break; - case VK_NUMPAD6: key = CURSOR_RIGHT; break; - case VK_NUMPAD8: key = CURSOR_UP; break; - case VK_NUMPAD2: key = CURSOR_DOWN; break; - case VK_NUMPAD9: key = CURSOR_UP_RIGHT; break; - case VK_NUMPAD3: key = CURSOR_DOWN_RIGHT; break; - case VK_NUMPAD7: key = CURSOR_UP_LEFT; break; - case VK_NUMPAD1: key = CURSOR_DOWN_LEFT; break; + case VK_NUMPAD4: key = MOD_NUM_KEYPAD | '4'; break; + case VK_NUMPAD6: key = MOD_NUM_KEYPAD | '6'; break; + case VK_NUMPAD8: key = MOD_NUM_KEYPAD | '8'; break; + case VK_NUMPAD2: key = MOD_NUM_KEYPAD | '2'; break; + case VK_NUMPAD5: key = MOD_NUM_KEYPAD | '5'; break; + case VK_NUMPAD9: key = MOD_NUM_KEYPAD | '9'; break; + case VK_NUMPAD3: key = MOD_NUM_KEYPAD | '3'; break; + case VK_NUMPAD7: key = MOD_NUM_KEYPAD | '7'; break; + case VK_NUMPAD1: key = MOD_NUM_KEYPAD | '1'; break; + case VK_NUMPAD0: key = MOD_NUM_KEYPAD | '0'; break; } if (key != -1) { @@ -1101,7 +1402,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = game_name; + wndclass.lpszClassName = thegame.name; RegisterClass(&wndclass); } @@ -1111,7 +1412,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (!new_window(inst, *cmdline ? cmdline : NULL, &error)) { char buf[128]; - sprintf(buf, "%.100s Error", game_name); + sprintf(buf, "%.100s Error", thegame.name); MessageBox(NULL, error, buf, MB_OK|MB_ICONERROR); return 1; }