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