1
2 #include "build.h"
3
4 #ifdef _WIN32
5 # include "windows_inc.h"
6 # include "winbits.h"
7 #elif defined __APPLE__
8 # include "osxbits.h"
9 #endif
10
11 #include "common.h"
12 #include "common_game.h"
13 #include "grpscan.h"
14
15 uint8_t SW_GameFlags;
16
17 static const char *defaultgrpfilename = "SW.GRP";
18 static const char *defaultdeffilename = "sw.def";
19
20 // g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
21 char *g_grpNamePtr = NULL;
22
clearGrpNamePtr(void)23 void clearGrpNamePtr(void)
24 {
25 Bfree(g_grpNamePtr);
26 // g_grpNamePtr assumed to be assigned to right after
27 }
28
G_DefaultGrpFile(void)29 const char *G_DefaultGrpFile(void)
30 {
31 return defaultgrpfilename;
32 }
G_GrpFile(void)33 const char *G_GrpFile(void)
34 {
35 if (g_grpNamePtr == NULL)
36 return G_DefaultGrpFile();
37 else
38 return g_grpNamePtr;
39 }
40
G_DefaultDefFile(void)41 const char *G_DefaultDefFile(void)
42 {
43 return defaultdeffilename;
44 }
G_DefFile(void)45 const char *G_DefFile(void)
46 {
47 if (g_defNamePtr == NULL)
48 return G_DefaultDefFile();
49 else
50 return g_defNamePtr;
51 }
52
53
SW_InitMultiPsky(void)54 void SW_InitMultiPsky(void)
55 {
56 // default
57 psky_t * const defaultsky = tileSetupSky(DEFAULTPSKY);
58 defaultsky->lognumtiles = 1;
59 defaultsky->horizfrac = 8192;
60 }
61
62 int g_useCwd;
63 static char g_rootDir[BMAX_PATH];
64
SW_ExtPreInit(int32_t argc,char const * const * argv)65 void SW_ExtPreInit(int32_t argc, char const * const * argv)
66 {
67 g_useCwd = G_CheckCmdSwitch(argc, argv, "-usecwd");
68
69 #ifdef _WIN32
70 GetModuleFileName(NULL,g_rootDir,BMAX_PATH);
71 Bcorrectfilename(g_rootDir,1);
72 //buildvfs_chdir(g_rootDir);
73 #else
74 buildvfs_getcwd(g_rootDir,BMAX_PATH);
75 strcat(g_rootDir,"/");
76 #endif
77 }
78
79 #ifndef EDUKE32_STANDALONE
80
81 #if defined _WIN32 || defined __linux__ || defined EDUKE32_BSD || defined EDUKE32_OSX
SW_Add_GOG_SWCR(const char * path)82 static int32_t SW_Add_GOG_SWCR(const char * path)
83 {
84 char buf[BMAX_PATH];
85
86 addsearchpath_user(path, SEARCHPATH_REMOVE);
87 Bsnprintf(buf, sizeof(buf), "%s/addons", path);
88 addsearchpath_user(buf, SEARCHPATH_REMOVE);
89 Bsnprintf(buf, sizeof(buf), "%s/music", path);
90 return addsearchpath(buf);
91 }
SW_Add_GOG_SWCC(const char * path)92 static int32_t SW_Add_GOG_SWCC(const char * path)
93 {
94 char buf[BMAX_PATH];
95
96 addsearchpath_user(path, SEARCHPATH_REMOVE);
97 Bsnprintf(buf, sizeof(buf), "%s/MUSIC", path);
98 return addsearchpath(buf);
99 }
100 #endif
101
102 #if defined __linux__ || defined EDUKE32_BSD
SW_Add_GOG_SWCR_Linux(const char * path)103 static void SW_Add_GOG_SWCR_Linux(const char * path)
104 {
105 char buf[BMAX_PATH];
106
107 Bsnprintf(buf, sizeof(buf), "%s/game", path);
108 SW_Add_GOG_SWCR(buf);
109 }
SW_Add_GOG_SWCC_Linux(const char * path)110 static void SW_Add_GOG_SWCC_Linux(const char * path)
111 {
112 char buf[BMAX_PATH];
113
114 Bsnprintf(buf, sizeof(buf), "%s/data", path);
115 SW_Add_GOG_SWCC(buf);
116 }
117 #endif
118
119 #ifndef EDUKE32_TOUCH_DEVICES
120 #if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD
SW_AddSteamPaths(const char * basepath)121 static void SW_AddSteamPaths(const char *basepath)
122 {
123 char buf[BMAX_PATH];
124
125 // Shadow Warrior Classic Redux - Steam
126 static char const s_SWCR_Steam[] = "steamapps/common/Shadow Warrior Classic/gameroot";
127 Bsnprintf(buf, sizeof(buf), "%s/%s", basepath, s_SWCR_Steam);
128 addsearchpath_user(buf, SEARCHPATH_REMOVE);
129 Bsnprintf(buf, sizeof(buf), "%s/%s/addons", basepath, s_SWCR_Steam);
130 addsearchpath_user(buf, SEARCHPATH_REMOVE);
131 Bsnprintf(buf, sizeof(buf), "%s/%s/classic/MUSIC", basepath, s_SWCR_Steam);
132 if (addsearchpath(buf) == 0)
133 return;
134
135 // Shadow Warrior Classic (1997) - Steam
136 static char const s_SWC_Steam[] = "steamapps/common/Shadow Warrior Original/gameroot";
137 Bsnprintf(buf, sizeof(buf), "%s/%s", basepath, s_SWC_Steam);
138 addsearchpath_user(buf, SEARCHPATH_REMOVE);
139 Bsnprintf(buf, sizeof(buf), "%s/%s/MUSIC", basepath, s_SWC_Steam);
140 if (addsearchpath(buf) == 0)
141 return;
142
143 // Shadow Warrior (Classic) - 3D Realms Anthology - Steam
144 #if defined EDUKE32_OSX
145 Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Shadow Warrior DOS/Shadow Warrior.app/Contents/Resources/sw", basepath);
146 addsearchpath(buf);
147 #endif
148 }
149 #endif
150 #endif
151 #endif
152
SW_AddSearchPaths()153 static void SW_AddSearchPaths()
154 {
155 #ifndef EDUKE32_STANDALONE
156 #ifndef EDUKE32_TOUCH_DEVICES
157 #if defined __linux__ || defined EDUKE32_BSD
158 char buf[BMAX_PATH];
159 char *homepath = Bgethomedir();
160
161 Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath);
162 SW_AddSteamPaths(buf);
163
164 Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath);
165 Paths_ParseSteamLibraryVDF(buf, SW_AddSteamPaths);
166
167 // Shadow Warrior Classic Redux - GOG.com
168 Bsnprintf(buf, sizeof(buf), "%s/GOG Games/Shadow Warrior Classic Redux", homepath);
169 SW_Add_GOG_SWCR_Linux(buf);
170 Paths_ParseXDGDesktopFilesFromGOG(homepath, "Shadow_Warrior_Classic_Redux", SW_Add_GOG_SWCR_Linux);
171
172 // Shadow Warrior Classic Complete - GOG.com
173 Bsnprintf(buf, sizeof(buf), "%s/GOG Games/Shadow Warrior Classic Complete", homepath);
174 SW_Add_GOG_SWCC_Linux(buf);
175 Paths_ParseXDGDesktopFilesFromGOG(homepath, "Shadow_Warrior_Classic_Complete", SW_Add_GOG_SWCC_Linux);
176
177 Xfree(homepath);
178
179 addsearchpath("/usr/share/games/jfsw");
180 addsearchpath("/usr/local/share/games/jfsw");
181 addsearchpath("/usr/share/games/voidsw");
182 addsearchpath("/usr/local/share/games/voidsw");
183 #elif defined EDUKE32_OSX
184 char buf[BMAX_PATH];
185 int32_t i;
186 char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) };
187 char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) };
188
189 for (i = 0; i < 2; i++)
190 {
191 Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]);
192 SW_AddSteamPaths(buf);
193
194 Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]);
195 Paths_ParseSteamLibraryVDF(buf, SW_AddSteamPaths);
196
197 // Shadow Warrior Classic Complete - GOG.com
198 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior.app/Contents/Resources/Shadow Warrior.boxer/C swarrior_files.harddisk", applications[i]);
199 SW_Add_GOG_SWCC(buf);
200 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior Complete/Shadow Warrior.app/Contents/Resources/Shadow Warrior.boxer/C swarrior_files.harddisk", applications[i]);
201 SW_Add_GOG_SWCC(buf);
202 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior Complete.app/Contents/Resources/game/Shadow Warrior.app/Contents/Resources/Shadow Warrior.boxer/C swarrior_files.harddisk", applications[i]);
203 SW_Add_GOG_SWCC(buf);
204
205 // Shadow Warrior Classic Redux - GOG.com
206 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior Classic Redux.app/Contents/Resources/gameroot", applications[i]);
207 SW_Add_GOG_SWCR(buf);
208 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior Classic Redux/Shadow Warrior Classic Redux.app/Contents/Resources/gameroot", applications[i]);
209 SW_Add_GOG_SWCR(buf);
210 Bsnprintf(buf, sizeof(buf), "%s/Shadow Warrior Classic Redux.app/Contents/Resources/game/Shadow Warrior Classic Redux.app/Contents/Resources/gameroot", applications[i]);
211 SW_Add_GOG_SWCR(buf);
212 }
213
214 for (i = 0; i < 2; i++)
215 {
216 Bsnprintf(buf, sizeof(buf), "%s/JFSW", support[i]);
217 addsearchpath(buf);
218 Bsnprintf(buf, sizeof(buf), "%s/VoidSW", support[i]);
219 addsearchpath(buf);
220 }
221
222 for (i = 0; i < 2; i++)
223 {
224 Xfree(applications[i]);
225 Xfree(support[i]);
226 }
227 #elif defined (_WIN32)
228 char buf[BMAX_PATH] = {0};
229 DWORD bufsize;
230
231 // Shadow Warrior Classic Redux - Steam
232 bufsize = sizeof(buf);
233 if (Paths_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225160)", "InstallLocation", buf, &bufsize))
234 {
235 char * const suffix = buf + bufsize - 1;
236 DWORD const remaining = sizeof(buf) - bufsize;
237
238 Bstrncpy(suffix, "/gameroot", remaining);
239 addsearchpath_user(buf, SEARCHPATH_REMOVE);
240 Bstrncpy(suffix, "/gameroot/addons", remaining);
241 addsearchpath_user(buf, SEARCHPATH_REMOVE);
242 Bstrncpy(suffix, "/gameroot/classic/MUSIC", remaining);
243 if (addsearchpath(buf) == 0)
244 return;
245 }
246
247 // Shadow Warrior Classic (1997) - Steam
248 bufsize = sizeof(buf);
249 if (Paths_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 238070)", "InstallLocation", buf, &bufsize))
250 {
251 char * const suffix = buf + bufsize - 1;
252 DWORD const remaining = sizeof(buf) - bufsize;
253
254 Bstrncpy(suffix, "/gameroot", remaining);
255 addsearchpath_user(buf, SEARCHPATH_REMOVE);
256 Bstrncpy(suffix, "/gameroot/MUSIC", remaining);
257 if (addsearchpath(buf) == 0)
258 return;
259 }
260
261 // Shadow Warrior Classic Redux - GOG.com
262 bufsize = sizeof(buf);
263 if (Paths_ReadRegistryValue(R"(SOFTWARE\GOG.com\Games\1618073558)", "PATH", buf, &bufsize))
264 {
265 if (SW_Add_GOG_SWCR(buf) == 0)
266 return;
267 }
268
269 // Shadow Warrior Classic Complete - GOG.com
270 bufsize = sizeof(buf);
271 if (Paths_ReadRegistryValue(R"(SOFTWARE\GOG.com\Games\1207659142)", "PATH", buf, &bufsize))
272 {
273 if (SW_Add_GOG_SWCC(buf) == 0)
274 return;
275 }
276 bufsize = sizeof(buf);
277 if (Paths_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGSHADOWARRIOR", "PATH", buf, &bufsize))
278 {
279 if (SW_Add_GOG_SWCC(buf) == 0)
280 return;
281 }
282
283 // Shadow Warrior Classic Complete - ZOOM Platform
284 bufsize = sizeof(buf);
285 if (Paths_ReadRegistryValue(R"(SOFTWARE\ZOOM PLATFORM\Shadow Warrior Classic Complete)", "InstallPath", buf, &bufsize))
286 {
287 if (SW_Add_GOG_SWCC(buf) == 0)
288 return;
289 }
290
291 // Shadow Warrior (Classic) - 3D Realms Anthology - Steam
292 bufsize = sizeof(buf);
293 if (Paths_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 358400)", "InstallLocation", buf, &bufsize))
294 {
295 char * const suffix = buf + bufsize - 1;
296 DWORD const remaining = sizeof(buf) - bufsize;
297
298 Bstrncpy(suffix, "/Shadow Warrior", remaining);
299 addsearchpath(buf);
300 }
301
302 // Shadow Warrior - 3D Realms Anthology
303 bufsize = sizeof(buf);
304 if (Paths_ReadRegistryValue("SOFTWARE\\3DRealms\\Shadow Warrior", NULL, buf, &bufsize))
305 {
306 char * const suffix = buf + bufsize - 1;
307 DWORD const remaining = sizeof(buf) - bufsize;
308
309 Bstrncpy(suffix, "/Shadow Warrior", remaining);
310 addsearchpath(buf);
311 }
312
313 // 3D Realms Anthology
314 bufsize = sizeof(buf);
315 if (Paths_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize))
316 {
317 char * const suffix = buf + bufsize - 1;
318 DWORD const remaining = sizeof(buf) - bufsize;
319
320 Bstrncpy(suffix, "/Shadow Warrior", remaining);
321 addsearchpath(buf);
322 }
323 #endif
324 #endif
325 #endif
326 }
327
SW_CleanupSearchPaths()328 void SW_CleanupSearchPaths()
329 {
330 removesearchpaths_withuser(SEARCHPATH_REMOVE);
331 }
332
SW_AddMusicFolder()333 static inline void SW_AddMusicFolder()
334 {
335 #ifndef _WIN32
336 if (addsearchpath("MUSIC") == 0)
337 return;
338 #endif
339 addsearchpath("music");
340 }
341
SW_ExtInit()342 void SW_ExtInit()
343 {
344 if (!g_useCwd)
345 SW_AddSearchPaths();
346
347 #ifdef EDUKE32_OSX
348 char *appdir = Bgetappdir();
349 addsearchpath(appdir);
350 Xfree(appdir);
351 #endif
352
353 char cwd[BMAX_PATH];
354 #ifdef USE_PHYSFS
355 strncpy(cwd, PHYSFS_getBaseDir(), ARRAY_SIZE(cwd));
356 cwd[ARRAY_SIZE(cwd)-1] = '\0';
357 #else
358 if (buildvfs_getcwd(cwd, ARRAY_SIZE(cwd)) && Bstrcmp(cwd, "/") != 0)
359 #endif
360 addsearchpath(cwd);
361 #if defined(_WIN32) && !defined(EDUKE32_STANDALONE)
362 if (buildvfs_exists("user_profiles_enabled"))
363 #else
364 if (g_useCwd == 0 && !buildvfs_exists("user_profiles_disabled"))
365 #endif
366 {
367 char *homedir;
368 int32_t asperr;
369
370 if ((homedir = Bgethomedir()))
371 {
372 Bsnprintf(cwd, ARRAY_SIZE(cwd), "%s/"
373 #if defined(_WIN32)
374 APPNAME
375 #elif defined(GEKKO)
376 "apps/" APPBASENAME
377 #else
378 ".config/" APPBASENAME
379 #endif
380 ,homedir);
381 asperr = addsearchpath(cwd);
382 if (asperr == -2)
383 {
384 if (buildvfs_mkdir(cwd,S_IRWXU) == 0) asperr = addsearchpath(cwd);
385 else asperr = -1;
386 }
387 if (asperr == 0)
388 buildvfs_chdir(cwd);
389 Xfree(homedir);
390 }
391 }
392
393 SW_AddMusicFolder();
394
395 #ifndef EDUKE32_STANDALONE
396 if (g_grpNamePtr == NULL)
397 {
398 const char *cp = getenv("SWGRP");
399 if (cp)
400 {
401 clearGrpNamePtr();
402 g_grpNamePtr = dup_filename(cp);
403 initprintf("Using \"%s\" as main GRP file\n", g_grpNamePtr);
404 }
405 }
406 #endif
407 }
408
409 struct grpfile const * g_selectedGrp;
410
SW_ScanGroups()411 void SW_ScanGroups()
412 {
413 ScanGroups();
414
415 g_selectedGrp = NULL;
416
417 char const * const currentGrp = G_GrpFile();
418
419 for (grpfile_t const *fg = foundgrps; fg; fg=fg->next)
420 {
421 if (!Bstrcasecmp(fg->filename, currentGrp))
422 {
423 g_selectedGrp = fg;
424 break;
425 }
426 }
427
428 if (g_selectedGrp == NULL)
429 g_selectedGrp = foundgrps;
430 }
431
SW_TryLoadingGrp(char const * const grpfile,internalgrpfile const * type=nullptr)432 static int32_t SW_TryLoadingGrp(char const * const grpfile, internalgrpfile const * type = nullptr)
433 {
434 int32_t i;
435
436 if ((i = initgroupfile(grpfile)) == -1)
437 initprintf("Warning: could not find main data file \"%s\"!\n", grpfile);
438 else
439 {
440 initprintf("Using \"%s\" as main game data file.\n", grpfile);
441 if (type && type->postprocessing)
442 type->postprocessing(i);
443 SW_GameFlags |= type->gameflags;
444 }
445
446 return i;
447 }
448
SW_LoadGrpDependencyChain(grpfile_t const * const grp)449 static int32_t SW_LoadGrpDependencyChain(grpfile_t const * const grp)
450 {
451 if (!grp)
452 return -1;
453
454 if ((grp->type->flags & GRP_HAS_DEPENDENCY) && grp->type->dependency != grp->type->crcval)
455 SW_LoadGrpDependencyChain(FindGroup(grp->type->dependency));
456
457 int32_t const i = SW_TryLoadingGrp(grp->filename, grp->type);
458
459 return i;
460 }
461
462 int g_addonNum = -1;
463
SW_LoadGroups()464 void SW_LoadGroups()
465 {
466 if (g_addonNum != -1)
467 SW_LoadAddon();
468
469 if (SW_LoadGrpDependencyChain(g_selectedGrp) != -1)
470 {
471 clearGrpNamePtr();
472 g_grpNamePtr = dup_filename(g_selectedGrp->filename);
473 }
474 else
475 {
476 SW_TryLoadingGrp(G_GrpFile());
477 }
478 }
479