From ea0e4ed34482cf1089708b1e6a9de69f53f022f4 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 13 Sep 2013 10:07:43 +0200 Subject: [PATCH 01/21] - fixed: The Hexen bridge must make its balls disappear when it gets destroyed. Hexen did this with a call to A_BridgeRemove in Thing_Destroy which merely set a flag in the bridge object, which cannot be done safely in ZDoom because it's not guaranteed that the ball object calls A_BridgeOrbit and the garbage collector may delete the bridge actor before it can be checked so now the Bridge's Destroy method deletes all balls attached to the bridge object itself. --- src/g_shared/a_bridge.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index 7e743a0af..d669cc3bd 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -38,6 +38,7 @@ class ACustomBridge : public AActor DECLARE_CLASS (ACustomBridge, AActor) public: void BeginPlay (); + void Destroy(); }; IMPLEMENT_CLASS(ACustomBridge) @@ -58,6 +59,24 @@ void ACustomBridge::BeginPlay () } } +void ACustomBridge::Destroy() +{ + // Hexen originally just set a flag to make the bridge balls remove themselves in A_BridgeOrbit. + // But this is not safe with custom bridge balls that do not necessarily call that function. + // So the best course of action is to look for all bridge balls here and destroy them ourselves. + + TThinkerIterator it; + AActor *thing; + + while ((thing = it.Next())) + { + if (thing->target == this) + { + thing->Destroy(); + } + } +} + // Action functions for the non-Doom bridge -------------------------------- #define ORBIT_RADIUS 15 @@ -89,10 +108,6 @@ DEFINE_ACTION_FUNCTION(AActor, A_BridgeOrbit) // Set rotation radius if (self->target->args[4]) rotationradius = ((self->target->args[4] * self->target->radius) / (100 * FRACUNIT)); - if (self->target->special1) - { - self->SetState (NULL); - } self->angle += rotationspeed; self->x = self->target->x + rotationradius * finecosine[self->angle >> ANGLETOFINESHIFT]; self->y = self->target->y + rotationradius * finesine[self->angle >> ANGLETOFINESHIFT]; @@ -115,7 +130,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) cy = self->y; cz = self->z; startangle = pr_orbit() << 24; - self->special1 = 0; // Spawn triad into world -- may be more than a triad now. int ballcount = self->args[2]==0 ? 3 : self->args[2]; @@ -129,14 +143,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_BridgeInit) } } -/* never used -void A_BridgeRemove (AActor *self) -{ - self->special1 = true; // Removing the bridge - self->flags &= ~MF_SOLID; - self->SetState (&ABridge::States[S_FREE_BRIDGE]); -} -*/ // Invisible bridge -------------------------------------------------------- From da02a44126c67e0e7e084c1517dee8fd888f2961 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 14 Sep 2013 21:02:47 -0500 Subject: [PATCH 02/21] Consolidate special path functions into m_specialpaths.cpp - Also remove CDROM_DIR while I'm at it. --- src/CMakeLists.txt | 1 + src/b_game.cpp | 24 +- src/d_main.cpp | 11 - src/g_game.cpp | 26 +-- src/gameconfigfile.cpp | 94 +------- src/m_misc.cpp | 112 +-------- src/m_misc.h | 15 +- src/m_specialpaths.cpp | 500 +++++++++++++++++++++++++++++++++++++++++ src/p_glnodes.cpp | 51 +---- src/version.h | 2 - zdoom.vcproj | 4 + 11 files changed, 541 insertions(+), 299 deletions(-) create mode 100644 src/m_specialpaths.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 82f347fd8..4223598f5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -701,6 +701,7 @@ add_executable( zdoom WIN32 m_misc.cpp m_png.cpp m_random.cpp + m_specialpaths.cpp memarena.cpp md5.cpp name.cpp diff --git a/src/b_game.cpp b/src/b_game.cpp index ed3a5c848..f3878b8bb 100644 --- a/src/b_game.cpp +++ b/src/b_game.cpp @@ -505,31 +505,13 @@ bool FCajunMaster::LoadBots () bool gotteam = false; bglobal.ForgetBots (); -#ifndef __unix__ - tmp = progdir; - tmp += "zcajun/" BOTFILENAME; - if (!FileExists (tmp)) + tmp = M_GetCajunPath(BOTFILENAME); + if (tmp.IsEmpty()) { DPrintf ("No " BOTFILENAME ", so no bots\n"); return false; } -#else - tmp = GetUserFile (BOTFILENAME); - if (!FileExists (tmp)) - { - if (!FileExists (SHARE_DIR BOTFILENAME)) - { - DPrintf ("No " BOTFILENAME ", so no bots\n"); - return false; - } - else - sc.OpenFile (SHARE_DIR BOTFILENAME); - } -#endif - else - { - sc.OpenFile (tmp); - } + sc.OpenFile(tmp); while (sc.GetString ()) { diff --git a/src/d_main.cpp b/src/d_main.cpp index b70e5d779..f72dc368b 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2137,17 +2137,6 @@ static void CheckCmdLine() Printf ("%s", GStrings("D_DEVSTR")); } -#if !defined(__unix__) && !defined(__APPLE__) - // We do not need to support -cdrom under Unix, because all the files - // that would go to c:\\zdoomdat are already stored in .zdoom inside - // the user's home directory. - if (Args->CheckParm("-cdrom")) - { - Printf ("%s", GStrings("D_CDROM")); - mkdir (CDROM_DIR, 0); - } -#endif - // turbo option // [RH] (now a cvar) v = Args->CheckValue("-turbo"); if (v != NULL) diff --git a/src/g_game.cpp b/src/g_game.cpp index 79cd4b233..698b52e79 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1919,32 +1919,10 @@ FString G_BuildSaveName (const char *prefix, int slot) leader = Args->CheckValue ("-savedir"); if (leader.IsEmpty()) { -#if !defined(__unix__) && !defined(__APPLE__) - if (Args->CheckParm ("-cdrom")) - { - leader = CDROM_DIR "/"; - } - else -#endif - { - leader = save_dir; - } + leader = save_dir; if (leader.IsEmpty()) { -#ifdef __unix__ - leader = "~/" GAME_DIR; -#elif defined(__APPLE__) - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - leader << cpath << "/" GAME_DIR "/Savegames/"; - } -#else - leader = progdir; -#endif + leader = M_GetSavegamesPath(); } } size_t len = leader.Len(); diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index 211ef96c6..f679bec3d 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -42,8 +42,6 @@ #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #include -#include -#include extern HWND Window; #define USE_WINDOWS_DWORD #endif @@ -588,106 +586,20 @@ void FGameConfigFile::ArchiveGlobalData () FString FGameConfigFile::GetConfigPath (bool tryProg) { const char *pathval; - FString path; pathval = Args->CheckValue ("-config"); if (pathval != NULL) { return FString(pathval); } -#ifdef _WIN32 - path = NULL; - HRESULT hr; - - TCHAR uname[UNLEN+1]; - DWORD unamelen = countof(uname); - - // Because people complained, try for a user-specific .ini in the program directory first. - // If that is not writeable, use the one in the home directory instead. - hr = GetUserName (uname, &unamelen); - if (SUCCEEDED(hr) && uname[0] != 0) - { - // Is it valid for a user name to have slashes? - // Check for them and substitute just in case. - char *probe = uname; - while (*probe != 0) - { - if (*probe == '\\' || *probe == '/') - *probe = '_'; - ++probe; - } - - path = progdir; - path += "zdoom-"; - path += uname; - path += ".ini"; - if (tryProg) - { - if (!FileExists (path.GetChars())) - { - path = ""; - } - } - else - { // check if writeable - FILE *checker = fopen (path.GetChars(), "a"); - if (checker == NULL) - { - path = ""; - } - else - { - fclose (checker); - } - } - } - - if (path.IsEmpty()) - { - if (Args->CheckParm ("-cdrom")) - return CDROM_DIR "\\zdoom.ini"; - - path = progdir; - path += "zdoom.ini"; - } - return path; -#elif defined(__APPLE__) - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - path = cpath; - path += "/zdoom.ini"; - return path; - } - // Ungh. - return "zdoom.ini"; -#else - return GetUserFile ("zdoom.ini"); -#endif + return M_GetConfigPath(tryProg); } void FGameConfigFile::CreateStandardAutoExec(const char *section, bool start) { if (!SetSection(section)) { - FString path; -#ifdef __APPLE__ - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - path << cpath << "/" GAME_DIR "/autoexec.cfg"; - } -#elif !defined(__unix__) - path = "$PROGDIR/autoexec.cfg"; -#else - path = GetUserFile ("autoexec.cfg"); -#endif + FString path = M_GetAutoexecPath(); SetSection (section, true); SetValueForKey ("Path", path.GetChars()); } @@ -794,6 +706,6 @@ void FGameConfigFile::SetRavenDefaults (bool isHexen) CCMD (whereisini) { - FString path = GameConfig->GetConfigPath (false); + FString path = M_GetConfigPath(false); Printf ("%s\n", path.GetChars()); } diff --git a/src/m_misc.cpp b/src/m_misc.cpp index e218cadc4..14b9d9b1b 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -31,9 +31,6 @@ #include #include #include -#ifdef __APPLE__ -#include -#endif #include "doomtype.h" #include "version.h" @@ -333,65 +330,6 @@ static long ParseCommandLine (const char *args, int *argc, char **argv) } -#if defined(__unix__) -FString GetUserFile (const char *file) -{ - FString path; - struct stat info; - - path = NicePath("~/" GAME_DIR "/"); - - if (stat (path, &info) == -1) - { - struct stat extrainfo; - - // Sanity check for ~/.config - FString configPath = NicePath("~/.config/"); - if (stat (configPath, &extrainfo) == -1) - { - if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create ~/.config directory:\n%s", strerror(errno)); - } - } - else if (!S_ISDIR(extrainfo.st_mode)) - { - I_FatalError ("~/.config must be a directory"); - } - - // This can be removed after a release or two - // Transfer the old zdoom directory to the new location - bool moved = false; - FString oldpath = NicePath("~/.zdoom/"); - if (stat (oldpath, &extrainfo) != -1) - { - if (rename(oldpath, path) == -1) - { - I_Error ("Failed to move old zdoom directory (%s) to new location (%s).", - oldpath.GetChars(), path.GetChars()); - } - else - moved = true; - } - - if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError ("Failed to create %s directory:\n%s", - path.GetChars(), strerror (errno)); - } - } - else - { - if (!S_ISDIR(info.st_mode)) - { - I_FatalError ("%s must be a directory", path.GetChars()); - } - } - path += file; - return path; -} -#endif - // // M_SaveDefaults // @@ -698,48 +636,22 @@ void M_ScreenShot (const char *filename) // find a file name to save it to if (filename == NULL || filename[0] == '\0') { -#if !defined(__unix__) && !defined(__APPLE__) - if (Args->CheckParm ("-cdrom")) + size_t dirlen; + autoname = Args->CheckValue("-shotdir"); + if (autoname.IsEmpty()) { - autoname = CDROM_DIR "\\"; + autoname = screenshot_dir; } - else -#endif + dirlen = autoname.Len(); + if (dirlen == 0) { - size_t dirlen; - autoname = Args->CheckValue("-shotdir"); - if (autoname.IsEmpty()) + autoname = M_GetScreenshotsPath(); + } + else if (dirlen > 0) + { + if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') { - autoname = screenshot_dir; - } - dirlen = autoname.Len(); - if (dirlen == 0) - { -#ifdef __unix__ - autoname = "~/" GAME_DIR "/screenshots/"; -#elif defined(__APPLE__) - char cpath[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) - { - autoname << cpath << "/" GAME_DIR "/Screenshots/"; - } - else - { - autoname = "~"; - } -#else - autoname = progdir; -#endif - } - else if (dirlen > 0) - { - if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') - { - autoname += '/'; - } + autoname += '/'; } } autoname = NicePath(autoname); diff --git a/src/m_misc.h b/src/m_misc.h index 27006cf87..327df3de4 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -24,6 +24,7 @@ #define __M_MISC__ #include "basictypes.h" +#include "zstring.h" class FConfigFile; class FGameConfigFile; @@ -44,9 +45,19 @@ bool M_SaveDefaults (const char *filename); void M_SaveCustomKeys (FConfigFile *config, char *section, char *subsection, size_t sublen); -// Prepends ~/.zdoom to path -FString GetUserFile (const char *path); FString M_ZLibError(int zerrnum); +// Get special directory paths (defined in m_specialpaths.cpp) + +#ifdef __unix__ +FString GetUserFile (const char *path); // Prepends ~/.zdoom to path +#endif +FString M_GetCachePath(); +FString M_GetAutoexecPath(); +FString M_GetCajunPath(const char *filename); +FString M_GetConfigPath(bool for_reading); +FString M_GetScreenshotsPath(); +FString M_GetSavegamesPath(); + #endif diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp new file mode 100644 index 000000000..6f77551ae --- /dev/null +++ b/src/m_specialpaths.cpp @@ -0,0 +1,500 @@ +#ifdef __APPLE__ +#include +#endif + +#ifdef _WIN32 +#include +#include +#include +#define USE_WINDOWS_DWORD +#endif + +#include "cmdlib.h" +#include "m_misc.h" + +#if defined(_WIN32) + +//=========================================================================== +// +// M_GetCachePath Windows +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath() +{ + FString path; + + char pathstr[MAX_PATH]; + if (0 != SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathstr)) + { // Failed (e.g. On Win9x): use program directory + path = progdir; + } + else + { + path = pathstr; + } + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + path += "/zdoom/cache"; + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath Windows +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + return "$PROGDIR/autoexec.cfg"; +} + +//=========================================================================== +// +// M_GetCajunPath Windows +// +// Returns the location of the Cajun Bot definitions. +// +//=========================================================================== + +FString M_GetCajunPath(const char *botfilename) +{ + FString path; + + path << progdir << "zcajun/" << botfilename; + if (!FileExists(path)) + { + path = ""; + } + return path; +} + +//=========================================================================== +// +// M_GetConfigPath Windows +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + FString path; + HRESULT hr; + + TCHAR uname[UNLEN+1]; + DWORD unamelen = countof(uname); + + // Because people complained, try for a user-specific .ini in the program directory first. + // If that is not writeable, use the one in the home directory instead. + hr = GetUserName(uname, &unamelen); + if (SUCCEEDED(hr) && uname[0] != 0) + { + // Is it valid for a user name to have slashes? + // Check for them and substitute just in case. + char *probe = uname; + while (*probe != 0) + { + if (*probe == '\\' || *probe == '/') + *probe = '_'; + ++probe; + } + + path = progdir; + path += "zdoom-"; + path += uname; + path += ".ini"; + if (for_reading) + { + if (!FileExists(path.GetChars())) + { + path = ""; + } + } + else + { // check if writeable + FILE *checker = fopen (path.GetChars(), "a"); + if (checker == NULL) + { + path = ""; + } + else + { + fclose (checker); + } + } + } + return path; +} + +//=========================================================================== +// +// M_GetScreenshotsPath Windows +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + FString path; + path = progdir; + return path; +} + +//=========================================================================== +// +// M_GetSavegamesPath Windows +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + FString path; + path = progdir; + return path; +} + +#elif defined(__APPLE__) + +//=========================================================================== +// +// M_GetCachePath Mac OS X +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath() +{ + FString path; + + char pathstr[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) + { + path = pathstr; + } + else + { + path = progdir; + } + path += "/zdoom/cache"; + return path; +} + +//=========================================================================== +// +// M_GetAutoexecPath Mac OS X +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + FString path; + + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/autoexec.cfg"; + } + return path; +} + +//=========================================================================== +// +// M_GetCajunPath Mac OS X +// +// Returns the location of the Cajun Bot definitions. +// +//=========================================================================== + +FString M_GetCajunPath(const char *botfilename) +{ + FString path; + + // Just copies the Windows code. Should this be more Mac-specific? + path << progdir << "zcajun/" << botfilename; + if (!FileExists(path)) + { + path = ""; + } + return path; +} + +//=========================================================================== +// +// M_GetConfigPath Mac OS X +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kPreferencesFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + FString path; + path << cpath << "/zdoom.ini"; + return path; + } + // Ungh. + return "zdoom.ini"; +} + +//=========================================================================== +// +// M_GetScreenshotsPath Mac OS X +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + FString path; + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/Screenshots/"; + } + else + { + path = "~/"; + } + return path; +} + +//=========================================================================== +// +// M_GetSavegamesPath Mac OS X +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + FString path; + char cpath[PATH_MAX]; + FSRef folder; + + if (noErr == FSFindFolder(kUserDomain, kDocumentsFolderType, kCreateFolder, &folder) && + noErr == FSRefMakePath(&folder, (UInt8*)cpath, PATH_MAX)) + { + path << cpath << "/" GAME_DIR "/Savegames/"; + } + return path; +} + +#else // Linux, et al. + +FString GetUserFile(const char *file) +{ + FString path; + struct stat info; + + path = NicePath("~/" GAME_DIR "/"); + + if (stat(path, &info) == -1) + { + struct stat extrainfo; + + // Sanity check for ~/.config + FString configPath = NicePath("~/.config/"); + if (stat(configPath, &extrainfo) == -1) + { + if (mkdir(configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError("Failed to create ~/.config directory:\n%s", strerror(errno)); + } + } + else if (!S_ISDIR(extrainfo.st_mode)) + { + I_FatalError("~/.config must be a directory"); + } + + // This can be removed after a release or two + // Transfer the old zdoom directory to the new location + bool moved = false; + FString oldpath = NicePath("~/.zdoom/"); + if (stat #if defined(__unix__) +FString GetUserFile (const char *file) +{ + FString path; + struct stat info; + + path = NicePath("~/" GAME_DIR "/"); + + if (stat (path, &info) == -1) + { + struct stat extrainfo; + + // Sanity check for ~/.config + FString configPath = NicePath("~/.config/"); + if (stat (configPath, &extrainfo) == -1) + { + if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create ~/.config directory:\n%s", strerror(errno)); + } + } + else if (!S_ISDIR(extrainfo.st_mode)) + { + I_FatalError ("~/.config must be a directory"); + } + + // This can be removed after a release or two + // Transfer the old zdoom directory to the new location + bool moved = false; + FString oldpath = NicePath("~/.zdoom/"); + if (stat (oldpath, &extrainfo) != -1) + { + if (rename(oldpath, path) == -1) + { + I_Error ("Failed to move old zdoom directory (%s) to new location (%s).", + oldpath.GetChars(), path.GetChars()); + } + else + moved = true; + } + + if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1) + { + I_FatalError ("Failed to create %s directory:\n%s", + path.GetChars(), strerror (errno)); + } + } + else + { + if (!S_ISDIR(info.st_mode)) + { + I_FatalError ("%s must be a directory", path.GetChars()); + } + } + path += file; + return path; +} + +//=========================================================================== +// +// M_GetCachePath Unix +// +// Returns the path for cache GL nodes. +// +//=========================================================================== + +FString M_GetCachePath() +{ + // Don't use GAME_DIR and such so that ZDoom and its child ports can + // share the node cache. + return NicePath("~/.config/zdoom/cache"); +} + +//=========================================================================== +// +// M_GetAutoexecPath Unix +// +// Returns the expected location of autoexec.cfg. +// +//=========================================================================== + +FString M_GetAutoexecPath() +{ + return GetUserFile("autoexec.cfg"); +} + +//=========================================================================== +// +// M_GetCajunPath Unix +// +// Returns the location of the Cajun Bot definitions. +// +//=========================================================================== + +FString M_GetCajunPath(const char *botfilename) +{ + FString path; + + // Check first in ~/.config/zdoom./botfilename. + path = GetUserFile(BOTFILENAME); + if (!FileExists(tmp)) + { + // Then check in SHARE_DIR/botfilename. (Some allowance for Macs + // should probably be made here.) + path = SHARE_DIR BOTFILENAME; + if (!FileExists(path)) + { + path =""; + } + } + return path; +} + +//=========================================================================== +// +// M_GetConfigPath Unix +// +// Returns the path to the config file. On Windows, this can vary for reading +// vs writing. i.e. If $PROGDIR/zdoom-.ini does not exist, it will try +// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini. +// +//=========================================================================== + +FString M_GetConfigPath(bool for_reading) +{ + return GetUserFile("zdoom.ini"); +} + +//=========================================================================== +// +// M_GetScreenshotsPath Unix +// +// Returns the path to the default screenshots directory. +// +//=========================================================================== + +FString M_GetScreenshotsPath() +{ + return "~/" GAME_DIR "/screenshots/"; +} + +//=========================================================================== +// +// M_GetSavegamesPath Unix +// +// Returns the path to the default save games directory. +// +//=========================================================================== + +FString M_GetSavegamesPath() +{ + return = "~/" GAME_DIR; +} + +#endif diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 2665f69ba..7dde9c80f 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -43,17 +43,6 @@ #define rmdir _rmdir -// TODO, maybe: stop using DWORD so I don't need to worry about conflicting -// with Windows' typedef. Then I could just include the header file instead -// of declaring everything here. -#define MAX_PATH 260 -#define CSIDL_LOCAL_APPDATA 0x001c -extern "C" __declspec(dllimport) long __stdcall SHGetFolderPathA(void *hwnd, int csidl, void *hToken, unsigned long dwFlags, char *pszPath); - -#endif - -#ifdef __APPLE__ -#include #endif #include "templates.h" @@ -75,6 +64,7 @@ extern "C" __declspec(dllimport) long __stdcall SHGetFolderPathA(void *hwnd, int #include "x86.h" #include "version.h" #include "md5.h" +#include "m_misc.h" void P_GetPolySpots (MapData * lump, TArray &spots, TArray &anchors); @@ -1048,45 +1038,10 @@ bool P_CheckNodes(MapData * map, bool rebuilt, int buildtime) typedef TArray MemFile; -static FString GetCachePath() -{ - FString path; - -#ifdef _WIN32 - char pathstr[MAX_PATH]; - if (0 != SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathstr)) - { // Failed (e.g. On Win9x): use program directory - path = progdir; - } - else - { - path = pathstr; - } - path += "/zdoom/cache"; -#elif defined(__APPLE__) - char pathstr[PATH_MAX]; - FSRef folder; - - if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &folder) && - noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) - { - path = pathstr; - } - else - { - path = progdir; - } - path += "/zdoom/cache"; -#else - // Don't use GAME_DIR and such so that ZDoom and its child ports can share the node cache. - path = NicePath("~/.config/zdoom/cache"); -#endif - return path; -} static FString CreateCacheName(MapData *map, bool create) { - FString path = GetCachePath(); + FString path = M_GetCachePath(); FString lumpname = Wads.GetLumpFullPath(map->lumpnum); int separator = lumpname.IndexOf(':'); path << '/' << lumpname.Left(separator); @@ -1299,7 +1254,7 @@ errorout: CCMD(clearnodecache) { TArray list; - FString path = GetCachePath(); + FString path = M_GetCachePath(); path += "/"; try diff --git a/src/version.h b/src/version.h index d7acf1e6a..5fee0bd83 100644 --- a/src/version.h +++ b/src/version.h @@ -95,8 +95,6 @@ const char *GetVersionString(); #define GAME_DIR ".config/zdoom" #elif defined(__APPLE__) #define GAME_DIR GAMENAME -#else -#define CDROM_DIR "C:\\ZDOOMDAT" #endif diff --git a/zdoom.vcproj b/zdoom.vcproj index 89cf4c7b0..b6ebdeb90 100644 --- a/zdoom.vcproj +++ b/zdoom.vcproj @@ -710,6 +710,10 @@ RelativePath=".\src\m_random.cpp" > + + From 0645053431884fafdcc7ede11694058b16d2b3af Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sat, 14 Sep 2013 23:07:59 -0500 Subject: [PATCH 03/21] Add support for standard file paths on Windows. - If the current user does not have write permissions for the directory zdoom.exe is located in, use standard folder paths located in their home directory instead. This is a common scenario when people put ZDoom into Program Files. (Ironically, zdoom.ini used to be in AppData, buth then people complained when it wasn't in the same directory as zdoom.exe, so it got turned into zdoom-.ini so at least it could retain some multi-user support. I'm not sure when the AppData support was removed, though, since it should have still been kept around for migrating configs to the new name.) --- src/m_misc.cpp | 3 +- src/m_misc.h | 2 +- src/m_specialpaths.cpp | 242 +++++++++++++++++++++++++++++++++-------- src/p_glnodes.cpp | 4 +- 4 files changed, 202 insertions(+), 49 deletions(-) diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 14b9d9b1b..c550c4593 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -646,8 +646,9 @@ void M_ScreenShot (const char *filename) if (dirlen == 0) { autoname = M_GetScreenshotsPath(); + dirlen = autoname.Len(); } - else if (dirlen > 0) + if (dirlen > 0) { if (autoname[dirlen-1] != '/' && autoname[dirlen-1] != '\\') { diff --git a/src/m_misc.h b/src/m_misc.h index 327df3de4..90844221f 100644 --- a/src/m_misc.h +++ b/src/m_misc.h @@ -53,7 +53,7 @@ FString M_ZLibError(int zerrnum); #ifdef __unix__ FString GetUserFile (const char *path); // Prepends ~/.zdoom to path #endif -FString M_GetCachePath(); +FString M_GetCachePath(bool create); FString M_GetAutoexecPath(); FString M_GetCajunPath(const char *filename); FString M_GetConfigPath(bool for_reading); diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index 6f77551ae..cd116e538 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -14,6 +14,114 @@ #if defined(_WIN32) +#include "version.h" // for GAMENAME +typedef HRESULT (*GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); + +//=========================================================================== +// +// IsProgramDirectoryWritable +// +// If the program directory is writable, then dump everything in there for +// historical reasons. Otherwise, known folders get used instead. +// +//=========================================================================== + +bool UseKnownFolders() +{ + // Cache this value so the semantics don't change during a single run + // of the program. (e.g. Somebody could add write access while the + // program is running.) + static INTBOOL iswritable = -1; + FString testpath; + HANDLE file; + + if (iswritable >= 0) + { + return !iswritable; + } + testpath << progdir << "writest"; + file = CreateFile(testpath, GENERIC_READ | GENERIC_WRITE, 0, NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL); + if (file != INVALID_HANDLE_VALUE) + { + CloseHandle(file); + Printf("Using program directory for storage\n"); + iswritable = true; + return false; + } + Printf("Using known folders for storage\n"); + iswritable = false; + return true; +} + +//=========================================================================== +// +// GetKnownFolder +// +// Returns the known_folder if SHGetKnownFolderPath is available, otherwise +// returns the shell_folder using SHGetFolderPath. +// +//=========================================================================== + +bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path) +{ + static GKFP SHGetKnownFolderPath = NULL; + static bool tested = false; + + if (!tested) + { + tested = true; + HMODULE shell32 = GetModuleHandle("shell32.dll"); + if (shell32 != NULL) + { + SHGetKnownFolderPath = (GKFP)GetProcAddress(shell32, "SHGetKnownFolderPath"); + } + } + + char pathstr[MAX_PATH]; + + // SHGetKnownFolderPath knows about more folders than SHGetFolderPath, but is + // new to Vista, hence the reason we support both. + if (SHGetKnownFolderPath == NULL) + { + if (shell_folder < 0) + { // Not supported by SHGetFolderPath + return false; + } + if (create) + { + shell_folder |= CSIDL_FLAG_CREATE; + } + if (FAILED(SHGetFolderPathA(NULL, shell_folder, NULL, 0, pathstr))) + { + return false; + } + path = pathstr; + return true; + } + else + { + PWSTR wpath; + if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath))) + { + return false; + } + // FIXME: Support Unicode, at least for filenames. This function + // has no MBCS equivalent, so we have to convert it since we don't + // support Unicode. :( + bool converted = false; + if (WideCharToMultiByte(GetACP(), WC_NO_BEST_FIT_CHARS, wpath, -1, + pathstr, countof(pathstr), NULL, NULL) > 0) + { + path = pathstr; + converted = true; + } + CoTaskMemFree(wpath); + return converted; + } +} + //=========================================================================== // // M_GetCachePath Windows @@ -22,19 +130,14 @@ // //=========================================================================== -FString M_GetCachePath() +FString M_GetCachePath(bool create) { FString path; - char pathstr[MAX_PATH]; - if (0 != SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, pathstr)) + if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path)) { // Failed (e.g. On Win9x): use program directory path = progdir; } - else - { - path = pathstr; - } // Don't use GAME_DIR and such so that ZDoom and its child ports can // share the node cache. path += "/zdoom/cache"; @@ -89,48 +192,50 @@ FString M_GetConfigPath(bool for_reading) FString path; HRESULT hr; - TCHAR uname[UNLEN+1]; - DWORD unamelen = countof(uname); - - // Because people complained, try for a user-specific .ini in the program directory first. - // If that is not writeable, use the one in the home directory instead. - hr = GetUserName(uname, &unamelen); - if (SUCCEEDED(hr) && uname[0] != 0) + // Construct a user-specific config name + if (UseKnownFolders() && GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true, path)) { - // Is it valid for a user name to have slashes? - // Check for them and substitute just in case. - char *probe = uname; - while (*probe != 0) - { - if (*probe == '\\' || *probe == '/') - *probe = '_'; - ++probe; - } + path += "/zdoom"; + CreatePath(path); + path += "/zdoom.ini"; + } + else + { // construct "$PROGDIR/zdoom-$USER.ini" + TCHAR uname[UNLEN+1]; + DWORD unamelen = countof(uname); path = progdir; - path += "zdoom-"; - path += uname; - path += ".ini"; - if (for_reading) + hr = GetUserName(uname, &unamelen); + if (SUCCEEDED(hr) && uname[0] != 0) { - if (!FileExists(path.GetChars())) + // Is it valid for a user name to have slashes? + // Check for them and substitute just in case. + char *probe = uname; + while (*probe != 0) { - path = ""; + if (*probe == '\\' || *probe == '/') + *probe = '_'; + ++probe; } + path << "zdoom-" << uname << ".ini"; } else - { // check if writeable - FILE *checker = fopen (path.GetChars(), "a"); - if (checker == NULL) - { - path = ""; - } - else - { - fclose (checker); - } + { // Couldn't get user name, so just use zdoom.ini + path += "zdoom.ini"; } } + + // If we are reading the config file, check if it exists. If not, fallback + // to $PROGDIR/zdoom.ini + if (for_reading) + { + if (!FileExists(path)) + { + path = progdir; + path << "zdoom.ini"; + } + } + return path; } @@ -142,10 +247,31 @@ FString M_GetConfigPath(bool for_reading) // //=========================================================================== +// I'm not sure when FOLDERID_Screenshots was added, but it was probably +// for Windows 8, since it's not in the v7.0 Windows SDK. +static const GUID MyFOLDERID_Screenshots = { 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f }; + FString M_GetScreenshotsPath() { FString path; - path = progdir; + + if (!UseKnownFolders()) + { + return progdir; + } + else if (GetKnownFolder(-1, MyFOLDERID_Screenshots, true, path)) + { + path << "/" GAMENAME; + } + else if (GetKnownFolder(CSIDL_MYPICTURES, FOLDERID_Pictures, true, path)) + { + path << "/Screenshots/" GAMENAME; + } + else + { + return progdir; + } + CreatePath(path); return path; } @@ -160,7 +286,28 @@ FString M_GetScreenshotsPath() FString M_GetSavegamesPath() { FString path; - path = progdir; + + if (!UseKnownFolders()) + { + return progdir; + } + // Try standard Saved Games folder + else if (GetKnownFolder(-1, FOLDERID_SavedGames, true, path)) + { + path << "/" GAMENAME; + } + // Try defacto My Documents/My Games folder + else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path)) + { + // I assume since this isn't a standard folder, it doesn't have + // a localized name either. + path << "/My Games/" GAMENAME; + CreatePath(path); + } + else + { + path = progdir; + } return path; } @@ -174,14 +321,14 @@ FString M_GetSavegamesPath() // //=========================================================================== -FString M_GetCachePath() +FString M_GetCachePath(bool create) { FString path; char pathstr[PATH_MAX]; FSRef folder; - if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, kCreateFolder, &folder) && + if (noErr == FSFindFolder(kLocalDomain, kApplicationSupportFolderType, create ? kCreateFolder : 0, &folder) && noErr == FSRefMakePath(&folder, (UInt8*)pathstr, PATH_MAX)) { path = pathstr; @@ -409,11 +556,16 @@ FString GetUserFile (const char *file) // //=========================================================================== -FString M_GetCachePath() +FString M_GetCachePath(bool create) { // Don't use GAME_DIR and such so that ZDoom and its child ports can // share the node cache. - return NicePath("~/.config/zdoom/cache"); + FString path = NicePath("~/.config/zdoom/cache"); + if (create) + { + CreatePath(create); + } + return path; } //=========================================================================== diff --git a/src/p_glnodes.cpp b/src/p_glnodes.cpp index 7dde9c80f..b07d50aed 100644 --- a/src/p_glnodes.cpp +++ b/src/p_glnodes.cpp @@ -1041,7 +1041,7 @@ typedef TArray MemFile; static FString CreateCacheName(MapData *map, bool create) { - FString path = M_GetCachePath(); + FString path = M_GetCachePath(create); FString lumpname = Wads.GetLumpFullPath(map->lumpnum); int separator = lumpname.IndexOf(':'); path << '/' << lumpname.Left(separator); @@ -1254,7 +1254,7 @@ errorout: CCMD(clearnodecache) { TArray list; - FString path = M_GetCachePath(); + FString path = M_GetCachePath(false); path += "/"; try From d36afb975ca7017920998998248e2f4f35b0229e Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 15 Sep 2013 08:57:22 +0200 Subject: [PATCH 04/21] - fixed the Linux portion of m_specialpaths.cpp which had a section of GetUserFile duplicated. --- src/m_specialpaths.cpp | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index cd116e538..469a2fa6b 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -461,36 +461,7 @@ FString M_GetSavegamesPath() #else // Linux, et al. -FString GetUserFile(const char *file) -{ - FString path; - struct stat info; - path = NicePath("~/" GAME_DIR "/"); - - if (stat(path, &info) == -1) - { - struct stat extrainfo; - - // Sanity check for ~/.config - FString configPath = NicePath("~/.config/"); - if (stat(configPath, &extrainfo) == -1) - { - if (mkdir(configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1) - { - I_FatalError("Failed to create ~/.config directory:\n%s", strerror(errno)); - } - } - else if (!S_ISDIR(extrainfo.st_mode)) - { - I_FatalError("~/.config must be a directory"); - } - - // This can be removed after a release or two - // Transfer the old zdoom directory to the new location - bool moved = false; - FString oldpath = NicePath("~/.zdoom/"); - if (stat #if defined(__unix__) FString GetUserFile (const char *file) { FString path; From 8847d5649adf011ac5e8cb327e94554f04d2896f Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 15 Sep 2013 23:11:55 +0200 Subject: [PATCH 05/21] - fixed: Bridge needs to call Super::Destroy. --- src/g_shared/a_bridge.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/g_shared/a_bridge.cpp b/src/g_shared/a_bridge.cpp index d669cc3bd..4caa56287 100644 --- a/src/g_shared/a_bridge.cpp +++ b/src/g_shared/a_bridge.cpp @@ -75,6 +75,7 @@ void ACustomBridge::Destroy() thing->Destroy(); } } + Super::Destroy(); } // Action functions for the non-Doom bridge -------------------------------- From 88b05fe2a10f20299a44ce7f23de7892489a552b Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 17 Sep 2013 17:31:29 -0500 Subject: [PATCH 06/21] Fixed: SHGetKnownFolderPath needs to be declared as WINAPI. --- src/m_specialpaths.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index cd116e538..469f7587e 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -15,7 +15,7 @@ #if defined(_WIN32) #include "version.h" // for GAMENAME -typedef HRESULT (*GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); +typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); //=========================================================================== // From e021fba5e1813636245baad445d260240da73a63 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Tue, 17 Sep 2013 20:44:13 -0500 Subject: [PATCH 07/21] Improve NoDelay reliability. - Instead of tying NoDelay behavior to OF_JustSpawned, use a new actor flag, MF7_HANDLENODELAY. This only gets cleared once it has actually been checked by Tick(). This is necessary because freeze mode delays the initial run of Tick() past the initial spawn, so OF_JustSpawned will no longer be set when it does the initial tick. - Delay NoDelay processing if an actor is spawned dormant. Actors spawned dormant have Deactivate() called before they tick, so MF7_HANDLENODELAY will remain set as long as an actor is dormant. This allows the NoDelay handling to occur as expected once it is activated. --- src/actor.h | 3 ++- src/dobject.h | 2 +- src/dthinker.cpp | 2 +- src/p_mobj.cpp | 27 ++++++++++++++++----------- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/actor.h b/src/actor.h index c60b6a516..3a97ef49a 100644 --- a/src/actor.h +++ b/src/actor.h @@ -334,11 +334,12 @@ enum MF6_NOTONAUTOMAP = 0x40000000, // will not be shown on automap with the 'scanner' powerup. MF6_RELATIVETOFLOOR = 0x80000000, // [RC] Make flying actors be affected by lifts. -// --- mobj.flags6 --- +// --- mobj.flags7 --- MF7_NEVERTARGET = 0x00000001, // can not be targetted at all, even if monster friendliness is considered. MF7_NOTELESTOMP = 0x00000002, // cannot telefrag under any circumstances (even when set by MAPINFO) MF7_ALWAYSTELEFRAG = 0x00000004, // will unconditionally be telefragged when in the way. Overrides all other settings. + MF7_HANDLENODELAY = 0x00000008, // respect NoDelay state flag // --- mobj.renderflags --- diff --git a/src/dobject.h b/src/dobject.h index 2ae5493c6..40b47ee5c 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -473,7 +473,7 @@ public: // use this method. virtual size_t PointerSubstitution (DObject *old, DObject *notOld); static size_t StaticPointerSubstitution (DObject *old, DObject *notOld); - + PClass *GetClass() const { if (Class == NULL) diff --git a/src/dthinker.cpp b/src/dthinker.cpp index 15206dabd..327b29731 100644 --- a/src/dthinker.cpp +++ b/src/dthinker.cpp @@ -457,7 +457,7 @@ int DThinker::TickThinkers (FThinkerList *list, FThinkerList *dest) node->PostBeginPlay(); } else if (dest != NULL) - { // Move thinker from this list to the destination list + { I_Error("There is a thinker in the fresh list that has already ticked.\n"); } diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 13f9de0af..492dd3389 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -3525,19 +3525,23 @@ void AActor::Tick () Destroy(); return; } - if (ObjectFlags & OF_JustSpawned && state->GetNoDelay()) + if ((flags7 & MF7_HANDLENODELAY) && !(flags2 & MF2_DORMANT)) { - // For immediately spawned objects with the NoDelay flag set for their - // Spawn state, explicitly set the current state so that it calls its - // action and chains 0-tic states. - int starttics = tics; - if (!SetState(state)) - return; // freed itself - // If the initial state had a duration of 0 tics, let the next state run - // normally. Otherwise, increment tics by 1 so that we don't double up ticks. - if (starttics > 0 && tics >= 0) + flags7 &= ~MF7_HANDLENODELAY; + if (state->GetNoDelay()) { - tics++; + // For immediately spawned objects with the NoDelay flag set for their + // Spawn state, explicitly set the current state so that it calls its + // action and chains 0-tic states. + int starttics = tics; + if (!SetState(state)) + return; // freed itself + // If the initial state had a duration of 0 tics, let the next state run + // normally. Otherwise, increment tics by 1 so that we don't double up ticks. + else if (starttics > 0 && tics >= 0) + { + tics++; + } } } // cycle through states, calling action functions at transitions @@ -4024,6 +4028,7 @@ void AActor::PostBeginPlay () Renderer->StateChanged(this); } PrevAngle = angle; + flags7 |= MF7_HANDLENODELAY; } void AActor::MarkPrecacheSounds() const From f591c5df5e3a1a18c8d737777d1f7f5f62835c20 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 18 Sep 2013 09:40:40 +0200 Subject: [PATCH 08/21] - fixed: saving the config to the user's known folders should use the GAME_DIR #define, not 'zdoom' so that child ports can have their own. --- src/m_specialpaths.cpp | 2 +- src/version.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index 469a2fa6b..d9b776d58 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -195,7 +195,7 @@ FString M_GetConfigPath(bool for_reading) // Construct a user-specific config name if (UseKnownFolders() && GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true, path)) { - path += "/zdoom"; + path << '/' << GAME_DIR; CreatePath(path); path += "/zdoom.ini"; } diff --git a/src/version.h b/src/version.h index 5fee0bd83..b0717fbf8 100644 --- a/src/version.h +++ b/src/version.h @@ -95,6 +95,8 @@ const char *GetVersionString(); #define GAME_DIR ".config/zdoom" #elif defined(__APPLE__) #define GAME_DIR GAMENAME +#else +#define GAME_DIR "zdoom" #endif From e748c49dd0c672829d23ab31358e6671ebf5b215 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 17:29:42 -0500 Subject: [PATCH 09/21] - Fixed: m_specialpaths.cpp did not compile under Linux. --- src/m_specialpaths.cpp | 31 +++++++++++++++++++------------ src/version.h | 6 ++---- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/m_specialpaths.cpp b/src/m_specialpaths.cpp index 1f17f90c2..b4fcba3c3 100644 --- a/src/m_specialpaths.cpp +++ b/src/m_specialpaths.cpp @@ -12,9 +12,16 @@ #include "cmdlib.h" #include "m_misc.h" -#if defined(_WIN32) +#if !defined(__APPLE__) && !defined(_WIN32) +#include +#include +#include "i_system.h" +#endif #include "version.h" // for GAMENAME + +#if defined(_WIN32) + typedef HRESULT (WINAPI *GKFP)(REFKNOWNFOLDERID, DWORD, HANDLE, PWSTR *); //=========================================================================== @@ -195,7 +202,7 @@ FString M_GetConfigPath(bool for_reading) // Construct a user-specific config name if (UseKnownFolders() && GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true, path)) { - path << '/' << GAME_DIR; + path += "/" GAME_DIR; CreatePath(path); path += "/zdoom.ini"; } @@ -534,7 +541,7 @@ FString M_GetCachePath(bool create) FString path = NicePath("~/.config/zdoom/cache"); if (create) { - CreatePath(create); + CreatePath(path); } return path; } @@ -564,16 +571,16 @@ FString M_GetCajunPath(const char *botfilename) { FString path; - // Check first in ~/.config/zdoom./botfilename. - path = GetUserFile(BOTFILENAME); - if (!FileExists(tmp)) + // Check first in ~/.config/zdoom/botfilename. + path = GetUserFile(botfilename); + if (!FileExists(path)) { - // Then check in SHARE_DIR/botfilename. (Some allowance for Macs - // should probably be made here.) - path = SHARE_DIR BOTFILENAME; + // Then check in SHARE_DIR/botfilename. + path = SHARE_DIR; + path << botfilename; if (!FileExists(path)) { - path =""; + path = ""; } } return path; @@ -604,7 +611,7 @@ FString M_GetConfigPath(bool for_reading) FString M_GetScreenshotsPath() { - return "~/" GAME_DIR "/screenshots/"; + return NicePath("~/" GAME_DIR "/screenshots/"); } //=========================================================================== @@ -617,7 +624,7 @@ FString M_GetScreenshotsPath() FString M_GetSavegamesPath() { - return = "~/" GAME_DIR; + return NicePath("~/" GAME_DIR); } #endif diff --git a/src/version.h b/src/version.h index b0717fbf8..66e2f8938 100644 --- a/src/version.h +++ b/src/version.h @@ -91,12 +91,10 @@ const char *GetVersionString(); #define FORUM_URL "http://forum.zdoom.org" #define BUGS_FORUM_URL "http://forum.zdoom.org/index.php?c=3" -#ifdef __unix__ -#define GAME_DIR ".config/zdoom" -#elif defined(__APPLE__) +#if defined(__APPLE__) || defined(_WIN32) #define GAME_DIR GAMENAME #else -#define GAME_DIR "zdoom" +#define GAME_DIR ".config/zdoom" #endif From 285be8db926d3fc7ebc7af992f00171d3dbd7336 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 20:45:39 -0500 Subject: [PATCH 10/21] Fixed: wi_noautostartmap was not sync safe - Make wi_noautostartmap a userinfo cvar. This allows it to be communicated across the network and saved in demos. If any player has it set, then the intermission screen will not automatically advance to the next level. --- src/d_player.h | 4 ++++ src/namedef.h | 1 + src/wi_stuff.cpp | 25 +++++++++++++++++++++---- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/d_player.h b/src/d_player.h index 75ed533d9..69487070e 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -325,6 +325,10 @@ struct userinfo_t : TMap { return *static_cast(*CheckKey(NAME_Gender)); } + bool GetNoAutostartMap() const + { + return *static_cast(*CheckKey(NAME_Wi_NoAutostartMap)); + } void Reset(); int TeamChanged(int team); diff --git a/src/namedef.h b/src/namedef.h index f7607400e..644d0deb4 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -568,3 +568,4 @@ xx(NeverSwitchOnPickup) xx(MoveBob) xx(StillBob) xx(PlayerClass) +xx(Wi_NoAutostartMap) \ No newline at end of file diff --git a/src/wi_stuff.cpp b/src/wi_stuff.cpp index 6ae9148af..7aef939b1 100644 --- a/src/wi_stuff.cpp +++ b/src/wi_stuff.cpp @@ -62,7 +62,7 @@ typedef enum CVAR (Bool, wi_percents, true, CVAR_ARCHIVE) CVAR (Bool, wi_showtotaltime, true, CVAR_ARCHIVE) -CVAR (Bool, wi_noautostartmap, false, CVAR_ARCHIVE) +CVAR (Bool, wi_noautostartmap, false, CVAR_USERINFO|CVAR_ARCHIVE) void WI_loadData (); @@ -1098,11 +1098,28 @@ void WI_updateNoState () { WI_updateAnimatedBack(); + if (acceleratestage) + { + cnt = 0; + } + else + { + bool noauto = noautostartmap; - if (!wi_noautostartmap && !noautostartmap) cnt--; - if (acceleratestage) cnt=0; + for (int i = 0; !noauto && i < MAXPLAYERS; ++i) + { + if (playeringame[i]) + { + noauto |= players[i].userinfo.GetNoAutostartMap(); + } + } + if (!noauto) + { + cnt--; + } + } - if (cnt==0) + if (cnt == 0) { WI_End(); G_WorldDone(); From 0cf68af7d26978b3c3623855ece6633d0ce56946 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:14:44 -0500 Subject: [PATCH 11/21] Overload operator = for player_t - This fixes crashes when quitting multiplayer games because the default byte-for-byte copy caused PredictionPlayerBackup and the console player to point to the exact same userinfo data and to both try and free it when they are deleted. --- src/d_netinfo.cpp | 1 + src/d_player.h | 1 + src/p_user.cpp | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/src/d_netinfo.cpp b/src/d_netinfo.cpp index 6832a047e..12fb187ae 100644 --- a/src/d_netinfo.cpp +++ b/src/d_netinfo.cpp @@ -1058,4 +1058,5 @@ userinfo_t::~userinfo_t() { delete pair->Value; } + this->Clear(); } diff --git a/src/d_player.h b/src/d_player.h index 69487070e..f6f7674d7 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -352,6 +352,7 @@ class player_t { public: player_t(); + player_t &operator= (const player_t &p); void Serialize (FArchive &arc); size_t FixPointers (const DObject *obj, DObject *replacement); diff --git a/src/p_user.cpp b/src/p_user.cpp index e2c8b80c9..901f6cfaa 100644 --- a/src/p_user.cpp +++ b/src/p_user.cpp @@ -314,6 +314,115 @@ player_t::player_t() memset (&skill, 0, sizeof(skill)); } +player_t &player_t::operator=(const player_t &p) +{ + mo = p.mo; + playerstate = p.playerstate; + cmd = p.cmd; + original_cmd = p.original_cmd; + original_oldbuttons = p.original_oldbuttons; + // Intentionally not copying userinfo! + cls = p.cls; + DesiredFOV = p.DesiredFOV; + FOV = p.FOV; + viewz = p.viewz; + viewheight = p.viewheight; + deltaviewheight = p.deltaviewheight; + bob = p.bob; + velx = p.velx; + vely = p.vely; + centering = p.centering; + turnticks = p.turnticks; + attackdown = p.attackdown; + usedown = p.usedown; + oldbuttons = p.oldbuttons; + health = p.health; + inventorytics = p.inventorytics; + CurrentPlayerClass = p.CurrentPlayerClass; + backpack = p.backpack; + memcpy(frags, &p.frags, sizeof(frags)); + fragcount = p.fragcount; + lastkilltime = p.lastkilltime; + multicount = p.multicount; + spreecount = p.spreecount; + WeaponState = p.WeaponState; + ReadyWeapon = p.ReadyWeapon; + PendingWeapon = p.PendingWeapon; + cheats = p.cheats; + timefreezer = p.timefreezer; + refire = p.refire; + inconsistant = p.inconsistant; + waiting = p.waiting; + killcount = p.killcount; + itemcount = p.itemcount; + secretcount = p.secretcount; + damagecount = p.damagecount; + bonuscount = p.bonuscount; + hazardcount = p.hazardcount; + poisoncount = p.poisoncount; + poisontype = p.poisontype; + poisonpaintype = p.poisonpaintype; + poisoner = p.poisoner; + attacker = p.attacker; + extralight = p.extralight; + fixedcolormap = p.fixedcolormap; + fixedlightlevel = p.fixedlightlevel; + memcpy(psprites, &p.psprites, sizeof(psprites)); + morphTics = p.morphTics; + MorphedPlayerClass = p.MorphedPlayerClass; + MorphStyle = p.MorphStyle; + MorphExitFlash = p.MorphExitFlash; + PremorphWeapon = p.PremorphWeapon; + chickenPeck = p.chickenPeck; + jumpTics = p.jumpTics; + respawn_time = p.respawn_time; + camera = p.camera; + air_finished = p.air_finished; + LastDamageType = p.LastDamageType; + savedyaw = p.savedyaw; + savedpitch = p.savedpitch; + angle = p.angle; + dest = p.dest; + prev = p.prev; + enemy = p.enemy; + missile = p.missile; + mate = p.mate; + last_mate = p.last_mate; + settings_controller = p.settings_controller; + skill = p.skill; + t_active = p.t_active; + t_respawn = p.t_respawn; + t_strafe = p.t_strafe; + t_react = p.t_react; + t_fight = p.t_fight; + t_roam = p.t_roam; + t_rocket = p.t_rocket; + isbot = p.isbot; + first_shot = p.first_shot; + sleft = p.sleft; + allround = p.allround; + oldx = p.oldx; + oldy = p.oldy; + BlendR = p.BlendR; + BlendG = p.BlendG; + BlendB = p.BlendB; + BlendA = p.BlendA; + LogText = p.LogText; + MinPitch = p.MinPitch; + MaxPitch = p.MaxPitch; + crouching = p.crouching; + crouchdir = p.crouchdir; + crouchfactor = p.crouchfactor; + crouchoffset = p.crouchoffset; + crouchviewdelta = p.crouchviewdelta; + weapons = p.weapons; + ConversationNPC = p.ConversationNPC; + ConversationPC = p.ConversationPC; + ConversationNPCAngle = p.ConversationNPCAngle; + ConversationFaceTalker = p.ConversationFaceTalker; + return *this; +} + // This function supplements the pointer cleanup in dobject.cpp, because // player_t is not derived from DObject. (I tried it, and DestroyScan was // unable to properly determine the player object's type--possibly From d05cdb79ef9b25ad8aac0d66012209c20b9d89bc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:22:21 -0500 Subject: [PATCH 12/21] Switch true to LAF_ISMELEEATTACK inside A_Punch's call to P_LineAttack() --- src/g_doom/a_doomweaps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 9dd055711..368d7ce8b 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -53,7 +53,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Punch) angle += pr_punch.Random2() << 18; pitch = P_AimLineAttack (self, angle, MELEERANGE, &linetarget); - P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, true, &linetarget); + P_LineAttack (self, angle, MELEERANGE, pitch, damage, NAME_Melee, NAME_BulletPuff, LAF_ISMELEEATTACK, &linetarget); // turn to face target if (linetarget) From a7a7d5d6b3dc5075ea5c82b7b50ac2c12dbadfa4 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:25:00 -0500 Subject: [PATCH 13/21] Add missing prantheses for A_CustomPunch's puffFlags calculation - Fixed: Need parentheses for precedence when setting puffFlags in A_CustomPunch. Otherwise, it's completely broken. --- src/thingdef/thingdef_codeptr.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f5ef45f45..c97aee39c 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1404,7 +1404,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) } if (!PuffType) PuffType = PClass::FindClass(NAME_BulletPuff); - int puffFlags = LAF_ISMELEEATTACK | (flags & CPF_NORANDOMPUFFZ)? LAF_NORANDOMPUFFZ : 0; + int puffFlags = LAF_ISMELEEATTACK | ((flags & CPF_NORANDOMPUFFZ) ? LAF_NORANDOMPUFFZ : 0); P_LineAttack (self, angle, Range, pitch, Damage, NAME_Melee, PuffType, puffFlags, &linetarget, &actualdamage); @@ -1426,7 +1426,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (flags & CPF_PULLIN) self->flags |= MF_JUSTATTACKED; if (flags & CPF_DAGGER) P_DaggerAlert (self, linetarget); - } } From e3741c809752f67d07a9004df823849ae5b55d0e Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:29:19 -0500 Subject: [PATCH 14/21] GetSelectedSize() needs to check for a valid selection. - With mouse navigation, there's no guarantee that there even is a selected item. --- src/menu/videomenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index 8a6e6720d..f26b90704 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -348,7 +348,7 @@ void M_InitVideoModesMenu () static bool GetSelectedSize (int *width, int *height) { FOptionMenuDescriptor *opt = GetVideoModeMenu(); - if (opt != NULL) + if (opt != NULL && (unsigned)opt->mSelectedItem < opt->mItems.Size()) { int line = opt->mSelectedItem; int hsel; From 75535fba727d0aa9c733c4ee4cf9d32d1d75ab93 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:32:46 -0500 Subject: [PATCH 15/21] Do not enter testing mode if a valid mode is not selected. - It doesn't make much sense to "test" the current mode if a non-video mode is selected in the menu, so don't. --- src/menu/videomenu.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/menu/videomenu.cpp b/src/menu/videomenu.cpp index f26b90704..1d1d02383 100644 --- a/src/menu/videomenu.cpp +++ b/src/menu/videomenu.cpp @@ -166,15 +166,18 @@ public: NewWidth = SCREENWIDTH; NewHeight = SCREENHEIGHT; } - OldWidth = SCREENWIDTH; - OldHeight = SCREENHEIGHT; - OldBits = DisplayBits; - NewBits = BitTranslate[DummyDepthCvar]; - setmodeneeded = true; - testingmode = I_GetTime(false) + 5 * TICRATE; - S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); - SetModesMenu (NewWidth, NewHeight, NewBits); - return true; + else + { + OldWidth = SCREENWIDTH; + OldHeight = SCREENHEIGHT; + OldBits = DisplayBits; + NewBits = BitTranslate[DummyDepthCvar]; + setmodeneeded = true; + testingmode = I_GetTime(false) + 5 * TICRATE; + S_Sound (CHAN_VOICE | CHAN_UI, "menu/choose", snd_menuvolume, ATTN_NONE); + SetModesMenu (NewWidth, NewHeight, NewBits); + return true; + } } return Super::Responder(ev); } From ad7aefff20b4047b5bac744a13743dcba24cc775 Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 21:37:51 -0500 Subject: [PATCH 16/21] - Fixed: Do not apply AVOIDMELEE logic when moving toward a goal --- src/p_enemy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 81a58ac15..359b49f9c 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -915,7 +915,7 @@ void P_NewChaseDir(AActor * actor) // MBF's monster_backing option. Made an actor flag instead. Also cleaned the code up to make it readable. // Todo: implement the movement logic AActor *target = actor->target; - if (target->health > 0 && !actor->IsFriend(target)) + if (target->health > 0 && !actor->IsFriend(target) && target != actor->goal) { // Live enemy target if (actor->flags3 & MF3_AVOIDMELEE) From 5850279090bc29f3f76811baaf719eb319bdf1bc Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 18 Sep 2013 22:03:59 -0500 Subject: [PATCH 17/21] - Fixed: Thing_SetGoal could put an actor's target and goal out of sync. If an actor is already targeting a goal, and Thing_SetGoal is used on it, it would still be left targeting the old goal instead of the new one. This messed up checks in A_Chase for walking towards a goal vs a real target. --- src/p_lnspec.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/p_lnspec.cpp b/src/p_lnspec.cpp index 869fd5169..12c877116 100644 --- a/src/p_lnspec.cpp +++ b/src/p_lnspec.cpp @@ -1562,9 +1562,21 @@ FUNC(LS_Thing_SetGoal) ok = true; if (self->flags & MF_SHOOTABLE) { + if (self->target == self->goal) + { // Targeting a goal already? -> don't target it anymore. + // A_Look will set it to the goal, presuming no real targets + // come into view by then. + self->target = NULL; + } self->goal = goal; - if (arg3 == 0) self->flags5 &=~ MF5_CHASEGOAL; - else self->flags5 |= MF5_CHASEGOAL; + if (arg3 == 0) + { + self->flags5 &= ~MF5_CHASEGOAL; + } + else + { + self->flags5 |= MF5_CHASEGOAL; + } if (self->target == NULL) { self->reactiontime = arg2 * TICRATE; From a144221174b99341051f26af21b39c4da8e450de Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 20 Sep 2013 10:43:10 +0200 Subject: [PATCH 18/21] - changed the invisible waiting frame of the ExplosiveBarrel to use TNTA10 instead of the real barrel frame. This is so that sprite checks do not erroneously determine that there's still something to see. GZDoom's dynamic light code has problems with this. --- wadsrc/static/actors/doom/doommisc.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wadsrc/static/actors/doom/doommisc.txt b/wadsrc/static/actors/doom/doommisc.txt index 131bb273d..fadab2b05 100644 --- a/wadsrc/static/actors/doom/doommisc.txt +++ b/wadsrc/static/actors/doom/doommisc.txt @@ -27,8 +27,8 @@ ACTOR ExplosiveBarrel 2035 BEXP C 5 BRIGHT BEXP D 5 BRIGHT A_Explode BEXP E 10 BRIGHT - BEXP E 1050 BRIGHT A_BarrelDestroy - BEXP E 5 A_Respawn + TNT1 A 1050 BRIGHT A_BarrelDestroy + TNT1 A 5 A_Respawn Wait } } From f73275ad8892fc6ce46d78b1318e6966ee5e8d44 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 21 Sep 2013 12:46:19 -0400 Subject: [PATCH 19/21] - Applied Tesseract's patch for drawimage extensions. (Extended icon support and maximum width/height.) --- src/g_shared/sbar.h | 16 ++- src/g_shared/sbarinfo.cpp | 8 +- src/g_shared/sbarinfo_commands.cpp | 165 +++++++++++++++++++++++------ src/g_shared/shared_hud.cpp | 48 ++++++--- 4 files changed, 188 insertions(+), 49 deletions(-) diff --git a/src/g_shared/sbar.h b/src/g_shared/sbar.h index 3d8c62001..b8dde5850 100644 --- a/src/g_shared/sbar.h +++ b/src/g_shared/sbar.h @@ -444,6 +444,20 @@ void ST_LoadCrosshair(bool alwaysload=false); void ST_Clear(); extern FTexture *CrosshairImage; -FTextureID GetWeaponIcon(AWeapon *weapon); +FTextureID GetInventoryIcon(AInventory *item, DWORD flags, bool *applyscale); + +enum DI_Flags +{ + DI_SKIPICON = 0x1, + DI_SKIPALTICON = 0x2, + DI_SKIPSPAWN = 0x4, + DI_SKIPREADY = 0x8, + DI_ALTICONFIRST = 0x10, + + DI_DRAWINBOX = 0x20, // Set when either width or height is not zero + + DI_FORCESCALE = 0x40, + DI_ALTERNATEONFAIL = 0x80 +}; #endif /* __SBAR_H__ */ diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp index 09be47363..3e1c364e2 100644 --- a/src/g_shared/sbarinfo.cpp +++ b/src/g_shared/sbarinfo.cpp @@ -1187,8 +1187,12 @@ public: if((offsetflags & SBarInfoCommand::CENTER) == SBarInfoCommand::CENTER) { - dx -= (texture->GetScaledWidthDouble()/2.0)-texture->GetScaledLeftOffsetDouble(); - dy -= (texture->GetScaledHeightDouble()/2.0)-texture->GetScaledTopOffsetDouble(); + if (forceWidth < 0) dx -= (texture->GetScaledWidthDouble()/2.0)-texture->GetScaledLeftOffsetDouble(); + else dx -= forceWidth*(0.5-(texture->GetScaledLeftOffsetDouble()/texture->GetScaledWidthDouble())); + //Unoptimalized formula is dx -= forceWidth/2.0-(texture->GetScaledLeftOffsetDouble()*forceWidth/texture->GetScaledWidthDouble()); + + if (forceHeight < 0) dy -= (texture->GetScaledHeightDouble()/2.0)-texture->GetScaledTopOffsetDouble(); + else dy -= forceHeight*(0.5-(texture->GetScaledTopOffsetDouble()/texture->GetScaledHeightDouble())); } dx += xOffset; diff --git a/src/g_shared/sbarinfo_commands.cpp b/src/g_shared/sbarinfo_commands.cpp index febf32b80..d5ee06d11 100644 --- a/src/g_shared/sbarinfo_commands.cpp +++ b/src/g_shared/sbarinfo_commands.cpp @@ -41,28 +41,65 @@ // classes. //////////////////////////////////////////////////////////////////////////////// - -class CommandDrawImage : public SBarInfoCommand +class CommandDrawImage : public SBarInfoCommandFlowControl { public: - CommandDrawImage(SBarInfo *script) : SBarInfoCommand(script), - translatable(false), type(NORMAL_IMAGE), image(-1), offset(static_cast (TOP|LEFT)), + CommandDrawImage(SBarInfo *script) : SBarInfoCommandFlowControl(script), + translatable(false), type(NORMAL_IMAGE), image(-1), maxwidth(-1), + maxheight(-1), spawnScaleX(1.0f), spawnScaleY(1.0f), flags(0), + applyscale(false), offset(static_cast (TOP|LEFT)), texture(NULL), alpha(FRACUNIT) { } void Draw(const SBarInfoMainBlock *block, const DSBarInfo *statusBar) { + if(flags & DI_ALTERNATEONFAIL) + SBarInfoCommandFlowControl::Draw(block, statusBar); + if(texture == NULL) return; + int w = maxwidth, h = maxheight; + // We must calculate this per frame in order to prevent glitches with cl_capfps true. fixed_t frameAlpha = block->Alpha(); if(alpha != FRACUNIT) frameAlpha = fixed_t(((double) block->Alpha() / (double) FRACUNIT) * ((double) alpha / (double) OPAQUE) * FRACUNIT); - + + if(flags & DI_DRAWINBOX) + { + double scale1, scale2; + scale1 = scale2 = 1.0f; + double texwidth = (int) (texture->GetScaledWidthDouble()*spawnScaleX); + double texheight = (int) (texture->GetScaledHeightDouble()*spawnScaleY); + + if (w != -1 && (wGetScaledWidthDouble()*spawnScaleX); + h=(int) (texture->GetScaledHeightDouble()*spawnScaleY); + } statusBar->DrawGraphic(texture, imgx, imgy, block->XOffset(), block->YOffset(), frameAlpha, block->FullScreenOffsets(), - translatable, false, offset); + translatable, false, offset, false, w, h); } void Parse(FScanner &sc, bool fullScreenOffsets) { @@ -98,7 +135,7 @@ class CommandDrawImage : public SBarInfoCommand type = HEXENARMOR_AMULET; else { - sc.ScriptMessage("Unkown armor type: '%s'", sc.String); + sc.ScriptMessage("Unknown armor type: '%s'", sc.String); type = HEXENARMOR_ARMOR; } sc.MustGetToken(','); @@ -141,48 +178,90 @@ class CommandDrawImage : public SBarInfoCommand offset = CENTER; else if(sc.Compare("centerbottom")) offset = static_cast (HMIDDLE|BOTTOM); - else + else if(!sc.Compare("lefttop")) //That's already set sc.ScriptError("'%s' is not a valid alignment.", sc.String); } - sc.MustGetToken(';'); + if(sc.CheckToken(',')) + { + sc.MustGetToken(TK_IntConst); + if((maxwidth = sc.Number) > 0) + flags |= DI_DRAWINBOX; + else + maxwidth = -1; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + if ((maxheight = sc.Number) > 0) + flags |= DI_DRAWINBOX; + else + maxheight = -1; + } + if(sc.CheckToken(',')) + { + while(sc.CheckToken(TK_Identifier)) + { + if(sc.Compare("skipicon")) + flags |= DI_SKIPICON; + else if(sc.Compare("skipalticon")) + flags |= DI_SKIPALTICON; + else if(sc.Compare("skipspawn")) + flags |= DI_SKIPSPAWN; + else if(sc.Compare("skipready")) + flags |= DI_SKIPREADY; + else if(sc.Compare("alticonfirst")) + flags |= DI_ALTICONFIRST; + else if(sc.Compare("forcescale")) + { + if(flags & DI_DRAWINBOX) + flags |= DI_FORCESCALE; + } + else if(sc.Compare("alternateonfail")) + flags |= DI_ALTERNATEONFAIL; + else + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|') && !sc.CheckToken(',')) break; + } + } + if(flags & DI_ALTERNATEONFAIL) + SBarInfoCommandFlowControl::Parse(sc, fullScreenOffsets); + else + sc.MustGetToken(';'); } void Tick(const SBarInfoMainBlock *block, const DSBarInfo *statusBar, bool hudChanged) { + SBarInfoCommandFlowControl::Tick(block, statusBar, hudChanged); + texture = NULL; alpha = FRACUNIT; + if (applyscale) + { + spawnScaleX = spawnScaleY = 1.0f; + applyscale = false; + } if(type == PLAYERICON) texture = TexMan[statusBar->CPlayer->mo->ScoreIcon]; else if(type == AMMO1) { - if(statusBar->ammo1 != NULL) - texture = TexMan[statusBar->ammo1->Icon]; + AAmmo *ammo = statusBar->ammo1; + if(ammo != NULL) + GetIcon(ammo); } else if(type == AMMO2) { - if(statusBar->ammo2 != NULL) - texture = TexMan[statusBar->ammo2->Icon]; + AAmmo *ammo = statusBar->ammo2; + if(ammo != NULL) + GetIcon(ammo); } else if(type == ARMOR) { - if(statusBar->armor != NULL && statusBar->armor->Amount != 0) - texture = TexMan(statusBar->armor->Icon); + ABasicArmor *armor = statusBar->armor; + if(armor != NULL && armor->Amount != 0) + GetIcon(armor); } else if(type == WEAPONICON) { AWeapon *weapon = statusBar->CPlayer->ReadyWeapon; if(weapon != NULL) - { - FTextureID icon; - if (weapon->Icon.isValid()) - { - icon = weapon->Icon; - } - else - { - icon = GetWeaponIcon(weapon); - } - texture = TexMan[icon]; - } + GetIcon(weapon); } else if(type == SIGIL) { @@ -213,8 +292,26 @@ class CommandDrawImage : public SBarInfoCommand texture = TexMan(statusBar->CPlayer->mo->InvSel->Icon); else if(image >= 0) texture = statusBar->Images[image]; + + if (flags & DI_ALTERNATEONFAIL) + { + SetTruth(texture == NULL || !(texture->GetID().isValid()), block, statusBar); + } } protected: + void GetIcon(AInventory *item) + { + FTextureID icon = GetInventoryIcon(item, flags, &applyscale); + + if (applyscale) + { + spawnScaleX = FIXED2FLOAT(item->scaleX); + spawnScaleY = FIXED2FLOAT(item->scaleY); + } + + texture = TexMan[icon]; + } + enum ImageType { PLAYERICON, @@ -238,6 +335,12 @@ class CommandDrawImage : public SBarInfoCommand ImageType type; int image; FTextureID sprite; + int maxwidth; + int maxheight; + double spawnScaleX; + double spawnScaleY; + DWORD flags; + bool applyscale; //Set remotely from from GetInventoryIcon when selected sprite comes from Spawn state // I'm using imgx/imgy here so that I can inherit drawimage with drawnumber for some commands. SBarInfoCoordinate imgx; SBarInfoCoordinate imgy; @@ -1479,11 +1582,11 @@ class CommandDrawMugShot : public SBarInfoCommand //////////////////////////////////////////////////////////////////////////////// -class CommandDrawSelectedInventory : public SBarInfoCommandFlowControl, private CommandDrawImage, private CommandDrawNumber +class CommandDrawSelectedInventory : public CommandDrawImage, private CommandDrawNumber { public: - CommandDrawSelectedInventory(SBarInfo *script) : SBarInfoCommandFlowControl(script), - CommandDrawImage(script), CommandDrawNumber(script), alternateOnEmpty(false), + CommandDrawSelectedInventory(SBarInfo *script) : CommandDrawImage(script), + CommandDrawNumber(script), alternateOnEmpty(false), artiflash(false), alwaysShowCounter(false) { length = INT_MAX; // Counter size @@ -3011,7 +3114,7 @@ class CommandDrawGem : public SBarInfoCommand else sc.ScriptError("Unknown drawgem flag '%s'.", sc.String); if(!sc.CheckToken('|')) - sc.MustGetToken(','); + sc.MustGetToken(','); } sc.MustGetToken(TK_StringConst); //chain chain = script->newImage(sc.String); diff --git a/src/g_shared/shared_hud.cpp b/src/g_shared/shared_hud.cpp index 3416bb82d..964a28e2b 100644 --- a/src/g_shared/shared_hud.cpp +++ b/src/g_shared/shared_hud.cpp @@ -135,12 +135,12 @@ static void DrawImageToBox(FTexture * tex, int x, int y, int w, int h, int trans if (tex) { - int texwidth=tex->GetWidth(); - int texheight=tex->GetHeight(); + double texwidth=tex->GetScaledWidthDouble(); + double texheight=tex->GetScaledHeightDouble(); - if (wGetClass()); + FTextureID picnum, AltIcon = GetHUDIcon(item->GetClass()); FState * state=NULL, *ReadyState; - FTextureID picnum = !AltIcon.isNull()? AltIcon : weapon->Icon; - - if (picnum.isNull()) + picnum.SetNull(); + if (flags & DI_ALTICONFIRST) { - if (weapon->SpawnState && weapon->SpawnState->sprite!=0) + if (!(flags & DI_SKIPALTICON) && AltIcon.isValid()) + picnum = AltIcon; + else if (!(flags & DI_SKIPICON)) + picnum = item->Icon; + } + else + { + if (!(flags & DI_SKIPICON) && item->Icon.isValid()) + picnum = item->Icon; + else if (!(flags & DI_SKIPALTICON)) + picnum = AltIcon; + } + + if (!picnum.isValid()) //isNull() is bad for checking, because picnum could be also invalid (-1) + { + if (!(flags & DI_SKIPSPAWN) && item->SpawnState && item->SpawnState->sprite!=0) { - state = weapon->SpawnState; + state = item->SpawnState; + + if (applyscale != NULL && !(flags & DI_FORCESCALE)) + { + *applyscale = true; + } } - // no spawn state - now try the ready state - else if ((ReadyState = weapon->FindState(NAME_Ready)) && ReadyState->sprite!=0) + // no spawn state - now try the ready state if it's weapon + else if (!(flags & DI_SKIPREADY) && item->GetClass()->IsDescendantOf(RUNTIME_CLASS(AWeapon)) && (ReadyState = item->FindState(NAME_Ready)) && ReadyState->sprite!=0) { state = ReadyState; } @@ -651,7 +669,7 @@ static void DrawOneWeapon(player_t * CPlayer, int x, int & y, AWeapon * weapon) if (weapon==CPlayer->ReadyWeapon || weapon==CPlayer->ReadyWeapon->SisterWeapon) trans=0xd999; } - FTextureID picnum = GetWeaponIcon(weapon); + FTextureID picnum = GetInventoryIcon(weapon, DI_ALTICONFIRST); if (picnum.isValid()) { From e8bcbd14fbbac6e407f1b85553024b9302da6ee3 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 21 Sep 2013 13:20:36 -0400 Subject: [PATCH 20/21] - Added vid_asyncblit for Linux and OS X. It defaults to true and sets SDL_AYNCBLIT on the frame buffer. This allows for ZDoom to obtain ~100% CPU usage with an uncapped frame rate on Linux like it should. (Not sure if it does anything for OS X yet.) It also makes uncapped play smoothly for me (as long as the frame rate is >= 2*refresh rate), but I'm not sure if capped feels more jittery or not. I could use some feedback here. Do note that vid_asyncblit requires a restart after the value is changed. --- src/sdl/i_video.h | 64 ----------------------------------------------- 1 file changed, 64 deletions(-) delete mode 100644 src/sdl/i_video.h diff --git a/src/sdl/i_video.h b/src/sdl/i_video.h deleted file mode 100644 index 2865df02f..000000000 --- a/src/sdl/i_video.h +++ /dev/null @@ -1,64 +0,0 @@ -// Emacs style mode select -*- C++ -*- -//----------------------------------------------------------------------------- -// -// $Id:$ -// -// Copyright (C) 1993-1996 by id Software, Inc. -// -// This source is available for distribution and/or modification -// only under the terms of the DOOM Source Code License as -// published by id Software. All rights reserved. -// -// The source is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License -// for more details. -// -// DESCRIPTION: -// System specific interface stuff. -// -//----------------------------------------------------------------------------- - - -#ifndef __I_VIDEO_H__ -#define __I_VIDEO_H__ - -#include "basictypes.h" - -class DCanvas; - -// [RH] Set the display mode -void I_SetMode (int &width, int &height, int &bits); - -// Takes full 8 bit values. -void I_SetPalette (DWORD *palette); - -void I_BeginUpdate (void); // [RH] Locks screen[0] -void I_FinishUpdate (void); -void I_FinishUpdateNoBlit (void); - -// Wait for vertical retrace or pause a bit. -void I_WaitVBL(int count); - -void I_ReadScreen (BYTE *scr); - -bool I_CheckResolution (int width, int height, int bits); -void I_ClosestResolution (int *width, int *height, int bits); -bool I_SetResolution (int width, int height, int bits); - -bool I_AllocateScreen (DCanvas *canvas, int width, int height, int bits); -void I_FreeScreen (DCanvas *canvas); - -void I_LockScreen (DCanvas *canvas); -void I_UnlockScreen (DCanvas *canvas); -void I_Blit (DCanvas *from, int srcx, int srcy, int srcwidth, int srcheight, - DCanvas *to, int destx, int desty, int destwidth, int destheight); - -enum EDisplayType -{ - DISPLAY_WindowOnly, - DISPLAY_FullscreenOnly, - DISPLAY_Both -}; - -#endif // __I_VIDEO_H__ From 658b4f7e0ff4bf723105fbafe993cfcd8fbc5964 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sat, 21 Sep 2013 15:30:32 -0400 Subject: [PATCH 21/21] - For some reason git decided not to include the actual changes for the last commit. --- src/sdl/sdlvideo.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/sdl/sdlvideo.cpp b/src/sdl/sdlvideo.cpp index 2f11b8bbd..92741d325 100644 --- a/src/sdl/sdlvideo.cpp +++ b/src/sdl/sdlvideo.cpp @@ -87,6 +87,10 @@ EXTERN_CVAR (Bool, cl_capfps) CVAR (Int, vid_displaybits, 8, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) +// vid_asyncblit needs a restart to work. SDL doesn't seem to change if the +// frame buffer is changed at run time. +CVAR (Bool, vid_asyncblit, 1, CVAR_NOINITCALL|CVAR_ARCHIVE|CVAR_GLOBALCONFIG) + CUSTOM_CVAR (Float, rgamma, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) { if (screen != NULL) @@ -301,9 +305,8 @@ SDLFB::SDLFB (int width, int height, bool fullscreen) UpdatePending = false; NotPaletted = false; FlashAmount = 0; - Screen = SDL_SetVideoMode (width, height, vid_displaybits, - SDL_HWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF|SDL_ANYFORMAT| + (vid_asyncblit ? SDL_ASYNCBLIT : 0)|SDL_HWSURFACE|SDL_HWPALETTE|SDL_DOUBLEBUF|SDL_ANYFORMAT| (fullscreen ? SDL_FULLSCREEN : 0)); if (Screen == NULL)