1 // FBAlpha Game Info and Favorites handling
2 #include "burner.h"
3 
4 static HWND hGameInfoDlg	= NULL;
5 static HWND hParent			= NULL;
6 static HWND hTabControl		= NULL;
7 static HMODULE hRiched		= NULL;
8 static HBITMAP hPreview		= NULL;
9 HBITMAP hGiBmp				= NULL;
10 static TCHAR szFullName[1024];
11 static int nGiDriverSelected;
12 static HBRUSH hWhiteBGBrush;
13 
OpenPreview(TCHAR * szPath)14 static FILE* OpenPreview(TCHAR *szPath)
15 {
16 	TCHAR szBaseName[MAX_PATH];
17 	TCHAR szFileName[MAX_PATH];
18 
19 	FILE* fp = NULL;
20 
21 	// Try to load a .PNG preview image
22 	_sntprintf(szBaseName, sizeof(szBaseName), _T("%s%s"), szPath, BurnDrvGetText(DRV_NAME));
23 	_stprintf(szFileName, _T("%s.png"), szBaseName);
24 	fp = _tfopen(szFileName, _T("rb"));
25 
26 	if (!fp && BurnDrvGetText(DRV_PARENT)) {						// Try the parent
27 		_sntprintf(szBaseName, sizeof(szBaseName), _T("%s%s"), szPath, BurnDrvGetText(DRV_PARENT));
28 		_stprintf(szFileName, _T("%s.png"), szBaseName);
29 		fp = _tfopen(szFileName, _T("rb"));
30 	}
31 
32 	return fp;
33 }
34 
35 #define IMG_MAX_HEIGHT			380
36 #define IMG_MAX_WIDTH			700
37 #define IMG_DEFAULT_WIDTH		506
38 #define IMG_DEFAULT_WIDTH_V		285
39 #define IMG_ASPECT_4_3			1
40 #define IMG_ASPECT_PRESERVE		2
41 
SetPreview(TCHAR * szPreviewDir,int nAspectFlag)42 static void SetPreview(TCHAR* szPreviewDir, int nAspectFlag)
43 {
44 	HWND hDlg = hGameInfoDlg;
45 
46 	HBITMAP hNewImage	= NULL;
47 
48 	if (hGiBmp) {
49 		DeleteObject((HGDIOBJ)hGiBmp);
50 		hGiBmp = NULL;
51 	}
52 
53 	// get image dimensions and work out what to resize to (default to 4:3)
54 	IMAGE img = { 0, 0, 0, 0, NULL, NULL, 0};
55 	int img_width = IMG_DEFAULT_WIDTH;
56 	int img_height = IMG_MAX_HEIGHT;
57 
58 	FILE *fp = OpenPreview(szPreviewDir);
59 	if (fp) {
60 		PNGGetInfo(&img, fp);
61 
62 		// vertical 3:4
63 		if (img.height > img.width) {
64 			img_width = IMG_DEFAULT_WIDTH_V;
65 		}
66 
67 		// preserve aspect support
68 		if (nAspectFlag == IMG_ASPECT_PRESERVE) {
69 			double nAspect = (double)img.width / img.height;
70 			img_width = (int)((double)IMG_MAX_HEIGHT * nAspect);
71 
72 			if (img_width > IMG_MAX_WIDTH) {
73 				img_width = IMG_MAX_WIDTH;
74 				img_height = (int)((double)IMG_MAX_WIDTH / nAspect);
75 			}
76 		}
77 
78 		img_free(&img);
79 		fclose(fp);
80 	}
81 
82 	fp = OpenPreview(szPreviewDir);
83 	if (fp) {
84 		hNewImage = PNGLoadBitmap(hDlg, fp, img_width, img_height, 3);
85 		fclose(fp);
86 	}
87 
88 	if (hNewImage) {
89 
90 		if(hGiBmp) DeleteObject((HGDIOBJ)hGiBmp);
91 
92 		hGiBmp = hNewImage;
93 
94 		if (bPngImageOrientation == 0) {
95 			SendDlgItemMessage(hDlg, IDC_SCREENSHOT_H, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hGiBmp);
96 			SendDlgItemMessage(hDlg, IDC_SCREENSHOT_V, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
97 			ShowWindow(GetDlgItem(hDlg, IDC_SCREENSHOT_V), SW_HIDE);
98 		} else {
99 			SendDlgItemMessage(hDlg, IDC_SCREENSHOT_H, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
100 			ShowWindow(GetDlgItem(hDlg, IDC_SCREENSHOT_V), SW_SHOW);
101 			SendDlgItemMessage(hDlg, IDC_SCREENSHOT_V, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hGiBmp);
102 		}
103 
104 	} else {
105 		SendDlgItemMessage(hDlg, IDC_SCREENSHOT_H, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)LoadBitmap(hAppInst, MAKEINTRESOURCE(BMP_SPLASH)));
106 		SendDlgItemMessage(hDlg, IDC_SCREENSHOT_V, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
107 		ShowWindow(GetDlgItem(hDlg, IDC_SCREENSHOT_V), SW_HIDE);
108 	}
109 }
110 
DisplayRomInfo()111 static int DisplayRomInfo()
112 {
113 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_HIDE);
114 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_HIDE);
115 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST1), SW_SHOW);
116 	UpdateWindow(hGameInfoDlg);
117 
118 	return 0;
119 }
120 
DisplayHDDInfo()121 static int DisplayHDDInfo()
122 {
123 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_HIDE);
124 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_HIDE);
125 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST3), SW_SHOW);
126 	UpdateWindow(hGameInfoDlg);
127 
128 	return 0;
129 }
130 
DisplaySampleInfo()131 static int DisplaySampleInfo()
132 {
133 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_HIDE);
134 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_HIDE);
135 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST2), SW_SHOW);
136 	UpdateWindow(hGameInfoDlg);
137 
138 	return 0;
139 }
140 
DisplayHistory()141 static int DisplayHistory()
142 {
143 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_HIDE);
144 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST1), SW_HIDE);
145 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST2), SW_HIDE);
146 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST3), SW_HIDE);
147 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_SHOW);
148 	UpdateWindow(hGameInfoDlg);
149 
150 	return 0;
151 }
152 
153 // make gcc 8.x happy about sprintf() usage below...
154 #if __GNUC__ == 8
155 #pragma GCC diagnostic push
156 #pragma GCC diagnostic ignored "-Wformat-overflow="
157 #endif
158 
GameInfoInit()159 static int GameInfoInit()
160 {
161 	// Get the games full name
162 	TCHAR szText[1024] = _T("");
163 	TCHAR* pszPosition = szText;
164 	TCHAR* pszName = BurnDrvGetText(DRV_FULLNAME);
165 
166 	pszPosition += _sntprintf(szText, 1024, pszName);
167 
168 	pszName = BurnDrvGetText(DRV_FULLNAME);
169 	while ((pszName = BurnDrvGetText(DRV_NEXTNAME | DRV_FULLNAME)) != NULL) {
170 		if (pszPosition + _tcslen(pszName) - 1024 > szText) {
171 			break;
172 		}
173 		pszPosition += _stprintf(pszPosition, _T(SEPERATOR_2) _T("%s"), pszName);
174 	}
175 
176 	_tcscpy(szFullName, szText);
177 
178 	_stprintf(szText, _T("%s") _T(SEPERATOR_1) _T("%s"), FBALoadStringEx(hAppInst, IDS_GAMEINFO_DIALOGTITLE, true), szFullName);
179 
180 	// Set the window caption
181 	SetWindowText(hGameInfoDlg, szText);
182 
183 	// Setup the tabs
184 	hTabControl = GetDlgItem(hGameInfoDlg, IDC_TAB1);
185     TC_ITEM TCI;
186     TCI.mask = TCIF_TEXT;
187 
188 	UINT idsString[17] = {  IDS_GAMEINFO_ROMINFO, IDS_GAMEINFO_HDD, IDS_GAMEINFO_SAMPLES, IDS_GAMEINFO_HISTORY, IDS_GAMEINFO_INGAME, IDS_GAMEINFO_TITLE, IDS_GAMEINFO_SELECT, IDS_GAMEINFO_VERSUS, IDS_GAMEINFO_HOWTO, IDS_GAMEINFO_SCORES, IDS_GAMEINFO_BOSSES, IDS_GAMEINFO_GAMEOVER, IDS_GAMEINFO_FLYER, IDS_GAMEINFO_CABINET, IDS_GAMEINFO_MARQUEE, IDS_GAMEINFO_CONTROLS, IDS_GAMEINFO_PCB };
189 
190 	for(int i = 0; i < 17; i++) {
191 		TCI.pszText = FBALoadStringEx(hAppInst, idsString[i], true);
192 		SendMessage(hTabControl, TCM_INSERTITEM, (WPARAM) i, (LPARAM) &TCI);
193 	}
194 
195 	// Load the preview image
196 	hPreview = LoadBitmap(hAppInst, MAKEINTRESOURCE(BMP_SPLASH));
197 
198 	// Display preview image
199 	SendDlgItemMessage(hGameInfoDlg, IDC_SCREENSHOT_H, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
200 	SendDlgItemMessage(hGameInfoDlg, IDC_SCREENSHOT_V, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
201 
202 	// Favorite game checkbox
203 	CheckDlgButton(hGameInfoDlg,IDFAVORITESET,(CheckFavorites(BurnDrvGetTextA(DRV_NAME)) != -1) ? BST_CHECKED : BST_UNCHECKED);
204 
205 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST1), SW_HIDE);
206 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST2), SW_HIDE);
207 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST3), SW_HIDE);
208 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_HIDE);
209 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_SHOW);
210 	ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_V), SW_SHOW);
211 	UpdateWindow(hGameInfoDlg);
212 
213 	nBurnDrvActive = nGiDriverSelected;
214 	DisplayRomInfo();
215 
216 	// Display the game title
217 	TCHAR szItemText[1024];
218 	HWND hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTCOMMENT);
219 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szFullName);
220 
221 	// Display the romname
222 	bool bBracket = false;
223 	hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTROMNAME);
224 	_stprintf(szItemText, _T("%s"), BurnDrvGetText(DRV_NAME));
225 	if ((BurnDrvGetFlags() & BDF_CLONE) && BurnDrvGetTextA(DRV_PARENT)) {
226 		int nOldDrvSelect = nBurnDrvActive;
227 		pszName = BurnDrvGetText(DRV_PARENT);
228 
229 		_stprintf(szItemText + _tcslen(szItemText), _T(" (clone of %s"), BurnDrvGetText(DRV_PARENT));
230 
231 		for (nBurnDrvActive = 0; nBurnDrvActive < nBurnDrvCount; nBurnDrvActive++) {
232 			if (!_tcsicmp(pszName, BurnDrvGetText(DRV_NAME))) {
233 				break;
234 			}
235 		}
236 		if (nBurnDrvActive < nBurnDrvCount) {
237 			if (BurnDrvGetText(DRV_PARENT)) {
238 				_stprintf(szItemText + _tcslen(szItemText), _T(", uses ROMs from %s"), BurnDrvGetText(DRV_PARENT));
239 			}
240 		}
241 		nBurnDrvActive = nOldDrvSelect;
242 		bBracket = true;
243 	} else {
244 		if (BurnDrvGetTextA(DRV_PARENT)) {
245 			_stprintf(szItemText + _tcslen(szItemText), _T("%suses ROMs from %s"), bBracket ? _T(", ") : _T(" ("), BurnDrvGetText(DRV_PARENT));
246 			bBracket = true;
247 		}
248 	}
249 	if (BurnDrvGetTextA(DRV_SAMPLENAME)) {
250 		_stprintf(szItemText + _tcslen(szItemText), _T("%suses samples from %s"), bBracket ? _T(", ") : _T(" ("), BurnDrvGetText(DRV_SAMPLENAME));
251 		bBracket = true;
252 	}
253 	if (bBracket) {
254 		_stprintf(szItemText + _tcslen(szItemText), _T(")"));
255 	}
256 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
257 
258 	//Display the rom info
259 	bool bUseInfo = false;
260 	szItemText[0] = _T('\0');
261 	hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTROMINFO);
262 	if (BurnDrvGetFlags() & BDF_PROTOTYPE) {
263 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_SEL_PROTOTYPE, true));
264 		bUseInfo = true;
265 	}
266 	if (BurnDrvGetFlags() & BDF_BOOTLEG) {
267 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_SEL_BOOTLEG, true), bUseInfo ? _T(", ") : _T(""));
268 		bUseInfo = true;
269 	}
270 	if (BurnDrvGetFlags() & BDF_HACK) {
271 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_SEL_HACK, true), bUseInfo ? _T(", ") : _T(""));
272 		bUseInfo = true;
273 	}
274 	if (BurnDrvGetFlags() & BDF_HOMEBREW) {
275 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_SEL_HOMEBREW, true), bUseInfo ? _T(", ") : _T(""));
276 		bUseInfo = true;
277 	}
278 	if (BurnDrvGetFlags() & BDF_DEMO) {
279 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_SEL_DEMO, true), bUseInfo ? _T(", ") : _T(""));
280 		bUseInfo = true;
281 	}
282 	TCHAR szPlayersMax[100];
283 	_stprintf(szPlayersMax, FBALoadStringEx(hAppInst, IDS_NUM_PLAYERS_MAX, true));
284 	_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_NUM_PLAYERS, true), bUseInfo ? _T(", ") : _T(""), BurnDrvGetMaxPlayers(), (BurnDrvGetMaxPlayers() != 1) ? szPlayersMax : _T(""));
285 	bUseInfo = true;
286 	if (BurnDrvGetText(DRV_BOARDROM)) {
287 		_stprintf(szItemText + _tcslen(szItemText), FBALoadStringEx(hAppInst, IDS_BOARD_ROMS_FROM, true), bUseInfo ? _T(", ") : _T(""), BurnDrvGetText(DRV_BOARDROM));
288 		SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
289 		bUseInfo = true;
290 	}
291 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
292 
293 	// Display the release info
294 	szItemText[0] = _T('\0');
295 	hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTSYSTEM);
296 	TCHAR szUnknown[100];
297 	TCHAR szCartridge[100];
298 	_stprintf(szUnknown, FBALoadStringEx(hAppInst, IDS_ERR_UNKNOWN, true));
299 	_stprintf(szCartridge, FBALoadStringEx(hAppInst, IDS_MVS_CARTRIDGE, true));
300 	_stprintf(szItemText, FBALoadStringEx(hAppInst, IDS_HARDWARE_DESC, true), BurnDrvGetTextA(DRV_MANUFACTURER) ? BurnDrvGetText(DRV_MANUFACTURER) : szUnknown, BurnDrvGetText(DRV_DATE), (((BurnDrvGetHardwareCode() & HARDWARE_SNK_MVS) == HARDWARE_SNK_MVS) && ((BurnDrvGetHardwareCode() & HARDWARE_PUBLIC_MASK)) == HARDWARE_SNK_NEOGEO)? szCartridge : BurnDrvGetText(DRV_SYSTEM));
301 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
302 
303 	// Display any comments
304 	szItemText[0] = _T('\0');
305 	hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTNOTES);
306 	_stprintf(szItemText, _T("%s"), BurnDrvGetTextA(DRV_COMMENT) ? BurnDrvGetText(DRV_COMMENT) : _T(""));
307 	if (BurnDrvGetFlags() & BDF_HISCORE_SUPPORTED) {
308 		_stprintf(szItemText + _tcslen(szItemText), _T("%shigh scores supported"), _tcslen(szItemText) ? _T(", ") : _T(""));
309 	}
310 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
311 
312 	// Display the genre
313 	szItemText[0] = _T('\0');
314 	hInfoControl = GetDlgItem(hGameInfoDlg, IDC_TEXTGENRE);
315 	_stprintf(szItemText, _T("%s"), DecorateGenreInfo());
316 	SendMessage(hInfoControl, WM_SETTEXT, (WPARAM)0, (LPARAM)szItemText);
317 
318 	// Set up the rom info list
319 	HWND hList = GetDlgItem(hGameInfoDlg, IDC_LIST1);
320 	LV_COLUMN LvCol;
321 	LV_ITEM LvItem;
322 
323 	ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
324 
325 	memset(&LvCol, 0, sizeof(LvCol));
326 	LvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
327 	LvCol.cx = 200;
328 	LvCol.pszText = _T("Name");
329 	SendMessage(hList, LVM_INSERTCOLUMN , 0, (LPARAM)&LvCol);
330 	LvCol.cx = 100;
331 	LvCol.pszText = _T("Size (bytes)");
332 	SendMessage(hList, LVM_INSERTCOLUMN , 1, (LPARAM)&LvCol);
333 	LvCol.cx = 100;
334 	LvCol.pszText = _T("CRC32");
335 	SendMessage(hList, LVM_INSERTCOLUMN , 2, (LPARAM)&LvCol);
336 	LvCol.cx = 200;
337 	LvCol.pszText = _T("Type");
338 	SendMessage(hList, LVM_INSERTCOLUMN , 3, (LPARAM)&LvCol);
339 	LvCol.cx = 100;
340 	LvCol.pszText = _T("Flags");
341 	SendMessage(hList, LVM_INSERTCOLUMN , 4, (LPARAM)&LvCol);
342 	LvCol.cx = 100;
343 
344 	memset(&LvItem, 0, sizeof(LvItem));
345 	LvItem.mask=  LVIF_TEXT;
346 	LvItem.cchTextMax = 256;
347 	int RomPos = 0;
348 	for (int i = 0; i < 0x100; i++) { // assume max 0x100 roms per game
349 		int nRet;
350 		struct BurnRomInfo ri;
351 		char nLen[10] = "";
352 		char nCrc[10] = "";
353 		char *szRomName = NULL;
354 		char Type[100] = "";
355 		char FormatType[100] = "";
356 
357 		memset(&ri, 0, sizeof(ri));
358 
359 		nRet = BurnDrvGetRomInfo(&ri, i);
360 		nRet += BurnDrvGetRomName(&szRomName, i, 0);
361 
362 		if (ri.nLen == 0) continue;
363 		if (ri.nType & BRF_BIOS) continue;
364 
365 		LvItem.iItem = RomPos;
366 		LvItem.iSubItem = 0;
367 		LvItem.pszText = ANSIToTCHAR(szRomName, NULL, 0);
368 		SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
369 
370 		sprintf(nLen, "%d", ri.nLen);
371 		LvItem.iSubItem = 1;
372 		LvItem.pszText = ANSIToTCHAR(nLen, NULL, 0);
373 		SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
374 
375 		sprintf(nCrc, "%08X", ri.nCrc);
376 		if (!(ri.nType & BRF_NODUMP)) {
377 			LvItem.iSubItem = 2;
378 			LvItem.pszText = ANSIToTCHAR(nCrc, NULL, 0);
379 			SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
380 		}
381 
382 		if (ri.nType & BRF_ESS) sprintf(Type, "%s, Essential", Type);
383 		if (ri.nType & BRF_OPT) sprintf(Type, "%s, Optional", Type);
384 		if (ri.nType & BRF_PRG)	sprintf(Type, "%s, Program", Type);
385 		if (ri.nType & BRF_GRA) sprintf(Type, "%s, Graphics", Type);
386 		if (ri.nType & BRF_SND) sprintf(Type, "%s, Sound", Type);
387 		if (ri.nType & BRF_BIOS) sprintf(Type, "%s, BIOS", Type);
388 
389 		for (int j = 0; j < 98; j++) {
390 			FormatType[j] = Type[j + 2];
391 		}
392 
393 		LvItem.iSubItem = 3;
394 		LvItem.pszText = ANSIToTCHAR(FormatType, NULL, 0);
395 		SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
396 
397 		LvItem.iSubItem = 4;
398 		LvItem.pszText = _T("");
399 		if (ri.nType & BRF_NODUMP) LvItem.pszText = _T("No Dump");
400 		SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
401 
402 		RomPos++;
403 	}
404 
405 	// Check for board roms
406 	if (BurnDrvGetTextA(DRV_BOARDROM)) {
407 		char szBoardName[12] = "";
408 		unsigned int nOldDrvSelect = nBurnDrvActive;
409 		strcpy(szBoardName, BurnDrvGetTextA(DRV_BOARDROM));
410 
411 		for (unsigned int i = 0; i < nBurnDrvCount; i++) {
412 			nBurnDrvActive = i;
413 			if (!strcmp(szBoardName, BurnDrvGetTextA(DRV_NAME))) break;
414 		}
415 
416 		for (int j = 0; j < 0x100; j++) {
417 			int nRetBoard;
418 			struct BurnRomInfo riBoard;
419 			char nLenBoard[10] = "";
420 			char nCrcBoard[10] = "";
421 			char *szBoardRomName = NULL;
422 			char BoardType[100] = "";
423 			char BoardFormatType[100] = "";
424 
425 			memset(&riBoard, 0, sizeof(riBoard));
426 
427 			nRetBoard = BurnDrvGetRomInfo(&riBoard, j);
428 			nRetBoard += BurnDrvGetRomName(&szBoardRomName, j, 0);
429 
430 			if (riBoard.nLen == 0) continue;
431 
432 			LvItem.iItem = RomPos;
433 			LvItem.iSubItem = 0;
434 			LvItem.pszText = ANSIToTCHAR(szBoardRomName, NULL, 0);
435 			SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
436 
437 			sprintf(nLenBoard, "%d", riBoard.nLen);
438 			LvItem.iSubItem = 1;
439 			LvItem.pszText = ANSIToTCHAR(nLenBoard, NULL, 0);
440 			SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
441 
442 			sprintf(nCrcBoard, "%08X", riBoard.nCrc);
443 			if (!(riBoard.nType & BRF_NODUMP)) {
444 				LvItem.iSubItem = 2;
445 				LvItem.pszText = ANSIToTCHAR(nCrcBoard, NULL, 0);
446 				SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
447 			}
448 
449 			if (riBoard.nType & BRF_ESS) sprintf(BoardType, "%s, Essential", BoardType);
450 			if (riBoard.nType & BRF_OPT) sprintf(BoardType, "%s, Optional", BoardType);
451 			if (riBoard.nType & BRF_PRG) sprintf(BoardType, "%s, Program", BoardType);
452 			if (riBoard.nType & BRF_GRA) sprintf(BoardType, "%s, Graphics", BoardType);
453 			if (riBoard.nType & BRF_SND) sprintf(BoardType, "%s, Sound", BoardType);
454 			if (riBoard.nType & BRF_BIOS) sprintf(BoardType, "%s, BIOS", BoardType);
455 
456 			for (int k = 0; k < 98; k++) {
457 				BoardFormatType[k] = BoardType[k + 2];
458 			}
459 
460 			LvItem.iSubItem = 3;
461 			LvItem.pszText = ANSIToTCHAR(BoardFormatType, NULL, 0);
462 			SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
463 
464 			LvItem.iSubItem = 4;
465 			LvItem.pszText = _T("");
466 			if (riBoard.nType & BRF_NODUMP) LvItem.pszText = _T("No Dump");
467 			SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
468 
469 			RomPos++;
470 		}
471 
472 		nBurnDrvActive = nOldDrvSelect;
473 	}
474 
475 	// Set up the sample info list
476 	hList = GetDlgItem(hGameInfoDlg, IDC_LIST2);
477 
478 	ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
479 
480 	memset(&LvCol, 0, sizeof(LvCol));
481 	LvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
482 	LvCol.cx = 200;
483 	LvCol.pszText = _T("Name");
484 	SendMessage(hList, LVM_INSERTCOLUMN , 0, (LPARAM)&LvCol);
485 
486 	memset(&LvItem, 0, sizeof(LvItem));
487 	LvItem.mask=  LVIF_TEXT;
488 	LvItem.cchTextMax = 256;
489 	int SamplePos = 0;
490 	if (BurnDrvGetTextA(DRV_SAMPLENAME) != NULL) {
491 		for (int i = 0; i < 0x100; i++) { // assume max 0x100 samples per game
492 			int nRet;
493 			struct BurnSampleInfo si;
494 			char *szSampleName = NULL;
495 
496 			memset(&si, 0, sizeof(si));
497 
498 			nRet = BurnDrvGetSampleInfo(&si, i);
499 			nRet += BurnDrvGetSampleName(&szSampleName, i, 0);
500 
501 			if (si.nFlags == 0) continue;
502 
503 			LvItem.iItem = SamplePos;
504 			LvItem.iSubItem = 0;
505 			LvItem.pszText = ANSIToTCHAR(szSampleName, NULL, 0);
506 			SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
507 
508 			SamplePos++;
509 		}
510 	}
511 
512 	// Set up the hdd info list
513 	hList = GetDlgItem(hGameInfoDlg, IDC_LIST3);
514 
515 	ListView_SetExtendedListViewStyle(hList, LVS_EX_FULLROWSELECT);
516 
517 	memset(&LvCol, 0, sizeof(LvCol));
518 	LvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
519 	LvCol.cx = 200;
520 	LvCol.pszText = _T("Name");
521 	SendMessage(hList, LVM_INSERTCOLUMN , 0, (LPARAM)&LvCol);
522 	LvCol.cx = 100;
523 	LvCol.pszText = _T("Size (bytes)");
524 	SendMessage(hList, LVM_INSERTCOLUMN , 1, (LPARAM)&LvCol);
525 	LvCol.cx = 100;
526 	LvCol.pszText = _T("CRC32");
527 	SendMessage(hList, LVM_INSERTCOLUMN , 2, (LPARAM)&LvCol);
528 	LvCol.cx = 100;
529 
530 	memset(&LvItem, 0, sizeof(LvItem));
531 	LvItem.mask=  LVIF_TEXT;
532 	LvItem.cchTextMax = 256;
533 	int HDDPos = 0;
534 	for (int i = 0; i < 0x100; i++) { // assume max 0x100 hdds per game
535 		int nRet;
536 		struct BurnHDDInfo hddi;
537 		char nLen[10] = "";
538 		char nCrc[10] = "";
539 		char *szHDDName = NULL;
540 
541 		memset(&hddi, 0, sizeof(hddi));
542 
543 		nRet = BurnDrvGetHDDInfo(&hddi, i);
544 		nRet += BurnDrvGetHDDName(&szHDDName, i, 0);
545 
546 		if (hddi.nLen == 0) continue;
547 
548 		LvItem.iItem = HDDPos;
549 		LvItem.iSubItem = 0;
550 		LvItem.pszText = ANSIToTCHAR(szHDDName, NULL, 0);
551 		SendMessage(hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
552 
553 		sprintf(nLen, "%d", hddi.nLen);
554 		LvItem.iSubItem = 1;
555 		LvItem.pszText = ANSIToTCHAR(nLen, NULL, 0);
556 		SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
557 
558 		sprintf(nCrc, "%08X", hddi.nCrc);
559 		LvItem.iSubItem = 2;
560 		LvItem.pszText = ANSIToTCHAR(nCrc, NULL, 0);
561 		SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
562 
563 		HDDPos++;
564 	}
565 
566 	// Get the history info
567 	CHAR szFileName[MAX_PATH] = "";
568 	sprintf(szFileName, "%shistory.dat", TCHARToANSI(szAppHistoryPath, NULL, 0));
569 
570 	FILE *fp = fopen(szFileName, "rt");
571 	char Temp[10000];
572 	int inGame = 0;
573 
574 #ifdef USE_SEGOE
575 	TCHAR szBuffer[50000] = _T("{\\rtf1\\ansi{\\fonttbl(\\f0\\fnil\\fcharset0 Verdana;)}{\\colortbl;\\red220\\green0\\blue0;\\red0\\green0\\blue0;}");
576 #else
577 	TCHAR szBuffer[50000] = _T("{\\rtf1\\ansi{\\fonttbl(\\f0\\fnil\\fcharset0 Segoe UI;)}{\\colortbl;\\red220\\green0\\blue0;\\red0\\green0\\blue0;}");
578 #endif
579 
580 	if (fp) {
581 		while (!feof(fp)) {
582 			char *Tokens;
583 
584 			fgets(Temp, 10000, fp);
585 			if (!strncmp("$info=", Temp, 6)) {
586 				Tokens = strtok(Temp, "=,");
587 				while (Tokens != NULL) {
588 					if (!strcmp(Tokens, BurnDrvGetTextA(DRV_NAME))) {
589 						inGame = 1;
590 						break;
591 					}
592 
593 					Tokens = strtok(NULL, "=,");
594 				}
595 			}
596 
597 			if (inGame) {
598 				int nTitleWrote = 0;
599 				while (strncmp("$end", Temp, 4)) {
600 					fgets(Temp, 10000, fp);
601 
602 					if (!strncmp("$", Temp, 1)) continue;
603 
604 					if (!nTitleWrote) {
605 						_stprintf(szBuffer, _T("%s{\\b\\f0\\fs28\\cf1 %s}"), szBuffer, ANSIToTCHAR(Temp, NULL, 0));
606 					} else {
607 						_stprintf(szBuffer, _T("%s\\line"), szBuffer);
608 						if (!strncmp("- ", Temp, 2)) {
609 							_stprintf(szBuffer, _T("%s{\\b\\f0\\fs16\\cf1 %s}"), szBuffer, ANSIToTCHAR(Temp, NULL, 0));
610 						} else {
611 							_stprintf(szBuffer, _T("%s{\\f0\\fs16\\cf2 %s}"), szBuffer, ANSIToTCHAR(Temp, NULL, 0));
612 						}
613 					}
614 
615 					if (strcmp("\n", Temp)) nTitleWrote = 1;
616 				}
617 				break;
618 			}
619 		}
620 		fclose(fp);
621 	}
622 
623 	_stprintf(szBuffer, _T("%s}"), szBuffer);
624 	SendMessage(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), WM_SETTEXT, (WPARAM)0, (LPARAM)szBuffer);
625 
626 	// Make a white brush
627 	hWhiteBGBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF));
628 
629 	return 0;
630 }
631 
632 #if __GNUC__ == 8
633 #pragma GCC diagnostic pop
634 #endif
635 
636 // make gcc 8.x happy about strncpy() usage below...
637 #if __GNUC__ == 8
638 #pragma GCC diagnostic push
639 #pragma GCC diagnostic ignored "-Wstringop-truncation"
640 #endif
641 
642 #define MAXFAVORITES 2000
643 char szFavorites[MAXFAVORITES][28];
644 INT32 nFavorites = 0;
645 
LoadFavorites()646 void LoadFavorites()
647 {
648 	char szTemp[255];
649 	char szFileName[] = "config/favorites.dat";
650 
651 	nFavorites = 0;
652 	memset(szFavorites, 0, sizeof(szFavorites));
653 
654 	FILE *fp = fopen(szFileName, "rb");
655 
656 	if (fp) {
657 		while (!feof(fp)) {
658 			memset(szTemp, 0, sizeof(szTemp));
659 			fgets(szTemp, 255, fp);
660 
661 			// Get rid of the linefeed at the end
662 			INT32 nLen = strlen(szTemp);
663 			while (nLen > 0 && (szTemp[nLen - 1] == 0x0A || szTemp[nLen - 1] == 0x0D)) {
664 				szTemp[nLen - 1] = 0;
665 				nLen--;
666 			}
667 
668 			if (strlen(szTemp) < 25 && strlen(szTemp) > 2) {
669 				strncpy(szFavorites[nFavorites++], szTemp, 25);
670 				//bprintf(0, _T("Loaded: %S.\n"), szFavorites[nFavorites-1]);
671 			}
672 		}
673 		fclose(fp);
674 	}
675 }
676 
SaveFavorites()677 static void SaveFavorites()
678 {
679 	char szFileName[] = "config/favorites.dat";
680 	FILE *fp = fopen(szFileName, "wb");
681 	INT32 nSaved = 0;
682 
683 	if (fp) {
684 		for (INT32 i = 0; i < nFavorites; i++) {
685 			if (strlen(szFavorites[i]) > 0) {
686 				fprintf(fp, "%s\n", szFavorites[i]);
687 				nSaved++;
688 			}
689 		}
690 		//bprintf(0, _T("Saved %X favorites.\n"), nSaved);
691 		fclose(fp);
692 	}
693 }
694 
CheckFavorites(char * name)695 INT32 CheckFavorites(char *name)
696 {
697 	for (INT32 i = 0; i < nFavorites; i++) {
698 		if (!strcmp(name, szFavorites[i])) {
699 			return i;
700 		}
701 	}
702 	return -1;
703 }
704 
AddFavorite(UINT8 addf)705 static void AddFavorite(UINT8 addf)
706 {
707 	UINT32 nOldDrvSelect = nBurnDrvActive;
708 	char szBoardName[28] = "";
709 
710 	LoadFavorites();
711 
712 	nBurnDrvActive = nGiDriverSelected; // get driver name under cursor
713 	strcpy(szBoardName, BurnDrvGetTextA(DRV_NAME));
714 	nBurnDrvActive = nOldDrvSelect;
715 
716 	INT32 inthere = CheckFavorites(szBoardName);
717 
718 	if (addf && inthere == -1) { // add favorite
719 		//bprintf(0, _T("[add %S]"), szBoardName);
720 		strcpy(szFavorites[nFavorites++], szBoardName);
721 	}
722 
723 	if (addf == 0 && inthere != -1) { // remove favorite
724 		//bprintf(0, _T("[remove %S]"), szBoardName);
725 		szFavorites[inthere][0] = '\0';
726 	}
727 
728 	SaveFavorites();
729 }
730 
AddFavorite_Ext(UINT8 addf)731 void AddFavorite_Ext(UINT8 addf)
732 { // For use outside of the gameinfo window.
733 	nGiDriverSelected = nBurnDrvActive;
734 	AddFavorite(addf);
735 }
736 
737 #if __GNUC__ == 8
738 #pragma GCC diagnostic pop
739 #endif
740 
MyEndDialog()741 static void MyEndDialog()
742 {
743 	SendDlgItemMessage(hGameInfoDlg, IDC_SCREENSHOT_H, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
744 	SendDlgItemMessage(hGameInfoDlg, IDC_SCREENSHOT_V, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
745 
746 	if (hGiBmp) {
747 		DeleteObject((HGDIOBJ)hGiBmp);
748 		hGiBmp = NULL;
749 	}
750 	if (hPreview) {
751 		DeleteObject((HGDIOBJ)hPreview);
752 		hPreview = NULL;
753 	}
754 
755 	hTabControl = NULL;
756 	memset(szFullName, 0, 1024 * sizeof(TCHAR));
757 
758 	EndDialog(hGameInfoDlg, 0);
759 }
760 
DialogProc(HWND hDlg,UINT Msg,WPARAM wParam,LPARAM lParam)761 static INT_PTR CALLBACK DialogProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
762 {
763 	if (Msg == WM_INITDIALOG) {
764 		hGameInfoDlg = hDlg;
765 
766 		if (bDrvOkay) {
767 			if (!kNetGame && bAutoPause) bRunPause = 1;
768 			AudSoundStop();
769 		}
770 
771 		GameInfoInit();
772 
773 		WndInMid(hDlg, hParent);
774 		SetFocus(hDlg);											// Enable Esc=close
775 
776 		return TRUE;
777 	}
778 
779 	if (Msg == WM_CLOSE) {
780 		MyEndDialog();
781 		DeleteObject(hWhiteBGBrush);
782 
783 		EnableWindow(hScrnWnd, TRUE);
784 		DestroyWindow(hGameInfoDlg);
785 
786 		FreeLibrary(hRiched);
787 		hRiched = NULL;
788 
789 		if (bDrvOkay) {
790 			if(!bAltPause && bRunPause) bRunPause = 0;
791 			AudSoundPlay();
792 		}
793 
794 		return 0;
795 	}
796 
797 	if (Msg == WM_COMMAND) {
798 		int Id = LOWORD(wParam);
799 		int Notify = HIWORD(wParam);
800 
801 		if (Id == IDCANCEL && Notify == BN_CLICKED) {
802 			SendMessage(hGameInfoDlg, WM_CLOSE, 0, 0);
803 			return 0;
804 		}
805 
806 		if (Id == IDFAVORITESET && Notify == BN_CLICKED) {
807 			INT32 nButtonState = SendDlgItemMessage(hGameInfoDlg, IDFAVORITESET, BM_GETSTATE, 0, 0);
808 
809 			AddFavorite((nButtonState & BST_CHECKED) ? 1 : 0);
810 			return 0;
811 		}
812 
813 		if (Id == IDRESCANSET && Notify == BN_CLICKED) {
814 			nBurnDrvActive = nGiDriverSelected;
815 			// use the nBurnDrvActive value from when the Rom Info button was clicked, because it can/will change
816 			// even though the selection list [window below it] doesn't have focus. -dink
817 			// for proof/symptoms - uncomment the line below and click the 'rescan' button after moving the window to different places on the screen.
818 			//bprintf(0, _T("nBurnDrvActive %d nGiDriverSelected %d\n"), nBurnDrvActive, nGiDriverSelected);
819 
820 			switch (BzipOpen(1)) {
821 				case 0: {
822 					gameAv[nGiDriverSelected] = 3;
823 					break;
824 				}
825 
826 				case 2: {
827 					gameAv[nGiDriverSelected] = 1;
828 					break;
829 				}
830 
831 				case 1: {
832 					gameAv[nGiDriverSelected] = 0;
833 					BzipClose();
834 					BzipOpen(0); // this time, get the missing roms/error message.
835 					{
836 						HWND hScrnWndtmp = hScrnWnd; // Crash preventer: Make the gameinfo dialog (this one) the parent modal for the popup message
837 						hScrnWnd = hGameInfoDlg;
838 						FBAPopupDisplay(PUF_TYPE_ERROR);
839 						hScrnWnd = hScrnWndtmp;
840 					}
841 					break;
842 				}
843 			}
844 
845 			if (gameAv[nGiDriverSelected] > 0) {
846 				int TabPage = TabCtrl_GetCurSel(hTabControl);
847 				if (TabPage != 0) {
848 					MessageBox(hGameInfoDlg, FBALoadStringEx(hAppInst, IDS_ERR_LOAD_OK, true), FBALoadStringEx(hAppInst, IDS_ERR_INFORMATION, true), MB_OK);
849 				}
850 				if (TabPage == 0) {
851 					// if the romset is OK, just say so in the rom info dialog (instead of popping up a window)
852 					HWND hList = GetDlgItem(hGameInfoDlg, IDC_LIST1);
853 					LV_ITEM LvItem;
854 					memset(&LvItem, 0, sizeof(LvItem));
855 					LvItem.mask=  LVIF_TEXT;
856 					LvItem.cchTextMax = 256;
857 					LvItem.iSubItem = 4;
858 					LvItem.pszText = _T("Romset OK!");
859 					SendMessage(hList, LVM_SETITEM, 0, (LPARAM)&LvItem);
860 					UpdateWindow(hGameInfoDlg);
861 				}
862 			}
863 			BzipClose();
864 			WriteGameAvb();
865 			return 0;
866 		}
867 	}
868 
869 	if (Msg == WM_NOTIFY) {
870 		NMHDR* pNmHdr = (NMHDR*)lParam;
871 
872 		if (pNmHdr->code == TCN_SELCHANGE) {
873 			int TabPage = TabCtrl_GetCurSel(hTabControl);
874 
875 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST1), SW_HIDE);
876 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST2), SW_HIDE);
877 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_LIST3), SW_HIDE);
878 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_MESSAGE_EDIT_ENG), SW_HIDE);
879 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_H), SW_SHOW);
880 			ShowWindow(GetDlgItem(hGameInfoDlg, IDC_SCREENSHOT_V), SW_SHOW);
881 			UpdateWindow(hGameInfoDlg);
882 
883 			nBurnDrvActive = nGiDriverSelected;
884 
885 			if (TabPage == 0) DisplayRomInfo();
886 			if (TabPage == 1) DisplayHDDInfo();
887 			if (TabPage == 2) DisplaySampleInfo();
888 			if (TabPage == 3) DisplayHistory();
889 			if (TabPage == 4) SetPreview(szAppPreviewsPath, IMG_ASPECT_4_3);
890 			if (TabPage == 5) SetPreview(szAppTitlesPath, IMG_ASPECT_4_3);
891 			if (TabPage == 6) SetPreview(szAppSelectPath, IMG_ASPECT_4_3);
892 			if (TabPage == 7) SetPreview(szAppVersusPath, IMG_ASPECT_4_3);
893 			if (TabPage == 8) SetPreview(szAppHowtoPath, IMG_ASPECT_4_3);
894 			if (TabPage == 9) SetPreview(szAppScoresPath, IMG_ASPECT_4_3);
895 			if (TabPage == 10) SetPreview(szAppBossesPath, IMG_ASPECT_4_3);
896 			if (TabPage == 11) SetPreview(szAppGameoverPath, IMG_ASPECT_4_3);
897 			if (TabPage == 12) SetPreview(szAppFlyersPath, IMG_ASPECT_PRESERVE);
898 			if (TabPage == 13) SetPreview(szAppCabinetsPath, IMG_ASPECT_PRESERVE);
899 			if (TabPage == 14) SetPreview(szAppMarqueesPath, IMG_ASPECT_PRESERVE);
900 			if (TabPage == 15) SetPreview(szAppControlsPath, IMG_ASPECT_PRESERVE);
901 			if (TabPage == 16) SetPreview(szAppPCBsPath, IMG_ASPECT_PRESERVE);
902 
903 			return FALSE;
904 		}
905 	}
906 
907 	if (Msg == WM_CTLCOLORSTATIC) {
908 		if ((HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELCOMMENT) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELROMNAME) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELROMINFO) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELSYSTEM) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELNOTES) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_LABELGENRE) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTCOMMENT) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTROMNAME) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTROMINFO) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTSYSTEM) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTNOTES) || (HWND)lParam == GetDlgItem(hGameInfoDlg, IDC_TEXTGENRE)) {
909 			return (INT_PTR)hWhiteBGBrush;
910 		}
911 	}
912 
913 	return 0;
914 }
915 
GameInfoDialogCreate(HWND hParentWND,int nDrvSel)916 int GameInfoDialogCreate(HWND hParentWND, int nDrvSel)
917 {
918 	bGameInfoOpen = true;
919 	nGiDriverSelected = nDrvSel;
920 
921 #if defined (_UNICODE)
922 	hRiched = LoadLibrary(L"RICHED20.DLL");
923 #else
924 	hRiched = LoadLibrary("RICHED20.DLL");
925 #endif
926 
927 	if (hRiched) {
928 		hParent = hParentWND;
929 		FBADialogBox(hAppInst, MAKEINTRESOURCE(IDD_GAMEINFO), hParent, (DLGPROC)DialogProc);
930 	}
931 
932 	bGameInfoOpen = false;
933 	return 0;
934 }
935