diff --git a/linux/sys_linux.c b/linux/sys_linux.c index 08ccfd8..0c63446 100644 --- a/linux/sys_linux.c +++ b/linux/sys_linux.c @@ -50,6 +50,11 @@ unsigned sys_frame_time; uid_t saved_euid; qboolean stdin_active = true; +// Knightmare- added exe / pref dirs +static char exe_dir[MAX_OSPATH]; +static char pref_dir[MAX_OSPATH]; +static char download_dir[MAX_OSPATH]; + // ======================================================================= // General routines // ======================================================================= @@ -202,6 +207,11 @@ char *Sys_ConsoleInput(void) return text; } +// Knightmare added +void Sys_ShowConsole (qboolean show) +{ +} + /*****************************************************************************/ static void *game_library; @@ -302,6 +312,99 @@ char *Sys_GetClipboardData(void) return NULL; } +/*****************************************************************************/ + +// Knightmare- adapted from DK 1.3 Linux port +const char* Sys_ExeDir(void) +{ + return exe_dir; +} + +const char* Sys_PrefDir(void) +{ + return pref_dir; +} + +const char* Sys_DownloadDir(void) +{ + return download_dir; +} + +static void Init_ExeDir (const char* argv0) +{ +#if 1 + memset(exe_dir, 0, sizeof(exe_dir)); + Q_snprintfz(exe_dir, sizeof(exe_dir), "."); +#else + char buf[MAX_OSPATH] = {0}; + const char *lastSlash; + static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + size_t buflen; + size_t len = lastSlash ? (lastSlash - buf) : 0; + + memset(exe_dir, 0, sizeof(exe_dir)); + +#ifdef __linux__ + readlink("/proc/self/exe", buf, MAX_OSPATH-1); +#elif __FreeBSD__ + sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &buflen, NULL, 0); +#endif + + if (!*buf) + { + printf("WARNING: Couldn't get path to executable, reading from argv[0]!\n"); + + if (strlen(argv0) < sizeof(buf)) + { + Q_strncpyz(buf, argv0, sizeof(buf)); + } + else + { + buf[0] = '\0'; + } + } + + // starting at the last slash the executable name begins - we only want the path up to there + lastSlash = strrchr(buf, '/'); + len = lastSlash ? (lastSlash - buf) : 0; + if (lastSlash == NULL || len >= sizeof(exe_dir) || len == 0) + { + printf("WARNING: Couldn't get path to executable! Defaulting to \".\"!\n"); + Q_snprintfz(exe_dir, sizeof(exe_dir), "."); + } + else + { + memcpy(exe_dir, buf, len); + } +#endif +} + +static void Sys_InitPrefDir (void) +{ + char *pp = getenv("XDG_DATA_HOME"); + + memset(pref_dir, 0, sizeof(pref_dir)); + + if (pp == NULL) + { + Q_snprintfz(pref_dir, sizeof(pref_dir), "%s/.local/share/Daikatana", getenv("HOME")); + return; + } + + if (strlen(pp) >= sizeof(pref_dir) - 1) + { + printf("WARNING: $XDG_DATA_HOME contains a too long path, defaulting to installation dir!\n"); + Q_strncpyz(pref_dir, exe_dir, sizeof(pref_dir)); + return; + } + + Q_strncpyz (pref_dir, pp, sizeof(pref_dir)); + Q_strncpyz (download_dir, pp, sizeof(download_dir)); +} +// end Knightmare + +/*****************************************************************************/ + int main (int argc, char **argv) { int time, oldtime, newtime; @@ -310,6 +413,10 @@ int main (int argc, char **argv) saved_euid = geteuid(); seteuid(getuid()); + // Knightmare- init exe/pref dirs + Init_ExeDir(argv[0]); + Sys_InitPrefDir(); + Qcommon_Init(argc, argv); fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); diff --git a/missionpack/g_weapon_q1.c b/missionpack/g_weapon_q1.c index 5fff92b..f824d8f 100644 --- a/missionpack/g_weapon_q1.c +++ b/missionpack/g_weapon_q1.c @@ -768,7 +768,7 @@ void q1_fire_firepod (edict_t *self, vec3_t dir) /* ================= -q1_fire_firepod +q1_fire_lavaball Fires a lavaball. Used by Chthon. ================= diff --git a/qcommon/files.c b/qcommon/files.c index 458c09d..8ec3408 100644 --- a/qcommon/files.c +++ b/qcommon/files.c @@ -27,6 +27,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../include/zlibpng/zip.h" #endif +#ifdef _WIN32 +#include "../win32/winquake.h" +#endif + // enables faster binary pak searck, still experimental #define BINARY_PACK_SEARCH @@ -68,6 +72,7 @@ instruct clients to write files over areas they shouldn't. #define MAX_WRITE 0x10000 #define MAX_FIND_FILES 0x04000 +//#define USE_SAVEGAMEDIR // whether to use new Ffs_savegamedir/fs_downloaddir paths // // in memory @@ -142,6 +147,9 @@ cvar_t *fs_gamedirvar; cvar_t *fs_debug; cvar_t *fs_roguegame; +#ifdef _WIN32 +cvar_t *win_use_profile_dir; // whether to use user profile dir for savegames, configs, screenshots, etc +#endif void CDAudio_Stop (void); void Com_FileExtension (const char *path, char *dst, int dstSize); @@ -2303,6 +2311,7 @@ void FS_InitFilesystem (void) // basedir // allows the game to run from outside the data tree fs_basedir = Cvar_Get ("basedir", ".", CVAR_NOSET); +// fs_basedir = Cvar_Get ("basedir", (char *)Sys_ExeDir(), CVAR_NOSET); // cddir // Logically concatenates the cddir after the basedir for @@ -2313,7 +2322,6 @@ void FS_InitFilesystem (void) // start up with baseq2 by default FS_AddGameDirectory (va("%s/"BASEDIRNAME, fs_basedir->string) ); - // any set gamedirs will be freed up to here fs_baseSearchPaths = fs_searchPaths; @@ -2329,6 +2337,17 @@ void FS_InitFilesystem (void) fs_basegamedir3 = Cvar_Get ("basegame3", "", CVAR_LATCH); // Knightmare added fs_gamedirvar = Cvar_Get ("game", "", CVAR_LATCH|CVAR_SERVERINFO); + // set up pref dir under Win32 here +#ifdef _WIN32 + // whether to use user profile dir for savegames, configs, screenshots, etc + if ( COM_CheckParm ("-portable") || COM_CheckParm ("+portable") || (FS_LoadFile("portable.cfg", NULL) != -1) ) + win_use_profile_dir = Cvar_Get ("win_use_profile_dir", "0", CVAR_NOSET); + else + win_use_profile_dir = Cvar_Get ("win_use_profile_dir", "1", CVAR_NOSET); + + Sys_InitPrefDir (); // set up pref dir now instead of calling a function every time it's needed +#endif + // check and load game directory if (fs_gamedirvar->string[0]) FS_SetGamedir (fs_gamedirvar->string); diff --git a/qcommon/qcommon.h b/qcommon/qcommon.h index 848a16b..aa277e7 100644 --- a/qcommon/qcommon.h +++ b/qcommon/qcommon.h @@ -963,6 +963,20 @@ void Sys_Quit (void); char *Sys_GetClipboardData( void ); void Sys_CopyProtect (void); +// DG: returns the directory the executable (kmquake2.exe on Win32) resides in +// *without* a path seperator ("/" or "\") at the end +const char* Sys_ExeDir(); + +// DG: returns the directory where user data (savegames, configs, demos, +// ... - everything written by the game really) +// should be written to, e.g. $HOME/.local/share/KMQuake2 +// *without* path seperator ("/" or "\") at the end +const char* Sys_PrefDir(); + +// Knightmare- returns the directory where autodownload content +// (maps, textures, sounds, skies, models, etc) should be written to +const char* Sys_DownloadDir(); + /* ============================================================== diff --git a/ui/ui_backend.c b/ui/ui_backend.c index 6c89283..2265749 100644 --- a/ui/ui_backend.c +++ b/ui/ui_backend.c @@ -820,7 +820,7 @@ void Menu_DrawStatusBar (const char *string) SCR_DrawString( SCREEN_WIDTH/2-(l/2)*MENU_FONT_SIZE, SCREEN_HEIGHT-(MENU_FONT_SIZE+1), MENU_FONT_SIZE, ALIGN_BOTTOM, string, 255 ); } else - SCR_DrawFill( 0, SCREEN_HEIGHT-(MENU_FONT_SIZE+3), SCREEN_WIDTH, MENU_FONT_SIZE+3, ALIGN_BOTTOM_STRETCH, 0,0,0,255 ); + SCR_DrawFill( 0, SCREEN_HEIGHT-(MENU_FONT_SIZE+3), SCREEN_WIDTH, MENU_FONT_SIZE+4, ALIGN_BOTTOM_STRETCH, 0,0,0,255 ); // go 1 pixel past screen bottom to prevent gap from scaling } void Menu_DrawString (int x, int y, int size, const char *string, int alpha) diff --git a/ui/ui_options.c b/ui/ui_options.c index 61ec35f..6e01330 100644 --- a/ui/ui_options.c +++ b/ui/ui_options.c @@ -83,6 +83,7 @@ void Options_MenuInit ( void ) s_options_sound_section.generic.x = 0; s_options_sound_section.generic.y = MENU_FONT_SIZE * 2; s_options_sound_section.generic.callback = MenuSoundFunc; + s_options_sound_section.generic.statusbar = "change sound settings"; // s_options_sound_section.generic.cursor_offset = -(MENU_FONT_SIZE*10); s_options_controls_section.generic.type = MTYPE_ACTION; @@ -92,6 +93,7 @@ void Options_MenuInit ( void ) s_options_controls_section.generic.x = 0; s_options_controls_section.generic.y = MENU_FONT_SIZE * 4; s_options_controls_section.generic.callback = MenuControlsFunc; + s_options_controls_section.generic.statusbar = "change control settings and bind keys"; // s_options_controls_section.generic.cursor_offset = -(MENU_FONT_SIZE*10); s_options_screen_section.generic.type = MTYPE_ACTION; @@ -101,6 +103,7 @@ void Options_MenuInit ( void ) s_options_screen_section.generic.x = 0; s_options_screen_section.generic.y = MENU_FONT_SIZE * 6; s_options_screen_section.generic.callback = MenuScreenFunc; + s_options_screen_section.generic.statusbar = "change HUD/crosshair settings"; // s_options_screen_section.generic.cursor_offset = -(MENU_FONT_SIZE*10); s_options_effects_section.generic.type = MTYPE_ACTION; @@ -110,6 +113,7 @@ void Options_MenuInit ( void ) s_options_effects_section.generic.x = 0; s_options_effects_section.generic.y = MENU_FONT_SIZE * 8; s_options_effects_section.generic.callback = MenuEffectsFunc; + s_options_effects_section.generic.statusbar = "change ingame effects settings"; // s_options_effects_section.generic.cursor_offset = -(MENU_FONT_SIZE*10); s_options_interface_section.generic.type = MTYPE_ACTION; @@ -119,6 +123,7 @@ void Options_MenuInit ( void ) s_options_interface_section.generic.x = 0; s_options_interface_section.generic.y = MENU_FONT_SIZE * 10; s_options_interface_section.generic.callback = MenuInterfaceFunc; + s_options_interface_section.generic.statusbar = "change menu/console settings"; // s_options_interface_section.generic.cursor_offset = -(MENU_FONT_SIZE*10); s_options_back_action.generic.type = MTYPE_ACTION; diff --git a/unix/sys_unix.c b/unix/sys_unix.c index ee5aef4..32556a6 100644 --- a/unix/sys_unix.c +++ b/unix/sys_unix.c @@ -52,6 +52,11 @@ uid_t saved_euid; qboolean stdin_active = true; int ActiveApp; +// Knightmare- added exe / pref dirs +static char exe_dir[MAX_OSPATH]; +static char pref_dir[MAX_OSPATH]; +static char download_dir[MAX_OSPATH]; + // ======================================================================= // General routines // ======================================================================= @@ -204,6 +209,11 @@ char *Sys_ConsoleInput(void) return text; } +// Knightmare added +void Sys_ShowConsole (qboolean show) +{ +} + /*****************************************************************************/ static void *game_library; @@ -305,6 +315,97 @@ void Sys_SendKeyEvents (void) /*****************************************************************************/ +// Knightmare- adapted from DK 1.3 Linux port +const char* Sys_ExeDir(void) +{ + return exe_dir; +} + +const char* Sys_PrefDir(void) +{ + return pref_dir; +} + +const char* Sys_DownloadDir(void) +{ + return download_dir; +} + +static void Init_ExeDir (const char* argv0) +{ +#if 1 + memset(exe_dir, 0, sizeof(exe_dir)); + Q_snprintfz(exe_dir, sizeof(exe_dir), "."); +#else + char buf[MAX_OSPATH] = {0}; + const char *lastSlash; + static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; + size_t buflen; + size_t len = lastSlash ? (lastSlash - buf) : 0; + + memset(exe_dir, 0, sizeof(exe_dir)); + +#ifdef __linux__ + readlink("/proc/self/exe", buf, MAX_OSPATH-1); +#elif __FreeBSD__ + sysctl(mib, sizeof(mib)/sizeof(*mib), buf, &buflen, NULL, 0); +#endif + + if (!*buf) + { + printf("WARNING: Couldn't get path to executable, reading from argv[0]!\n"); + + if (strlen(argv0) < sizeof(buf)) + { + Q_strncpyz(buf, argv0, sizeof(buf)); + } + else + { + buf[0] = '\0'; + } + } + + // starting at the last slash the executable name begins - we only want the path up to there + lastSlash = strrchr(buf, '/'); + len = lastSlash ? (lastSlash - buf) : 0; + if (lastSlash == NULL || len >= sizeof(exe_dir) || len == 0) + { + printf("WARNING: Couldn't get path to executable! Defaulting to \".\"!\n"); + Q_snprintfz(exe_dir, sizeof(exe_dir), "."); + } + else + { + memcpy(exe_dir, buf, len); + } +#endif +} + +static void Sys_InitPrefDir (void) +{ + char *pp = getenv("XDG_DATA_HOME"); + + memset(pref_dir, 0, sizeof(pref_dir)); + + if (pp == NULL) + { + Q_snprintfz(pref_dir, sizeof(pref_dir), "%s/.local/share/Daikatana", getenv("HOME")); + return; + } + + if (strlen(pp) >= sizeof(pref_dir) - 1) + { + printf("WARNING: $XDG_DATA_HOME contains a too long path, defaulting to installation dir!\n"); + Q_strncpyz(pref_dir, exe_dir, sizeof(pref_dir)); + return; + } + + Q_strncpyz (pref_dir, pp, sizeof(pref_dir)); + Q_strncpyz (download_dir, pp, sizeof(download_dir)); +} +// end Knightmare + +/*****************************************************************************/ + int main (int argc, char **argv) { int time, oldtime, newtime; @@ -319,7 +420,11 @@ int main (int argc, char **argv) printf ("Linux Port by QuDos\n"); printf ("http://qudos.quakedev.com/\n"); printf ("Compiled: "__DATE__" -- "__TIME__"\n"); - printf ("==========================================\n\n"); + printf ("==========================================\n\n"); + + // Knightmare- init exe/pref dirs + Init_ExeDir(argv[0]); + Sys_InitPrefDir(); Qcommon_Init(argc, argv); diff --git a/win32/sys_win.c b/win32/sys_win.c index 8cfea90..394cb83 100644 --- a/win32/sys_win.c +++ b/win32/sys_win.c @@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include +#include #include "../win32/conproc.h" // [Slipyx] mingw support for _controlfp. from float.h. these would be defined @@ -45,6 +46,10 @@ _CRTIMP unsigned int __cdecl __MINGW_NOTHROW _controlfp (unsigned int unNew, uns qboolean s_win95; +qboolean s_win9X; +qboolean s_winNT; +qboolean s_winNT6; + int starttime; int ActiveApp; qboolean Minimized; @@ -61,6 +66,32 @@ static HANDLE qwclsemaphore; int argc; char *argv[MAX_NUM_ARGVS]; +#define NT5_SAVEDIR "My Games/KMQuake2" +#define NT6_SAVEDIR "KMQuake2" +#define NT5_DLDIR "My Downloads/KMQuake2" +#define NT6_DLDIR "KMQuake2" +static char exe_dir[MAX_OSPATH]; +static char pref_dir[MAX_OSPATH]; +static char download_dir[MAX_OSPATH]; + +qboolean Detect_WinNT5orLater (void); +qboolean Detect_WinNT6orLater (void); + +typedef HRESULT (WINAPI *SHGETFOLDERPATHW) (HWND hwnd, int CSIDL, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath); +SHGETFOLDERPATHW fnSHGetFolderPathW = NULL; + +// from DarkPlaces +const GUID qFOLDERID_SavedGames = {0x4C5C32FF, 0xBB9D, 0x43b0, {0xB5, 0xB4, 0x2D, 0x72, 0xE5, 0x4E, 0xAA, 0xA4}}; +const GUID qFOLDERID_Downloads = {0x374DE290, 0x123F, 0x4565, {0x91, 0x64, 0x39, 0xC4, 0x92, 0x5E, 0x46, 0x7B}}; +#define qREFKNOWNFOLDERID const GUID * +#define qKF_FLAG_CREATE 0x8000 +#define qKF_FLAG_NO_ALIAS 0x1000 +static HRESULT (WINAPI *fnSHGetKnownFolderPath) (qREFKNOWNFOLDERID rfid, DWORD dwFlags, HANDLE hToken, PWSTR *ppszPath); +static HRESULT (WINAPI *fnCoInitializeEx)(LPVOID pvReserved, DWORD dwCoInit); +static void (WINAPI *fnCoUninitialize)(void); +static void (WINAPI *fnCoTaskMemFree)(LPVOID pv); +// end DarkPlaces code + #ifndef NEW_DED_CONSOLE /* @@ -1395,6 +1426,352 @@ void ParseCommandLine (LPSTR lpCmdLine) } +/* +================== +ReplaceBackSlashes + +Replaces backslashes in a path with slashes. +================== +*/ +static void ReplaceBackSlashes (char *path) +{ + char *cur, *old; + + cur = old = path; + if (strstr(cur, "\\") != NULL) + { + while (cur != NULL) + { + if ((cur - old) > 1) { + *cur = '/'; + } + old = cur; + cur = strchr(old + 1, '\\'); + } + } +} + + +/* +================== +Sys_ExeDir +================== +*/ +const char *Sys_ExeDir (void) +{ + return exe_dir; +} + + +/* +================== +Sys_PrefDir +================== +*/ +const char *Sys_PrefDir (void) +{ + return pref_dir; +} + + +/* +================== +Sys_DownloadDir +================== +*/ +const char *Sys_DownloadDir (void) +{ + return download_dir; +} + + +/* +================== +Sys_InitPrefDir + +Adapted from DK 1.3 source +================== +*/ +void Sys_InitPrefDir (void) +{ + if ( win_use_profile_dir && win_use_profile_dir->integer ) + { + char profile[MAX_PATH], dlPath[MAX_PATH]; + const char *reason = "No error!"; + const char *reason_dl = "No error!"; + int len, len_dl; + qboolean bGotNT6SavedGames=false, bGotNT6Downloads=false; + + // Use Saved Games/KMQuake2 on Win Vista and later, unless "mygames" parameter is set + if ( Detect_WinNT6orLater() && !COM_CheckParm ("-mygames") && !COM_CheckParm ("+mygames") ) + { + WCHAR *wprofile, *wDLPath; + HMODULE hShell32 = LoadLibrary("shell32"); + HMODULE hOle32 = LoadLibrary("ole32"); + + if ( !hShell32 || !hOle32 ) { + reason = reason_dl = "shell32.dll or ole32.dll couldn't be loaded"; + } + else + { + fnSHGetKnownFolderPath = (void *)GetProcAddress (hShell32, "SHGetKnownFolderPath"); + fnCoInitializeEx = (void *)GetProcAddress (hOle32, "CoInitializeEx"); + fnCoUninitialize = (void *)GetProcAddress (hOle32, "CoUninitialize"); + fnCoTaskMemFree = (void *)GetProcAddress (hOle32, "CoTaskMemFree"); + if ( !fnSHGetKnownFolderPath || !fnCoInitializeEx || !fnCoUninitialize || !fnCoTaskMemFree ) { + reason = reason_dl = "functions SHGetKnownFolderPath / CoInitializeEx / CoUninitialize / CoTaskMemFree couldn't be mapped"; + } + else + { + // from DarkPlaces + memset (profile, 0, sizeof(profile)); + fnCoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + if (fnSHGetKnownFolderPath(&qFOLDERID_SavedGames, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &wprofile) == S_OK) + { + memset(profile, 0, sizeof(profile)); + #if _MSC_VER >= 1400 + wcstombs_s(NULL, profile, sizeof(profile), wprofile, sizeof(profile)-1); + #else + wcstombs(profile, wprofile, sizeof(profile)-1); + #endif + fnCoTaskMemFree(wprofile); + } + // Also get Downloads Folder from qFOLDERID_Downloads + if (fnSHGetKnownFolderPath(&qFOLDERID_Downloads, qKF_FLAG_CREATE | qKF_FLAG_NO_ALIAS, NULL, &wDLPath) == S_OK) + { + memset(dlPath, 0, sizeof(dlPath)); + #if _MSC_VER >= 1400 + wcstombs_s(NULL, dlPath, sizeof(dlPath), wDLPath, sizeof(dlPath)-1); + #else + wcstombs(dlPath, wDLPath, sizeof(dlPath)-1); + #endif + fnCoTaskMemFree(wDLPath); + } + fnCoUninitialize(); + // end DarkPlaces code + + len = (int)strlen(profile); + if (len == 0) { + reason = "SHGetKnownFolderPath()/wcstombs() returned 0 length string"; + } + else + { + // Check if path is too long + if ( (len + strlen(NT6_SAVEDIR) + 3) >= 256 ) { + reason = "the resulting path would be too long (>= 256 chars)"; + } + else + { + // Replace backslashes with slashes + ReplaceBackSlashes (profile); + Com_sprintf (pref_dir, sizeof(pref_dir), "%s/%s", profile, NT6_SAVEDIR); + bGotNT6SavedGames = true; + // return; + } + } + + len_dl = (int)strlen(dlPath); + if (len_dl == 0) { + reason_dl = "SHGetKnownFolderPath()/wcstombs() returned 0 length string"; + } + else + { + // Check if path is too long + if ( (len_dl + strlen(NT6_DLDIR) + 3) >= 256 ) { + reason_dl = "the resulting path would be too long (>= 256 chars)"; + } + else + { + // Replace backslashes with slashes + ReplaceBackSlashes (dlPath); + Com_sprintf (download_dir, sizeof(download_dir), "%s/%s", dlPath, NT6_DLDIR); + bGotNT6Downloads = true; + // return; + } + } + } + } + if (bGotNT6SavedGames && bGotNT6Downloads) // successfully got both dirs, return now + return; + + // Output reason for why one or both dirs couldn't be found, then fall back on NT5 path + if (!bGotNT6SavedGames) + Com_Printf("Couldn't get PrefDir (Saved Games/KMQuake2), because %s.\n", reason); + if (!bGotNT6Downloads) + Com_Printf("Couldn't get DownloadDir (Downloads/KMQuake2), because %s.\n", reason_dl); + } + + // Use My Documents/My Games/KMQuake2 on Win2K / XP + if ( Detect_WinNT5orLater() ) + { + WCHAR sprofile[MAX_PATH]; + WCHAR uprofile[MAX_PATH]; + HMODULE hShell32 = LoadLibrary("shell32"); + + if (!hShell32) { + reason = "shell32.dll couldn't be loaded"; + } + else + { + fnSHGetFolderPathW = (SHGETFOLDERPATHW)GetProcAddress (hShell32, "SHGetFolderPathW"); + if (!fnSHGetFolderPathW) { + reason = "function SHGetFolderPathW couldn't be mapped"; + } + else + { + memset (pref_dir, 0, sizeof(pref_dir)); + + /* The following lines implement a horrible + hack to connect the UTF-16 WinAPI to the + ASCII Quake II. While this should work in + most cases, it'll fail if the "Windows to + DOS filename translation" is switched off. + In that case the function will return NULL + and no homedir is used. */ + + // Get path to "My Documents" folder + fnSHGetFolderPathW (NULL, CSIDL_PERSONAL, NULL, 8, uprofile); + + // Create a UTF-16 DOS path + len = GetShortPathNameW (uprofile, sprofile, sizeof(sprofile)); + + if (len == 0) { + reason = "GetShortPathNameW() returned 0"; + } + else + { + // Since the DOS path contains no UTF-16 characters, just convert it to ASCII + len = WideCharToMultiByte (CP_ACP, 0, sprofile, -1, profile, sizeof(profile), NULL, NULL); + + if (len == 0) { + reason = "WideCharToMultiByte() returned 0"; + } + else + { + // Check if path is too long + if ( ((len + strlen(NT5_SAVEDIR) + 3) >= 256) || ((len + strlen(NT5_DLDIR) + 3) >= 256) ) { + reason = "The resulting path would be too long (>= 256 chars)"; + } + else + { + // Replace backslashes with slashes + ReplaceBackSlashes (profile); + // Allow splitting of dirs from above NT6 section if only one failed + if (!bGotNT6SavedGames) + Com_sprintf (pref_dir, sizeof(pref_dir), "%s/%s", profile, NT5_SAVEDIR); + if (!bGotNT6Downloads) + Com_sprintf (download_dir, sizeof(download_dir), "%s/%s", profile, NT5_DLDIR); + return; + } + } + } + } + } + Com_Printf("Couldn't get PrefDir (My Documents/My Games/KMQuake2), because %s.\n", reason); + } + } + + Com_sprintf (pref_dir, sizeof(pref_dir), exe_dir); + Com_sprintf (download_dir, sizeof(download_dir), exe_dir); +} + + +/* +================== +Init_ExeDir +================== +*/ +static void Init_ExeDir (void) +{ +#if 0 + memset(exe_dir, 0, sizeof(exe_dir)); + Q_snprintfz (exe_dir, sizeof(exe_dir), "."); +#else + char buf[MAX_PATH]; + const char *lastSlash; + int dirLen; + + memset(buf, 0, sizeof(buf)); + memset(exe_dir, 0, sizeof(exe_dir)); + + GetModuleFileName (NULL, buf, sizeof(buf)-1); + + // get path up to last backslash + lastSlash = strrchr(buf, '\\'); + if (lastSlash == NULL) + lastSlash = strrchr(buf, '/'); + + dirLen = lastSlash ? (lastSlash - buf) : 0; + if ( lastSlash == NULL || dirLen == 0 || dirLen >= sizeof(exe_dir) ) { + Q_snprintfz (exe_dir, sizeof(exe_dir), "."); + } + else { + memcpy(exe_dir, buf, dirLen); + } +#endif +} + +/* +================== +Detect_WinNT5orLater +================== +*/ +qboolean Detect_WinNT5orLater (void) +{ + DWORD WinVersion; + DWORD WinLowByte, WinHighByte; + + WinVersion = GetVersion(); + WinLowByte = (DWORD)(LOBYTE(LOWORD(WinVersion))); + WinHighByte = (DWORD)(HIBYTE(HIWORD(WinVersion))); + + if (WinLowByte <= 4) { + Com_DPrintf("Windows 9x or NT 4 detected.\n"); + return false; + } + + if (WinLowByte >= 5) { + Com_DPrintf("Windows 5.x or later detected.\n"); + return true; + } + + return false; +} + + +/* +================== +Detect_WinNT6orLater +================== +*/ +qboolean Detect_WinNT6orLater (void) +{ + DWORD WinVersion; + DWORD WinLowByte, WinHighByte; + + WinVersion = GetVersion(); + WinLowByte = (DWORD)(LOBYTE(LOWORD(WinVersion))); + WinHighByte = (DWORD)(HIBYTE(HIWORD(WinVersion))); + + if (WinLowByte <= 4) { + Com_DPrintf("Windows 9x or NT 4 detected.\n"); + return false; + } + + if (WinLowByte == 5) { + Com_DPrintf("Windows 5.x (Win2K / XP / Server 2003) detected.\n"); + return false; + } + + if (WinLowByte >= 6) { + Com_DPrintf("Windows 6.x (WinVista / 7 / 8) detected.\n"); + return true; + } + + return false; +} + + /* ================== Sys_SetHighDPIMode @@ -1467,6 +1844,8 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin Sys_SetHighDPIMode (); // setup DPI awareness + Init_ExeDir (); // Knightmare added + #ifndef NEW_DED_CONSOLE // Knightmare- startup logo, code from TomazQuake //if (!(dedicated && dedicated->value)) @@ -1552,7 +1931,7 @@ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLin newtime = Sys_Milliseconds(); time = newtime - oldtime; if (time > 0) break; - Sleep(0); // may also use Speep(1); to free more CPU, but it can lower your fps + Sleep(0); // may also use Sleep(1); to free more CPU, but it can lower your fps } /*do { diff --git a/win32/winquake.h b/win32/winquake.h index 7c86d05..1b7d19f 100644 --- a/win32/winquake.h +++ b/win32/winquake.h @@ -67,6 +67,10 @@ void IN_MouseEvent (int mstate); extern int window_center_x, window_center_y; extern RECT window_rect; +// win_main.c +extern cvar_t *win_use_profile_dir; +void Sys_InitPrefDir (void); + extern HWND hwnd_dialog; // Knightmare added #define NEW_DED_CONSOLE // enable new dedicated console