1 /**
2  * @file appfat.cpp
3  *
4  * Implementation of error dialogs.
5  */
6 #include "all.h"
7 #include "../3rdParty/Storm/Source/storm.h"
8 #include <config.h>
9 
10 DEVILUTION_BEGIN_NAMESPACE
11 
12 /** Set to true when a fatal error is encountered and the application should shut down. */
13 BOOL terminating;
14 /** Thread id of the last callee to FreeDlg(). */
15 SDL_threadID cleanup_thread_id;
16 
17 /**
18  * @brief Displays an error message box based on the given format string and variable argument list.
19  * @param pszFmt Error message format
20  * @param va Additional parameters for message format
21  */
MsgBox(const char * pszFmt,va_list va)22 static void MsgBox(const char *pszFmt, va_list va)
23 {
24 	char text[256];
25 
26 	vsnprintf(text, 256, pszFmt, va);
27 
28 	UiErrorOkDialog("Error", text);
29 }
30 
31 /**
32  * @brief Cleans up after a fatal application error.
33  */
FreeDlg()34 static void FreeDlg()
35 {
36 	if (terminating && cleanup_thread_id != SDL_GetThreadID(NULL))
37 		SDL_Delay(20000);
38 
39 	terminating = TRUE;
40 	cleanup_thread_id = SDL_GetThreadID(NULL);
41 
42 	if (gbIsMultiplayer) {
43 		if (SNetLeaveGame(3))
44 			SDL_Delay(2000);
45 	}
46 
47 	SNetDestroy();
48 }
49 
50 /**
51  * @brief Terminates the game and displays an error message box.
52  * @param pszFmt Optional error message.
53  * @param ... (see printf)
54  */
app_fatal(const char * pszFmt,...)55 void app_fatal(const char *pszFmt, ...)
56 {
57 	va_list va;
58 
59 	va_start(va, pszFmt);
60 	FreeDlg();
61 
62 	if (pszFmt)
63 		MsgBox(pszFmt, va);
64 
65 	va_end(va);
66 
67 	diablo_quit(1);
68 }
69 
70 /**
71  * @brief Displays a warning message box based on the given formatted error message.
72  * @param pszFmt Error message format
73  * @param ... Additional parameters for message format
74  */
DrawDlg(const char * pszFmt,...)75 void DrawDlg(const char *pszFmt, ...)
76 {
77 	char text[256];
78 	va_list va;
79 
80 	va_start(va, pszFmt);
81 	vsnprintf(text, 256, pszFmt, va);
82 	va_end(va);
83 
84 	UiErrorOkDialog(PROJECT_NAME, text, false);
85 }
86 
87 #ifdef _DEBUG
88 /**
89  * @brief Show an error and exit the application.
90  * @param nLineNo The line number of the assertion
91  * @param pszFile File name where the assertion is located
92  * @param pszFail Fail message
93  */
assert_fail(int nLineNo,const char * pszFile,const char * pszFail)94 void assert_fail(int nLineNo, const char *pszFile, const char *pszFail)
95 {
96 	app_fatal("assertion failed (%s:%d)\n%s", pszFile, nLineNo, pszFail);
97 }
98 #endif
99 
100 /**
101  * @brief Terminates the game and displays an error dialog box based on the given dialog_id.
102  */
ErrDlg(const char * title,const char * error,const char * log_file_path,int log_line_nr)103 void ErrDlg(const char *title, const char *error, const char *log_file_path, int log_line_nr)
104 {
105 	char text[1024];
106 
107 	FreeDlg();
108 
109 	snprintf(text, 1024, "%s\n\nThe error occurred at: %s line %d", error, log_file_path, log_line_nr);
110 
111 	UiErrorOkDialog(title, text);
112 	app_fatal(NULL);
113 }
114 
115 /**
116  * @brief Terminates the game with a file not found error dialog.
117  */
FileErrDlg(const char * error)118 void FileErrDlg(const char *error)
119 {
120 	char text[1024];
121 
122 	FreeDlg();
123 
124 	if (!error)
125 		error = "";
126 	snprintf(
127 	    text,
128 	    1024,
129 	    "Unable to open a required file.\n"
130 	    "\n"
131 	    "Verify that the MD5 of diabdat.mpq matches one of the following values\n"
132 	    "011bc6518e6166206231080a4440b373\n"
133 	    "68f049866b44688a7af65ba766bef75a\n"
134 	    "\n"
135 	    "The problem occurred when loading:\n%s",
136 	    error);
137 
138 	UiErrorOkDialog("Data File Error", text);
139 	app_fatal(NULL);
140 }
141 
142 /**
143  * @brief Terminates the game with an insert CD error dialog.
144  */
InsertCDDlg()145 void InsertCDDlg()
146 {
147 	char text[1024];
148 	snprintf(
149 	    text,
150 	    1024,
151 	    "Unable to open main data archive (diabdat.mpq or spawn.mpq).\n"
152 	    "\n"
153 	    "Make sure that it is in the game folder and that the file name is in all lowercase.");
154 
155 	UiErrorOkDialog("Data File Error", text);
156 	app_fatal(NULL);
157 }
158 
159 /**
160  * @brief Terminates the game with a read-only directory error dialog.
161  */
DirErrorDlg(const char * error)162 void DirErrorDlg(const char *error)
163 {
164 	char text[1024];
165 
166 	snprintf(text, 1024, "Unable to write to location:\n%s", error);
167 
168 	UiErrorOkDialog("Read-Only Directory Error", text);
169 	app_fatal(NULL);
170 }
171 
172 DEVILUTION_END_NAMESPACE
173