2012-03-26 22:03:20 +00:00
|
|
|
//
|
|
|
|
// Common non-engine code/data for EDuke32 and Mapster32
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "compat.h"
|
2012-06-03 16:09:33 +00:00
|
|
|
#include "build.h"
|
2014-08-31 11:15:23 +00:00
|
|
|
#include "baselayer.h"
|
2016-06-21 00:33:06 +00:00
|
|
|
#include "palette.h"
|
2014-07-28 06:43:46 +00:00
|
|
|
|
2014-07-28 06:42:28 +00:00
|
|
|
#include "grpscan.h"
|
2012-03-26 22:03:20 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#include "vfs.h"
|
|
|
|
|
2013-03-21 09:48:21 +00:00
|
|
|
#ifdef _WIN32
|
2017-02-25 08:15:01 +00:00
|
|
|
# define NEED_SHLWAPI_H
|
|
|
|
# include "windows_inc.h"
|
2013-03-21 09:48:21 +00:00
|
|
|
# include "winbits.h"
|
2017-04-09 13:08:53 +00:00
|
|
|
# ifndef KEY_WOW64_64KEY
|
|
|
|
# define KEY_WOW64_64KEY 0x0100
|
|
|
|
# endif
|
2013-04-13 03:50:37 +00:00
|
|
|
# ifndef KEY_WOW64_32KEY
|
|
|
|
# define KEY_WOW64_32KEY 0x0200
|
|
|
|
# endif
|
2014-12-08 04:31:57 +00:00
|
|
|
#elif defined __APPLE__
|
|
|
|
# include "osxbits.h"
|
2013-03-21 09:48:21 +00:00
|
|
|
#endif
|
|
|
|
|
2012-03-26 22:03:20 +00:00
|
|
|
#include "common.h"
|
2012-06-03 16:09:33 +00:00
|
|
|
#include "common_game.h"
|
2012-03-26 22:03:20 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
struct grpfile_t const *g_selectedGrp;
|
|
|
|
|
2012-06-27 17:45:52 +00:00
|
|
|
int32_t g_gameType = GAMEFLAG_DUKE;
|
2016-08-27 01:41:33 +00:00
|
|
|
int g_addonNum = 0;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
|
|
|
// g_gameNamePtr can point to one of: grpfiles[].name (string literal), string
|
|
|
|
// literal, malloc'd block (XXX: possible leak)
|
|
|
|
const char *g_gameNamePtr = NULL;
|
|
|
|
|
2014-07-28 06:43:46 +00:00
|
|
|
// grp/con handling
|
2012-06-03 16:09:33 +00:00
|
|
|
|
2017-01-18 22:21:08 +00:00
|
|
|
static const char *defaultconfilename = "GAME.CON";
|
|
|
|
#ifndef EDUKE32_STANDALONE
|
2016-08-27 01:41:33 +00:00
|
|
|
static const char *defaultgamegrp[GAMECOUNT] = { "DUKE3D.GRP", "NAM.GRP", "NAPALM.GRP", "WW2GI.GRP" };
|
|
|
|
static const char *defaultdeffilename[GAMECOUNT] = { "duke3d.def", "nam.def", "napalm.def", "ww2gi.def" };
|
2014-12-02 06:15:49 +00:00
|
|
|
static const char *defaultgameconfilename[GAMECOUNT] = { "EDUKE.CON", "NAM.CON", "NAPALM.CON", "WW2GI.CON" };
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2012-06-03 16:09:33 +00:00
|
|
|
|
|
|
|
// g_grpNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
|
|
|
|
char *g_grpNamePtr = NULL;
|
|
|
|
// g_scriptNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
|
|
|
|
char *g_scriptNamePtr = NULL;
|
2018-02-11 05:03:55 +00:00
|
|
|
// g_rtsNamePtr can ONLY point to a malloc'd block (length BMAX_PATH)
|
|
|
|
char *g_rtsNamePtr = NULL;
|
2012-06-03 16:09:33 +00:00
|
|
|
|
|
|
|
void clearGrpNamePtr(void)
|
|
|
|
{
|
2015-09-23 17:55:31 +00:00
|
|
|
Bfree(g_grpNamePtr);
|
2012-06-03 16:09:33 +00:00
|
|
|
// g_grpNamePtr assumed to be assigned to right after
|
|
|
|
}
|
|
|
|
|
|
|
|
void clearScriptNamePtr(void)
|
|
|
|
{
|
2015-09-23 17:55:31 +00:00
|
|
|
Bfree(g_scriptNamePtr);
|
2012-06-03 16:09:33 +00:00
|
|
|
// g_scriptNamePtr assumed to be assigned to right after
|
|
|
|
}
|
|
|
|
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_DefaultGrpFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2012-06-03 16:09:33 +00:00
|
|
|
if (DUKE)
|
|
|
|
return defaultgamegrp[GAME_DUKE];
|
|
|
|
else if (NAPALM)
|
|
|
|
return defaultgamegrp[GAME_NAPALM];
|
|
|
|
else if (WW2GI)
|
|
|
|
return defaultgamegrp[GAME_WW2GI];
|
|
|
|
else if (NAM)
|
|
|
|
return defaultgamegrp[GAME_NAM];
|
|
|
|
|
|
|
|
return defaultgamegrp[0];
|
2017-01-18 22:21:08 +00:00
|
|
|
#else
|
|
|
|
return "(none)";
|
|
|
|
#endif
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_DefaultDefFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2012-06-03 16:09:33 +00:00
|
|
|
if (DUKE)
|
|
|
|
return defaultdeffilename[GAME_DUKE];
|
|
|
|
else if (WW2GI)
|
|
|
|
return defaultdeffilename[GAME_WW2GI];
|
|
|
|
else if (NAPALM)
|
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (!testkopen(defaultdeffilename[GAME_NAPALM],0) && testkopen(defaultdeffilename[GAME_NAM],0))
|
2013-03-28 09:05:18 +00:00
|
|
|
return defaultdeffilename[GAME_NAM]; // NAM/NAPALM Sharing
|
2012-06-03 16:09:33 +00:00
|
|
|
else
|
|
|
|
return defaultdeffilename[GAME_NAPALM];
|
|
|
|
}
|
|
|
|
else if (NAM)
|
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (!testkopen(defaultdeffilename[GAME_NAM],0) && testkopen(defaultdeffilename[GAME_NAPALM],0))
|
2013-03-28 09:05:18 +00:00
|
|
|
return defaultdeffilename[GAME_NAPALM]; // NAM/NAPALM Sharing
|
2012-06-03 16:09:33 +00:00
|
|
|
else
|
|
|
|
return defaultdeffilename[GAME_NAM];
|
|
|
|
}
|
|
|
|
|
|
|
|
return defaultdeffilename[0];
|
2017-01-18 22:21:08 +00:00
|
|
|
#else
|
|
|
|
return "(none)";
|
|
|
|
#endif
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_DefaultConFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2012-06-11 20:35:47 +00:00
|
|
|
if (DUKE && testkopen(defaultgameconfilename[GAME_DUKE],0))
|
2012-06-03 16:09:33 +00:00
|
|
|
return defaultgameconfilename[GAME_DUKE];
|
2012-06-11 20:35:47 +00:00
|
|
|
else if (WW2GI && testkopen(defaultgameconfilename[GAME_WW2GI],0))
|
2012-06-03 16:09:33 +00:00
|
|
|
return defaultgameconfilename[GAME_WW2GI];
|
|
|
|
else if (NAPALM)
|
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (!testkopen(defaultgameconfilename[GAME_NAPALM],0))
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (testkopen(defaultgameconfilename[GAME_NAM],0))
|
2013-03-28 09:05:18 +00:00
|
|
|
return defaultgameconfilename[GAME_NAM]; // NAM/NAPALM Sharing
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return defaultgameconfilename[GAME_NAPALM];
|
|
|
|
}
|
|
|
|
else if (NAM)
|
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (!testkopen(defaultgameconfilename[GAME_NAM],0))
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2012-06-11 20:35:47 +00:00
|
|
|
if (testkopen(defaultgameconfilename[GAME_NAPALM],0))
|
2013-03-28 09:05:18 +00:00
|
|
|
return defaultgameconfilename[GAME_NAPALM]; // NAM/NAPALM Sharing
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return defaultgameconfilename[GAME_NAM];
|
|
|
|
}
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2012-06-03 16:09:33 +00:00
|
|
|
return defaultconfilename;
|
|
|
|
}
|
|
|
|
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_GrpFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
return (g_grpNamePtr == NULL) ? G_DefaultGrpFile() : g_grpNamePtr;
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
2013-04-08 18:30:39 +00:00
|
|
|
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_DefFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
return (g_defNamePtr == NULL) ? G_DefaultDefFile() : g_defNamePtr;
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
2013-04-08 18:30:39 +00:00
|
|
|
|
2012-07-01 22:11:33 +00:00
|
|
|
const char *G_ConFile(void)
|
2012-06-03 16:09:33 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
return (g_scriptNamePtr == NULL) ? G_DefaultConFile() : g_scriptNamePtr;
|
2012-06-03 16:09:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////
|
2012-03-26 22:03:20 +00:00
|
|
|
|
2013-08-04 20:37:45 +00:00
|
|
|
// Set up new-style multi-psky handling.
|
2016-08-27 01:41:33 +00:00
|
|
|
void G_InitMultiPsky(int CLOUDYOCEAN__DYN, int MOONSKY1__DYN, int BIGORBIT1__DYN, int LA__DYN)
|
2012-11-25 04:25:31 +00:00
|
|
|
{
|
2013-08-04 20:37:45 +00:00
|
|
|
// When adding other multi-skies, take care that the tileofs[] values are
|
|
|
|
// <= PSKYOFF_MAX. (It can be increased up to MAXPSKYTILES, but should be
|
|
|
|
// set as tight as possible.)
|
2012-11-25 04:25:31 +00:00
|
|
|
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
// The default sky properties (all others are implicitly zero):
|
2018-04-12 21:03:47 +00:00
|
|
|
psky_t *sky = tileSetupSky(DEFAULTPSKY);
|
2016-08-27 01:41:33 +00:00
|
|
|
sky->lognumtiles = 3;
|
|
|
|
sky->horizfrac = 32768;
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
|
|
|
|
// CLOUDYOCEAN
|
|
|
|
// Aligns with the drawn scene horizon because it has one itself.
|
2018-04-12 21:03:47 +00:00
|
|
|
sky = tileSetupSky(CLOUDYOCEAN__DYN);
|
2016-08-27 01:41:33 +00:00
|
|
|
sky->lognumtiles = 3;
|
|
|
|
sky->horizfrac = 65536;
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
|
2012-11-25 04:25:31 +00:00
|
|
|
// MOONSKY1
|
|
|
|
// earth mountain mountain sun
|
2018-04-12 21:03:47 +00:00
|
|
|
sky = tileSetupSky(MOONSKY1__DYN);
|
2016-08-27 01:41:33 +00:00
|
|
|
sky->lognumtiles = 3;
|
|
|
|
sky->horizfrac = 32768;
|
|
|
|
sky->tileofs[6] = 1;
|
|
|
|
sky->tileofs[1] = 2;
|
|
|
|
sky->tileofs[4] = 2;
|
|
|
|
sky->tileofs[2] = 3;
|
2012-11-25 04:25:31 +00:00
|
|
|
|
|
|
|
// BIGORBIT1 // orbit
|
|
|
|
// earth1 2 3 moon/sun
|
2018-04-12 21:03:47 +00:00
|
|
|
sky = tileSetupSky(BIGORBIT1__DYN);
|
2016-08-27 01:41:33 +00:00
|
|
|
sky->lognumtiles = 3;
|
|
|
|
sky->horizfrac = 32768;
|
|
|
|
sky->tileofs[5] = 1;
|
|
|
|
sky->tileofs[6] = 2;
|
|
|
|
sky->tileofs[7] = 3;
|
|
|
|
sky->tileofs[2] = 4;
|
2012-11-25 04:25:31 +00:00
|
|
|
|
|
|
|
// LA // la city
|
|
|
|
// earth1 2 3 moon/sun
|
2018-04-12 21:03:47 +00:00
|
|
|
sky = tileSetupSky(LA__DYN);
|
2016-08-27 01:41:33 +00:00
|
|
|
sky->lognumtiles = 3;
|
|
|
|
sky->horizfrac = 16384 + 1024;
|
|
|
|
sky->tileofs[0] = 1;
|
|
|
|
sky->tileofs[1] = 2;
|
|
|
|
sky->tileofs[2] = 1;
|
|
|
|
sky->tileofs[3] = 3;
|
|
|
|
sky->tileofs[4] = 4;
|
|
|
|
sky->tileofs[5] = 0;
|
|
|
|
sky->tileofs[6] = 2;
|
|
|
|
sky->tileofs[7] = 3;
|
2013-08-04 20:37:45 +00:00
|
|
|
|
2015-05-27 08:47:34 +00:00
|
|
|
#if 0
|
|
|
|
// This assertion should hold. See note above.
|
2016-08-27 01:41:21 +00:00
|
|
|
for (bssize_t i=0; i<pskynummultis; ++i)
|
|
|
|
for (bssize_t j=0; j<(1<<multipsky[i].lognumtiles); ++j)
|
2013-08-04 20:37:45 +00:00
|
|
|
Bassert(multipsky[i].tileofs[j] <= PSKYOFF_MAX);
|
2015-05-27 08:47:34 +00:00
|
|
|
#endif
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void G_SetupGlobalPsky(void)
|
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
int skyIdx = 0;
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
|
|
|
|
// NOTE: Loop must be running backwards for the same behavior as the game
|
|
|
|
// (greatest sector index with matching parallaxed sky takes precedence).
|
2018-11-18 18:08:14 +00:00
|
|
|
for (int i = numsectors - 1; i >= 0; i--)
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
{
|
|
|
|
if (sector[i].ceilingstat & 1)
|
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
skyIdx = getpskyidx(sector[i].ceilingpicnum);
|
|
|
|
if (skyIdx > 0)
|
Clean up parallaxed sky functionality, part 2.
- Rename sky_t members: yscale -> horizfrac, bits -> lognumtiles.
- Add default sky (8 tiles, horizfrac=32768 (i.e. 1/2 the scene horiz), offsets
all zero) and CLOUDYOCEAN sky (8 tiles, horizfrac=65536, offsets all zero)
to multipsky[].
- Get rid of "psky_t g_psky", merely maintaining a g_pskyidx instead. Set it up
at map load time so as to keep the behavior of the legacy per-map psky:
the last sector index with a matching psky ceiling wins.
- In mapstate_t, save g_pskyidx too, not (former) pskybits and pskyoffs[].
- Make on-map-load global psky setup consistent for the game and editor by
factoring it out into common.c: G_SetupGlobalPsky().
- Remove a couple of useless initializations, add some static assertions.
This commit is more likely to introduce subtle differences in behavior.
Specifically, getpsky() now always returns the default sky properties instead of
the global sky ones (but with all-zero offsets) when no match for a suiting
multi-psky is found. This is only likely to affect the yscale/horizfrac of
non-multi-pskies when a global non-default multi-psky has been set up.
Bump BYTEVERSION again.
git-svn-id: https://svn.eduke32.com/eduke32@3976 1a8010ca-5511-0410-912e-c29ae57300e0
2013-08-04 20:37:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-11-25 04:25:31 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
g_pskyidx = skyIdx;
|
2012-11-25 04:25:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//////////
|
|
|
|
|
2014-07-28 06:42:28 +00:00
|
|
|
static char g_rootDir[BMAX_PATH];
|
|
|
|
char g_modDir[BMAX_PATH] = "/";
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd kopen4loadfrommod(const char *fileName, char searchfirst)
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd kFile = buildvfs_kfd_invalid;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
if (g_modDir[0] != '/' || g_modDir[1] != 0)
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
static char staticFileName[BMAX_PATH];
|
|
|
|
Bsnprintf(staticFileName, sizeof(staticFileName), "%s/%s", g_modDir, fileName);
|
|
|
|
kFile = kopen4load(staticFileName, searchfirst);
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
return (kFile == buildvfs_kfd_invalid) ? kopen4load(fileName, searchfirst) : kFile;
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
int g_useCwd;
|
2014-07-28 06:42:28 +00:00
|
|
|
static void G_LoadAddon(void);
|
|
|
|
int32_t g_groupFileHandle;
|
|
|
|
|
2016-01-12 10:30:56 +00:00
|
|
|
void G_ExtPreInit(int32_t argc,char const * const * argv)
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2016-08-27 01:41:33 +00:00
|
|
|
g_useCwd = G_CheckCmdSwitch(argc, argv, "-usecwd");
|
2014-07-28 06:42:28 +00:00
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
GetModuleFileName(NULL,g_rootDir,BMAX_PATH);
|
|
|
|
Bcorrectfilename(g_rootDir,1);
|
2019-03-01 08:51:50 +00:00
|
|
|
//buildvfs_chdir(g_rootDir);
|
2014-07-28 06:42:28 +00:00
|
|
|
#else
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_getcwd(g_rootDir,BMAX_PATH);
|
2014-07-28 06:42:28 +00:00
|
|
|
strcat(g_rootDir,"/");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void G_ExtInit(void)
|
|
|
|
{
|
|
|
|
char cwd[BMAX_PATH];
|
|
|
|
|
2015-02-14 07:26:10 +00:00
|
|
|
#ifdef EDUKE32_OSX
|
2014-12-08 04:31:57 +00:00
|
|
|
char *appdir = Bgetappdir();
|
|
|
|
addsearchpath(appdir);
|
|
|
|
Bfree(appdir);
|
2014-07-28 06:42:28 +00:00
|
|
|
#endif
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#ifdef USE_PHYSFS
|
|
|
|
strncpy(cwd, PHYSFS_getBaseDir(), ARRAY_SIZE(cwd));
|
|
|
|
cwd[ARRAY_SIZE(cwd)-1] = '\0';
|
|
|
|
#else
|
|
|
|
if (buildvfs_getcwd(cwd, ARRAY_SIZE(cwd)) && Bstrcmp(cwd, "/") != 0)
|
|
|
|
#endif
|
2014-07-28 06:42:28 +00:00
|
|
|
addsearchpath(cwd);
|
|
|
|
|
|
|
|
if (CommandPaths)
|
|
|
|
{
|
|
|
|
int32_t i;
|
|
|
|
struct strllist *s;
|
|
|
|
while (CommandPaths)
|
|
|
|
{
|
|
|
|
s = CommandPaths->next;
|
|
|
|
i = addsearchpath(CommandPaths->str);
|
|
|
|
if (i < 0)
|
|
|
|
{
|
|
|
|
initprintf("Failed adding %s for game data: %s\n", CommandPaths->str,
|
|
|
|
i==-1 ? "not a directory" : "no such directory");
|
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(CommandPaths->str);
|
|
|
|
Bfree(CommandPaths);
|
|
|
|
CommandPaths = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 04:21:46 +00:00
|
|
|
#if defined(_WIN32) && !defined(EDUKE32_STANDALONE)
|
2019-03-02 23:52:50 +00:00
|
|
|
if (buildvfs_exists("user_profiles_enabled"))
|
2014-07-28 06:42:28 +00:00
|
|
|
#else
|
2019-03-01 08:51:50 +00:00
|
|
|
if (g_useCwd == 0 && !buildvfs_exists("user_profiles_disabled"))
|
2013-03-21 09:49:12 +00:00
|
|
|
#endif
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
|
|
|
char *homedir;
|
|
|
|
int32_t asperr;
|
|
|
|
|
|
|
|
if ((homedir = Bgethomedir()))
|
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
Bsnprintf(cwd, ARRAY_SIZE(cwd), "%s/"
|
2014-07-28 06:42:28 +00:00
|
|
|
#if defined(_WIN32)
|
2018-03-08 03:55:52 +00:00
|
|
|
APPNAME
|
2014-07-28 06:42:28 +00:00
|
|
|
#elif defined(GEKKO)
|
2018-03-07 04:21:37 +00:00
|
|
|
"apps/" APPBASENAME
|
2014-07-28 06:42:28 +00:00
|
|
|
#else
|
2018-03-07 04:21:41 +00:00
|
|
|
".config/" APPBASENAME
|
2014-07-28 06:42:28 +00:00
|
|
|
#endif
|
|
|
|
,homedir);
|
|
|
|
asperr = addsearchpath(cwd);
|
|
|
|
if (asperr == -2)
|
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
if (buildvfs_mkdir(cwd,S_IRWXU) == 0) asperr = addsearchpath(cwd);
|
2014-07-28 06:42:28 +00:00
|
|
|
else asperr = -1;
|
|
|
|
}
|
|
|
|
if (asperr == 0)
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_chdir(cwd);
|
2014-07-28 06:42:28 +00:00
|
|
|
Bfree(homedir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// JBF 20031220: Because it's annoying renaming GRP files whenever I want to test different game data
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2014-07-28 06:42:28 +00:00
|
|
|
if (g_grpNamePtr == NULL)
|
|
|
|
{
|
|
|
|
const char *cp = getenv("DUKE3DGRP");
|
|
|
|
if (cp)
|
|
|
|
{
|
|
|
|
clearGrpNamePtr();
|
|
|
|
g_grpNamePtr = dup_filename(cp);
|
|
|
|
initprintf("Using \"%s\" as main GRP file\n", g_grpNamePtr);
|
|
|
|
}
|
|
|
|
}
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
void G_ScanGroups(void)
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
|
|
|
ScanGroups();
|
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
g_selectedGrp = NULL;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
char const * const currentGrp = G_GrpFile();
|
2015-02-11 05:22:19 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
for (grpfile_t const *fg = foundgrps; fg; fg=fg->next)
|
2015-02-11 05:22:19 +00:00
|
|
|
{
|
2015-03-27 12:30:35 +00:00
|
|
|
if (!Bstrcasecmp(fg->filename, currentGrp))
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2015-03-27 12:30:35 +00:00
|
|
|
g_selectedGrp = fg;
|
|
|
|
break;
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
}
|
2017-01-18 22:21:31 +00:00
|
|
|
|
|
|
|
if (g_selectedGrp == NULL)
|
|
|
|
g_selectedGrp = foundgrps;
|
2015-03-27 12:30:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t G_TryLoadingGrp(char const * const grpfile)
|
|
|
|
{
|
|
|
|
int32_t i;
|
|
|
|
|
|
|
|
if ((i = initgroupfile(grpfile)) == -1)
|
|
|
|
initprintf("Warning: could not find main data file \"%s\"!\n", grpfile);
|
|
|
|
else
|
|
|
|
initprintf("Using \"%s\" as main game data file.\n", grpfile);
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32_t G_LoadGrpDependencyChain(grpfile_t const * const grp)
|
|
|
|
{
|
|
|
|
if (!grp)
|
|
|
|
return -1;
|
|
|
|
|
2015-07-08 03:34:13 +00:00
|
|
|
if (grp->type->dependency && grp->type->dependency != grp->type->crcval)
|
2015-03-27 12:30:35 +00:00
|
|
|
G_LoadGrpDependencyChain(FindGroup(grp->type->dependency));
|
|
|
|
|
|
|
|
int32_t const i = G_TryLoadingGrp(grp->filename);
|
|
|
|
|
|
|
|
if (grp->type->postprocessing)
|
2017-10-30 03:48:28 +00:00
|
|
|
grp->type->postprocessing(i);
|
2015-03-27 12:30:35 +00:00
|
|
|
|
|
|
|
return i;
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
2013-03-21 09:49:12 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
void G_LoadGroups(int32_t autoload)
|
2013-03-21 09:49:12 +00:00
|
|
|
{
|
2014-07-28 06:42:28 +00:00
|
|
|
if (g_modDir[0] != '/')
|
|
|
|
{
|
|
|
|
char cwd[BMAX_PATH];
|
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
Bstrcat(g_rootDir, g_modDir);
|
2014-07-28 06:42:28 +00:00
|
|
|
addsearchpath(g_rootDir);
|
2015-02-11 05:22:19 +00:00
|
|
|
// addsearchpath(mod_dir);
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2018-09-06 19:06:55 +00:00
|
|
|
char path[BMAX_PATH];
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
if (buildvfs_getcwd(cwd, BMAX_PATH))
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2018-09-06 19:06:55 +00:00
|
|
|
Bsnprintf(path, sizeof(path), "%s/%s", cwd, g_modDir);
|
|
|
|
if (!Bstrcmp(g_rootDir, path))
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
2018-09-06 19:06:55 +00:00
|
|
|
if (addsearchpath(path) == -2)
|
2019-03-01 08:51:50 +00:00
|
|
|
if (buildvfs_mkdir(path, S_IRWXU) == 0)
|
2018-09-06 19:06:55 +00:00
|
|
|
addsearchpath(path);
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
if (g_addonNum)
|
2014-07-28 06:42:28 +00:00
|
|
|
G_LoadAddon();
|
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
const char *grpfile;
|
2015-02-11 05:22:19 +00:00
|
|
|
int32_t i;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
if ((i = G_LoadGrpDependencyChain(g_selectedGrp)) != -1)
|
2015-02-11 05:22:19 +00:00
|
|
|
{
|
2015-03-27 12:30:35 +00:00
|
|
|
grpfile = g_selectedGrp->filename;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
clearGrpNamePtr();
|
|
|
|
g_grpNamePtr = dup_filename(grpfile);
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
grpinfo_t const * const type = g_selectedGrp->type;
|
|
|
|
|
|
|
|
g_gameType = type->game;
|
|
|
|
g_gameNamePtr = type->name;
|
|
|
|
|
|
|
|
if (type->scriptname && g_scriptNamePtr == NULL)
|
|
|
|
g_scriptNamePtr = dup_filename(type->scriptname);
|
|
|
|
|
|
|
|
if (type->defname && g_defNamePtr == NULL)
|
|
|
|
g_defNamePtr = dup_filename(type->defname);
|
2018-02-11 05:03:55 +00:00
|
|
|
|
|
|
|
if (type->rtsname && g_rtsNamePtr == NULL)
|
|
|
|
g_rtsNamePtr = dup_filename(type->rtsname);
|
2015-03-27 12:30:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
grpfile = G_GrpFile();
|
|
|
|
i = G_TryLoadingGrp(grpfile);
|
|
|
|
}
|
2015-03-23 06:28:27 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
if (autoload)
|
|
|
|
{
|
|
|
|
G_LoadGroupsInDir("autoload");
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
if (i != -1)
|
|
|
|
G_DoAutoload(grpfile);
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (g_modDir[0] != '/')
|
|
|
|
G_LoadGroupsInDir(g_modDir);
|
|
|
|
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2014-07-28 06:42:28 +00:00
|
|
|
if (g_defNamePtr == NULL)
|
|
|
|
{
|
|
|
|
const char *tmpptr = getenv("DUKE3DDEF");
|
|
|
|
if (tmpptr)
|
|
|
|
{
|
|
|
|
clearDefNamePtr();
|
|
|
|
g_defNamePtr = dup_filename(tmpptr);
|
|
|
|
initprintf("Using \"%s\" as definitions file\n", g_defNamePtr);
|
|
|
|
}
|
|
|
|
}
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2014-07-28 06:42:28 +00:00
|
|
|
|
|
|
|
loaddefinitions_game(G_DefFile(), TRUE);
|
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
struct strllist *s;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-07-08 03:34:16 +00:00
|
|
|
int const bakpathsearchmode = pathsearchmode;
|
2015-02-11 05:22:19 +00:00
|
|
|
pathsearchmode = 1;
|
2015-07-08 03:34:16 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
while (CommandGrps)
|
|
|
|
{
|
|
|
|
int32_t j;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
s = CommandGrps->next;
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-02-11 05:22:19 +00:00
|
|
|
if ((j = initgroupfile(CommandGrps->str)) == -1)
|
|
|
|
initprintf("Could not find file \"%s\".\n", CommandGrps->str);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_groupFileHandle = j;
|
|
|
|
initprintf("Using file \"%s\" as game data.\n", CommandGrps->str);
|
|
|
|
if (autoload)
|
|
|
|
G_DoAutoload(CommandGrps->str);
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
2015-02-11 05:22:19 +00:00
|
|
|
|
|
|
|
Bfree(CommandGrps->str);
|
|
|
|
Bfree(CommandGrps);
|
|
|
|
CommandGrps = s;
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
2015-07-08 03:34:16 +00:00
|
|
|
pathsearchmode = bakpathsearchmode;
|
2013-03-21 09:49:12 +00:00
|
|
|
}
|
|
|
|
|
2017-06-17 11:42:20 +00:00
|
|
|
#if defined _WIN32 && !defined EDUKE32_STANDALONE
|
2015-11-25 12:08:14 +00:00
|
|
|
static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize)
|
2013-03-28 23:35:52 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
// KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
|
2017-04-09 13:08:53 +00:00
|
|
|
REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY };
|
|
|
|
|
2018-10-25 23:33:40 +00:00
|
|
|
for (auto &wow64key : wow64keys)
|
2017-04-09 13:08:53 +00:00
|
|
|
{
|
|
|
|
HKEY hkey;
|
2018-10-25 23:33:40 +00:00
|
|
|
LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey);
|
2013-03-28 23:35:52 +00:00
|
|
|
|
2017-04-09 13:08:53 +00:00
|
|
|
if (keygood != ERROR_SUCCESS)
|
|
|
|
continue;
|
2013-11-03 04:02:01 +00:00
|
|
|
|
2017-04-09 13:08:53 +00:00
|
|
|
LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize);
|
2013-03-28 23:35:52 +00:00
|
|
|
|
2017-04-09 13:08:53 +00:00
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
if (retval == ERROR_SUCCESS)
|
|
|
|
return 1;
|
|
|
|
}
|
2013-03-28 23:35:52 +00:00
|
|
|
|
2017-04-09 13:08:53 +00:00
|
|
|
return 0;
|
2013-03-28 23:35:52 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-28 06:42:28 +00:00
|
|
|
static void G_LoadAddon(void)
|
|
|
|
{
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2014-07-28 06:42:28 +00:00
|
|
|
int32_t crc = 0; // compiler-happy
|
|
|
|
|
2016-08-27 01:41:33 +00:00
|
|
|
switch (g_addonNum)
|
2014-07-28 06:42:28 +00:00
|
|
|
{
|
|
|
|
case ADDON_DUKEDC:
|
|
|
|
crc = DUKEDC_CRC;
|
|
|
|
break;
|
|
|
|
case ADDON_NWINTER:
|
|
|
|
crc = DUKENW_CRC;
|
|
|
|
break;
|
|
|
|
case ADDON_CARIBBEAN:
|
|
|
|
crc = DUKECB_CRC;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!crc) return;
|
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
grpfile_t const * const grp = FindGroup(crc);
|
2014-07-28 06:42:28 +00:00
|
|
|
|
2015-03-27 12:30:35 +00:00
|
|
|
if (grp)
|
|
|
|
g_selectedGrp = grp;
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2014-07-28 06:42:28 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2016-03-14 00:07:28 +00:00
|
|
|
#ifndef EDUKE32_TOUCH_DEVICES
|
2015-03-02 07:54:24 +00:00
|
|
|
#if defined EDUKE32_OSX || defined __linux__ || defined EDUKE32_BSD
|
2014-12-08 10:26:32 +00:00
|
|
|
static void G_AddSteamPaths(const char *basepath)
|
2014-12-08 04:31:57 +00:00
|
|
|
{
|
|
|
|
char buf[BMAX_PATH];
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D: Megaton Edition (Steam)
|
2014-12-08 04:31:57 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot", basepath);
|
2015-11-28 09:06:25 +00:00
|
|
|
addsearchpath(buf);
|
2014-12-08 04:31:57 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/dc", basepath);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2014-12-08 04:31:57 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/nw", basepath);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2014-12-08 04:31:57 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/gameroot/addons/vacation", basepath);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2015-01-08 15:15:10 +00:00
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
|
2015-05-13 08:57:11 +00:00
|
|
|
#if defined EDUKE32_OSX
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Duke Nukem 3D/Duke Nukem 3D.app/drive_c/Program Files/Duke Nukem 3D", basepath);
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
|
|
|
#endif
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// NAM (Steam)
|
2015-02-14 07:26:10 +00:00
|
|
|
#if defined EDUKE32_OSX
|
2014-12-08 04:31:57 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/Nam.app/Contents/Resources/Nam.boxer/C.harddisk/NAM", basepath);
|
2014-12-08 10:26:32 +00:00
|
|
|
#else
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/Nam/NAM", basepath);
|
|
|
|
#endif
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_NAM);
|
2015-11-25 12:08:37 +00:00
|
|
|
|
|
|
|
// WWII GI (Steam)
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/steamapps/common/World War II GI/WW2GI", basepath);
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_WW2GI);
|
2014-12-08 04:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// A bare-bones "parser" for Valve's KeyValues VDF format.
|
|
|
|
// There is no guarantee this will function properly with ill-formed files.
|
|
|
|
static void KeyValues_SkipWhitespace(char **vdfbuf, char * const vdfbufend)
|
|
|
|
{
|
|
|
|
while (((*vdfbuf)[0] == ' ' || (*vdfbuf)[0] == '\n' || (*vdfbuf)[0] == '\r' || (*vdfbuf)[0] == '\t' || (*vdfbuf)[0] == '\0') && *vdfbuf < vdfbufend)
|
|
|
|
(*vdfbuf)++;
|
|
|
|
|
|
|
|
// comments
|
|
|
|
if ((*vdfbuf) + 2 < vdfbufend && (*vdfbuf)[0] == '/' && (*vdfbuf)[1] == '/')
|
|
|
|
{
|
|
|
|
while ((*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && *vdfbuf < vdfbufend)
|
|
|
|
(*vdfbuf)++;
|
|
|
|
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void KeyValues_SkipToEndOfQuotedToken(char **vdfbuf, char * const vdfbufend)
|
|
|
|
{
|
|
|
|
(*vdfbuf)++;
|
|
|
|
while ((*vdfbuf)[0] != '\"' && (*vdfbuf)[-1] != '\\' && *vdfbuf < vdfbufend)
|
|
|
|
(*vdfbuf)++;
|
|
|
|
}
|
|
|
|
static void KeyValues_SkipToEndOfUnquotedToken(char **vdfbuf, char * const vdfbufend)
|
|
|
|
{
|
|
|
|
while ((*vdfbuf)[0] != ' ' && (*vdfbuf)[0] != '\n' && (*vdfbuf)[0] != '\r' && (*vdfbuf)[0] != '\t' && (*vdfbuf)[0] != '\0' && *vdfbuf < vdfbufend)
|
|
|
|
(*vdfbuf)++;
|
|
|
|
}
|
|
|
|
static void KeyValues_SkipNextWhatever(char **vdfbuf, char * const vdfbufend)
|
|
|
|
{
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
|
|
|
|
if (*vdfbuf == vdfbufend)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ((*vdfbuf)[0] == '{')
|
|
|
|
{
|
|
|
|
(*vdfbuf)++;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
while ((*vdfbuf)[0] != '}');
|
|
|
|
(*vdfbuf)++;
|
|
|
|
}
|
|
|
|
else if ((*vdfbuf)[0] == '\"')
|
|
|
|
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
|
|
|
|
else if ((*vdfbuf)[0] != '}')
|
|
|
|
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
|
|
|
|
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
static char* KeyValues_NormalizeToken(char **vdfbuf, char * const vdfbufend)
|
|
|
|
{
|
|
|
|
char *token = *vdfbuf;
|
|
|
|
|
|
|
|
if ((*vdfbuf)[0] == '\"' && *vdfbuf < vdfbufend)
|
|
|
|
{
|
|
|
|
token++;
|
|
|
|
|
|
|
|
KeyValues_SkipToEndOfQuotedToken(vdfbuf, vdfbufend);
|
|
|
|
(*vdfbuf)[0] = '\0';
|
|
|
|
|
|
|
|
// account for escape sequences
|
|
|
|
char *writeseeker = token, *readseeker = token;
|
|
|
|
while (readseeker <= *vdfbuf)
|
|
|
|
{
|
|
|
|
if (readseeker[0] == '\\')
|
|
|
|
readseeker++;
|
|
|
|
|
|
|
|
writeseeker[0] = readseeker[0];
|
|
|
|
|
|
|
|
writeseeker++;
|
|
|
|
readseeker++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeyValues_SkipToEndOfUnquotedToken(vdfbuf, vdfbufend);
|
|
|
|
(*vdfbuf)[0] = '\0';
|
|
|
|
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
static void KeyValues_FindKey(char **vdfbuf, char * const vdfbufend, const char *token)
|
|
|
|
{
|
|
|
|
char *ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
|
|
|
if (token != NULL) // pass in NULL to find the next key instead of a specific one
|
|
|
|
while (Bstrcmp(ParentKey, token) != 0 && *vdfbuf < vdfbufend)
|
|
|
|
{
|
|
|
|
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
|
|
|
ParentKey = KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
static int32_t KeyValues_FindParentKey(char **vdfbuf, char * const vdfbufend, const char *token)
|
|
|
|
{
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
|
|
|
|
// end of scope
|
|
|
|
if ((*vdfbuf)[0] == '}')
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
|
|
|
|
|
|
|
// ignore the wrong type
|
|
|
|
while ((*vdfbuf)[0] != '{' && *vdfbuf < vdfbufend)
|
|
|
|
{
|
|
|
|
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
|
|
|
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*vdfbuf == vdfbufend)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
static char* KeyValues_FindKeyValue(char **vdfbuf, char * const vdfbufend, const char *token)
|
|
|
|
{
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
|
|
|
|
// end of scope
|
|
|
|
if ((*vdfbuf)[0] == '}')
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
|
|
|
|
|
|
|
// ignore the wrong type
|
|
|
|
while ((*vdfbuf)[0] == '{' && *vdfbuf < vdfbufend)
|
|
|
|
{
|
|
|
|
KeyValues_SkipNextWhatever(vdfbuf, vdfbufend);
|
|
|
|
KeyValues_FindKey(vdfbuf, vdfbufend, token);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeyValues_SkipWhitespace(vdfbuf, vdfbufend);
|
|
|
|
|
|
|
|
if (*vdfbuf == vdfbufend)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return KeyValues_NormalizeToken(vdfbuf, vdfbufend);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void G_ParseSteamKeyValuesForPaths(const char *vdf)
|
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_fd fd = buildvfs_open_read(vdf);
|
|
|
|
int32_t size = buildvfs_length(fd);
|
2014-12-08 04:31:57 +00:00
|
|
|
char *vdfbufstart, *vdfbuf, *vdfbufend;
|
|
|
|
|
|
|
|
if (size <= 0)
|
|
|
|
return;
|
|
|
|
|
2018-10-25 23:28:56 +00:00
|
|
|
vdfbufstart = vdfbuf = (char*)Xmalloc(size);
|
2019-03-01 08:51:50 +00:00
|
|
|
size = (int32_t)buildvfs_read(fd, vdfbuf, size);
|
|
|
|
buildvfs_close(fd);
|
2014-12-08 04:31:57 +00:00
|
|
|
vdfbufend = vdfbuf + size;
|
|
|
|
|
|
|
|
if (KeyValues_FindParentKey(&vdfbuf, vdfbufend, "LibraryFolders"))
|
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
vdfbuf++;
|
|
|
|
while ((result = KeyValues_FindKeyValue(&vdfbuf, vdfbufend, NULL)) != NULL)
|
2014-12-08 10:26:32 +00:00
|
|
|
G_AddSteamPaths(result);
|
2014-12-08 04:31:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bfree(vdfbufstart);
|
|
|
|
}
|
|
|
|
#endif
|
2016-03-14 00:07:28 +00:00
|
|
|
#endif
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2013-03-21 09:48:21 +00:00
|
|
|
void G_AddSearchPaths(void)
|
|
|
|
{
|
2017-01-18 22:21:08 +00:00
|
|
|
#ifndef EDUKE32_STANDALONE
|
2016-03-14 00:07:28 +00:00
|
|
|
#ifndef EDUKE32_TOUCH_DEVICES
|
2015-03-02 07:54:24 +00:00
|
|
|
#if defined __linux__ || defined EDUKE32_BSD
|
2014-12-08 10:26:32 +00:00
|
|
|
char buf[BMAX_PATH];
|
|
|
|
char *homepath = Bgethomedir();
|
|
|
|
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam", homepath);
|
|
|
|
G_AddSteamPaths(buf);
|
|
|
|
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/.steam/steam/steamapps/libraryfolders.vdf", homepath);
|
|
|
|
G_ParseSteamKeyValuesForPaths(buf);
|
|
|
|
|
|
|
|
Bfree(homepath);
|
|
|
|
|
2013-03-21 09:48:21 +00:00
|
|
|
addsearchpath("/usr/share/games/jfduke3d");
|
|
|
|
addsearchpath("/usr/local/share/games/jfduke3d");
|
|
|
|
addsearchpath("/usr/share/games/eduke32");
|
|
|
|
addsearchpath("/usr/local/share/games/eduke32");
|
2015-02-14 07:26:10 +00:00
|
|
|
#elif defined EDUKE32_OSX
|
2014-12-08 04:31:57 +00:00
|
|
|
char buf[BMAX_PATH];
|
2014-12-08 07:32:58 +00:00
|
|
|
int32_t i;
|
|
|
|
char *applications[] = { osx_getapplicationsdir(0), osx_getapplicationsdir(1) };
|
|
|
|
char *support[] = { osx_getsupportdir(0), osx_getsupportdir(1) };
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2014-12-08 07:32:58 +00:00
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/Steam", support[i]);
|
2014-12-08 10:26:32 +00:00
|
|
|
G_AddSteamPaths(buf);
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2014-12-08 07:32:58 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/Steam/steamapps/libraryfolders.vdf", support[i]);
|
|
|
|
G_ParseSteamKeyValuesForPaths(buf);
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D: Atomic Edition (GOG.com)
|
2014-12-08 07:32:58 +00:00
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/Duke Nukem 3D.app/Contents/Resources/Duke Nukem 3D.boxer/C.harddisk", applications[i]);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2014-12-08 07:32:58 +00:00
|
|
|
}
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2014-12-08 07:32:58 +00:00
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/JFDuke3D", support[i]);
|
|
|
|
addsearchpath(buf);
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/EDuke32", support[i]);
|
|
|
|
addsearchpath(buf);
|
|
|
|
}
|
2014-12-08 04:31:57 +00:00
|
|
|
|
2014-12-08 07:32:58 +00:00
|
|
|
for (i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
Bfree(applications[i]);
|
|
|
|
Bfree(support[i]);
|
|
|
|
}
|
2013-03-21 09:48:21 +00:00
|
|
|
#elif defined (_WIN32)
|
2015-11-25 12:08:14 +00:00
|
|
|
char buf[BMAX_PATH] = {0};
|
|
|
|
DWORD bufsize;
|
2013-03-27 01:39:18 +00:00
|
|
|
|
2017-04-09 13:09:01 +00:00
|
|
|
// Duke Nukem 3D: 20th Anniversary World Tour (Steam)
|
|
|
|
bufsize = sizeof(buf);
|
2018-10-16 06:08:36 +00:00
|
|
|
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize))
|
2017-04-09 13:09:01 +00:00
|
|
|
{
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D: Megaton Edition (Steam)
|
|
|
|
bufsize = sizeof(buf);
|
2018-10-16 06:08:36 +00:00
|
|
|
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize))
|
2013-03-27 01:39:18 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
2013-03-28 23:35:52 +00:00
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
Bstrncpy(suffix, "/gameroot", remaining);
|
2015-11-25 12:08:17 +00:00
|
|
|
addsearchpath(buf);
|
2015-11-25 12:08:14 +00:00
|
|
|
Bstrncpy(suffix, "/gameroot/addons/dc", remaining);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2015-11-25 12:08:14 +00:00
|
|
|
Bstrncpy(suffix, "/gameroot/addons/nw", remaining);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2015-11-25 12:08:14 +00:00
|
|
|
Bstrncpy(suffix, "/gameroot/addons/vacation", remaining);
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2013-03-27 01:39:18 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
|
|
|
|
bufsize = sizeof(buf);
|
2018-10-16 06:08:36 +00:00
|
|
|
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize))
|
2015-05-13 08:57:11 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
|
|
|
|
|
|
|
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
|
2015-05-13 08:57:11 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D: Atomic Edition (GOG.com)
|
|
|
|
bufsize = sizeof(buf);
|
|
|
|
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize))
|
|
|
|
{
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
|
|
|
}
|
2014-12-02 06:16:02 +00:00
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// Duke Nukem 3D (3D Realms Anthology)
|
|
|
|
bufsize = sizeof(buf);
|
|
|
|
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize))
|
2014-12-02 06:16:02 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
|
|
|
|
|
|
|
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2014-12-02 06:16:02 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// 3D Realms Anthology
|
|
|
|
bufsize = sizeof(buf);
|
|
|
|
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize))
|
2014-12-02 06:16:02 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
|
|
|
|
|
|
|
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_REMOVE);
|
2014-12-02 06:16:02 +00:00
|
|
|
}
|
|
|
|
|
2015-11-25 12:08:14 +00:00
|
|
|
// NAM (Steam)
|
|
|
|
bufsize = sizeof(buf);
|
2018-10-16 06:08:36 +00:00
|
|
|
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize))
|
2014-12-02 06:16:02 +00:00
|
|
|
{
|
2015-11-25 12:08:14 +00:00
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
|
|
|
|
|
|
|
Bstrncpy(suffix, "/NAM", remaining);
|
2015-01-08 15:14:47 +00:00
|
|
|
addsearchpath_user(buf, SEARCHPATH_NAM);
|
2014-12-02 06:16:02 +00:00
|
|
|
}
|
2015-11-25 12:08:37 +00:00
|
|
|
|
|
|
|
// WWII GI (Steam)
|
|
|
|
bufsize = sizeof(buf);
|
2018-10-16 06:08:36 +00:00
|
|
|
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize))
|
2015-11-25 12:08:37 +00:00
|
|
|
{
|
|
|
|
char * const suffix = buf + bufsize - 1;
|
|
|
|
DWORD const remaining = sizeof(buf) - bufsize;
|
|
|
|
|
|
|
|
Bstrncpy(suffix, "/WW2GI", remaining);
|
|
|
|
addsearchpath_user(buf, SEARCHPATH_WW2GI);
|
|
|
|
}
|
2013-03-21 09:48:21 +00:00
|
|
|
#endif
|
2016-03-14 00:07:28 +00:00
|
|
|
#endif
|
2017-01-18 22:21:08 +00:00
|
|
|
#endif
|
2013-03-21 09:48:21 +00:00
|
|
|
}
|
|
|
|
|
2013-04-08 18:30:39 +00:00
|
|
|
void G_CleanupSearchPaths(void)
|
|
|
|
{
|
2015-01-08 15:14:47 +00:00
|
|
|
removesearchpaths_withuser(SEARCHPATH_REMOVE);
|
2014-09-30 03:53:14 +00:00
|
|
|
|
2015-11-25 12:08:24 +00:00
|
|
|
if (!NAM)
|
2015-01-08 15:14:47 +00:00
|
|
|
removesearchpaths_withuser(SEARCHPATH_NAM);
|
2015-11-25 12:08:37 +00:00
|
|
|
|
|
|
|
if (!WW2GI)
|
|
|
|
removesearchpaths_withuser(SEARCHPATH_WW2GI);
|
2013-04-08 18:30:39 +00:00
|
|
|
}
|
|
|
|
|
2013-03-21 09:48:21 +00:00
|
|
|
//////////
|
|
|
|
|
2012-03-26 22:03:20 +00:00
|
|
|
struct strllist *CommandPaths, *CommandGrps;
|
|
|
|
|
2018-02-17 22:30:39 +00:00
|
|
|
GrowArray<char *> g_scriptModules;
|
2013-11-03 04:02:23 +00:00
|
|
|
|
2012-03-26 22:03:20 +00:00
|
|
|
void G_AddGroup(const char *buffer)
|
|
|
|
{
|
|
|
|
char buf[BMAX_PATH];
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
|
2012-03-26 22:03:20 +00:00
|
|
|
|
|
|
|
Bstrcpy(buf, buffer);
|
|
|
|
|
|
|
|
if (Bstrchr(buf,'.') == 0)
|
|
|
|
Bstrcat(buf,".grp");
|
|
|
|
|
2014-05-30 00:02:19 +00:00
|
|
|
s->str = Xstrdup(buf);
|
2012-03-26 22:03:20 +00:00
|
|
|
|
|
|
|
if (CommandGrps)
|
|
|
|
{
|
|
|
|
struct strllist *t;
|
|
|
|
for (t = CommandGrps; t->next; t=t->next) ;
|
|
|
|
t->next = s;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CommandGrps = s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void G_AddPath(const char *buffer)
|
|
|
|
{
|
2014-05-30 00:02:19 +00:00
|
|
|
struct strllist *s = (struct strllist *)Xcalloc(1,sizeof(struct strllist));
|
|
|
|
s->str = Xstrdup(buffer);
|
2012-03-26 22:03:20 +00:00
|
|
|
|
|
|
|
if (CommandPaths)
|
|
|
|
{
|
|
|
|
struct strllist *t;
|
|
|
|
for (t = CommandPaths; t->next; t=t->next) ;
|
|
|
|
t->next = s;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CommandPaths = s;
|
|
|
|
}
|
2012-03-26 22:05:23 +00:00
|
|
|
|
2013-11-03 04:02:23 +00:00
|
|
|
void G_AddCon(const char *buffer)
|
|
|
|
{
|
|
|
|
clearScriptNamePtr();
|
|
|
|
g_scriptNamePtr = dup_filename(buffer);
|
|
|
|
initprintf("Using CON file \"%s\".\n",g_scriptNamePtr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void G_AddConModule(const char *buffer)
|
|
|
|
{
|
2018-02-17 22:30:39 +00:00
|
|
|
g_scriptModules.append(Xstrdup(buffer));
|
2013-11-03 04:02:23 +00:00
|
|
|
}
|
|
|
|
|
2012-03-26 22:05:23 +00:00
|
|
|
//////////
|
|
|
|
|
2012-12-12 02:53:10 +00:00
|
|
|
// loads all group (grp, zip, pk3/4) files in the given directory
|
2012-03-28 19:41:57 +00:00
|
|
|
void G_LoadGroupsInDir(const char *dirname)
|
|
|
|
{
|
2016-03-14 00:07:55 +00:00
|
|
|
static const char *extensions[] = { "*.grp", "*.zip", "*.ssi", "*.pk3", "*.pk4" };
|
2012-03-28 19:41:57 +00:00
|
|
|
char buf[BMAX_PATH];
|
|
|
|
fnlist_t fnlist = FNLIST_INITIALIZER;
|
|
|
|
|
2018-10-25 23:33:40 +00:00
|
|
|
for (auto & extension : extensions)
|
2012-03-28 19:41:57 +00:00
|
|
|
{
|
|
|
|
CACHE1D_FIND_REC *rec;
|
|
|
|
|
2018-10-25 23:33:40 +00:00
|
|
|
fnlist_getnames(&fnlist, dirname, extension, -1, 0);
|
2012-03-28 19:41:57 +00:00
|
|
|
|
|
|
|
for (rec=fnlist.findfiles; rec; rec=rec->next)
|
|
|
|
{
|
|
|
|
Bsnprintf(buf, sizeof(buf), "%s/%s", dirname, rec->name);
|
|
|
|
initprintf("Using group file \"%s\".\n", buf);
|
|
|
|
initgroupfile(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
fnlist_clearnames(&fnlist);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void G_DoAutoload(const char *dirname)
|
|
|
|
{
|
|
|
|
char buf[BMAX_PATH];
|
|
|
|
|
|
|
|
Bsnprintf(buf, sizeof(buf), "autoload/%s", dirname);
|
|
|
|
G_LoadGroupsInDir(buf);
|
|
|
|
}
|
2014-07-28 06:45:53 +00:00
|
|
|
|
|
|
|
//////////
|
|
|
|
|
2015-09-23 17:54:55 +00:00
|
|
|
void G_LoadLookups(void)
|
2014-07-28 06:45:53 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
int32_t j;
|
|
|
|
buildvfs_kfd fp;
|
2014-07-28 06:45:53 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
if ((fp=kopen4loadfrommod("lookup.dat",0)) == buildvfs_kfd_invalid)
|
|
|
|
if ((fp=kopen4loadfrommod("lookup.dat",1)) == buildvfs_kfd_invalid)
|
2015-09-23 17:54:55 +00:00
|
|
|
return;
|
2014-07-28 06:45:53 +00:00
|
|
|
|
2018-04-12 21:03:12 +00:00
|
|
|
j = paletteLoadLookupTable(fp);
|
2014-07-28 06:45:53 +00:00
|
|
|
|
|
|
|
if (j < 0)
|
|
|
|
{
|
|
|
|
if (j == -1)
|
|
|
|
initprintf("ERROR loading \"lookup.dat\": failed reading enough data.\n");
|
2015-09-23 17:54:55 +00:00
|
|
|
|
|
|
|
return kclose(fp);
|
2014-07-28 06:45:53 +00:00
|
|
|
}
|
|
|
|
|
2015-09-23 17:55:02 +00:00
|
|
|
uint8_t paldata[768];
|
|
|
|
|
2014-07-28 06:45:53 +00:00
|
|
|
for (j=1; j<=5; j++)
|
|
|
|
{
|
|
|
|
// Account for TITLE and REALMS swap between basepal number and on-disk order.
|
|
|
|
int32_t basepalnum = (j == 3 || j == 4) ? 4+3-j : j;
|
|
|
|
|
2015-09-23 17:55:02 +00:00
|
|
|
if (kread_and_test(fp, paldata, 768))
|
2015-09-23 17:54:55 +00:00
|
|
|
return kclose(fp);
|
2015-09-23 17:55:02 +00:00
|
|
|
|
2018-10-25 23:33:40 +00:00
|
|
|
for (unsigned char & k : paldata)
|
|
|
|
k <<= 2;
|
2015-09-23 17:55:11 +00:00
|
|
|
|
2018-04-12 21:03:12 +00:00
|
|
|
paletteSetColorTable(basepalnum, paldata);
|
2014-07-28 06:45:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
kclose(fp);
|
|
|
|
}
|
2015-01-25 12:17:59 +00:00
|
|
|
|
2015-11-25 12:08:07 +00:00
|
|
|
//////////
|
|
|
|
|
2016-01-12 10:31:05 +00:00
|
|
|
#ifdef FORMAT_UPGRADE_ELIGIBLE
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
static buildvfs_kfd S_TryFormats(char * const testfn, char * const fn_suffix, char const searchfirst)
|
2015-01-25 12:17:59 +00:00
|
|
|
{
|
2015-11-25 12:08:07 +00:00
|
|
|
#ifdef HAVE_FLAC
|
|
|
|
{
|
|
|
|
Bstrcpy(fn_suffix, ".flac");
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd const fp = kopen4loadfrommod(testfn, searchfirst);
|
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2015-11-25 12:08:07 +00:00
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_VORBIS
|
|
|
|
{
|
|
|
|
Bstrcpy(fn_suffix, ".ogg");
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd const fp = kopen4loadfrommod(testfn, searchfirst);
|
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2015-11-25 12:08:07 +00:00
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
#endif
|
2015-01-25 12:17:59 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
return buildvfs_kfd_invalid;
|
2015-11-25 12:08:07 +00:00
|
|
|
}
|
2015-01-25 12:17:59 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
static buildvfs_kfd S_TryExtensionReplacements(char * const testfn, char const searchfirst, uint8_t const ismusic)
|
2015-11-25 12:08:07 +00:00
|
|
|
{
|
|
|
|
char * extension = Bstrrchr(testfn, '.');
|
|
|
|
char * const fn_end = Bstrchr(testfn, '\0');
|
|
|
|
|
|
|
|
// ex: grabbag.voc --> grabbag_voc.*
|
2015-05-27 08:46:12 +00:00
|
|
|
if (extension != NULL)
|
2015-01-25 12:17:59 +00:00
|
|
|
{
|
2015-05-27 08:46:12 +00:00
|
|
|
*extension = '_';
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd const fp = S_TryFormats(testfn, fn_end, searchfirst);
|
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2015-05-27 08:46:12 +00:00
|
|
|
return fp;
|
2015-11-25 12:08:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extension = fn_end;
|
|
|
|
}
|
2015-05-27 08:46:12 +00:00
|
|
|
|
2015-11-25 12:08:07 +00:00
|
|
|
// ex: grabbag.mid --> grabbag.*
|
2017-02-25 08:16:04 +00:00
|
|
|
if (ismusic)
|
2015-11-25 12:08:07 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd const fp = S_TryFormats(testfn, extension, searchfirst);
|
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2015-11-25 12:08:07 +00:00
|
|
|
return fp;
|
|
|
|
}
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
return buildvfs_kfd_invalid;
|
2015-11-25 12:08:07 +00:00
|
|
|
}
|
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd S_OpenAudio(const char *fn, char searchfirst, uint8_t const ismusic)
|
2015-11-25 12:08:07 +00:00
|
|
|
{
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd const origfp = kopen4loadfrommod(fn, searchfirst);
|
|
|
|
#ifndef USE_PHYSFS
|
|
|
|
char const * const origparent = origfp != buildvfs_kfd_invalid ? kfileparent(origfp) : NULL;
|
2018-11-18 18:12:11 +00:00
|
|
|
uint32_t const parentlength = origparent != NULL ? Bstrlen(origparent) : 0;
|
2015-11-25 12:08:07 +00:00
|
|
|
|
2018-11-18 18:12:11 +00:00
|
|
|
auto testfn = (char *)Xmalloc(Bstrlen(fn) + 12 + parentlength); // "music/" + overestimation of parent minus extension + ".flac" + '\0'
|
2019-03-01 08:51:50 +00:00
|
|
|
#else
|
|
|
|
auto testfn = (char *)Xmalloc(Bstrlen(fn) + 12);
|
|
|
|
#endif
|
2015-11-25 12:08:07 +00:00
|
|
|
|
|
|
|
// look in ./
|
|
|
|
// ex: ./grabbag.mid
|
2018-11-18 18:12:11 +00:00
|
|
|
Bstrcpy(testfn, fn);
|
2019-03-01 08:51:50 +00:00
|
|
|
buildvfs_kfd fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
|
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2018-11-18 18:12:11 +00:00
|
|
|
goto success;
|
2015-05-27 08:46:12 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
#ifndef USE_PHYSFS
|
2015-11-25 12:08:07 +00:00
|
|
|
// look in ./music/<file's parent GRP name>/
|
|
|
|
// ex: ./music/duke3d/grabbag.mid
|
|
|
|
// ex: ./music/nwinter/grabbag.mid
|
|
|
|
if (origparent != NULL)
|
|
|
|
{
|
2018-11-18 18:12:11 +00:00
|
|
|
char const * const parentextension = Bstrrchr(origparent, '.');
|
|
|
|
uint32_t const namelength = parentextension != NULL ? (unsigned)(parentextension - origparent) : parentlength;
|
2015-11-25 12:08:07 +00:00
|
|
|
|
|
|
|
Bsprintf(testfn, "music/%.*s/%s", namelength, origparent, fn);
|
2018-11-18 18:12:11 +00:00
|
|
|
fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
|
2019-03-01 08:51:50 +00:00
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2018-11-18 18:12:11 +00:00
|
|
|
goto success;
|
2015-11-25 12:08:07 +00:00
|
|
|
}
|
2015-01-25 12:17:59 +00:00
|
|
|
|
2015-11-25 12:08:07 +00:00
|
|
|
// look in ./music/
|
|
|
|
// ex: ./music/grabbag.mid
|
2018-11-18 18:12:11 +00:00
|
|
|
Bsprintf(testfn, "music/%s", fn);
|
|
|
|
fp = S_TryExtensionReplacements(testfn, searchfirst, ismusic);
|
2019-03-01 08:51:50 +00:00
|
|
|
if (fp != buildvfs_kfd_invalid)
|
2018-11-18 18:12:11 +00:00
|
|
|
goto success;
|
2019-03-01 08:51:50 +00:00
|
|
|
#endif
|
2015-01-25 12:17:59 +00:00
|
|
|
|
|
|
|
Bfree(testfn);
|
2019-03-01 08:51:50 +00:00
|
|
|
return origfp;
|
2018-11-18 18:12:11 +00:00
|
|
|
|
2019-03-01 08:51:50 +00:00
|
|
|
success:
|
|
|
|
Bfree(testfn);
|
|
|
|
kclose(origfp);
|
2018-11-18 18:12:11 +00:00
|
|
|
return fp;
|
2015-01-25 12:17:59 +00:00
|
|
|
}
|
2016-01-12 10:31:05 +00:00
|
|
|
|
2018-02-11 05:03:55 +00:00
|
|
|
void Duke_CommonCleanup(void)
|
|
|
|
{
|
|
|
|
DO_FREE_AND_NULL(g_grpNamePtr);
|
|
|
|
DO_FREE_AND_NULL(g_scriptNamePtr);
|
|
|
|
DO_FREE_AND_NULL(g_rtsNamePtr);
|
|
|
|
}
|
|
|
|
|
2016-01-12 10:31:05 +00:00
|
|
|
#endif
|