1 //
2 // Copyright(C) 2005-2014 Simon Howard
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "doomtype.h"
19
20 #include "config.h"
21 #include "textscreen.h"
22
23 #include "doomtype.h"
24 #include "d_mode.h"
25 #include "d_iwad.h"
26 #include "i_system.h"
27 #include "m_argv.h"
28 #include "m_config.h"
29 #include "m_controls.h"
30 #include "m_misc.h"
31
32 #include "accessibility.h"
33 #include "compatibility.h"
34 #include "display.h"
35 #include "joystick.h"
36 #include "keyboard.h"
37 #include "mouse.h"
38 #include "multiplayer.h"
39 #include "sound.h"
40
41 #include "mode.h"
42
43 GameMission_t gamemission;
44 static const iwad_t **iwads;
45
46 typedef struct
47 {
48 const char *label;
49 GameMission_t mission;
50 int mask;
51 const char *name;
52 const char *config_file;
53 const char *extra_config_file;
54 const char *executable;
55 } mission_config_t;
56
57 // Default mission to fall back on, if no IWADs are found at all:
58
59 #define DEFAULT_MISSION (&mission_configs[0])
60
61 static mission_config_t mission_configs[] =
62 {
63 {
64 "Doom",
65 doom,
66 IWAD_MASK_DOOM,
67 "doom",
68 "default.cfg",
69 PROGRAM_PREFIX "doom.cfg",
70 PROGRAM_PREFIX "doom"
71 },
72 {
73 "Heretic",
74 heretic,
75 IWAD_MASK_HERETIC,
76 "heretic",
77 "heretic.cfg",
78 PROGRAM_PREFIX "heretic.cfg",
79 PROGRAM_PREFIX "heretic"
80 },
81 {
82 "Hexen",
83 hexen,
84 IWAD_MASK_HEXEN,
85 "hexen",
86 "hexen.cfg",
87 PROGRAM_PREFIX "hexen.cfg",
88 PROGRAM_PREFIX "hexen"
89 },
90 {
91 "Strife",
92 strife,
93 IWAD_MASK_STRIFE,
94 "strife",
95 "strife.cfg",
96 PROGRAM_PREFIX "strife.cfg",
97 PROGRAM_PREFIX "strife"
98 }
99 };
100
101 static GameSelectCallback game_selected_callback;
102
103 // Miscellaneous variables that aren't used in setup.
104
105 static int showMessages = 1;
106 static int screenblocks = 10;
107 static int detailLevel = 0;
108 static char *savedir = NULL;
109 static char *executable = NULL;
110 static const char *game_title = "Doom";
111 static char *back_flat = "F_PAVE01";
112 static int comport = 0;
113 static char *nickname = NULL;
114
BindMiscVariables(void)115 static void BindMiscVariables(void)
116 {
117 if (gamemission == doom)
118 {
119 M_BindIntVariable("detaillevel", &detailLevel);
120 M_BindIntVariable("show_messages", &showMessages);
121 }
122
123 if (gamemission == hexen)
124 {
125 M_BindStringVariable("savedir", &savedir);
126 M_BindIntVariable("messageson", &showMessages);
127
128 // Hexen has a variable to control the savegame directory
129 // that is used.
130
131 savedir = M_GetSaveGameDir("hexen.wad");
132
133 // On Windows, hexndata\ is the default.
134
135 if (!strcmp(savedir, ""))
136 {
137 free(savedir);
138 savedir = "hexndata" DIR_SEPARATOR_S;
139 }
140 }
141
142 if (gamemission == strife)
143 {
144 // Strife has a different default value than the other games
145 screenblocks = 10;
146
147 M_BindStringVariable("back_flat", &back_flat);
148 M_BindStringVariable("nickname", &nickname);
149
150 M_BindIntVariable("screensize", &screenblocks);
151 M_BindIntVariable("comport", &comport);
152 }
153 else
154 {
155 M_BindIntVariable("screenblocks", &screenblocks);
156 }
157
158 }
159
160 //
161 // Initialise all configuration file bindings.
162 //
163
InitBindings(void)164 void InitBindings(void)
165 {
166 M_ApplyPlatformDefaults();
167
168 // Keyboard, mouse, joystick controls
169
170 M_BindBaseControls();
171 M_BindWeaponControls();
172 M_BindMapControls();
173 M_BindMenuControls();
174
175 if (gamemission == heretic || gamemission == hexen)
176 {
177 M_BindHereticControls();
178 }
179
180 if (gamemission == hexen)
181 {
182 M_BindHexenControls();
183 }
184
185 if (gamemission == strife)
186 {
187 M_BindStrifeControls();
188 }
189
190 // All other variables
191
192 BindAccessibilityVariables();
193 BindCompatibilityVariables();
194 BindDisplayVariables();
195 BindJoystickVariables();
196 BindKeyboardVariables();
197 BindMouseVariables();
198 BindSoundVariables();
199 BindMiscVariables();
200 BindMultiplayerVariables();
201 }
202
203 // Set the name of the executable program to run the game:
204
SetExecutable(mission_config_t * config)205 static void SetExecutable(mission_config_t *config)
206 {
207 char *extension;
208
209 free(executable);
210
211 #ifdef _WIN32
212 extension = ".exe";
213 #else
214 extension = "";
215 #endif
216
217 executable = M_StringJoin(config->executable, extension, NULL);
218 }
219
SetMission(mission_config_t * config)220 static void SetMission(mission_config_t *config)
221 {
222 iwads = D_FindAllIWADs(config->mask);
223 gamemission = config->mission;
224 SetExecutable(config);
225 game_title = config->label;
226 M_SetConfigFilenames(config->config_file, config->extra_config_file);
227 }
228
GetMissionForName(const char * name)229 static mission_config_t *GetMissionForName(const char *name)
230 {
231 int i;
232
233 for (i=0; i<arrlen(mission_configs); ++i)
234 {
235 if (!strcmp(mission_configs[i].name, name))
236 {
237 return &mission_configs[i];
238 }
239 }
240
241 return NULL;
242 }
243
244 // Check the name of the executable. If it contains one of the game
245 // names (eg. chocolate-hexen-setup.exe) then use that game.
246
CheckExecutableName(GameSelectCallback callback)247 static boolean CheckExecutableName(GameSelectCallback callback)
248 {
249 mission_config_t *config;
250 const char *exe_name;
251 int i;
252
253 exe_name = M_GetExecutableName();
254
255 for (i=0; i<arrlen(mission_configs); ++i)
256 {
257 config = &mission_configs[i];
258
259 if (strstr(exe_name, config->name) != NULL)
260 {
261 SetMission(config);
262 callback();
263 return true;
264 }
265 }
266
267 return false;
268 }
269
GameSelected(TXT_UNCAST_ARG (widget),TXT_UNCAST_ARG (config))270 static void GameSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(config))
271 {
272 TXT_CAST_ARG(mission_config_t, config);
273
274 SetMission(config);
275 game_selected_callback();
276 }
277
OpenGameSelectDialog(GameSelectCallback callback)278 static void OpenGameSelectDialog(GameSelectCallback callback)
279 {
280 mission_config_t *mission = NULL;
281 txt_window_t *window;
282 const iwad_t **iwads;
283 int num_games;
284 int i;
285
286 window = TXT_NewWindow("Select game");
287
288 TXT_AddWidget(window, TXT_NewLabel("Select a game to configure:\n"));
289 num_games = 0;
290
291 // Add a button for each game.
292
293 for (i=0; i<arrlen(mission_configs); ++i)
294 {
295 // Do we have any IWADs for this game installed?
296 // If so, add a button.
297
298 iwads = D_FindAllIWADs(mission_configs[i].mask & (IWAD_MASK_DOOM|IWAD_MASK_HERETIC)); // [crispy] restrict game choice to Doom and Heretic
299
300 if (iwads[0] != NULL)
301 {
302 mission = &mission_configs[i];
303 TXT_AddWidget(window, TXT_NewButton2(mission_configs[i].label,
304 GameSelected,
305 &mission_configs[i]));
306 ++num_games;
307 }
308
309 free(iwads);
310 }
311
312 TXT_AddWidget(window, TXT_NewStrut(0, 1));
313
314 // No IWADs found at all? Fall back to doom, then.
315
316 if (num_games == 0)
317 {
318 TXT_CloseWindow(window);
319 SetMission(DEFAULT_MISSION);
320 callback();
321 return;
322 }
323
324 // Only one game? Use that game, and don't bother with a dialog.
325
326 if (num_games == 1)
327 {
328 TXT_CloseWindow(window);
329 SetMission(mission);
330 callback();
331 return;
332 }
333
334 game_selected_callback = callback;
335 }
336
SetupMission(GameSelectCallback callback)337 void SetupMission(GameSelectCallback callback)
338 {
339 mission_config_t *config;
340 const char *mission_name;
341 int p;
342
343 //!
344 // @arg <game>
345 //
346 // Specify the game to configure the settings for. Valid
347 // values are 'doom', 'heretic', 'hexen' and 'strife'.
348 //
349
350 p = M_CheckParm("-game");
351
352 if (p > 0)
353 {
354 mission_name = myargv[p + 1];
355
356 config = GetMissionForName(mission_name);
357
358 if (config == NULL)
359 {
360 I_Error("Invalid parameter - '%s'", mission_name);
361 }
362
363 SetMission(config);
364 callback();
365 }
366 else if (!CheckExecutableName(callback))
367 {
368 OpenGameSelectDialog(callback);
369 }
370 }
371
GetExecutableName(void)372 const char *GetExecutableName(void)
373 {
374 return executable;
375 }
376
GetGameTitle(void)377 const char *GetGameTitle(void)
378 {
379 return game_title;
380 }
381
GetIwads(void)382 const iwad_t **GetIwads(void)
383 {
384 return iwads;
385 }
386
387