win32.c
changeset 1468 8073826fe82d
parent 1466 fd5c1d8c992a
child 1480 852ef4df7338
equal deleted inserted replaced
1467:c8a9a122dac4 1468:8073826fe82d
    47 #endif
    47 #endif
    48 
    48 
    49 static void MakePalette(void)
    49 static void MakePalette(void)
    50 {
    50 {
    51 	LOGPALETTE *pal;
    51 	LOGPALETTE *pal;
    52 	int i;
    52 	uint i;
    53 	byte *b;
    53 	byte *b;
    54 
    54 
    55 	pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY));
    55 	pal = alloca(sizeof(LOGPALETTE) + (256-1) * sizeof(PALETTEENTRY));
    56 
    56 
    57 	pal->palVersion = 0x300;
    57 	pal->palVersion = 0x300;
    58 	pal->palNumEntries = 256;
    58 	pal->palNumEntries = 256;
    59 
    59 
    60 	for(i=0,b=_cur_palette; i!=256;i++,b+=3) {
    60 	for (i = 0, b = _cur_palette; i != 256; i++, b += 3) {
    61 		pal->palPalEntry[i].peRed = b[0];
    61 		pal->palPalEntry[i].peRed = b[0];
    62 		pal->palPalEntry[i].peGreen = b[1];
    62 		pal->palPalEntry[i].peGreen = b[1];
    63 		pal->palPalEntry[i].peBlue = b[2];
    63 		pal->palPalEntry[i].peBlue = b[2];
    64 		pal->palPalEntry[i].peFlags = 0;
    64 		pal->palPalEntry[i].peFlags = 0;
    65 
    65 
    73 {
    73 {
    74 	RGBQUAD rgb[256];
    74 	RGBQUAD rgb[256];
    75 	uint i;
    75 	uint i;
    76 	byte *b;
    76 	byte *b;
    77 
    77 
    78 		for(i=0,b = _cur_palette + start*3; i!=count; i++,b+=3) {
    78 		for (i = 0, b = _cur_palette + start * 3; i != count; i++, b += 3) {
    79 		rgb[i].rgbRed = b[0];
    79 		rgb[i].rgbRed = b[0];
    80 		rgb[i].rgbGreen = b[1];
    80 		rgb[i].rgbGreen = b[1];
    81 		rgb[i].rgbBlue = b[2];
    81 		rgb[i].rgbBlue = b[2];
    82 		rgb[i].rgbReserved = 0;
    82 		rgb[i].rgbReserved = 0;
    83 	}
    83 	}
   100 	byte vk_from;
   100 	byte vk_from;
   101 	byte vk_count;
   101 	byte vk_count;
   102 	byte map_to;
   102 	byte map_to;
   103 } VkMapping;
   103 } VkMapping;
   104 
   104 
   105 #define AS(x,z) {x,0,z}
   105 #define AS(x, z) {x, 0, z}
   106 #define AM(x,y,z,w) {x,y-x,z}
   106 #define AM(x, y, z, w) {x, y - x, z}
   107 
   107 
   108 #ifndef	VK_OEM_3
   108 #ifndef	VK_OEM_3
   109 #define VK_OEM_3 0xC0
   109 #define VK_OEM_3 0xC0
   110 #endif
   110 #endif
   111 
   111 
   159 static void MakeWindow(bool full_screen);
   159 static void MakeWindow(bool full_screen);
   160 static bool AllocateDibSection(int w, int h);
   160 static bool AllocateDibSection(int w, int h);
   161 
   161 
   162 static void ClientSizeChanged(int w, int h)
   162 static void ClientSizeChanged(int w, int h)
   163 {
   163 {
   164 	if (_wnd.double_size) { w >>= 1; h >>= 1; }
   164 	if (_wnd.double_size) {
       
   165 		w /= 2;
       
   166 		h /= 2;
       
   167 	}
   165 
   168 
   166 	// allocate new dib section of the new size
   169 	// allocate new dib section of the new size
   167 	if (AllocateDibSection(w, h)) {
   170 	if (AllocateDibSection(w, h)) {
   168 		// mark all palette colors dirty
   171 		// mark all palette colors dirty
   169 		_pal_first_dirty = 0;
   172 		_pal_first_dirty = 0;
   180 
   183 
   181 void DoExitSave(void);
   184 void DoExitSave(void);
   182 
   185 
   183 static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   186 static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
   184 {
   187 {
   185 	switch(msg) {
   188 	switch (msg) {
   186 	case WM_PAINT: {
   189 	case WM_PAINT: {
   187 		PAINTSTRUCT ps;
   190 		PAINTSTRUCT ps;
   188 		HDC dc,dc2;
   191 		HDC dc,dc2;
   189 		HBITMAP old_bmp;
   192 		HBITMAP old_bmp;
   190 		HPALETTE old_palette;
   193 		HPALETTE old_palette;
   224 
   227 
   225 	case WM_CLOSE:
   228 	case WM_CLOSE:
   226 		if (_game_mode == GM_MENU) { // do not ask to quit on the main screen
   229 		if (_game_mode == GM_MENU) { // do not ask to quit on the main screen
   227 			_exit_game = true;
   230 			_exit_game = true;
   228 		} else if (_patches.autosave_on_exit) {
   231 		} else if (_patches.autosave_on_exit) {
   229 				DoExitSave();
   232 			DoExitSave();
   230 				_exit_game = true;
   233 			_exit_game = true;
   231 		} else
   234 		} else
   232 			AskExitGame();
   235 			AskExitGame();
   233 
   236 
   234 		return 0;
   237 		return 0;
   235 
   238 
   259 		int x = (int16)LOWORD(lParam);
   262 		int x = (int16)LOWORD(lParam);
   260 		int y = (int16)HIWORD(lParam);
   263 		int y = (int16)HIWORD(lParam);
   261 		POINT pt;
   264 		POINT pt;
   262 
   265 
   263 		if (_wnd.double_size) {
   266 		if (_wnd.double_size) {
   264 			x >>= 1;
   267 			x /= 2;
   265 			y >>= 1;
   268 			y /= 2;
   266 		}
   269 		}
   267 
   270 
   268 		if (_cursor.fix_at) {
   271 		if (_cursor.fix_at) {
   269 			int dx = x - _cursor.pos.x;
   272 			int dx = x - _cursor.pos.x;
   270 			int dy = y - _cursor.pos.y;
   273 			int dy = y - _cursor.pos.y;
   306 		r = ToAscii(wParam, scan, ks, &w, 0);
   309 		r = ToAscii(wParam, scan, ks, &w, 0);
   307 		if (r == 0) w = 0; // no translation was possible
   310 		if (r == 0) w = 0; // no translation was possible
   308 
   311 
   309 		_pressed_key = w | MapWindowsKey(wParam) << 16;
   312 		_pressed_key = w | MapWindowsKey(wParam) << 16;
   310 
   313 
   311 		if( scancode == 41 )
   314 		if (scancode == 41)
   312 			_pressed_key = w | WKC_BACKQUOTE << 16;
   315 			_pressed_key = w | WKC_BACKQUOTE << 16;
   313 
   316 
   314 		if ((_pressed_key>>16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) {
   317 		if ((_pressed_key >> 16) == ('D' | WKC_CTRL) && !_wnd.fullscreen) {
   315 			_double_size ^= 1;
   318 			_double_size ^= 1;
   316 			_wnd.double_size = _double_size;
   319 			_wnd.double_size = _double_size;
   317 			ClientSizeChanged(_wnd.width, _wnd.height);
   320 			ClientSizeChanged(_wnd.width, _wnd.height);
   318 			MarkWholeScreenDirty();
   321 			MarkWholeScreenDirty();
   319 		}
   322 		}
   320 	}	break;
   323 	}	break;
   321 
   324 
   322 
   325 
   323 	case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
   326 	case WM_SYSKEYDOWN: /* user presses F10 or Alt, both activating the title-menu */
   324 		switch(wParam) {
   327 		switch (wParam) {
   325 		case VK_RETURN: /* Full Screen */
   328 		case VK_RETURN: /* Full Screen */
   326 			MakeWindow(!_wnd.fullscreen);
   329 			MakeWindow(!_wnd.fullscreen);
   327 			return 0;
   330 			return 0;
   328 		case VK_MENU: /* Just ALT */
   331 		case VK_MENU: /* Just ALT */
   329 			return 0; // do nothing
   332 			return 0; // do nothing
   350 		SetRect(&r2, 0, 0, 0, 0);
   353 		SetRect(&r2, 0, 0, 0, 0);
   351 		AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   354 		AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   352 
   355 
   353 		w = r->right - r->left - (r2.right - r2.left);
   356 		w = r->right - r->left - (r2.right - r2.left);
   354 		h = r->bottom - r->top - (r2.bottom - r2.top);
   357 		h = r->bottom - r->top - (r2.bottom - r2.top);
   355 		if (_wnd.double_size) { w >>= 1; h >>= 1; }
   358 		if (_wnd.double_size) {
       
   359 			w /= 2;
       
   360 			h /= 2;
       
   361 		}
   356 		w = clamp(w, 64, MAX_SCREEN_WIDTH);
   362 		w = clamp(w, 64, MAX_SCREEN_WIDTH);
   357 		h = clamp(h, 64, MAX_SCREEN_HEIGHT);
   363 		h = clamp(h, 64, MAX_SCREEN_HEIGHT);
   358 		if (_wnd.double_size) { w <<= 1; h <<= 1; }
   364 		if (_wnd.double_size) {
       
   365 			w *= 2;
       
   366 			h *= 2;
       
   367 		}
   359 		SetRect(&r2, 0, 0, w, h);
   368 		SetRect(&r2, 0, 0, w, h);
   360 
   369 
   361 		AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   370 		AdjustWindowRect(&r2, GetWindowLong(hwnd, GWL_STYLE), FALSE);
   362 		w = r2.right - r2.left;
   371 		w = r2.right - r2.left;
   363 		h = r2.bottom - r2.top;
   372 		h = r2.bottom - r2.top;
   403 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
   412 # define GET_WHEEL_DELTA_WPARAM(wparam) ((short)HIWORD(wparam))
   404 #endif  //GET_WHEEL_DELTA_WPARAM
   413 #endif  //GET_WHEEL_DELTA_WPARAM
   405 
   414 
   406 	case WM_MOUSEWHEEL: {
   415 	case WM_MOUSEWHEEL: {
   407 		int delta = GET_WHEEL_DELTA_WPARAM(wParam);
   416 		int delta = GET_WHEEL_DELTA_WPARAM(wParam);
       
   417 
   408 		if (delta < 0) {
   418 		if (delta < 0) {
   409 			_cursor.wheel++;
   419 			_cursor.wheel++;
   410 		} else if (delta > 0) {
   420 		} else if (delta > 0) {
   411 			_cursor.wheel--;
   421 			_cursor.wheel--;
   412 		}
   422 		}
   450 	_fullscreen = full_screen;
   460 	_fullscreen = full_screen;
   451 
   461 
   452 	_wnd.double_size = _double_size && !full_screen;
   462 	_wnd.double_size = _double_size && !full_screen;
   453 
   463 
   454 	// recreate window?
   464 	// recreate window?
   455 	if ((full_screen|_wnd.fullscreen) && _wnd.main_wnd) {
   465 	if ((full_screen || _wnd.fullscreen) && _wnd.main_wnd) {
   456 		DestroyWindow(_wnd.main_wnd);
   466 		DestroyWindow(_wnd.main_wnd);
   457 		_wnd.main_wnd = 0;
   467 		_wnd.main_wnd = 0;
   458 	}
   468 	}
   459 
   469 
   460 	if (full_screen) {
   470 	if (full_screen) {
   467 			settings.dmBitsPerPel = _fullscreen_bpp;
   477 			settings.dmBitsPerPel = _fullscreen_bpp;
   468 			settings.dmFields |= DM_BITSPERPEL;
   478 			settings.dmFields |= DM_BITSPERPEL;
   469 		}
   479 		}
   470 		settings.dmPelsWidth = _wnd.width_org;
   480 		settings.dmPelsWidth = _wnd.width_org;
   471 		settings.dmPelsHeight = _wnd.height_org;
   481 		settings.dmPelsHeight = _wnd.height_org;
   472 		if ((settings.dmDisplayFrequency = _display_hz) != 0)
   482 		settings.dmDisplayFrequency = _display_hz;
       
   483 		if (settings.dmDisplayFrequency != 0)
   473 			settings.dmFields |= DM_DISPLAYFREQUENCY;
   484 			settings.dmFields |= DM_DISPLAYFREQUENCY;
   474 		if ( !ChangeDisplaySettings(&settings, CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL ) {
   485 		if (ChangeDisplaySettings(&settings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
   475 			MakeWindow(false);
   486 			MakeWindow(false);
   476 			return;
   487 			return;
   477 		}
   488 		}
   478 	} else if (_wnd.fullscreen) {
   489 	} else if (_wnd.fullscreen) {
   479 		// restore display?
   490 		// restore display?
   483 	{
   494 	{
   484 		RECT r;
   495 		RECT r;
   485 		uint style;
   496 		uint style;
   486 		int x, y, w, h;
   497 		int x, y, w, h;
   487 
   498 
   488 		if ((_wnd.fullscreen=full_screen) != false) {
   499 		_wnd.fullscreen = full_screen;
       
   500 		if (_wnd.fullscreen) {
   489 			style = WS_POPUP | WS_VISIBLE;
   501 			style = WS_POPUP | WS_VISIBLE;
   490 			SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
   502 			SetRect(&r, 0, 0, _wnd.width_org, _wnd.height_org);
   491 		} else {
   503 		} else {
   492 			style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
   504 			style = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
   493 			SetRect(&r, 0, 0, _wnd.width, _wnd.height);
   505 			SetRect(&r, 0, 0, _wnd.width, _wnd.height);
   494 		}
   506 		}
   495 
   507 
   496 		AdjustWindowRect(&r, style, FALSE);
   508 		AdjustWindowRect(&r, style, FALSE);
   497 		w = r.right - r.left;
   509 		w = r.right - r.left;
   498 		h = r.bottom - r.top;
   510 		h = r.bottom - r.top;
   499 		x = (GetSystemMetrics(SM_CXSCREEN)-w)>>1;
   511 		x = (GetSystemMetrics(SM_CXSCREEN) - w) / 2;
   500 		y = (GetSystemMetrics(SM_CYSCREEN)-h)>>1;
   512 		y = (GetSystemMetrics(SM_CYSCREEN) - h) / 2;
   501 
   513 
   502 		if (_wnd.main_wnd) {
   514 		if (_wnd.main_wnd) {
   503 			SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
   515 			SetWindowPos(_wnd.main_wnd, 0, x, y, w, h, SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
   504 		} else {
   516 		} else {
   505 			char Windowtitle[50] = "OpenTTD ";
   517 			char Windowtitle[50] = "OpenTTD ";
   506 			// also show revision number/release in window title
   518 
   507 			strncat(Windowtitle, _openttd_revision, sizeof(Windowtitle)-(strlen(Windowtitle) + 1));
   519 			snprintf(Windowtitle, lengthof(Windowtitle), "OpenTTD %s",
       
   520 				_openttd_revision);
   508 
   521 
   509 			_wnd.main_wnd = CreateWindow("TTD", Windowtitle, style, x, y, w, h, 0, 0, _inst, 0);
   522 			_wnd.main_wnd = CreateWindow("TTD", Windowtitle, style, x, y, w, h, 0, 0, _inst, 0);
   510 			if (_wnd.main_wnd == NULL)
   523 			if (_wnd.main_wnd == NULL)
   511 				error("CreateWindow failed");
   524 				error("CreateWindow failed");
   512 		}
   525 		}
   538 	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
   551 	memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD)*256);
   539 	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   552 	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
   540 
   553 
   541 	if (_wnd.double_size) {
   554 	if (_wnd.double_size) {
   542 		w = (w + 3) & ~0x3;
   555 		w = (w + 3) & ~0x3;
   543 		_wnd.alloced_bits = _wnd.buffer_bits = (byte*)malloc(w * h);
   556 		_wnd.alloced_bits = _wnd.buffer_bits = malloc(w * h);
   544 		w *= 2;
   557 		w *= 2;
   545 		h *= 2;
   558 		h *= 2;
   546 	}
   559 	}
   547 
   560 
   548 	bi->bmiHeader.biWidth = _wnd.width = w;
   561 	bi->bmiHeader.biWidth = _wnd.width = w;
   586 	int i = 0, n = 0;
   599 	int i = 0, n = 0;
   587 	DEVMODE dm;
   600 	DEVMODE dm;
   588 
   601 
   589 	while (EnumDisplaySettings(NULL, i++, &dm)) {
   602 	while (EnumDisplaySettings(NULL, i++, &dm)) {
   590 		if (dm.dmBitsPerPel == 8 &&
   603 		if (dm.dmBitsPerPel == 8 &&
   591 				IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH+1) &&
   604 				IS_INT_INSIDE(dm.dmPelsWidth, 640, MAX_SCREEN_WIDTH + 1) &&
   592 				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT+1) &&
   605 				IS_INT_INSIDE(dm.dmPelsHeight, 480, MAX_SCREEN_HEIGHT + 1) && (
   593 				(n == 0 || _resolutions[n-1][0] != dm.dmPelsWidth || _resolutions[n-1][1] != dm.dmPelsHeight)) {
   606 					n == 0 ||
       
   607 					_resolutions[n - 1][0] != dm.dmPelsWidth ||
       
   608 					_resolutions[n - 1][1] != dm.dmPelsHeight
       
   609 				)) {
   594 			_resolutions[n][0] = dm.dmPelsWidth;
   610 			_resolutions[n][0] = dm.dmPelsWidth;
   595 			_resolutions[n][1] = dm.dmPelsHeight;
   611 			_resolutions[n][1] = dm.dmPelsHeight;
   596 			if (++n == sizeof(_resolutions) / (sizeof(uint16)*2)) break;
   612 			if (++n == lengthof(_resolutions)) break;
   597 		}
   613 		}
   598 	}
   614 	}
   599 
   615 
   600 	if (n == 0) {
   616 	if (n == 0) {
   601 		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
   617 		memcpy(_resolutions, default_resolutions, sizeof(default_resolutions));
   602 		n = 6;
   618 		n = lengthof(default_resolutions);
   603 	}
   619 	}
   604 
   620 
   605 	_num_resolutions = n;
   621 	_num_resolutions = n;
   606 }
   622 }
   607 
   623 
   629 	return NULL;
   645 	return NULL;
   630 }
   646 }
   631 
   647 
   632 static void Win32GdiStop(void)
   648 static void Win32GdiStop(void)
   633 {
   649 {
   634 	if ( _wnd.fullscreen ) {
   650 	if (_wnd.fullscreen) ChangeDisplaySettings(NULL, 0);
   635 		ChangeDisplaySettings(NULL, 0);
       
   636 	}
       
   637 	MyShowCursor(true);
   651 	MyShowCursor(true);
   638 	DeleteObject(_wnd.gdi_palette);
   652 	DeleteObject(_wnd.gdi_palette);
   639 	DeleteObject(_wnd.dib_sect);
   653 	DeleteObject(_wnd.dib_sect);
   640 	DestroyWindow(_wnd.main_wnd);
   654 	DestroyWindow(_wnd.main_wnd);
   641 }
   655 }
   644 static void filter(int left, int top, int width, int height)
   658 static void filter(int left, int top, int width, int height)
   645 {
   659 {
   646 	uint p = _screen.pitch;
   660 	uint p = _screen.pitch;
   647 	byte *s = (byte*)_wnd.buffer_bits + top * p + left;
   661 	byte *s = (byte*)_wnd.buffer_bits + top * p + left;
   648 	byte *d = (byte*)_wnd.bitmap_bits + top * p * 4 + left * 2;
   662 	byte *d = (byte*)_wnd.bitmap_bits + top * p * 4 + left * 2;
   649 	int i;
   663 
   650 
   664 	for (; height > 0; height--) {
   651 	while (height) {
   665 		int i;
   652 		for(i=0; i!=width; i++) {
   666 
   653 			d[i*2] = d[i*2+1] = d[i*2+p*2] = d[i*2+1+p*2] = s[i];
   667 		for (i = 0; i != width; i++) {
       
   668 			d[i * 2] = d[i * 2 + 1] = d[i * 2 + p * 2] = d[i * 2 + 1 + p * 2] = s[i];
   654 		}
   669 		}
   655 		s += p;
   670 		s += p;
   656 		d += p * 4;
   671 		d += p * 4;
   657 		height--;
       
   658 	}
   672 	}
   659 }
   673 }
   660 
   674 
   661 static void Win32GdiMakeDirty(int left, int top, int width, int height)
   675 static void Win32GdiMakeDirty(int left, int top, int width, int height)
   662 {
   676 {
   663 	RECT r = {left, top, left+width, top+height};
   677 	RECT r = { left, top, left + width, top + height };
       
   678 
   664 	if (_wnd.double_size) {
   679 	if (_wnd.double_size) {
   665 		filter(left, top, width, height);
   680 		filter(left, top, width, height);
   666 		//filter(0, 0, 640, 480);
   681 		r.left *= 2;
   667 		r.left *= 2;r.top *= 2;r.right *= 2;r.bottom *= 2;
   682 		r.top *= 2;
       
   683 		r.right *= 2;
       
   684 		r.bottom *= 2;
   668 	}
   685 	}
   669 	InvalidateRect(_wnd.main_wnd, &r, FALSE);
   686 	InvalidateRect(_wnd.main_wnd, &r, FALSE);
   670 }
   687 }
   671 
   688 
   672 static void CheckPaletteAnim(void)
   689 static void CheckPaletteAnim(void)
   697 #else
   714 #else
   698 		if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0) {
   715 		if (_wnd.has_focus && GetAsyncKeyState(VK_TAB) < 0) {
   699 #endif
   716 #endif
   700 			/* Disable speeding up game with ALT+TAB (if syskey is pressed, the
   717 			/* Disable speeding up game with ALT+TAB (if syskey is pressed, the
   701 			 * real key is in the upper 16 bits (see WM_SYSKEYDOWN in WndProcGdi()) */
   718 			 * real key is in the upper 16 bits (see WM_SYSKEYDOWN in WndProcGdi()) */
   702 			if (((_pressed_key>>16) & WKC_TAB) && !_networking && _game_mode != GM_MENU) _fast_forward |= 2;
   719 			if ((_pressed_key >> 16) & WKC_TAB && !_networking &&
       
   720 					_game_mode != GM_MENU)
       
   721 				_fast_forward |= 2;
   703 		} else if (_fast_forward & 2)
   722 		} else if (_fast_forward & 2)
   704 			_fast_forward = 0;
   723 			_fast_forward = 0;
   705 
   724 
   706 		cur_ticks = GetTickCount();
   725 		cur_ticks = GetTickCount();
   707 		if ((_fast_forward && !_pause) || cur_ticks > next_tick)
   726 		if ((_fast_forward && !_pause) || cur_ticks > next_tick)
   764 
   783 
   765 /**********************
   784 /**********************
   766  * WIN32 MIDI PLAYER
   785  * WIN32 MIDI PLAYER
   767  **********************/
   786  **********************/
   768 
   787 
   769 struct {
   788 static struct {
   770 	bool stop_song;
   789 	bool stop_song;
   771 	bool terminate;
   790 	bool terminate;
   772 	bool playing;
   791 	bool playing;
   773 	int new_vol;
   792 	int new_vol;
   774 	HANDLE wait_obj;
   793 	HANDLE wait_obj;
   785 
   804 
   786 static void Win32MidiStopSong(void)
   805 static void Win32MidiStopSong(void)
   787 {
   806 {
   788 	if (_midi.playing) {
   807 	if (_midi.playing) {
   789 		_midi.stop_song = true;
   808 		_midi.stop_song = true;
   790 		_midi.start_song[0] = 0;
   809 		_midi.start_song[0] = '\0';
   791 		SetEvent(_midi.wait_obj);
   810 		SetEvent(_midi.wait_obj);
   792 	}
   811 	}
   793 }
   812 }
   794 
   813 
   795 static bool Win32MidiIsSongPlaying(void)
   814 static bool Win32MidiIsSongPlaying(void)
   804 }
   823 }
   805 
   824 
   806 static long CDECL MidiSendCommand(const char *cmd, ...) {
   825 static long CDECL MidiSendCommand(const char *cmd, ...) {
   807 	va_list va;
   826 	va_list va;
   808 	char buf[512];
   827 	char buf[512];
       
   828 
   809 	va_start(va, cmd);
   829 	va_start(va, cmd);
   810 	vsprintf(buf, cmd, va);
   830 	vsprintf(buf, cmd, va);
   811 	va_end(va);
   831 	va_end(va);
   812 	return mciSendStringA(buf, NULL, 0, 0);
   832 	return mciSendStringA(buf, NULL, 0, 0);
   813 }
   833 }
   829 }
   849 }
   830 
   850 
   831 static void MidiIntSetVolume(int vol)
   851 static void MidiIntSetVolume(int vol)
   832 {
   852 {
   833 	uint v = (vol * 65535 / 127);
   853 	uint v = (vol * 65535 / 127);
   834 	midiOutSetVolume((HMIDIOUT)-1, v + (v<<16));
   854 	midiOutSetVolume((HMIDIOUT)-1, v + (v << 16));
   835 }
   855 }
   836 
   856 
   837 static bool MidiIntIsSongPlaying(void)
   857 static bool MidiIntIsSongPlaying(void)
   838 {
   858 {
   839 	char buf[16];
   859 	char buf[16];
   841 	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
   861 	return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0;
   842 }
   862 }
   843 
   863 
   844 static DWORD WINAPI MidiThread(LPVOID arg)
   864 static DWORD WINAPI MidiThread(LPVOID arg)
   845 {
   865 {
   846 	char *s;
       
   847 	int vol;
       
   848 
       
   849 	_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL);
   866 	_midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL);
   850 
   867 
   851 	do {
   868 	do {
   852 		if ((vol=_midi.new_vol) != -1) {
   869 		char *s;
       
   870 		int vol;
       
   871 
       
   872 		vol = _midi.new_vol;
       
   873 		if (vol != -1) {
   853 			_midi.new_vol = -1;
   874 			_midi.new_vol = -1;
   854 			MidiIntSetVolume(vol);
   875 			MidiIntSetVolume(vol);
   855 
   876 		}
   856 		}
   877 
   857 		if ((s=_midi.start_song)[0]) {
   878 		s = _midi.start_song;
       
   879 		if (s[0] != '\0') {
   858 			_midi.playing = MidiIntPlaySong(s);
   880 			_midi.playing = MidiIntPlaySong(s);
   859 			s[0] = 0;
   881 			s[0] = '\0';
   860 
   882 
   861 			// Delay somewhat in case we don't manage to play.
   883 			// Delay somewhat in case we don't manage to play.
   862 			if (!_midi.playing) {
   884 			if (!_midi.playing) {
   863 				Sleep(5000);
   885 				Sleep(5000);
   864 			}
   886 			}
   865 		}
   887 		}
   866 		if (_midi.stop_song != false && _midi.playing) {
   888 
       
   889 		if (_midi.stop_song && _midi.playing) {
   867 			_midi.stop_song = false;
   890 			_midi.stop_song = false;
   868 			_midi.playing = false;
   891 			_midi.playing = false;
   869 			MidiIntStopSong();
   892 			MidiIntStopSong();
   870 		}
   893 		}
   871 
   894 
   880 }
   903 }
   881 
   904 
   882 static const char *Win32MidiStart(const char * const *parm)
   905 static const char *Win32MidiStart(const char * const *parm)
   883 {
   906 {
   884 	DWORD threadId;
   907 	DWORD threadId;
       
   908 
   885 	memset(&_midi, 0, sizeof(_midi));
   909 	memset(&_midi, 0, sizeof(_midi));
   886 	_midi.new_vol = -1;
   910 	_midi.new_vol = -1;
   887 	CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId);
   911 	CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId);
   888 	return 0;
   912 	return 0;
   889 }
   913 }
   908 static HWAVEOUT _waveout;
   932 static HWAVEOUT _waveout;
   909 static WAVEHDR _wave_hdr[2];
   933 static WAVEHDR _wave_hdr[2];
   910 static int _bufsize;
   934 static int _bufsize;
   911 static void PrepareHeader(WAVEHDR *hdr)
   935 static void PrepareHeader(WAVEHDR *hdr)
   912 {
   936 {
   913 	hdr->dwBufferLength = _bufsize*4;
   937 	hdr->dwBufferLength = _bufsize * 4;
   914 	hdr->dwFlags = 0;
   938 	hdr->dwFlags = 0;
   915 	hdr->lpData = malloc(_bufsize*4);
   939 	hdr->lpData = malloc(_bufsize * 4);
   916 	if (hdr->lpData == NULL || waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
   940 	if (hdr->lpData == NULL ||
       
   941 			waveOutPrepareHeader(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
   917 		error("waveOutPrepareHeader failed");
   942 		error("waveOutPrepareHeader failed");
   918 }
   943 }
   919 
   944 
   920 static void FillHeaders(void)
   945 static void FillHeaders(void)
   921 {
   946 {
   922 	WAVEHDR *hdr;
   947 	WAVEHDR *hdr;
   923 	for(hdr=_wave_hdr; hdr != endof(_wave_hdr); hdr++) {
   948 
       
   949 	for (hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
   924 		if (!(hdr->dwFlags & WHDR_INQUEUE)) {
   950 		if (!(hdr->dwFlags & WHDR_INQUEUE)) {
   925 			MxMixSamples(_mixer, hdr->lpData, hdr->dwBufferLength >> 2);
   951 			MxMixSamples(_mixer, hdr->lpData, hdr->dwBufferLength / 4);
   926 			if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
   952 			if (waveOutWrite(_waveout, hdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR)
   927 				error("waveOutWrite failed");
   953 				error("waveOutWrite failed");
   928 		}
   954 		}
   929 	}
   955 	}
   930 }
   956 }
   931 
   957 
   932 static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
   958 static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
   933 {
   959 	DWORD dwParam1, DWORD dwParam2)
   934 	switch(uMsg) {
   960 {
   935 	case WOM_DONE:
   961 	switch (uMsg) {
   936 		if (_waveout)
   962 		case WOM_DONE:
   937 			FillHeaders();
   963 			if (_waveout) FillHeaders();
   938 		break;
   964 			break;
       
   965 
       
   966 		default:
       
   967 			break;
   939 	}
   968 	}
   940 }
   969 }
   941 
   970 
   942 static const char *Win32SoundStart(const char * const *parm)
   971 static const char *Win32SoundStart(const char * const *parm)
   943 {
   972 {
   961 }
   990 }
   962 
   991 
   963 static void Win32SoundStop(void)
   992 static void Win32SoundStop(void)
   964 {
   993 {
   965 	HWAVEOUT waveout = _waveout;
   994 	HWAVEOUT waveout = _waveout;
       
   995 
   966 	_waveout = NULL;
   996 	_waveout = NULL;
   967 	waveOutReset(waveout);
   997 	waveOutReset(waveout);
   968 	waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR));
   998 	waveOutUnprepareHeader(waveout, &_wave_hdr[0], sizeof(WAVEHDR));
   969 	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
   999 	waveOutUnprepareHeader(waveout, &_wave_hdr[1], sizeof(WAVEHDR));
   970 	waveOutClose(waveout);
  1000 	waveOutClose(waveout);
   979 bool LoadLibraryList(void **proc, const char *dll)
  1009 bool LoadLibraryList(void **proc, const char *dll)
   980 {
  1010 {
   981 	HMODULE lib;
  1011 	HMODULE lib;
   982 	void *p;
  1012 	void *p;
   983 
  1013 
   984 	while (*dll) {
  1014 	while (*dll != '\0') {
   985 		lib = LoadLibrary(dll);
  1015 		lib = LoadLibrary(dll);
   986 		if (lib == NULL)
  1016 		if (lib == NULL)
   987 			return false;
  1017 			return false;
   988 		while (true) {
  1018 		while (true) {
   989 			while(*dll++);
  1019 			while(*dll++ != '\0');
   990 			if (!*dll)
  1020 			if (*dll == '\0')
   991 				break;
  1021 				break;
   992 			p = GetProcAddress(lib, dll);
  1022 			p = GetProcAddress(lib, dll);
   993 			if (p == NULL)
  1023 			if (p == NULL)
   994 				return false;
  1024 				return false;
   995 			*proc++ = p;
  1025 			*proc++ = p;
  1034 	uint32 crc, poly = 0xEDB88320L;
  1064 	uint32 crc, poly = 0xEDB88320L;
  1035 	int	i, j;
  1065 	int	i, j;
  1036 
  1066 
  1037 	_crc_table = table;
  1067 	_crc_table = table;
  1038 
  1068 
  1039 	for (i=0; i!=256; i++) {
  1069 	for (i = 0; i != 256; i++) {
  1040 		crc = i;
  1070 		crc = i;
  1041 		for (j=8; j!=0; j--) {
  1071 		for (j = 8; j != 0; j--) {
  1042 			if (crc & 1)
  1072 			if (crc & 1)
  1043 				crc = (crc >> 1) ^ poly;
  1073 				crc = (crc >> 1) ^ poly;
  1044 			else
  1074 			else
  1045 				crc>>=1;
  1075 				crc >>= 1;
  1046 		}
  1076 		}
  1047 		table[i] = crc;
  1077 		table[i] = crc;
  1048 	}
  1078 	}
  1049 }
  1079 }
  1050 
  1080 
  1051 static uint32 CalcCRC(byte *data, uint size, uint32 crc) {
  1081 static uint32 CalcCRC(byte *data, uint size, uint32 crc) {
  1052 	do {
  1082 	for (; size > 0; size--) {
  1053 		crc = ((crc>>8) & 0x00FFFFFF) ^ _crc_table[ (crc^(*data++)) & 0xFF ];
  1083 		crc = ((crc >> 8) & 0x00FFFFFF) ^ _crc_table[(crc ^ *data++) & 0xFF];
  1054 	} while (--size);
  1084 	}
  1055 	return crc;
  1085 	return crc;
  1056 }
  1086 }
  1057 
  1087 
  1058 static void GetFileInfo(DebugFileInfo *dfi, const char *filename)
  1088 static void GetFileInfo(DebugFileInfo *dfi, const char *filename)
  1059 {
  1089 {
  1065 		DWORD numread;
  1095 		DWORD numread;
  1066 		uint32 filesize = 0;
  1096 		uint32 filesize = 0;
  1067 		FILETIME write_time;
  1097 		FILETIME write_time;
  1068 		uint32 crc = (uint32)-1;
  1098 		uint32 crc = (uint32)-1;
  1069 
  1099 
  1070 		file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
  1100 		file = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
       
  1101 			OPEN_EXISTING, 0, 0);
  1071 		if (file != INVALID_HANDLE_VALUE) {
  1102 		if (file != INVALID_HANDLE_VALUE) {
  1072 			while(true) {
  1103 			while(true) {
  1073 				if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 || numread==0)
  1104 				if (ReadFile(file, buffer, sizeof(buffer), &numread, NULL) == 0 ||
       
  1105 						numread == 0)
  1074 					break;
  1106 					break;
  1075 				filesize += numread;
  1107 				filesize += numread;
  1076 				crc = CalcCRC(buffer, numread, crc);
  1108 				crc = CalcCRC(buffer, numread, crc);
  1077 			}
  1109 			}
  1078 			dfi->size = filesize;
  1110 			dfi->size = filesize;
  1089 
  1121 
  1090 static char *PrintModuleInfo(char *output, HMODULE mod)
  1122 static char *PrintModuleInfo(char *output, HMODULE mod)
  1091 {
  1123 {
  1092 	char buffer[MAX_PATH];
  1124 	char buffer[MAX_PATH];
  1093 	DebugFileInfo dfi;
  1125 	DebugFileInfo dfi;
       
  1126 
  1094 	GetModuleFileName(mod, buffer, MAX_PATH);
  1127 	GetModuleFileName(mod, buffer, MAX_PATH);
  1095 	GetFileInfo(&dfi, buffer);
  1128 	GetFileInfo(&dfi, buffer);
  1096 	output += sprintf(output, " %-20s handle: %.8X size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n",
  1129 	output += sprintf(output, " %-20s handle: %.8X size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\r\n",
  1097 		buffer,
  1130 		buffer,
  1098 		mod,
  1131 		mod,
  1121 		proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
  1154 		proc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
  1122 		if (proc) {
  1155 		if (proc) {
  1123 			res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
  1156 			res = EnumProcessModules(proc, modules, sizeof(modules), &needed);
  1124 			CloseHandle(proc);
  1157 			CloseHandle(proc);
  1125 			if (res) {
  1158 			if (res) {
  1126 				count = min(needed/sizeof(HMODULE*), sizeof(modules)/sizeof(HMODULE*));
  1159 				count =
  1127 				for(i=0; i!=count; i++)
  1160 					min(needed / sizeof(HMODULE), lengthof(modules));
       
  1161 				for (i = 0; i != count; i++)
  1128 					output = PrintModuleInfo(output, modules[i]);
  1162 					output = PrintModuleInfo(output, modules[i]);
  1129 				return output;
  1163 				return output;
  1130 			}
  1164 			}
  1131 		}
  1165 		}
  1132 	}
  1166 	}
  1135 }
  1169 }
  1136 
  1170 
  1137 static const char _crash_desc[] =
  1171 static const char _crash_desc[] =
  1138 	"A serious fault condition occured in the game. The game will shut down.\n"
  1172 	"A serious fault condition occured in the game. The game will shut down.\n"
  1139 	"Press \"Submit report\" to send crash information to the developers. "
  1173 	"Press \"Submit report\" to send crash information to the developers. "
  1140 	"This will greatly help debugging. The information contained in the report is "
  1174 	"This will greatly help debugging. "
  1141 	"displayed below.\n"
  1175 	"The information contained in the report is displayed below.\n"
  1142 	"Press \"Emergency save\" to attempt saving the game.";
  1176 	"Press \"Emergency save\" to attempt saving the game.";
  1143 
  1177 
  1144 static const char _save_succeeded[] =
  1178 static const char _save_succeeded[] =
  1145 	"Emergency save succeeded.\nBe aware that critical parts of the internal game state "
  1179 	"Emergency save succeeded.\n"
  1146 	"may have become corrupted. The saved game is not guaranteed to work.";
  1180 	"Be aware that critical parts of the internal game state may have become "
       
  1181 	"corrupted. The saved game is not guaranteed to work.";
  1147 
  1182 
  1148 bool EmergencySave();
  1183 bool EmergencySave();
  1149 
  1184 
  1150 
  1185 
  1151 typedef struct {
  1186 typedef struct {
  1253 	SetDlgItemText(wnd, 15, _expand_texts[mode == 1]);
  1288 	SetDlgItemText(wnd, 15, _expand_texts[mode == 1]);
  1254 
  1289 
  1255 	if (mode >= 0) {
  1290 	if (mode >= 0) {
  1256 		GetWindowRect(GetDlgItem(wnd, 11), &r2);
  1291 		GetWindowRect(GetDlgItem(wnd, 11), &r2);
  1257 		offs = r2.bottom - r2.top + 10;
  1292 		offs = r2.bottom - r2.top + 10;
  1258 		if (!mode) offs=-offs;
  1293 		if (!mode) offs = -offs;
  1259 		SetWindowPos(wnd, HWND_TOPMOST, 0, 0, r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER);
  1294 		SetWindowPos(wnd, HWND_TOPMOST, 0, 0,
       
  1295 			r.right - r.left, r.bottom - r.top + offs, SWP_NOMOVE | SWP_NOZORDER);
  1260 	} else {
  1296 	} else {
  1261 		SetWindowPos(wnd, HWND_TOPMOST,
  1297 		SetWindowPos(wnd, HWND_TOPMOST,
  1262 			(GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) >> 1,
  1298 			(GetSystemMetrics(SM_CXSCREEN) - (r.right - r.left)) / 2,
  1263 			(GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) >> 1,
  1299 			(GetSystemMetrics(SM_CYSCREEN) - (r.bottom - r.top)) / 2,
  1264 			0, 0, SWP_NOSIZE);
  1300 			0, 0, SWP_NOSIZE);
  1265 	}
  1301 	}
  1266 }
  1302 }
  1267 
  1303 
  1268 static bool DoEmergencySave(HWND wnd)
  1304 static bool DoEmergencySave(HWND wnd)
  1348 static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
  1384 static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
  1349 {
  1385 {
  1350 	char *output;
  1386 	char *output;
  1351 	static bool had_exception;
  1387 	static bool had_exception;
  1352 
  1388 
  1353 	if (had_exception) { ExitProcess(0); }
  1389 	if (had_exception) ExitProcess(0);
  1354 	had_exception = true;
  1390 	had_exception = true;
  1355 
  1391 
  1356 	_ident = GetTickCount(); // something pretty unique
  1392 	_ident = GetTickCount(); // something pretty unique
  1357 
  1393 
  1358 	MakeCRCTable(alloca(256 * sizeof(uint32)));
  1394 	MakeCRCTable(alloca(256 * sizeof(uint32)));
  1373 			time.wSecond,
  1409 			time.wSecond,
  1374 			"???"
  1410 			"???"
  1375 		);
  1411 		);
  1376 	}
  1412 	}
  1377 
  1413 
  1378 	if (_exception_string) output += sprintf(output, "Reason: %s\r\n", _exception_string);
  1414 	if (_exception_string)
       
  1415 		output += sprintf(output, "Reason: %s\r\n", _exception_string);
  1379 
  1416 
  1380 	output += sprintf(output, "Exception %.8X at %.8X\r\n"
  1417 	output += sprintf(output, "Exception %.8X at %.8X\r\n"
  1381 		"Registers:\r\n"
  1418 		"Registers:\r\n"
  1382 		" EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\r\n"
  1419 		" EAX: %.8X EBX: %.8X ECX: %.8X EDX: %.8X\r\n"
  1383 		" ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\r\n"
  1420 		" ESI: %.8X EDI: %.8X EBP: %.8X ESP: %.8X\r\n"
  1398 	);
  1435 	);
  1399 
  1436 
  1400 	{
  1437 	{
  1401 		byte *b = (byte*)ep->ContextRecord->Eip;
  1438 		byte *b = (byte*)ep->ContextRecord->Eip;
  1402 		int i;
  1439 		int i;
  1403 		for(i=0; i!=24; i++) {
  1440 		for (i = 0; i != 24; i++) {
  1404 			if (IsBadReadPtr(b, 1)) {
  1441 			if (IsBadReadPtr(b, 1)) {
  1405 				output += sprintf(output, " ??"); // OCR: WAS: , 0);
  1442 				output += sprintf(output, " ??"); // OCR: WAS: , 0);
  1406 			} else {
  1443 			} else {
  1407 				output += sprintf(output, " %.2X", *b);
  1444 				output += sprintf(output, " %.2X", *b);
  1408 			}
  1445 			}
  1415 	}
  1452 	}
  1416 
  1453 
  1417 	{
  1454 	{
  1418 		int i,j;
  1455 		int i,j;
  1419 		uint32 *b = (uint32*)ep->ContextRecord->Esp;
  1456 		uint32 *b = (uint32*)ep->ContextRecord->Esp;
  1420 		for(j=0; j!=24; j++) {
  1457 		for (j = 0; j != 24; j++) {
  1421 			for(i=0; i!=8; i++) {
  1458 			for (i = 0; i != 8; i++) {
  1422 				if (IsBadReadPtr(b,sizeof(uint32))) {
  1459 				if (IsBadReadPtr(b,sizeof(uint32))) {
  1423 					output += sprintf(output, " ????????"); //OCR: WAS - , 0);
  1460 					output += sprintf(output, " ????????"); //OCR: WAS - , 0);
  1424 				} else {
  1461 				} else {
  1425 					output += sprintf(output, " %.8X", *b);
  1462 					output += sprintf(output, " %.8X", *b);
  1426 				}
  1463 				}
  1436 	{
  1473 	{
  1437 		OSVERSIONINFO os;
  1474 		OSVERSIONINFO os;
  1438 		os.dwOSVersionInfoSize = sizeof(os);
  1475 		os.dwOSVersionInfoSize = sizeof(os);
  1439 		GetVersionEx(&os);
  1476 		GetVersionEx(&os);
  1440 		output += sprintf(output, "\r\nSystem information:\r\n"
  1477 		output += sprintf(output, "\r\nSystem information:\r\n"
  1441 			" Windows version %d.%d %d %s\r\n", os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion);
  1478 			" Windows version %d.%d %d %s\r\n",
       
  1479 			os.dwMajorVersion, os.dwMinorVersion, os.dwBuildNumber, os.szCSDVersion);
  1442 	}
  1480 	}
  1443 
  1481 
  1444 	{
  1482 	{
  1445 		HANDLE file = CreateFile("crash.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
  1483 		HANDLE file = CreateFile("crash.log", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
  1446 		DWORD num_written;
  1484 		DWORD num_written;
  1464 }
  1502 }
  1465 
  1503 
  1466 static void Win32InitializeExceptions(void)
  1504 static void Win32InitializeExceptions(void)
  1467 {
  1505 {
  1468 	_asm {
  1506 	_asm {
  1469 		mov _safe_esp,esp
  1507 		mov _safe_esp, esp
  1470 	}
  1508 	}
  1471 
  1509 
  1472 	SetUnhandledExceptionFilter(ExceptionHandler);
  1510 	SetUnhandledExceptionFilter(ExceptionHandler);
  1473 }
  1511 }
  1474 #else
  1512 #else
  1505 	sprintf(paths, "%s\\%s", path, file);
  1543 	sprintf(paths, "%s\\%s", path, file);
  1506 	return FindFirstFile(paths, fd);
  1544 	return FindFirstFile(paths, fd);
  1507 }
  1545 }
  1508 
  1546 
  1509 int CDECL compare_FiosItems (const void *a, const void *b) {
  1547 int CDECL compare_FiosItems (const void *a, const void *b) {
  1510 	const FiosItem *da = (const FiosItem *) a;
  1548 	const FiosItem *da = (const FiosItem *)a;
  1511 	const FiosItem *db = (const FiosItem *) b;
  1549 	const FiosItem *db = (const FiosItem *)b;
  1512 	int r;
  1550 	int r;
  1513 
  1551 
  1514 	if (_savegame_sort_order < 2) // sort by date
  1552 	if (_savegame_sort_order < 2) // sort by date
  1515     r = da->mtime < db->mtime ? -1 : 1;
  1553     r = da->mtime < db->mtime ? -1 : 1;
  1516 	else
  1554 	else
  1517 		r = stricmp(da->title[0] ? da->title : da->name, db->title[0] ? db->title : db->name);
  1555 		r = stricmp(
       
  1556 			da->title[0] != '\0' ? da->title : da->name,
       
  1557 			db->title[0] != '\0' ? db->title : db->name
       
  1558 		);
  1518 
  1559 
  1519 	if (_savegame_sort_order & 1) r = -r;
  1560 	if (_savegame_sort_order & 1) r = -r;
  1520 	return r;
  1561 	return r;
  1521 }
  1562 }
  1522 
  1563 
  1550 	// Show subdirectories first
  1591 	// Show subdirectories first
  1551 	h = MyFindFirstFile(_fios_path, "*.*", &fd);
  1592 	h = MyFindFirstFile(_fios_path, "*.*", &fd);
  1552 	if (h != INVALID_HANDLE_VALUE) {
  1593 	if (h != INVALID_HANDLE_VALUE) {
  1553 		do {
  1594 		do {
  1554 			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  1595 			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  1555 					!(fd.cFileName[0] == '.' && (fd.cFileName[1] == 0 || (fd.cFileName[1] == '.' && fd.cFileName[2] == 0)))) {
  1596 					strcmp(fd.cFileName, ".") != 0 &&
       
  1597 					strcmp(fd.cFileName, "..") != 0) {
  1556 				fios = FiosAlloc();
  1598 				fios = FiosAlloc();
  1557 				fios->type = FIOS_TYPE_DIR;
  1599 				fios->type = FIOS_TYPE_DIR;
  1558 				strcpy(fios->name, fd.cFileName);
  1600 				strcpy(fios->name, fd.cFileName);
  1559 				sprintf(fios->title, "\\%s (Directory)", fd.cFileName);
  1601 				sprintf(fios->title, "\\%s (Directory)", fd.cFileName);
  1560 			}
  1602 			}
  1583 					fios->type = FIOS_TYPE_FILE;
  1625 					fios->type = FIOS_TYPE_FILE;
  1584 					fios->title[0] = 0;
  1626 					fios->title[0] = 0;
  1585 					ttd_strlcpy(fios->name, fd.cFileName, strlen(fd.cFileName)-3);
  1627 					ttd_strlcpy(fios->name, fd.cFileName, strlen(fd.cFileName)-3);
  1586 				}	else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
  1628 				}	else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
  1587 					int ext = 0; // start of savegame extensions in _old_extensions[]
  1629 					int ext = 0; // start of savegame extensions in _old_extensions[]
  1588 					if (t && ((ext++, !stricmp(t, ".SS1")) || (ext++, !stricmp(t, ".SV1")) || (ext++, !stricmp(t, ".SV2"))) ) { // TTDLX(Patch)
  1630 					if (t != NULL && (
       
  1631 								(ext++, stricmp(t, ".SS1") == 0) ||
       
  1632 								(ext++, stricmp(t, ".SV1") == 0) ||
       
  1633 								(ext++, stricmp(t, ".SV2") == 0)
       
  1634 							)) { // TTDLX(Patch)
  1589 						fios = FiosAlloc();
  1635 						fios = FiosAlloc();
  1590 						fios->old_extension = ext-1;
  1636 						fios->old_extension = ext-1;
  1591 						fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1637 						fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1592 						sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1638 						sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1593 						fios->type = FIOS_TYPE_OLDFILE;
  1639 						fios->type = FIOS_TYPE_OLDFILE;
  1637 	}
  1683 	}
  1638 
  1684 
  1639 	_fios_path = _fios_scn_path;
  1685 	_fios_path = _fios_scn_path;
  1640 
  1686 
  1641 	// Parent directory, only if not of the type C:\.
  1687 	// Parent directory, only if not of the type C:\.
  1642 	if (_fios_path[3] != 0 && mode != SLD_NEW_GAME) {
  1688 	if (_fios_path[3] != '\0' && mode != SLD_NEW_GAME) {
  1643 		fios = FiosAlloc();
  1689 		fios = FiosAlloc();
  1644 		fios->type = FIOS_TYPE_PARENT;
  1690 		fios->type = FIOS_TYPE_PARENT;
  1645 		strcpy(fios->title, ".. (Parent directory)");
  1691 		strcpy(fios->title, ".. (Parent directory)");
  1646 	}
  1692 	}
  1647 
  1693 
  1648 	// Show subdirectories first
  1694 	// Show subdirectories first
  1649 	h = MyFindFirstFile(_fios_scn_path, "*.*", &fd);
  1695 	h = MyFindFirstFile(_fios_scn_path, "*.*", &fd);
  1650 	if (h != INVALID_HANDLE_VALUE && mode != SLD_NEW_GAME) {
  1696 	if (h != INVALID_HANDLE_VALUE && mode != SLD_NEW_GAME) {
  1651 		do {
  1697 		do {
  1652 			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  1698 			if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY &&
  1653 					!(fd.cFileName[0] == '.' && (fd.cFileName[1] == 0 || (fd.cFileName[1] == '.' && fd.cFileName[2] == 0)))) {
  1699 					strcmp(fd.cFileName, ".") != 0 &&
       
  1700 					strcmp(fd.cFileName, "..") != 0) {
  1654 				fios = FiosAlloc();
  1701 				fios = FiosAlloc();
  1655 				fios->type = FIOS_TYPE_DIR;
  1702 				fios->type = FIOS_TYPE_DIR;
  1656 				strcpy(fios->name, fd.cFileName);
  1703 				strcpy(fios->name, fd.cFileName);
  1657 				sprintf(fios->title, "\\%s (Directory)", fd.cFileName);
  1704 				sprintf(fios->title, "\\%s (Directory)", fd.cFileName);
  1658 			}
  1705 			}
  1671 	h = MyFindFirstFile(_fios_scn_path, "*.*", &fd);
  1718 	h = MyFindFirstFile(_fios_scn_path, "*.*", &fd);
  1672 	if (h != INVALID_HANDLE_VALUE) {
  1719 	if (h != INVALID_HANDLE_VALUE) {
  1673 		do {
  1720 		do {
  1674 			if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1721 			if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  1675 				char *t = strrchr(fd.cFileName, '.');
  1722 				char *t = strrchr(fd.cFileName, '.');
  1676 				if (t && !stricmp(t, ".SCN")) { // OpenTTD
  1723 
       
  1724 				if (t != NULL && !stricmp(t, ".SCN")) { // OpenTTD
  1677 					fios = FiosAlloc();
  1725 					fios = FiosAlloc();
  1678 					fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1726 					fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1679 					sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1727 					sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1680 					fios->type = FIOS_TYPE_SCENARIO;
  1728 					fios->type = FIOS_TYPE_SCENARIO;
  1681 					fios->title[0] = 0;
  1729 					fios->title[0] = '\0';
  1682 					ttd_strlcpy(fios->name, fd.cFileName, strlen(fd.cFileName)-3);
  1730 					ttd_strlcpy(fios->name, fd.cFileName, strlen(fd.cFileName)-3);
  1683 				}	else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
  1731 				}	else if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO ||
       
  1732 						mode == SLD_NEW_GAME) {
  1684 					int ext = 3; // start of scenario extensions in _old_extensions[]
  1733 					int ext = 3; // start of scenario extensions in _old_extensions[]
  1685 					if (t && ((ext++, !stricmp(t, ".SV0")) || (ext++, !stricmp(t, ".SS0"))) ) { // TTDLX(Patch)
  1734 
       
  1735 					if (t != NULL && (
       
  1736 								(ext++, stricmp(t, ".SV0") == 0) ||
       
  1737 								(ext++, stricmp(t, ".SS0") == 0)
       
  1738 							)) { // TTDLX(Patch)
  1686 						fios = FiosAlloc();
  1739 						fios = FiosAlloc();
  1687 						fios->old_extension = ext-1;
  1740 						fios->old_extension = ext-1;
  1688 						fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1741 						fios->mtime = *(uint64*)&fd.ftLastWriteTime;
  1689 						sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1742 						sprintf(buf, "%s\\%s", _fios_path, fd.cFileName);
  1690 						fios->type = FIOS_TYPE_OLD_SCENARIO;
  1743 						fios->type = FIOS_TYPE_OLD_SCENARIO;
  1700 	qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
  1753 	qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
  1701 
  1754 
  1702 	// Drives
  1755 	// Drives
  1703 	if (mode != SLD_NEW_GAME) {
  1756 	if (mode != SLD_NEW_GAME) {
  1704 		char drives[256];
  1757 		char drives[256];
  1705 		char *s;
  1758 		const char *s;
       
  1759 
  1706 		GetLogicalDriveStrings(sizeof(drives), drives);
  1760 		GetLogicalDriveStrings(sizeof(drives), drives);
  1707 		s=drives;
  1761 		for (s = drives; *s != '\0';) {
  1708 		while (*s) {
       
  1709 			fios = FiosAlloc();
  1762 			fios = FiosAlloc();
  1710 			fios->type = FIOS_TYPE_DRIVE;
  1763 			fios->type = FIOS_TYPE_DRIVE;
  1711 			fios->title[0] = s[0];
  1764 			sprintf(fios->title, "%c:", s[0]);
  1712 			fios->title[1] = ':';
  1765 			while (*s++ != '\0') {}
  1713 			fios->title[2] = 0;
       
  1714 			while (*s++) {}
       
  1715 		}
  1766 		}
  1716 	}
  1767 	}
  1717 
  1768 
  1718 	*num = _fios_count;
  1769 	*num = _fios_count;
  1719 	return _fios_items;
  1770 	return _fios_items;
  1730 // Browse to
  1781 // Browse to
  1731 char *FiosBrowseTo(const FiosItem *item)
  1782 char *FiosBrowseTo(const FiosItem *item)
  1732 {
  1783 {
  1733 	static char str_buffr[512];
  1784 	static char str_buffr[512];
  1734 	char *path = _fios_path;
  1785 	char *path = _fios_path;
  1735 	char *s;
  1786 
  1736 
  1787 	switch (item->type) {
  1737 	switch(item->type) {
       
  1738 	case FIOS_TYPE_DRIVE:
  1788 	case FIOS_TYPE_DRIVE:
  1739 		sprintf(path, "%c:\\", item->title[0]);
  1789 		sprintf(path, "%c:\\", item->title[0]);
  1740 		break;
  1790 		break;
  1741 
  1791 
  1742 	case FIOS_TYPE_PARENT:
  1792 	case FIOS_TYPE_PARENT: {
       
  1793 		char *s;
       
  1794 
  1743 		// Skip drive part
  1795 		// Skip drive part
  1744 		path += 3;
  1796 		path += 3;
  1745 		s = path;
  1797 		s = path;
  1746 		while (*path) {
  1798 		for (; *path != '\0'; path++) {
  1747 			if (*path== '\\')
  1799 			if (*path== '\\') s = path;
  1748 				s = path;
  1800 		}
  1749 			path++;
  1801 		*s = '\0';
  1750 		}
       
  1751 		*s = 0;
       
  1752 		break;
  1802 		break;
       
  1803 	}
  1753 
  1804 
  1754 	case FIOS_TYPE_DIR:
  1805 	case FIOS_TYPE_DIR:
  1755 		// Scan to end
  1806 		// Scan to end
  1756 		while (*++path);
  1807 		while (*++path != '\0');
  1757 		// Add backslash?
  1808 		// Add backslash?
  1758 		if (path[-1] != '\\') *path++ = '\\';
  1809 		if (path[-1] != '\\') *path++ = '\\';
  1759 
  1810 
  1760 		strcpy(path, item->name);
  1811 		strcpy(path, item->name);
  1761 		break;
  1812 		break;
  1763 	case FIOS_TYPE_FILE:
  1814 	case FIOS_TYPE_FILE:
  1764 		FiosMakeSavegameName(str_buffr, item->name);
  1815 		FiosMakeSavegameName(str_buffr, item->name);
  1765 		return str_buffr;
  1816 		return str_buffr;
  1766 
  1817 
  1767 	case FIOS_TYPE_OLDFILE:
  1818 	case FIOS_TYPE_OLDFILE:
  1768 		sprintf(str_buffr, "%s\\%s.%s", _fios_path, item->name, _old_extensions[item->old_extension]);
  1819 		sprintf(str_buffr, "%s\\%s.%s",
       
  1820 			_fios_path, item->name, _old_extensions[item->old_extension]);
  1769 		return str_buffr;
  1821 		return str_buffr;
  1770 
  1822 
  1771 	case FIOS_TYPE_SCENARIO:
  1823 	case FIOS_TYPE_SCENARIO:
  1772 		sprintf(str_buffr, "%s\\%s.scn", path, item->name);
  1824 		sprintf(str_buffr, "%s\\%s.scn", path, item->name);
  1773 		return str_buffr;
  1825 		return str_buffr;
       
  1826 
  1774 	case FIOS_TYPE_OLD_SCENARIO:
  1827 	case FIOS_TYPE_OLD_SCENARIO:
  1775 		sprintf(str_buffr, "%s\\%s.%s", path, item->name, _old_extensions[item->old_extension]);
  1828 		sprintf(str_buffr, "%s\\%s.%s",
       
  1829 			path, item->name, _old_extensions[item->old_extension]);
  1776 		return str_buffr;
  1830 		return str_buffr;
  1777 	}
  1831 	}
  1778 
  1832 
  1779 	return NULL;
  1833 	return NULL;
  1780 }
  1834 }
  1786 {
  1840 {
  1787 	char root[4];
  1841 	char root[4];
  1788 	DWORD spc, bps, nfc, tnc;
  1842 	DWORD spc, bps, nfc, tnc;
  1789 	*path = _fios_path;
  1843 	*path = _fios_path;
  1790 
  1844 
  1791 	root[0] = _fios_path[0];
  1845 	sprintf(root, "%c:\\", _fios_path[0]);
  1792 	root[1] = ':';
       
  1793 	root[2] = '\\';
       
  1794 	root[3] = 0;
       
  1795 	if (GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
  1846 	if (GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
  1796 		uint32 tot = ((spc*bps)*(uint64)nfc) >> 20;
  1847 		uint32 tot = ((spc * bps) * (uint64)nfc) >> 20;
  1797 		SetDParam(0, tot);
  1848 		SetDParam(0, tot);
  1798 		return STR_4005_BYTES_FREE;
  1849 		return STR_4005_BYTES_FREE;
  1799 	} else {
  1850 	} else {
  1800 		return STR_4006_UNABLE_TO_READ_DRIVE;
  1851 		return STR_4006_UNABLE_TO_READ_DRIVE;
  1801 	}
  1852 	}
  1802 }
  1853 }
  1803 
  1854 
  1804 void FiosMakeSavegameName(char *buf, const char *name)
  1855 void FiosMakeSavegameName(char *buf, const char *name)
  1805 {
  1856 {
  1806 	if(_game_mode == GM_EDITOR)
  1857 	if (_game_mode == GM_EDITOR)
  1807 		sprintf(buf, "%s\\%s.scn", _fios_path, name);
  1858 		sprintf(buf, "%s\\%s.scn", _fios_path, name);
  1808 	else
  1859 	else
  1809 		sprintf(buf, "%s\\%s.sav", _fios_path, name);
  1860 		sprintf(buf, "%s\\%s.sav", _fios_path, name);
  1810 }
  1861 }
  1811 
  1862 
  1926 		// skip whitespace
  1977 		// skip whitespace
  1927 		while (*line == ' ' || *line == '\t')
  1978 		while (*line == ' ' || *line == '\t')
  1928 			line++;
  1979 			line++;
  1929 
  1980 
  1930 		// end?
  1981 		// end?
  1931 		if (*line == 0)
  1982 		if (*line == '\0')
  1932 			break;
  1983 			break;
  1933 
  1984 
  1934 		// special handling when quoted
  1985 		// special handling when quoted
  1935 		if (*line == '"') {
  1986 		if (*line == '"') {
  1936 			argv[n++] = ++line;
  1987 			argv[n++] = ++line;
  1937 			while (*line != '"') {
  1988 			while (*line != '"') {
  1938 				if (*line == 0) return n;
  1989 				if (*line == '\0') return n;
  1939 				line++;
  1990 				line++;
  1940 			}
  1991 			}
  1941 		} else {
  1992 		} else {
  1942 			argv[n++] = line;
  1993 			argv[n++] = line;
  1943 			while (*line != ' ' && *line != '\t') {
  1994 			while (*line != ' ' && *line != '\t') {
  1944 				if (*line == 0) return n;
  1995 				if (*line == '\0') return n;
  1945 				line++;
  1996 				line++;
  1946 			}
  1997 			}
  1947 		}
  1998 		}
  1948 		*line++ = 0;
  1999 		*line++ = '\0';
  1949 	} while (n != max_argc);
  2000 	} while (n != max_argc);
  1950 
  2001 
  1951 	return n;
  2002 	return n;
  1952 }
  2003 }
  1953 
  2004 
  1954 
  2005 
  1955 #if defined(_MSC_VER)
  2006 #if defined(_MSC_VER)
  1956 __int64 _declspec(naked) rdtsc()
  2007 static uint64 _declspec(naked) rdtsc(void)
  1957 {
  2008 {
  1958 	_asm {
  2009 	_asm {
  1959 		rdtsc
  2010 		rdtsc
  1960 		ret
  2011 		ret
  1961 	}
  2012 	}
  1988 	*stdout = *fdopen(1, "w" );
  2039 	*stdout = *fdopen(1, "w" );
  1989 	*stdin = *fdopen(0, "r" );
  2040 	*stdin = *fdopen(0, "r" );
  1990 	*stderr = *fdopen(2, "w" );
  2041 	*stderr = *fdopen(2, "w" );
  1991 #endif
  2042 #endif
  1992 
  2043 
  1993 	setvbuf( stdin, NULL, _IONBF, 0 );
  2044 	setvbuf(stdin, NULL, _IONBF, 0);
  1994 	setvbuf( stdout, NULL, _IONBF, 0 );
  2045 	setvbuf(stdout, NULL, _IONBF, 0);
  1995 	setvbuf( stderr, NULL, _IONBF, 0 );
  2046 	setvbuf(stderr, NULL, _IONBF, 0);
  1996 }
  2047 }
  1997 
  2048 
  1998 void ShowInfo(const char *str)
  2049 void ShowInfo(const char *str)
  1999 {
  2050 {
  2000 	if (_has_console)
  2051 	if (_has_console)
  2012 		MyShowCursor(old);
  2063 		MyShowCursor(old);
  2013 	}
  2064 	}
  2014 }
  2065 }
  2015 
  2066 
  2016 
  2067 
  2017 int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
  2068 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
       
  2069 	LPTSTR lpCmdLine, int nCmdShow)
  2018 {
  2070 {
  2019 	int argc;
  2071 	int argc;
  2020 	char *argv[64]; // max 64 command line arguments
  2072 	char *argv[64]; // max 64 command line arguments
  2021 	_inst = hInstance;
  2073 	_inst = hInstance;
  2022 
  2074 
  2029 
  2081 
  2030 	// setup random seed to something quite random
  2082 	// setup random seed to something quite random
  2031 #if defined(_MSC_VER)
  2083 #if defined(_MSC_VER)
  2032 	{
  2084 	{
  2033 		uint64 seed = rdtsc();
  2085 		uint64 seed = rdtsc();
  2034 		_random_seeds[0][0] = ((uint32*)&seed)[0];
  2086 		_random_seeds[0][0] = seed & 0xffffffff;
  2035 		_random_seeds[0][1] = ((uint32*)&seed)[1];
  2087 		_random_seeds[0][1] = seed >> 32;
  2036 	}
  2088 	}
  2037 #else
  2089 #else
  2038 	_random_seeds[0][0] = GetTickCount();
  2090 	_random_seeds[0][0] = GetTickCount();
  2039 	_random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
  2091 	_random_seeds[0][1] = _random_seeds[0][0] * 0x1234567;
  2040 #endif
  2092 #endif
  2068 	_path.personal_dir = _path.game_data_dir = cfg = malloc(MAX_PATH);
  2120 	_path.personal_dir = _path.game_data_dir = cfg = malloc(MAX_PATH);
  2069 	GetCurrentDirectory(MAX_PATH - 1, cfg);
  2121 	GetCurrentDirectory(MAX_PATH - 1, cfg);
  2070 
  2122 
  2071 
  2123 
  2072 	s = strchr(cfg, 0);
  2124 	s = strchr(cfg, 0);
  2073 	if (s[-1] != '\\') { s[0] = '\\'; s[1] = 0; }
  2125 	if (s[-1] != '\\') strcpy(s, "\\");
  2074 
  2126 
  2075 	_path.save_dir = str_fmt("%ssave", cfg);
  2127 	_path.save_dir = str_fmt("%ssave", cfg);
  2076 	_path.autosave_dir = str_fmt("%s\\autosave", _path.save_dir);
  2128 	_path.autosave_dir = str_fmt("%s\\autosave", _path.save_dir);
  2077 	_path.scenario_dir = str_fmt("%sscenario", cfg);
  2129 	_path.scenario_dir = str_fmt("%sscenario", cfg);
  2078 	_path.gm_dir = str_fmt("%sgm\\", cfg);
  2130 	_path.gm_dir = str_fmt("%sgm\\", cfg);