mirror of
				https://github.com/KartKrewDev/RingRacers.git
				synced 2025-10-30 08:01:28 +00:00 
			
		
		
		
	Merge branch 'discord-rpc-support' into 'next'
Discord Rich Presence See merge request KartKrew/Kart-Public!207
This commit is contained in:
		
						commit
						4b9188b626
					
				
					 38 changed files with 1751 additions and 90 deletions
				
			
		
							
								
								
									
										23
									
								
								cmake/Modules/FindDiscordRPC.cmake
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								cmake/Modules/FindDiscordRPC.cmake
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
include(LibFindMacros)
 | 
			
		||||
 | 
			
		||||
libfind_pkg_check_modules(DISCORDRPC_PKGCONF DISCORDRPC)
 | 
			
		||||
 | 
			
		||||
find_path(DISCORDRPC_INCLUDE_DIR
 | 
			
		||||
	NAMES discord_rpc.h
 | 
			
		||||
	PATHS
 | 
			
		||||
		${DISCORDRPC_PKGCONF_INCLUDE_DIRS}
 | 
			
		||||
		"/usr/include"
 | 
			
		||||
		"/usr/local/include"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
find_library(DISCORDRPC_LIBRARY
 | 
			
		||||
	NAMES discord-rpc
 | 
			
		||||
	PATHS
 | 
			
		||||
		${DISCORDRPC_PKGCONF_LIBRARY_DIRS}
 | 
			
		||||
		"/usr/lib"
 | 
			
		||||
		"/usr/local/lib"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(DISCORDRPC_PROCESS_INCLUDES DISCORDRPC_INCLUDE_DIR)
 | 
			
		||||
set(DISCORDRPC_PROCESS_LIBS DISCORDRPC_LIBRARY)
 | 
			
		||||
libfind_process(DISCORDRPC)
 | 
			
		||||
| 
						 | 
				
			
			@ -2,10 +2,7 @@ tar-ignore = "assets/*.srb"
 | 
			
		|||
tar-ignore = "assets/*.pk3"
 | 
			
		||||
tar-ignore = "assets/*.dta"
 | 
			
		||||
tar-ignore = "assets/*.wad"
 | 
			
		||||
<<<<<<< HEAD:debian-template/source/options
 | 
			
		||||
tar-ignore = "assets/*.kart"
 | 
			
		||||
=======
 | 
			
		||||
>>>>>>> e251f9c230beda984cdcdea7e903d765f1c68f6f:debian-template/source/options
 | 
			
		||||
tar-ignore = "assets/debian/${PACKAGE_NAME}-data/*"
 | 
			
		||||
tar-ignore = "assets/debian/tmp/*"
 | 
			
		||||
tar-ignore = "*.obj"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
# SRB2Kart - Which DLLs do I need to bundle?
 | 
			
		||||
 | 
			
		||||
Updated 12/4/2018 (v2.1.21)
 | 
			
		||||
Updated 8/23/2020 (v1.3)
 | 
			
		||||
 | 
			
		||||
Here are the required DLLs, per build. For each architecture, copy all the binaries from these folders:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ and don't forget to build r_opengl.dll for srb2dd.
 | 
			
		|||
 | 
			
		||||
* libs\dll-binaries\i686\exchndl.dll
 | 
			
		||||
* libs\dll-binaries\i686\libgme.dll
 | 
			
		||||
* libs\dll-binaries\i686\discord-rpc.dll
 | 
			
		||||
* libs\dll-binaries\i686\mgwhelp.dll (depend for exchndl.dll)
 | 
			
		||||
* libs\SDL2\i686-w64-mingw32\bin\SDL2.dll
 | 
			
		||||
* libs\SDL2_mixer\i686-w64-mingw32\bin\*.dll (get everything)
 | 
			
		||||
| 
						 | 
				
			
			@ -22,22 +23,7 @@ and don't forget to build r_opengl.dll for srb2dd.
 | 
			
		|||
 | 
			
		||||
* libs\dll-binaries\x86_64\exchndl.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\libgme.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\discord-rpc.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\mgwhelp.dll (depend for exchndl.dll)
 | 
			
		||||
* libs\SDL2\x86_64-w64-mingw32\bin\SDL2.dll
 | 
			
		||||
* libs\SDL2_mixer\x86_64-w64-mingw32\bin\*.dll (get everything)
 | 
			
		||||
 | 
			
		||||
## srb2kartdd, 32-bit
 | 
			
		||||
 | 
			
		||||
* libs\dll-binaries\i686\exchndl.dll
 | 
			
		||||
* libs\dll-binaries\i686\fmodex.dll
 | 
			
		||||
* libs\dll-binaries\i686\libgme.dll
 | 
			
		||||
* libs\dll-binaries\i686\mgwhelp.dll (depend for exchndl.dll)
 | 
			
		||||
* r_opengl.dll (build this from make)
 | 
			
		||||
 | 
			
		||||
## srb2kartdd, 64-bit
 | 
			
		||||
 | 
			
		||||
* libs\dll-binaries\x86_64\exchndl.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\fmodex.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\libgme.dll
 | 
			
		||||
* libs\dll-binaries\x86_64\mgwhelp.dll (depend for exchndl.dll)
 | 
			
		||||
* r_opengl.dll (build this from make)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								libs/discord-rpc.props
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								libs/discord-rpc.props
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 | 
			
		||||
  <ImportGroup Label="PropertySheets" />
 | 
			
		||||
  <PropertyGroup Label="UserMacros" />
 | 
			
		||||
  <LibraryPath Condition="'$(Platform)' == 'Win32'">$(SolutionDir)libs\discord-rpc\win32-dynamic\lib;$(LibraryPath)</LibraryPath>
 | 
			
		||||
  <IncludePath Condition="'$(Platform)' == 'Win32'">$(SolutionDir)libs\discord-rpc\win32-dynamic\lib;$(IncludePath)</IncludePath>
 | 
			
		||||
  <LibraryPath Condition="'$(Platform)' == 'x64'">$(SolutionDir)libs\discord-rpc\win64-dynamic\lib;$(LibraryPath)</LibraryPath>
 | 
			
		||||
  <IncludePath Condition="'$(Platform)' == 'x64'">$(SolutionDir)libs\discord-rpc\win64-dynamic\lib;$(IncludePath)</IncludePath>
 | 
			
		||||
  </PropertyGroup>
 | 
			
		||||
  <ItemDefinitionGroup Condition="'$(Platform)' == 'Win32' OR '$(Platform)' == 'x64'">
 | 
			
		||||
    <Link>
 | 
			
		||||
      <AdditionalDependencies>discord-rpc.dll.a;%(AdditionalDependencies)</AdditionalDependencies>
 | 
			
		||||
    </Link>
 | 
			
		||||
  </ItemDefinitionGroup>
 | 
			
		||||
  <ItemGroup />
 | 
			
		||||
</Project>
 | 
			
		||||
							
								
								
									
										26
									
								
								libs/discord-rpc/win32-dynamic/include/discord_register.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								libs/discord-rpc/win32-dynamic/include/discord_register.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#if defined(DISCORD_DYNAMIC_LIB)
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
#if defined(DISCORD_BUILDING_SDK)
 | 
			
		||||
#define DISCORD_EXPORT __declspec(dllexport)
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT __declspec(dllimport)
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT __attribute__((visibility("default")))
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command);
 | 
			
		||||
DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										87
									
								
								libs/discord-rpc/win32-dynamic/include/discord_rpc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								libs/discord-rpc/win32-dynamic/include/discord_rpc.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
 | 
			
		||||
#if defined(DISCORD_DYNAMIC_LIB)
 | 
			
		||||
#  if defined(_WIN32)
 | 
			
		||||
#    if defined(DISCORD_BUILDING_SDK)
 | 
			
		||||
#      define DISCORD_EXPORT __declspec(dllexport)
 | 
			
		||||
#    else
 | 
			
		||||
#      define DISCORD_EXPORT __declspec(dllimport)
 | 
			
		||||
#    endif
 | 
			
		||||
#  else
 | 
			
		||||
#    define DISCORD_EXPORT __attribute__((visibility("default")))
 | 
			
		||||
#  endif
 | 
			
		||||
#else
 | 
			
		||||
#  define DISCORD_EXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordRichPresence {
 | 
			
		||||
    const char* state;   /* max 128 bytes */
 | 
			
		||||
    const char* details; /* max 128 bytes */
 | 
			
		||||
    int64_t startTimestamp;
 | 
			
		||||
    int64_t endTimestamp;
 | 
			
		||||
    const char* largeImageKey;  /* max 32 bytes */
 | 
			
		||||
    const char* largeImageText; /* max 128 bytes */
 | 
			
		||||
    const char* smallImageKey;  /* max 32 bytes */
 | 
			
		||||
    const char* smallImageText; /* max 128 bytes */
 | 
			
		||||
    const char* partyId;        /* max 128 bytes */
 | 
			
		||||
    int partySize;
 | 
			
		||||
    int partyMax;
 | 
			
		||||
    const char* matchSecret;    /* max 128 bytes */
 | 
			
		||||
    const char* joinSecret;     /* max 128 bytes */
 | 
			
		||||
    const char* spectateSecret; /* max 128 bytes */
 | 
			
		||||
    int8_t instance;
 | 
			
		||||
} DiscordRichPresence;
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordUser {
 | 
			
		||||
    const char* userId;
 | 
			
		||||
    const char* username;
 | 
			
		||||
    const char* discriminator;
 | 
			
		||||
    const char* avatar;
 | 
			
		||||
} DiscordUser;
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordEventHandlers {
 | 
			
		||||
    void (*ready)(const DiscordUser* request);
 | 
			
		||||
    void (*disconnected)(int errorCode, const char* message);
 | 
			
		||||
    void (*errored)(int errorCode, const char* message);
 | 
			
		||||
    void (*joinGame)(const char* joinSecret);
 | 
			
		||||
    void (*spectateGame)(const char* spectateSecret);
 | 
			
		||||
    void (*joinRequest)(const DiscordUser* request);
 | 
			
		||||
} DiscordEventHandlers;
 | 
			
		||||
 | 
			
		||||
#define DISCORD_REPLY_NO 0
 | 
			
		||||
#define DISCORD_REPLY_YES 1
 | 
			
		||||
#define DISCORD_REPLY_IGNORE 2
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
 | 
			
		||||
                                       DiscordEventHandlers* handlers,
 | 
			
		||||
                                       int autoRegister,
 | 
			
		||||
                                       const char* optionalSteamId);
 | 
			
		||||
DISCORD_EXPORT void Discord_Shutdown(void);
 | 
			
		||||
 | 
			
		||||
/* checks for incoming messages, dispatches callbacks */
 | 
			
		||||
DISCORD_EXPORT void Discord_RunCallbacks(void);
 | 
			
		||||
 | 
			
		||||
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
 | 
			
		||||
#ifdef DISCORD_DISABLE_IO_THREAD
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdateConnection(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
 | 
			
		||||
DISCORD_EXPORT void Discord_ClearPresence(void);
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								libs/discord-rpc/win32-dynamic/lib/discord-rpc.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/discord-rpc/win32-dynamic/lib/discord-rpc.lib
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										26
									
								
								libs/discord-rpc/win64-dynamic/include/discord_register.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								libs/discord-rpc/win64-dynamic/include/discord_register.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
 | 
			
		||||
#if defined(DISCORD_DYNAMIC_LIB)
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
#if defined(DISCORD_BUILDING_SDK)
 | 
			
		||||
#define DISCORD_EXPORT __declspec(dllexport)
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT __declspec(dllimport)
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT __attribute__((visibility("default")))
 | 
			
		||||
#endif
 | 
			
		||||
#else
 | 
			
		||||
#define DISCORD_EXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command);
 | 
			
		||||
DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										87
									
								
								libs/discord-rpc/win64-dynamic/include/discord_rpc.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								libs/discord-rpc/win64-dynamic/include/discord_rpc.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
#pragma once
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
 | 
			
		||||
#if defined(DISCORD_DYNAMIC_LIB)
 | 
			
		||||
#  if defined(_WIN32)
 | 
			
		||||
#    if defined(DISCORD_BUILDING_SDK)
 | 
			
		||||
#      define DISCORD_EXPORT __declspec(dllexport)
 | 
			
		||||
#    else
 | 
			
		||||
#      define DISCORD_EXPORT __declspec(dllimport)
 | 
			
		||||
#    endif
 | 
			
		||||
#  else
 | 
			
		||||
#    define DISCORD_EXPORT __attribute__((visibility("default")))
 | 
			
		||||
#  endif
 | 
			
		||||
#else
 | 
			
		||||
#  define DISCORD_EXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// clang-format on
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordRichPresence {
 | 
			
		||||
    const char* state;   /* max 128 bytes */
 | 
			
		||||
    const char* details; /* max 128 bytes */
 | 
			
		||||
    int64_t startTimestamp;
 | 
			
		||||
    int64_t endTimestamp;
 | 
			
		||||
    const char* largeImageKey;  /* max 32 bytes */
 | 
			
		||||
    const char* largeImageText; /* max 128 bytes */
 | 
			
		||||
    const char* smallImageKey;  /* max 32 bytes */
 | 
			
		||||
    const char* smallImageText; /* max 128 bytes */
 | 
			
		||||
    const char* partyId;        /* max 128 bytes */
 | 
			
		||||
    int partySize;
 | 
			
		||||
    int partyMax;
 | 
			
		||||
    const char* matchSecret;    /* max 128 bytes */
 | 
			
		||||
    const char* joinSecret;     /* max 128 bytes */
 | 
			
		||||
    const char* spectateSecret; /* max 128 bytes */
 | 
			
		||||
    int8_t instance;
 | 
			
		||||
} DiscordRichPresence;
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordUser {
 | 
			
		||||
    const char* userId;
 | 
			
		||||
    const char* username;
 | 
			
		||||
    const char* discriminator;
 | 
			
		||||
    const char* avatar;
 | 
			
		||||
} DiscordUser;
 | 
			
		||||
 | 
			
		||||
typedef struct DiscordEventHandlers {
 | 
			
		||||
    void (*ready)(const DiscordUser* request);
 | 
			
		||||
    void (*disconnected)(int errorCode, const char* message);
 | 
			
		||||
    void (*errored)(int errorCode, const char* message);
 | 
			
		||||
    void (*joinGame)(const char* joinSecret);
 | 
			
		||||
    void (*spectateGame)(const char* spectateSecret);
 | 
			
		||||
    void (*joinRequest)(const DiscordUser* request);
 | 
			
		||||
} DiscordEventHandlers;
 | 
			
		||||
 | 
			
		||||
#define DISCORD_REPLY_NO 0
 | 
			
		||||
#define DISCORD_REPLY_YES 1
 | 
			
		||||
#define DISCORD_REPLY_IGNORE 2
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
 | 
			
		||||
                                       DiscordEventHandlers* handlers,
 | 
			
		||||
                                       int autoRegister,
 | 
			
		||||
                                       const char* optionalSteamId);
 | 
			
		||||
DISCORD_EXPORT void Discord_Shutdown(void);
 | 
			
		||||
 | 
			
		||||
/* checks for incoming messages, dispatches callbacks */
 | 
			
		||||
DISCORD_EXPORT void Discord_RunCallbacks(void);
 | 
			
		||||
 | 
			
		||||
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
 | 
			
		||||
#ifdef DISCORD_DISABLE_IO_THREAD
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdateConnection(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
 | 
			
		||||
DISCORD_EXPORT void Discord_ClearPresence(void);
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
 | 
			
		||||
 | 
			
		||||
DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								libs/discord-rpc/win64-dynamic/lib/discord-rpc.lib
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/discord-rpc/win64-dynamic/lib/discord-rpc.lib
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/dll-binaries/i686/discord-rpc.dll
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/dll-binaries/i686/discord-rpc.dll
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libs/dll-binaries/x86_64/discord-rpc.dll
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libs/dll-binaries/x86_64/discord-rpc.dll
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -221,6 +221,8 @@ set(SRB2_CONFIG_HAVE_ZLIB ON CACHE BOOL
 | 
			
		|||
	"Enable zlib support.")
 | 
			
		||||
set(SRB2_CONFIG_HAVE_GME ON CACHE BOOL
 | 
			
		||||
	"Enable GME support.")
 | 
			
		||||
set(SRB2_CONFIG_HAVE_DISCORDRPC OFF CACHE BOOL
 | 
			
		||||
	"Enable Discord rich presence support.")
 | 
			
		||||
set(SRB2_CONFIG_HAVE_CURL ON CACHE BOOL
 | 
			
		||||
	"Enable curl support, used for downloading files via HTTP.")
 | 
			
		||||
set(SRB2_CONFIG_HWRENDER ON CACHE BOOL
 | 
			
		||||
| 
						 | 
				
			
			@ -235,7 +237,7 @@ set(SRB2_CONFIG_STATIC_OPENGL OFF CACHE BOOL
 | 
			
		|||
### use internal libraries?
 | 
			
		||||
if(${CMAKE_SYSTEM} MATCHES "Windows") ###set on Windows only
 | 
			
		||||
	set(SRB2_CONFIG_USE_INTERNAL_LIBRARIES OFF CACHE BOOL
 | 
			
		||||
	"Use SRB2's internal copies of required dependencies (SDL2, PNG, zlib, GME).")
 | 
			
		||||
	"Use SRB2Kart's internal copies of required dependencies (SDL2, PNG, zlib, GME).")
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(${SRB2_CONFIG_HAVE_BLUA})
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +332,7 @@ if(${SRB2_CONFIG_HAVE_GME})
 | 
			
		|||
	if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
 | 
			
		||||
		set(GME_FOUND ON)
 | 
			
		||||
		set(GME_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/gme/include)
 | 
			
		||||
        if(${SRB2_SYSTEM_BITS} EQUAL 64)
 | 
			
		||||
		if(${SRB2_SYSTEM_BITS} EQUAL 64)
 | 
			
		||||
			set(GME_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/gme/win64 -lgme")
 | 
			
		||||
		else() # 32-bit
 | 
			
		||||
			set(GME_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/gme/win32 -lgme")
 | 
			
		||||
| 
						 | 
				
			
			@ -346,6 +348,32 @@ if(${SRB2_CONFIG_HAVE_GME})
 | 
			
		|||
	endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(${SRB2_CONFIG_HAVE_DISCORDRPC})
 | 
			
		||||
	if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
 | 
			
		||||
		set(DISCORDRPC_FOUND ON)
 | 
			
		||||
		if(${SRB2_SYSTEM_BITS} EQUAL 64)
 | 
			
		||||
			set(DISCORDRPC_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/discord-rpc/win64-dynamic/include)
 | 
			
		||||
			set(DISCORDRPC_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/discord-rpc/win64-dynamic/lib -ldiscord-rpc")
 | 
			
		||||
		else() # 32-bit
 | 
			
		||||
			set(DISCORDRPC_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/discord-rpc/win32-dynamic/include)
 | 
			
		||||
			set(DISCORDRPC_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/discord-rpc/win32-dynamic/lib -ldiscord-rpc")
 | 
			
		||||
		endif()
 | 
			
		||||
	else()
 | 
			
		||||
		find_package(DiscordRPC)
 | 
			
		||||
	endif()
 | 
			
		||||
	if(${DISCORDRPC_FOUND})
 | 
			
		||||
		set(SRB2_HAVE_DISCORDRPC ON)
 | 
			
		||||
		add_definitions(-DHAVE_DISCORDRPC)
 | 
			
		||||
		set(SRB2_DISCORDRPC_SOURCES discord.c)
 | 
			
		||||
		set(SRB2_DISCORDRPC_HEADERS discord.h)
 | 
			
		||||
		prepend_sources(SRB2_DISCORDRPC_SOURCES)
 | 
			
		||||
		prepend_sources(SRB2_DISCORDRPC_HEADERS)
 | 
			
		||||
		source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS})
 | 
			
		||||
	else()
 | 
			
		||||
		message(WARNING "You have specified that Discord Rich Presence is available but it was not found.")
 | 
			
		||||
	endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
if(${SRB2_CONFIG_HAVE_ZLIB})
 | 
			
		||||
	if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
 | 
			
		||||
		set(ZLIB_FOUND ON)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -385,6 +385,12 @@ CFLAGS+=-DHAVE_MINIUPNPC
 | 
			
		|||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifdef HAVE_DISCORDRPC
 | 
			
		||||
LIBS+=-ldiscord-rpc
 | 
			
		||||
CFLAGS+=-DHAVE_DISCORDRPC
 | 
			
		||||
OBJS+=$(OBJDIR)/discord.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifndef NO_LUA
 | 
			
		||||
	include blua/Makefile.cfg
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,7 @@
 | 
			
		|||
#include "lua_script.h"
 | 
			
		||||
#include "lua_hook.h"
 | 
			
		||||
#include "k_kart.h"
 | 
			
		||||
#include "s_sound.h" // sfx_syfail
 | 
			
		||||
 | 
			
		||||
#ifdef CLIENT_LOADINGSCREEN
 | 
			
		||||
// cl loading screen
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +58,10 @@
 | 
			
		|||
#include "sdl12/SRB2XBOX/xboxhelp.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//
 | 
			
		||||
// NETWORKING
 | 
			
		||||
//
 | 
			
		||||
| 
						 | 
				
			
			@ -1457,7 +1462,7 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 | 
			
		|||
					mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl, mapheaderinfo[gamemap-1]->actnum) < 0)
 | 
			
		||||
				{
 | 
			
		||||
					// If there's an encoding error, send UNKNOWN, we accept that the above may be truncated
 | 
			
		||||
					strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 33);
 | 
			
		||||
					strncpy(netbuffer->u.serverinfo.maptitle, "Unknown", 33);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
| 
						 | 
				
			
			@ -1468,13 +1473,13 @@ static void SV_SendServerInfo(INT32 node, tic_t servertime)
 | 
			
		|||
					mapheaderinfo[gamemap-1]->lvlttl, mapheaderinfo[gamemap-1]->zonttl) < 0)
 | 
			
		||||
				{
 | 
			
		||||
					// If there's an encoding error, send UNKNOWN, we accept that the above may be truncated
 | 
			
		||||
					strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 33);
 | 
			
		||||
					strncpy(netbuffer->u.serverinfo.maptitle, "Unknown", 33);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		strncpy(netbuffer->u.serverinfo.maptitle, "UNKNOWN", 33);
 | 
			
		||||
		strncpy(netbuffer->u.serverinfo.maptitle, "Unknown", 33);
 | 
			
		||||
 | 
			
		||||
	netbuffer->u.serverinfo.maptitle[32] = '\0';
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1601,6 +1606,15 @@ static boolean SV_SendServerConfig(INT32 node)
 | 
			
		|||
		netbuffer->u.servercfg.playercolor[i] = (UINT8)players[i].skincolor;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	netbuffer->u.servercfg.maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
 | 
			
		||||
	netbuffer->u.servercfg.allownewplayer = cv_allownewplayer.value;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	netbuffer->u.servercfg.discordinvites = (boolean)cv_discordinvites.value;
 | 
			
		||||
#else
 | 
			
		||||
	netbuffer->u.servercfg.discordinvites = false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	memcpy(netbuffer->u.servercfg.server_context, server_context, 8);
 | 
			
		||||
	op = p = netbuffer->u.servercfg.varlengthinputs;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1798,7 +1812,7 @@ static void CL_LoadReceivedSavegame(void)
 | 
			
		|||
			if (strlen(mapheaderinfo[gamemap-1]->zonttl) > 0)
 | 
			
		||||
				CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->zonttl));
 | 
			
		||||
			else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
 | 
			
		||||
				CON_LogMessage(M_GetText(" ZONE"));
 | 
			
		||||
				CON_LogMessage(M_GetText(" Zone"));
 | 
			
		||||
			if (strlen(mapheaderinfo[gamemap-1]->actnum) > 0)
 | 
			
		||||
				CON_LogMessage(va(" %s", mapheaderinfo[gamemap-1]->actnum));
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3349,6 +3363,11 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
 | 
			
		|||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (msg == KICK_MSG_PLAYER_QUIT)
 | 
			
		||||
		S_StartSound(NULL, sfx_leave); // intended leave
 | 
			
		||||
	else
 | 
			
		||||
		S_StartSound(NULL, sfx_syfail); // he he he
 | 
			
		||||
 | 
			
		||||
	switch (msg)
 | 
			
		||||
	{
 | 
			
		||||
		case KICK_MSG_GO_AWAY:
 | 
			
		||||
| 
						 | 
				
			
			@ -3476,12 +3495,17 @@ static void Got_KickCmd(UINT8 **p, INT32 playernum)
 | 
			
		|||
static CV_PossibleValue_t netticbuffer_cons_t[] = {{0, "MIN"}, {3, "MAX"}, {0, NULL}};
 | 
			
		||||
consvar_t cv_netticbuffer = {"netticbuffer", "1", CV_SAVE, netticbuffer_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
 | 
			
		||||
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL	};
 | 
			
		||||
static void Joinable_OnChange(void);
 | 
			
		||||
 | 
			
		||||
consvar_t cv_allownewplayer = {"allowjoin", "On", CV_SAVE|CV_CALL, CV_OnOff, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
 | 
			
		||||
#ifdef VANILLAJOINNEXTROUND
 | 
			
		||||
consvar_t cv_joinnextround = {"joinnextround", "Off", CV_SAVE|CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; /// \todo not done
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static CV_PossibleValue_t maxplayers_cons_t[] = {{2, "MIN"}, {MAXPLAYERS, "MAX"}, {0, NULL}};
 | 
			
		||||
consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE, maxplayers_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
consvar_t cv_maxplayers = {"maxplayers", "8", CV_SAVE|CV_CALL, maxplayers_cons_t, Joinable_OnChange, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
 | 
			
		||||
static CV_PossibleValue_t resynchattempts_cons_t[] = {{0, "MIN"}, {20, "MAX"}, {0, NULL}};
 | 
			
		||||
consvar_t cv_resynchattempts = {"resynchattempts", "5", CV_SAVE, resynchattempts_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL	};
 | 
			
		||||
consvar_t cv_blamecfail = {"blamecfail", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL	};
 | 
			
		||||
| 
						 | 
				
			
			@ -3498,6 +3522,15 @@ consvar_t cv_downloadspeed = {"downloadspeed", "16", CV_SAVE, downloadspeed_cons
 | 
			
		|||
static void Got_AddPlayer(UINT8 **p, INT32 playernum);
 | 
			
		||||
static void Got_RemovePlayer(UINT8 **p, INT32 playernum);
 | 
			
		||||
 | 
			
		||||
static void Joinable_OnChange(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_SendDiscordInfo();
 | 
			
		||||
#else
 | 
			
		||||
	return;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// called one time at init
 | 
			
		||||
void D_ClientServerInit(void)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -3749,6 +3782,9 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
 | 
			
		|||
 | 
			
		||||
	if (netgame)
 | 
			
		||||
	{
 | 
			
		||||
		if (node != mynode)
 | 
			
		||||
			S_StartSound(NULL, sfx_join);
 | 
			
		||||
 | 
			
		||||
		if (server && cv_showjoinaddress.value)
 | 
			
		||||
		{
 | 
			
		||||
			const char *address;
 | 
			
		||||
| 
						 | 
				
			
			@ -3765,6 +3801,10 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum)
 | 
			
		|||
#ifdef HAVE_BLUA
 | 
			
		||||
	LUAh_PlayerJoin(newplayernum);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Xcmd XD_REMOVEPLAYER
 | 
			
		||||
| 
						 | 
				
			
			@ -3791,6 +3831,10 @@ static void Got_RemovePlayer(UINT8 **p, INT32 playernum)
 | 
			
		|||
	reason = READUINT8(*p);
 | 
			
		||||
 | 
			
		||||
	CL_RemovePlayer(pnum, reason);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean SV_AddWaitingPlayers(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -4284,6 +4328,12 @@ static void HandlePacketFromAwayNode(SINT8 node)
 | 
			
		|||
				memcpy(server_context, netbuffer->u.servercfg.server_context, 8);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
			discordInfo.maxPlayers = netbuffer->u.servercfg.maxplayer;
 | 
			
		||||
			discordInfo.joinsAllowed = netbuffer->u.servercfg.allownewplayer;
 | 
			
		||||
			discordInfo.everyoneCanInvite = netbuffer->u.servercfg.discordinvites;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
			nodeingame[(UINT8)servernode] = true;
 | 
			
		||||
			serverplayer = netbuffer->u.servercfg.serverplayer;
 | 
			
		||||
			doomcom->numslots = SHORT(netbuffer->u.servercfg.totalslotnum);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -334,6 +334,11 @@ typedef struct
 | 
			
		|||
 | 
			
		||||
	char server_context[8]; // Unique context id, generated at server startup.
 | 
			
		||||
 | 
			
		||||
	// Discord info (always defined for net compatibility)
 | 
			
		||||
	UINT8 maxplayer;
 | 
			
		||||
	boolean allownewplayer;
 | 
			
		||||
	boolean discordinvites;
 | 
			
		||||
 | 
			
		||||
	UINT8 varlengthinputs[0]; // Playernames and netvars
 | 
			
		||||
} ATTRPACK serverconfig_pak;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										69
									
								
								src/d_main.c
									
										
									
									
									
								
							
							
						
						
									
										69
									
								
								src/d_main.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -103,6 +103,10 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 | 
			
		|||
#include "lua_script.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// platform independant focus loss
 | 
			
		||||
UINT8 window_notinfocus = false;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -727,6 +731,10 @@ void D_SRB2Loop(void)
 | 
			
		|||
#ifdef HAVE_BLUA
 | 
			
		||||
		LUA_Step();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
		Discord_RunCallbacks();
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -841,9 +849,23 @@ static inline void D_CleanFile(char **filearray)
 | 
			
		|||
// Identify the SRB2 version, and IWAD file to use.
 | 
			
		||||
// ==========================================================================
 | 
			
		||||
 | 
			
		||||
static boolean AddIWAD(void)
 | 
			
		||||
{
 | 
			
		||||
	char * path = va(pandf,srb2path,"srb2.srb");
 | 
			
		||||
 | 
			
		||||
	if (FIL_ReadFileOK(path))
 | 
			
		||||
	{
 | 
			
		||||
		D_AddFile(path, startupwadfiles);
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void IdentifyVersion(void)
 | 
			
		||||
{
 | 
			
		||||
	char *srb2wad1, *srb2wad2;
 | 
			
		||||
	const char *srb2waddir = NULL;
 | 
			
		||||
 | 
			
		||||
#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
 | 
			
		||||
| 
						 | 
				
			
			@ -867,43 +889,28 @@ static void IdentifyVersion(void)
 | 
			
		|||
#ifdef _arch_dreamcast
 | 
			
		||||
			srb2waddir = "/cd";
 | 
			
		||||
#else
 | 
			
		||||
			srb2waddir = ".";
 | 
			
		||||
			srb2waddir = srb2path;
 | 
			
		||||
#endif
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#if defined (macintosh) && !defined (HAVE_SDL)
 | 
			
		||||
	// cwd is always "/" when app is dbl-clicked
 | 
			
		||||
	if (!stricmp(srb2waddir, "/"))
 | 
			
		||||
		srb2waddir = I_GetWadDir();
 | 
			
		||||
#endif
 | 
			
		||||
	// Commercial.
 | 
			
		||||
	srb2wad1 = malloc(strlen(srb2waddir)+1+8+1);
 | 
			
		||||
	srb2wad2 = malloc(strlen(srb2waddir)+1+8+1);
 | 
			
		||||
	if (srb2wad1 == NULL && srb2wad2 == NULL)
 | 
			
		||||
		I_Error("No more free memory to look in %s", srb2waddir);
 | 
			
		||||
	if (srb2wad1 != NULL)
 | 
			
		||||
		sprintf(srb2wad1, pandf, srb2waddir, "srb2.srb");
 | 
			
		||||
	if (srb2wad2 != NULL)
 | 
			
		||||
		sprintf(srb2wad2, pandf, srb2waddir, "srb2.wad");
 | 
			
		||||
	// Load the IWAD
 | 
			
		||||
	if (AddIWAD())
 | 
			
		||||
	{
 | 
			
		||||
		I_SaveCurrentWadDirectory();
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (!( I_UseSavedWadDirectory() && AddIWAD() ))
 | 
			
		||||
		{
 | 
			
		||||
			I_Error("SRB2.SRB not found! Expected in %s\n", srb2waddir);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// will be overwritten in case of -cdrom or unix/win home
 | 
			
		||||
	snprintf(configfile, sizeof configfile, "%s" PATHSEP CONFIGFILENAME, srb2waddir);
 | 
			
		||||
	configfile[sizeof configfile - 1] = '\0';
 | 
			
		||||
 | 
			
		||||
	// Load the IWAD
 | 
			
		||||
	if (srb2wad2 != NULL && FIL_ReadFileOK(srb2wad2))
 | 
			
		||||
		D_AddFile(srb2wad2, startupwadfiles);
 | 
			
		||||
	else if (srb2wad1 != NULL && FIL_ReadFileOK(srb2wad1))
 | 
			
		||||
		D_AddFile(srb2wad1, startupwadfiles);
 | 
			
		||||
	else
 | 
			
		||||
		I_Error("SRB2.SRB/SRB2.WAD not found! Expected in %s, ss files: %s or %s\n", srb2waddir, srb2wad1, srb2wad2);
 | 
			
		||||
 | 
			
		||||
	if (srb2wad1)
 | 
			
		||||
		free(srb2wad1);
 | 
			
		||||
	if (srb2wad2)
 | 
			
		||||
		free(srb2wad2);
 | 
			
		||||
 | 
			
		||||
	// if you change the ordering of this or add/remove a file, be sure to update the md5
 | 
			
		||||
	// checking in D_SRB2Main
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1610,6 +1617,10 @@ void D_SRB2Main(void)
 | 
			
		|||
		if (!P_SetupLevel(false))
 | 
			
		||||
			I_Quit(); // fail so reset game stuff
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_Init();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *D_Home(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,6 +55,10 @@
 | 
			
		|||
#define CV_RESTRICT 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// ------
 | 
			
		||||
// protos
 | 
			
		||||
// ------
 | 
			
		||||
| 
						 | 
				
			
			@ -77,6 +81,7 @@ static void Got_RandomSeed(UINT8 **cp, INT32 playernum);
 | 
			
		|||
static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum);
 | 
			
		||||
static void Got_Teamchange(UINT8 **cp, INT32 playernum);
 | 
			
		||||
static void Got_Clearscores(UINT8 **cp, INT32 playernum);
 | 
			
		||||
static void Got_DiscordInfo(UINT8 **cp, INT32 playernum);
 | 
			
		||||
 | 
			
		||||
static void PointLimit_OnChange(void);
 | 
			
		||||
static void TimeLimit_OnChange(void);
 | 
			
		||||
| 
						 | 
				
			
			@ -704,10 +709,12 @@ void D_RegisterServerCommands(void)
 | 
			
		|||
	CV_RegisterVar(&cv_showping);
 | 
			
		||||
 | 
			
		||||
#ifdef SEENAMES
 | 
			
		||||
	 CV_RegisterVar(&cv_allowseenames);
 | 
			
		||||
	CV_RegisterVar(&cv_allowseenames);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	CV_RegisterVar(&cv_dummyconsvar);
 | 
			
		||||
 | 
			
		||||
	RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// =========================================================================
 | 
			
		||||
| 
						 | 
				
			
			@ -1000,6 +1007,13 @@ void D_RegisterClientCommands(void)
 | 
			
		|||
#if defined(HAVE_BLUA) && defined(LUA_ALLOW_BYTECODE)
 | 
			
		||||
	COM_AddCommand("dumplua", Command_Dumplua_f);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	CV_RegisterVar(&cv_discordrp);
 | 
			
		||||
	CV_RegisterVar(&cv_discordstreamer);
 | 
			
		||||
	CV_RegisterVar(&cv_discordasks);
 | 
			
		||||
	CV_RegisterVar(&cv_discordinvites);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Checks if a name (as received from another player) is okay.
 | 
			
		||||
| 
						 | 
				
			
			@ -1859,6 +1873,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
 | 
			
		|||
	}
 | 
			
		||||
	else
 | 
			
		||||
		SetPlayerSkinByNum(playernum, skin);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	if (playernum == consoleplayer)
 | 
			
		||||
		DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SendWeaponPref(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -2670,6 +2689,10 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
 | 
			
		|||
	if (demo.recording) // Okay, level loaded, character spawned and skinned,
 | 
			
		||||
		G_BeginRecording(); // I AM NOW READY TO RECORD.
 | 
			
		||||
	demo.deferstart = true;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void Command_Pause(void)
 | 
			
		||||
| 
						 | 
				
			
			@ -4643,6 +4666,10 @@ static void TimeLimit_OnChange(void)
 | 
			
		|||
	}
 | 
			
		||||
	else if (netgame || multiplayer)
 | 
			
		||||
		CONS_Printf(M_GetText("Time limit disabled\n"));
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Adjusts certain settings to match a changed gametype.
 | 
			
		||||
| 
						 | 
				
			
			@ -5668,3 +5695,32 @@ static void KartEliminateLast_OnChange(void)
 | 
			
		|||
	if (G_RaceGametype() && cv_karteliminatelast.value)
 | 
			
		||||
		P_CheckRacers();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Got_DiscordInfo(UINT8 **p, INT32 playernum)
 | 
			
		||||
{
 | 
			
		||||
	if (playernum != serverplayer /*&& !IsPlayerAdmin(playernum)*/)
 | 
			
		||||
	{
 | 
			
		||||
		// protect against hacked/buggy client
 | 
			
		||||
		CONS_Alert(CONS_WARNING, M_GetText("Illegal Discord info command received from %s\n"), player_names[playernum]);
 | 
			
		||||
		if (server)
 | 
			
		||||
		{
 | 
			
		||||
			XBOXSTATIC UINT8 buf[2];
 | 
			
		||||
 | 
			
		||||
			buf[0] = (UINT8)playernum;
 | 
			
		||||
			buf[1] = KICK_MSG_CON_FAIL;
 | 
			
		||||
			SendNetXCmd(XD_KICK, &buf, 2);
 | 
			
		||||
		}
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Don't do anything with the information if we don't have Discord RP support
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	discordInfo.maxPlayers = READUINT8(*p);
 | 
			
		||||
	discordInfo.joinsAllowed = (boolean)READUINT8(*p);
 | 
			
		||||
	discordInfo.everyoneCanInvite = (boolean)READUINT8(*p);
 | 
			
		||||
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#else
 | 
			
		||||
	(*p) += 3;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,9 +178,10 @@ typedef enum
 | 
			
		|||
	XD_MODIFYVOTE,  // 23
 | 
			
		||||
	XD_PICKVOTE,    // 24
 | 
			
		||||
	XD_REMOVEPLAYER,// 25
 | 
			
		||||
	XD_DISCORD,     // 26
 | 
			
		||||
#ifdef HAVE_BLUA
 | 
			
		||||
	XD_LUACMD,      // 26
 | 
			
		||||
	XD_LUAVAR,      // 27
 | 
			
		||||
	XD_LUACMD,      // 27
 | 
			
		||||
	XD_LUAVAR,      // 28
 | 
			
		||||
#endif
 | 
			
		||||
	MAXNETXCMD
 | 
			
		||||
} netxcmd_t;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -925,6 +925,18 @@ static void readlevelheader(MYFILE *f, INT32 num)
 | 
			
		|||
					sizeof(mapheaderinfo[num-1]->subttl), va("Level header %d: subtitle", num));
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			else if (fastcmp(word, "LEVELNAME"))
 | 
			
		||||
			{
 | 
			
		||||
				deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
 | 
			
		||||
					sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			else if (fastcmp(word, "ZONETITLE"))
 | 
			
		||||
			{
 | 
			
		||||
				deh_strlcpy(mapheaderinfo[num-1]->zonttl, word2,
 | 
			
		||||
					sizeof(mapheaderinfo[num-1]->zonttl), va("Level header %d: zonetitle", num));
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Lua custom options also go above, contents may be case sensitive.
 | 
			
		||||
			if (fastncmp(word, "LUA.", 4))
 | 
			
		||||
| 
						 | 
				
			
			@ -987,16 +999,6 @@ static void readlevelheader(MYFILE *f, INT32 num)
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			// Strings that can be truncated
 | 
			
		||||
			else if (fastcmp(word, "LEVELNAME"))
 | 
			
		||||
			{
 | 
			
		||||
				deh_strlcpy(mapheaderinfo[num-1]->lvlttl, word2,
 | 
			
		||||
					sizeof(mapheaderinfo[num-1]->lvlttl), va("Level header %d: levelname", num));
 | 
			
		||||
			}
 | 
			
		||||
			else if (fastcmp(word, "ZONETITLE"))
 | 
			
		||||
			{
 | 
			
		||||
				deh_strlcpy(mapheaderinfo[num-1]->zonttl, word2,
 | 
			
		||||
					sizeof(mapheaderinfo[num-1]->zonttl), va("Level header %d: zonetitle", num));
 | 
			
		||||
			}
 | 
			
		||||
			else if (fastcmp(word, "SCRIPTNAME"))
 | 
			
		||||
			{
 | 
			
		||||
				deh_strlcpy(mapheaderinfo[num-1]->scriptname, word2,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										734
									
								
								src/discord.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										734
									
								
								src/discord.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,734 @@
 | 
			
		|||
// SONIC ROBO BLAST 2 KART
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour.
 | 
			
		||||
// Copyright (C) 2018-2020 by Kart Krew.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software distributed under the
 | 
			
		||||
// terms of the GNU General Public License, version 2.
 | 
			
		||||
// See the 'LICENSE' file for more details.
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
/// \file  discord.h
 | 
			
		||||
/// \brief Discord Rich Presence handling
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CURL
 | 
			
		||||
#include <curl/curl.h>
 | 
			
		||||
#endif // HAVE_CURL
 | 
			
		||||
 | 
			
		||||
#include "i_system.h"
 | 
			
		||||
#include "d_clisrv.h"
 | 
			
		||||
#include "d_netcmd.h"
 | 
			
		||||
#include "i_net.h"
 | 
			
		||||
#include "g_game.h"
 | 
			
		||||
#include "p_tick.h"
 | 
			
		||||
#include "m_menu.h" // gametype_cons_t
 | 
			
		||||
#include "r_things.h" // skins
 | 
			
		||||
#include "mserv.h" // ms_RoomId
 | 
			
		||||
#include "z_zone.h"
 | 
			
		||||
#include "byteptr.h"
 | 
			
		||||
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#include "doomdef.h"
 | 
			
		||||
 | 
			
		||||
// Feel free to provide your own, if you care enough to create another Discord app for this :P
 | 
			
		||||
#define DISCORD_APPID "503531144395096085"
 | 
			
		||||
 | 
			
		||||
// length of IP strings
 | 
			
		||||
#define IP_SIZE 16
 | 
			
		||||
 | 
			
		||||
consvar_t cv_discordrp = {"discordrp", "On", CV_SAVE|CV_CALL, CV_OnOff, DRPC_UpdatePresence, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
consvar_t cv_discordstreamer = {"discordstreamer", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
consvar_t cv_discordasks = {"discordasks", "Yes", CV_SAVE|CV_CALL, CV_YesNo, DRPC_UpdatePresence, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
 | 
			
		||||
static CV_PossibleValue_t discordinvites_cons_t[] = {{0, "Admins Only"}, {1, "Everyone"}, {0, NULL}};
 | 
			
		||||
consvar_t cv_discordinvites = {"discordinvites", "Everyone", CV_SAVE|CV_CALL, discordinvites_cons_t, DRPC_SendDiscordInfo, 0, NULL, NULL, 0, 0, NULL};
 | 
			
		||||
 | 
			
		||||
struct discordInfo_s discordInfo;
 | 
			
		||||
 | 
			
		||||
discordRequest_t *discordRequestList = NULL;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CURL
 | 
			
		||||
struct SelfIPbuffer
 | 
			
		||||
{
 | 
			
		||||
	CURL *curl;
 | 
			
		||||
	char *pointer;
 | 
			
		||||
	size_t length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static char self_ip[IP_SIZE];
 | 
			
		||||
#endif // HAVE_CURL
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static char *DRPC_XORIPString(const char *input)
 | 
			
		||||
 | 
			
		||||
		Simple XOR encryption/decryption. Not complex or
 | 
			
		||||
		very secretive because we aren't sending anything
 | 
			
		||||
		that isn't easily accessible via our Master Server anyway.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static char *DRPC_XORIPString(const char *input)
 | 
			
		||||
{
 | 
			
		||||
	const UINT8 xor[IP_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
 | 
			
		||||
	char *output = malloc(sizeof(char) * (IP_SIZE+1));
 | 
			
		||||
	UINT8 i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IP_SIZE; i++)
 | 
			
		||||
	{
 | 
			
		||||
		char xorinput;
 | 
			
		||||
 | 
			
		||||
		if (!input[i])
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		xorinput = input[i] ^ xor[i];
 | 
			
		||||
 | 
			
		||||
		if (xorinput < 32 || xorinput > 126)
 | 
			
		||||
		{
 | 
			
		||||
			xorinput = input[i];
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		output[i] = xorinput;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	output[i] = '\0';
 | 
			
		||||
 | 
			
		||||
	return output;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static void DRPC_HandleReady(const DiscordUser *user)
 | 
			
		||||
 | 
			
		||||
		Callback function, ran when the game connects to Discord.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		user - Struct containing Discord user info.
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		None
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_HandleReady(const DiscordUser *user)
 | 
			
		||||
{
 | 
			
		||||
	if (cv_discordstreamer.value)
 | 
			
		||||
	{
 | 
			
		||||
		CONS_Printf("Discord: connected to %s\n", user->username);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		CONS_Printf("Discord: connected to %s#%s (%s)\n", user->username, user->discriminator, user->userId);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static void DRPC_HandleDisconnect(int err, const char *msg)
 | 
			
		||||
 | 
			
		||||
		Callback function, ran when disconnecting from Discord.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		err - Error type
 | 
			
		||||
		msg - Error message
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		None
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_HandleDisconnect(int err, const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	CONS_Printf("Discord: disconnected (%d: %s)\n", err, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static void DRPC_HandleError(int err, const char *msg)
 | 
			
		||||
 | 
			
		||||
		Callback function, ran when Discord outputs an error.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		err - Error type
 | 
			
		||||
		msg - Error message
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		None
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_HandleError(int err, const char *msg)
 | 
			
		||||
{
 | 
			
		||||
	CONS_Alert(CONS_WARNING, "Discord error (%d: %s)\n", err, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static void DRPC_HandleJoin(const char *secret)
 | 
			
		||||
 | 
			
		||||
		Callback function, ran when Discord wants to
 | 
			
		||||
		connect a player to the game via a channel invite
 | 
			
		||||
		or a join request.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		secret - Value that links you to the server.
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		None
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_HandleJoin(const char *secret)
 | 
			
		||||
{
 | 
			
		||||
	char *ip = DRPC_XORIPString(secret);
 | 
			
		||||
	CONS_Printf("Connecting to %s via Discord\n", ip);
 | 
			
		||||
	COM_BufAddText(va("connect \"%s\"\n", ip));
 | 
			
		||||
	free(ip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static boolean DRPC_InvitesAreAllowed(void)
 | 
			
		||||
 | 
			
		||||
		Determines whenever or not invites or
 | 
			
		||||
		ask to join requests are allowed.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		None
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		true if invites are allowed, false otherwise.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static boolean DRPC_InvitesAreAllowed(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!Playing())
 | 
			
		||||
	{
 | 
			
		||||
		// We're not playing, so we should not be getting invites.
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cv_discordasks.value == 0)
 | 
			
		||||
	{
 | 
			
		||||
		// Client has the CVar set to off, so never allow invites from this client.
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (discordInfo.joinsAllowed == true)
 | 
			
		||||
	{
 | 
			
		||||
		if (discordInfo.everyoneCanInvite == true)
 | 
			
		||||
		{
 | 
			
		||||
			// Everyone's allowed!
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
		else if (consoleplayer == serverplayer || IsPlayerAdmin(consoleplayer))
 | 
			
		||||
		{
 | 
			
		||||
			// Only admins are allowed!
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Did not pass any of the checks
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static void DRPC_HandleJoinRequest(const DiscordUser *requestUser)
 | 
			
		||||
 | 
			
		||||
		Callback function, ran when Discord wants to
 | 
			
		||||
		ask the player if another Discord user can join
 | 
			
		||||
		or not.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		requestUser - DiscordUser struct for the user trying to connect.
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		None
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_HandleJoinRequest(const DiscordUser *requestUser)
 | 
			
		||||
{
 | 
			
		||||
	discordRequest_t *append = discordRequestList;
 | 
			
		||||
	discordRequest_t *newRequest;
 | 
			
		||||
 | 
			
		||||
	if (DRPC_InvitesAreAllowed() == false)
 | 
			
		||||
	{
 | 
			
		||||
		// Something weird happened if this occurred...
 | 
			
		||||
		Discord_Respond(requestUser->userId, DISCORD_REPLY_IGNORE);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newRequest = Z_Calloc(sizeof(discordRequest_t), PU_STATIC, NULL);
 | 
			
		||||
 | 
			
		||||
	newRequest->username = Z_Calloc(344, PU_STATIC, NULL);
 | 
			
		||||
	snprintf(newRequest->username, 344, "%s", requestUser->username);
 | 
			
		||||
 | 
			
		||||
	newRequest->discriminator = Z_Calloc(8, PU_STATIC, NULL);
 | 
			
		||||
	snprintf(newRequest->discriminator, 8, "%s", requestUser->discriminator);
 | 
			
		||||
 | 
			
		||||
	newRequest->userID = Z_Calloc(32, PU_STATIC, NULL);
 | 
			
		||||
	snprintf(newRequest->userID, 32, "%s", requestUser->userId);
 | 
			
		||||
 | 
			
		||||
	if (append != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		discordRequest_t *prev = NULL;
 | 
			
		||||
 | 
			
		||||
		while (append != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			// CHECK FOR DUPES!! Ignore any that already exist from the same user.
 | 
			
		||||
			if (!strcmp(newRequest->userID, append->userID))
 | 
			
		||||
			{
 | 
			
		||||
				Discord_Respond(newRequest->userID, DISCORD_REPLY_IGNORE);
 | 
			
		||||
				DRPC_RemoveRequest(newRequest);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			prev = append;
 | 
			
		||||
			append = append->next;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		newRequest->prev = prev;
 | 
			
		||||
		prev->next = newRequest;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		discordRequestList = newRequest;
 | 
			
		||||
		M_RefreshPauseMenu();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Made it to the end, request was valid, so play the request sound :)
 | 
			
		||||
	S_StartSound(NULL, sfx_requst);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_RemoveRequest(discordRequest_t *removeRequest)
 | 
			
		||||
 | 
			
		||||
		See header file for description.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
void DRPC_RemoveRequest(discordRequest_t *removeRequest)
 | 
			
		||||
{
 | 
			
		||||
	if (removeRequest->prev != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		removeRequest->prev->next = removeRequest->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (removeRequest->next != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		removeRequest->next->prev = removeRequest->prev;
 | 
			
		||||
 | 
			
		||||
		if (removeRequest == discordRequestList)
 | 
			
		||||
		{
 | 
			
		||||
			discordRequestList = removeRequest->next;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		if (removeRequest == discordRequestList)
 | 
			
		||||
		{
 | 
			
		||||
			discordRequestList = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Z_Free(removeRequest->username);
 | 
			
		||||
	Z_Free(removeRequest->userID);
 | 
			
		||||
	Z_Free(removeRequest);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_Init(void)
 | 
			
		||||
 | 
			
		||||
		See header file for description.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
void DRPC_Init(void)
 | 
			
		||||
{
 | 
			
		||||
	DiscordEventHandlers handlers;
 | 
			
		||||
	memset(&handlers, 0, sizeof(handlers));
 | 
			
		||||
 | 
			
		||||
	handlers.ready = DRPC_HandleReady;
 | 
			
		||||
	handlers.disconnected = DRPC_HandleDisconnect;
 | 
			
		||||
	handlers.errored = DRPC_HandleError;
 | 
			
		||||
	handlers.joinGame = DRPC_HandleJoin;
 | 
			
		||||
	handlers.joinRequest = DRPC_HandleJoinRequest;
 | 
			
		||||
 | 
			
		||||
	Discord_Initialize(DISCORD_APPID, &handlers, 1, NULL);
 | 
			
		||||
	I_AddExitFunc(Discord_Shutdown);
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_SendDiscordInfo(void)
 | 
			
		||||
 | 
			
		||||
		See header file for description.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
void DRPC_SendDiscordInfo(void)
 | 
			
		||||
{
 | 
			
		||||
	UINT8 buf[3];
 | 
			
		||||
	UINT8 *p = buf;
 | 
			
		||||
	UINT8 maxplayer;
 | 
			
		||||
 | 
			
		||||
	if (!server)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	maxplayer = (UINT8)(min((dedicated ? MAXPLAYERS-1 : MAXPLAYERS), cv_maxplayers.value));
 | 
			
		||||
 | 
			
		||||
	WRITEUINT8(p, maxplayer);
 | 
			
		||||
	WRITEUINT8(p, cv_allownewplayer.value);
 | 
			
		||||
	WRITEUINT8(p, cv_discordinvites.value);
 | 
			
		||||
 | 
			
		||||
	SendNetXCmd(XD_DISCORD, &buf, 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CURL
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata)
 | 
			
		||||
 | 
			
		||||
		Writing function for use with curl. Only intended to be used with simple text.
 | 
			
		||||
 | 
			
		||||
	Input Arguments:-
 | 
			
		||||
		s - Data to write
 | 
			
		||||
		size - Always 1.
 | 
			
		||||
		n - Length of data
 | 
			
		||||
		userdata - Passed in from CURLOPT_WRITEDATA, intended to be SelfIPbuffer
 | 
			
		||||
 | 
			
		||||
	Return:-
 | 
			
		||||
		Number of bytes wrote in this pass.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static size_t DRPC_WriteServerIP(char *s, size_t size, size_t n, void *userdata)
 | 
			
		||||
{
 | 
			
		||||
	struct SelfIPbuffer *buffer;
 | 
			
		||||
	size_t newlength;
 | 
			
		||||
 | 
			
		||||
	buffer = userdata;
 | 
			
		||||
 | 
			
		||||
	newlength = buffer->length + size*n;
 | 
			
		||||
	buffer->pointer = realloc(buffer->pointer, newlength+1);
 | 
			
		||||
 | 
			
		||||
	memcpy(buffer->pointer + buffer->length, s, size*n);
 | 
			
		||||
 | 
			
		||||
	buffer->pointer[newlength] = '\0';
 | 
			
		||||
	buffer->length = newlength;
 | 
			
		||||
 | 
			
		||||
	return size*n;
 | 
			
		||||
}
 | 
			
		||||
#endif // HAVE_CURL
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	static const char *DRPC_GetServerIP(void)
 | 
			
		||||
 | 
			
		||||
		Retrieves the IP address of the server that you're
 | 
			
		||||
		connected to. Will attempt to use curl for getting your
 | 
			
		||||
		own IP address, if it's not yours.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static const char *DRPC_GetServerIP(void)
 | 
			
		||||
{
 | 
			
		||||
	const char *address; 
 | 
			
		||||
 | 
			
		||||
	// If you're connected
 | 
			
		||||
	if (I_GetNodeAddress && (address = I_GetNodeAddress(servernode)) != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		if (strcmp(address, "self"))
 | 
			
		||||
		{
 | 
			
		||||
			// We're not the server, so we could successfully get the IP!
 | 
			
		||||
			// No need to do anything else :)
 | 
			
		||||
			return address; 
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CURL
 | 
			
		||||
	// This is a little bit goofy, but
 | 
			
		||||
	// there's practically no good way to get your own public IP address,
 | 
			
		||||
	// so we've gotta break out curl for this :V
 | 
			
		||||
	if (!self_ip[0])
 | 
			
		||||
	{
 | 
			
		||||
		CURL *curl;
 | 
			
		||||
 | 
			
		||||
		curl_global_init(CURL_GLOBAL_ALL);
 | 
			
		||||
		curl = curl_easy_init();
 | 
			
		||||
 | 
			
		||||
		if (curl)
 | 
			
		||||
		{
 | 
			
		||||
			// The API to get your public IP address from.
 | 
			
		||||
			// Picked because it's stupid simple and it's been up for a long time.
 | 
			
		||||
			const char *api = "http://ip4only.me/api/"; 
 | 
			
		||||
 | 
			
		||||
			struct SelfIPbuffer buffer;
 | 
			
		||||
			CURLcode success;
 | 
			
		||||
 | 
			
		||||
			buffer.length = 0;
 | 
			
		||||
			buffer.pointer = malloc(buffer.length+1);
 | 
			
		||||
			buffer.pointer[0] = '\0';
 | 
			
		||||
 | 
			
		||||
			curl_easy_setopt(curl, CURLOPT_URL, api);
 | 
			
		||||
			curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, DRPC_WriteServerIP);
 | 
			
		||||
			curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
 | 
			
		||||
 | 
			
		||||
			success = curl_easy_perform(curl);
 | 
			
		||||
 | 
			
		||||
			if (success == CURLE_OK)
 | 
			
		||||
			{
 | 
			
		||||
				char *tmp;
 | 
			
		||||
				tmp = strtok(buffer.pointer, ",");
 | 
			
		||||
 | 
			
		||||
				if (!strcmp(tmp, "IPv4")) // ensure correct type of IP
 | 
			
		||||
				{
 | 
			
		||||
					tmp = strtok(NULL, ",");
 | 
			
		||||
					strncpy(self_ip, tmp, IP_SIZE); // Yay, we have the IP :)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			free(buffer.pointer);
 | 
			
		||||
			curl_easy_cleanup(curl);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		curl_global_cleanup();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (self_ip[0])
 | 
			
		||||
		return self_ip;
 | 
			
		||||
	else
 | 
			
		||||
#endif // HAVE_CURL
 | 
			
		||||
		return NULL; // Could not get your IP for whatever reason, so we cannot do Discord invites
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_EmptyRequests(void)
 | 
			
		||||
 | 
			
		||||
		Empties the request list. Any existing requests
 | 
			
		||||
		will get an ignore reply.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
static void DRPC_EmptyRequests(void)
 | 
			
		||||
{
 | 
			
		||||
	while (discordRequestList != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		Discord_Respond(discordRequestList->userID, DISCORD_REPLY_IGNORE);
 | 
			
		||||
		DRPC_RemoveRequest(discordRequestList);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_UpdatePresence(void)
 | 
			
		||||
 | 
			
		||||
		See header file for description.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
void DRPC_UpdatePresence(void)
 | 
			
		||||
{
 | 
			
		||||
	char detailstr[48+1];
 | 
			
		||||
 | 
			
		||||
	char mapimg[8+1];
 | 
			
		||||
	char mapname[5+21+21+2+1];
 | 
			
		||||
 | 
			
		||||
	char charimg[4+SKINNAMESIZE+1];
 | 
			
		||||
	char charname[11+SKINNAMESIZE+1];
 | 
			
		||||
 | 
			
		||||
	boolean joinSecretSet = false;
 | 
			
		||||
 | 
			
		||||
	DiscordRichPresence discordPresence;
 | 
			
		||||
	memset(&discordPresence, 0, sizeof(discordPresence));
 | 
			
		||||
 | 
			
		||||
	if (!cv_discordrp.value)
 | 
			
		||||
	{
 | 
			
		||||
		// User doesn't want to show their game information, so update with empty presence.
 | 
			
		||||
		// This just shows that they're playing SRB2Kart. (If that's too much, then they should disable game activity :V)
 | 
			
		||||
		DRPC_EmptyRequests();
 | 
			
		||||
		Discord_UpdatePresence(&discordPresence);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef DEVELOP
 | 
			
		||||
	// This way, we can use the invite feature in-dev, but not have snoopers seeing any potential secrets! :P
 | 
			
		||||
	discordPresence.largeImageKey = "miscdevelop";
 | 
			
		||||
	discordPresence.largeImageText = "No peeking!";
 | 
			
		||||
	discordPresence.state = "Testing the game";
 | 
			
		||||
 | 
			
		||||
	DRPC_EmptyRequests();
 | 
			
		||||
	Discord_UpdatePresence(&discordPresence);
 | 
			
		||||
	return;
 | 
			
		||||
#endif // DEVELOP
 | 
			
		||||
 | 
			
		||||
	// Server info
 | 
			
		||||
	if (netgame)
 | 
			
		||||
	{
 | 
			
		||||
		switch (ms_RoomId)
 | 
			
		||||
		{
 | 
			
		||||
			case -1: discordPresence.state = "Private"; break; // Private server
 | 
			
		||||
			case 33: discordPresence.state = "Standard"; break;
 | 
			
		||||
			case 28: discordPresence.state = "Casual"; break;
 | 
			
		||||
			case 38: discordPresence.state = "Custom Gametypes"; break;
 | 
			
		||||
			case 31: discordPresence.state = "OLDC"; break;
 | 
			
		||||
			default: discordPresence.state = "Unknown Room"; break; // HOW
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		discordPresence.partyId = server_context; // Thanks, whoever gave us Mumble support, for implementing the EXACT thing Discord wanted for this field!
 | 
			
		||||
		discordPresence.partySize = D_NumPlayers(); // Players in server
 | 
			
		||||
		discordPresence.partyMax = discordInfo.maxPlayers; // Max players
 | 
			
		||||
 | 
			
		||||
		if (DRPC_InvitesAreAllowed() == true)
 | 
			
		||||
		{
 | 
			
		||||
			const char *join;
 | 
			
		||||
 | 
			
		||||
			// Grab the host's IP for joining.
 | 
			
		||||
			if ((join = DRPC_GetServerIP()) != NULL)
 | 
			
		||||
			{
 | 
			
		||||
				char *xorjoin = DRPC_XORIPString(join);
 | 
			
		||||
				discordPresence.joinSecret = xorjoin;
 | 
			
		||||
				free(xorjoin);
 | 
			
		||||
 | 
			
		||||
				joinSecretSet = true;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Reset discord info if you're not in a place that uses it!
 | 
			
		||||
		// Important for if you join a server that compiled without HAVE_DISCORDRPC,
 | 
			
		||||
		// so that you don't ever end up using bad information from another server.
 | 
			
		||||
		memset(&discordInfo, 0, sizeof(discordInfo));
 | 
			
		||||
 | 
			
		||||
		// Offline info
 | 
			
		||||
		if (Playing())
 | 
			
		||||
			discordPresence.state = "Offline";
 | 
			
		||||
		else if (demo.playback && !demo.title)
 | 
			
		||||
			discordPresence.state = "Watching Replay";
 | 
			
		||||
		else
 | 
			
		||||
			discordPresence.state = "Menu";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Gametype info
 | 
			
		||||
	if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING) && Playing())
 | 
			
		||||
	{
 | 
			
		||||
		if (modeattacking)
 | 
			
		||||
			discordPresence.details = "Time Attack";
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			snprintf(detailstr, 48, "%s%s%s",
 | 
			
		||||
				gametype_cons_t[gametype].strvalue,
 | 
			
		||||
				(gametype == GT_RACE) ? va(" | %s", kartspeed_cons_t[gamespeed].strvalue) : "",
 | 
			
		||||
				(encoremode == true) ? " | Encore" : ""
 | 
			
		||||
			);
 | 
			
		||||
			discordPresence.details = detailstr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((gamestate == GS_LEVEL || gamestate == GS_INTERMISSION) // Map info
 | 
			
		||||
		&& !(demo.playback && demo.title))
 | 
			
		||||
	{
 | 
			
		||||
		if ((gamemap >= 1 && gamemap <= 60) // supported race maps
 | 
			
		||||
			|| (gamemap >= 136 && gamemap <= 164)) // supported battle maps
 | 
			
		||||
		{
 | 
			
		||||
			snprintf(mapimg, 8, "%s", G_BuildMapName(gamemap));
 | 
			
		||||
			strlwr(mapimg);
 | 
			
		||||
			discordPresence.largeImageKey = mapimg; // Map image
 | 
			
		||||
		}
 | 
			
		||||
		else if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU)
 | 
			
		||||
		{
 | 
			
		||||
			// Hell map, use the method that got you here :P
 | 
			
		||||
			discordPresence.largeImageKey = "miscdice";
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// This is probably a custom map!
 | 
			
		||||
			discordPresence.largeImageKey = "mapcustom";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (mapheaderinfo[gamemap-1]->menuflags & LF2_HIDEINMENU)
 | 
			
		||||
		{
 | 
			
		||||
			// Hell map, hide the name
 | 
			
		||||
			discordPresence.largeImageText = "Map: ???";
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// Map name on tool tip
 | 
			
		||||
			snprintf(mapname, 48, "Map: %s", G_BuildMapTitle(gamemap));
 | 
			
		||||
			discordPresence.largeImageText = mapname;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (gamestate == GS_LEVEL && Playing())
 | 
			
		||||
		{
 | 
			
		||||
			const time_t currentTime = time(NULL);
 | 
			
		||||
			const time_t mapTimeStart = currentTime - ((leveltime + (modeattacking ? starttime : 0)) / TICRATE);
 | 
			
		||||
 | 
			
		||||
			discordPresence.startTimestamp = mapTimeStart;
 | 
			
		||||
 | 
			
		||||
			if (timelimitintics > 0)
 | 
			
		||||
			{
 | 
			
		||||
				const time_t mapTimeEnd = mapTimeStart + ((timelimitintics + starttime + 1) / TICRATE);
 | 
			
		||||
				discordPresence.endTimestamp = mapTimeEnd;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if (gamestate == GS_VOTING)
 | 
			
		||||
	{
 | 
			
		||||
		discordPresence.largeImageKey = (G_BattleGametype() ? "miscredplanet" : "miscblueplanet");
 | 
			
		||||
		discordPresence.largeImageText = "Voting";
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		discordPresence.largeImageKey = "misctitle";
 | 
			
		||||
		discordPresence.largeImageText = "Title Screen";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Character info
 | 
			
		||||
	if (Playing() && playeringame[consoleplayer] && !players[consoleplayer].spectator)
 | 
			
		||||
	{
 | 
			
		||||
		// Supported skin names
 | 
			
		||||
		static const char *supportedSkins[] = {
 | 
			
		||||
			// base game
 | 
			
		||||
			"sonic",
 | 
			
		||||
			"tails",
 | 
			
		||||
			"knuckles",
 | 
			
		||||
			"eggman",
 | 
			
		||||
			"metalsonic",
 | 
			
		||||
			// bonus chars
 | 
			
		||||
			"flicky",
 | 
			
		||||
			"motobug",
 | 
			
		||||
			"amy",
 | 
			
		||||
			"mighty",
 | 
			
		||||
			"ray",
 | 
			
		||||
			"espio",
 | 
			
		||||
			"vector",
 | 
			
		||||
			"chao",
 | 
			
		||||
			"gamma",
 | 
			
		||||
			"chaos",
 | 
			
		||||
			"shadow",
 | 
			
		||||
			"rouge",
 | 
			
		||||
			"herochao",
 | 
			
		||||
			"darkchao",
 | 
			
		||||
			"cream",
 | 
			
		||||
			"omega",
 | 
			
		||||
			"blaze",
 | 
			
		||||
			"silver",
 | 
			
		||||
			"wonderboy",
 | 
			
		||||
			"arle",
 | 
			
		||||
			"nights",
 | 
			
		||||
			"sakura",
 | 
			
		||||
			"ulala",
 | 
			
		||||
			"beat",
 | 
			
		||||
			"vyse",
 | 
			
		||||
			"aiai",
 | 
			
		||||
			"kiryu",
 | 
			
		||||
			"aigis",
 | 
			
		||||
			"miku",
 | 
			
		||||
			"doom",
 | 
			
		||||
			NULL
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		boolean customChar = true;
 | 
			
		||||
		UINT8 checkSkin = 0;
 | 
			
		||||
 | 
			
		||||
		// Character image
 | 
			
		||||
		while (supportedSkins[checkSkin] != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			if (!strcmp(skins[players[consoleplayer].skin].name, supportedSkins[checkSkin]))
 | 
			
		||||
			{
 | 
			
		||||
				snprintf(charimg, 21, "char%s", supportedSkins[checkSkin]);
 | 
			
		||||
				discordPresence.smallImageKey = charimg;
 | 
			
		||||
				customChar = false;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			checkSkin++;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (customChar == true)
 | 
			
		||||
		{
 | 
			
		||||
			// Use the custom character icon!
 | 
			
		||||
			discordPresence.smallImageKey = "charcustom";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		snprintf(charname, 28, "Character: %s", skins[players[consoleplayer].skin].realname);
 | 
			
		||||
		discordPresence.smallImageText = charname; // Character name
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (joinSecretSet == false)
 | 
			
		||||
	{
 | 
			
		||||
		// Not able to join? Flush the request list, if it exists.
 | 
			
		||||
		DRPC_EmptyRequests();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Discord_UpdatePresence(&discordPresence);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif // HAVE_DISCORDRPC
 | 
			
		||||
							
								
								
									
										91
									
								
								src/discord.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/discord.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
// SONIC ROBO BLAST 2 KART
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
// Copyright (C) 2018-2020 by Sally "TehRealSalt" Cochenour.
 | 
			
		||||
// Copyright (C) 2018-2020 by Kart Krew.
 | 
			
		||||
//
 | 
			
		||||
// This program is free software distributed under the
 | 
			
		||||
// terms of the GNU General Public License, version 2.
 | 
			
		||||
// See the 'LICENSE' file for more details.
 | 
			
		||||
//-----------------------------------------------------------------------------
 | 
			
		||||
/// \file  discord.h
 | 
			
		||||
/// \brief Discord Rich Presence handling
 | 
			
		||||
 | 
			
		||||
#ifndef __DISCORD__
 | 
			
		||||
#define __DISCORD__
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
 | 
			
		||||
#include "discord_rpc.h"
 | 
			
		||||
 | 
			
		||||
extern consvar_t cv_discordrp;
 | 
			
		||||
extern consvar_t cv_discordstreamer;
 | 
			
		||||
extern consvar_t cv_discordasks;
 | 
			
		||||
extern consvar_t cv_discordinvites;
 | 
			
		||||
 | 
			
		||||
extern struct discordInfo_s {
 | 
			
		||||
	UINT8 maxPlayers;
 | 
			
		||||
	boolean joinsAllowed;
 | 
			
		||||
	boolean everyoneCanInvite;
 | 
			
		||||
} discordInfo;
 | 
			
		||||
 | 
			
		||||
typedef struct discordRequest_s {
 | 
			
		||||
	char *username; // Discord user name.
 | 
			
		||||
	char *discriminator; // Discord discriminator (The little hashtag thing after the username). Separated for a "hide discriminators" cvar.
 | 
			
		||||
	char *userID; // The ID of the Discord user, gets used with Discord_Respond()
 | 
			
		||||
 | 
			
		||||
	// HAHAHA, no.
 | 
			
		||||
	// *Maybe* if it was only PNG I would boot up curl just to get AND convert this to Doom GFX,
 | 
			
		||||
	// but it can *also* be a JEPG, WebP, or GIF :)
 | 
			
		||||
	// Hey, wanna add ImageMagick as a dependency? :dying:
 | 
			
		||||
	//patch_t *avatar;
 | 
			
		||||
 | 
			
		||||
	struct discordRequest_s *next; // Next request in the list.
 | 
			
		||||
	struct discordRequest_s *prev; // Previous request in the list. Not used normally, but just in case something funky happens, this should repair the list.
 | 
			
		||||
} discordRequest_t;
 | 
			
		||||
 | 
			
		||||
extern discordRequest_t *discordRequestList;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_RemoveRequest(void);
 | 
			
		||||
 | 
			
		||||
		Removes an invite from the list.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void DRPC_RemoveRequest(discordRequest_t *removeRequest);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_Init(void);
 | 
			
		||||
 | 
			
		||||
		Initalizes Discord Rich Presence by linking the Application ID
 | 
			
		||||
		and setting the callback functions.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void DRPC_Init(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_SendDiscordInfo(void);
 | 
			
		||||
 | 
			
		||||
		Sends the server's information needed for
 | 
			
		||||
		the rich presence state.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void DRPC_SendDiscordInfo(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*--------------------------------------------------
 | 
			
		||||
	void DRPC_UpdatePresence(void);
 | 
			
		||||
 | 
			
		||||
		Updates what is displayed by Rich Presence on the user's profile.
 | 
			
		||||
		Should be called whenever something that is displayed is
 | 
			
		||||
		changed in-game.
 | 
			
		||||
--------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void DRPC_UpdatePresence(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // HAVE_DISCORDRPC
 | 
			
		||||
 | 
			
		||||
#endif // __DISCORD__
 | 
			
		||||
							
								
								
									
										11
									
								
								src/g_game.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								src/g_game.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -51,6 +51,10 @@
 | 
			
		|||
#include "md5.h" // demo checksums
 | 
			
		||||
#include "k_kart.h" // SRB2kart
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
gameaction_t gameaction;
 | 
			
		||||
gamestate_t gamestate = GS_NULL;
 | 
			
		||||
UINT8 ultimatemode = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -4717,7 +4721,7 @@ char *G_BuildMapTitle(INT32 mapnum)
 | 
			
		|||
		}
 | 
			
		||||
		else if (!(mapheaderinfo[mapnum-1]->levelflags & LF_NOZONE))
 | 
			
		||||
		{
 | 
			
		||||
			zonetext = M_GetText("ZONE");
 | 
			
		||||
			zonetext = M_GetText("Zone");
 | 
			
		||||
			len += strlen(zonetext) + 1;	// ' ' + zonetext
 | 
			
		||||
		}
 | 
			
		||||
		if (strlen(mapheaderinfo[mapnum-1]->actnum) > 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -6381,7 +6385,7 @@ void G_BeginRecording(void)
 | 
			
		|||
 | 
			
		||||
	// Full replay title
 | 
			
		||||
	demo_p += 64;
 | 
			
		||||
	snprintf(demo.titlename, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Record Attack" : connectedservername);
 | 
			
		||||
	snprintf(demo.titlename, 64, "%s - %s", G_BuildMapTitle(gamemap), modeattacking ? "Time Attack" : connectedservername);
 | 
			
		||||
 | 
			
		||||
	// demo checksum
 | 
			
		||||
	demo_p += 16;
 | 
			
		||||
| 
						 | 
				
			
			@ -8405,6 +8409,9 @@ boolean G_DemoTitleResponder(event_t *ev)
 | 
			
		|||
void G_SetGamestate(gamestate_t newstate)
 | 
			
		||||
{
 | 
			
		||||
	gamestate = newstate;
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* These functions handle the exitgame flag. Before, when the user
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -318,6 +318,15 @@ const CPUInfoFlags *I_CPUInfo(void);
 | 
			
		|||
*/
 | 
			
		||||
const char *I_LocateWad(void);
 | 
			
		||||
 | 
			
		||||
/**	\brief Save current wad directory to appdata
 | 
			
		||||
*/
 | 
			
		||||
void I_SaveCurrentWadDirectory(void);
 | 
			
		||||
 | 
			
		||||
/**	\brief Change directory to last known directory saved in appdata
 | 
			
		||||
		\return whether the directory could be saved
 | 
			
		||||
*/
 | 
			
		||||
boolean I_UseSavedWadDirectory(void);
 | 
			
		||||
 | 
			
		||||
/**	\brief First Joystick's events
 | 
			
		||||
*/
 | 
			
		||||
void I_GetJoystickEvents(void);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										282
									
								
								src/m_menu.c
									
										
									
									
									
								
							
							
						
						
									
										282
									
								
								src/m_menu.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -81,6 +81,11 @@ int	snprintf(char *str, size_t n, const char *fmt, ...);
 | 
			
		|||
//int	vsnprintf(char *str, size_t n, const char *fmt, va_list ap);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
//#include "discord_rpc.h"
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SKULLXOFF -32
 | 
			
		||||
#define LINEHEIGHT 16
 | 
			
		||||
#define STRINGHEIGHT 8
 | 
			
		||||
| 
						 | 
				
			
			@ -188,6 +193,12 @@ static void M_RoomMenu(INT32 choice);
 | 
			
		|||
// the haxor message menu
 | 
			
		||||
menu_t MessageDef;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
menu_t MISC_DiscordRequestsDef;
 | 
			
		||||
static void M_HandleDiscordRequests(INT32 choice);
 | 
			
		||||
static void M_DrawDiscordRequests(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
menu_t SPauseDef;
 | 
			
		||||
 | 
			
		||||
#define lsheadingheight 16
 | 
			
		||||
| 
						 | 
				
			
			@ -293,6 +304,9 @@ menu_t OP_SoundOptionsDef;
 | 
			
		|||
 | 
			
		||||
//Misc
 | 
			
		||||
menu_t OP_DataOptionsDef, OP_ScreenshotOptionsDef, OP_EraseDataDef;
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
menu_t OP_DiscordOptionsDef;
 | 
			
		||||
#endif
 | 
			
		||||
menu_t OP_HUDOptionsDef, OP_ChatOptionsDef;
 | 
			
		||||
menu_t OP_GameOptionsDef, OP_ServerOptionsDef;
 | 
			
		||||
#ifndef NONET
 | 
			
		||||
| 
						 | 
				
			
			@ -585,6 +599,10 @@ static menuitem_t MPauseMenu[] =
 | 
			
		|||
	{IT_STRING | IT_SUBMENU,  NULL, "Scramble Teams...", &MISC_ScrambleTeamDef,  16},
 | 
			
		||||
	{IT_STRING | IT_CALL,     NULL, "Switch Map..."    , M_MapChange,            24},
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	{IT_STRING | IT_SUBMENU,  NULL, "Ask To Join Requests...", &MISC_DiscordRequestsDef, 24},
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	{IT_CALL | IT_STRING,    NULL, "Continue",           M_SelectableClearMenus, 40},
 | 
			
		||||
	{IT_CALL | IT_STRING,    NULL, "P1 Setup...",        M_SetupMultiPlayer,     48}, // splitscreen
 | 
			
		||||
	{IT_CALL | IT_STRING,    NULL, "P2 Setup...",        M_SetupMultiPlayer2,    56}, // splitscreen
 | 
			
		||||
| 
						 | 
				
			
			@ -608,6 +626,9 @@ typedef enum
 | 
			
		|||
	mpause_addons = 0,
 | 
			
		||||
	mpause_scramble,
 | 
			
		||||
	mpause_switchmap,
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	mpause_discordrequests,
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	mpause_continue,
 | 
			
		||||
	mpause_psetupsplit,
 | 
			
		||||
| 
						 | 
				
			
			@ -658,6 +679,13 @@ typedef enum
 | 
			
		|||
	spause_quit
 | 
			
		||||
} spause_e;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
static menuitem_t MISC_DiscordRequestsMenu[] =
 | 
			
		||||
{
 | 
			
		||||
	{IT_KEYHANDLER|IT_NOTHING, NULL, "", M_HandleDiscordRequests, 0},
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// -----------------
 | 
			
		||||
// Misc menu options
 | 
			
		||||
// -----------------
 | 
			
		||||
| 
						 | 
				
			
			@ -1343,11 +1371,17 @@ static menuitem_t OP_SoundOptionsMenu[] =
 | 
			
		|||
 | 
			
		||||
static menuitem_t OP_DataOptionsMenu[] =
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
	{IT_STRING | IT_CALL,		NULL, "Screenshot Options...",	M_ScreenshotOptions,	 10},
 | 
			
		||||
	{IT_STRING | IT_CALL,		NULL, "Addon Options...",		M_AddonsOptions,		 20},
 | 
			
		||||
	{IT_STRING | IT_SUBMENU,	NULL, "Replay Options...",		&MISC_ReplayOptionsDef,	 30},
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	{IT_STRING | IT_SUBMENU,	NULL, "Discord Options...",		&OP_DiscordOptionsDef,	 40},
 | 
			
		||||
 | 
			
		||||
	{IT_STRING | IT_SUBMENU,	NULL, "Erase Data...",			&OP_EraseDataDef,		 60},
 | 
			
		||||
#else
 | 
			
		||||
	{IT_STRING | IT_SUBMENU,	NULL, "Erase Data...",			&OP_EraseDataDef,		 50},
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static menuitem_t OP_ScreenshotOptionsMenu[] =
 | 
			
		||||
| 
						 | 
				
			
			@ -1396,7 +1430,7 @@ static menuitem_t OP_AddonsOptionsMenu[] =
 | 
			
		|||
	{IT_HEADER,                      NULL, "Menu",                        NULL,                    0},
 | 
			
		||||
	{IT_STRING|IT_CVAR,              NULL, "Location",                    &cv_addons_option,      10},
 | 
			
		||||
	{IT_STRING|IT_CVAR|IT_CV_STRING, NULL, "Custom Folder",               &cv_addons_folder,      20},
 | 
			
		||||
	{IT_STRING|IT_CVAR,              NULL, "Identify addons via",        &cv_addons_md5,         48},
 | 
			
		||||
	{IT_STRING|IT_CVAR,              NULL, "Identify addons via",         &cv_addons_md5,         48},
 | 
			
		||||
	{IT_STRING|IT_CVAR,              NULL, "Show unsupported file types", &cv_addons_showall,     58},
 | 
			
		||||
 | 
			
		||||
	{IT_HEADER,                      NULL, "Search",                      NULL,                   76},
 | 
			
		||||
| 
						 | 
				
			
			@ -1409,6 +1443,19 @@ enum
 | 
			
		|||
	op_addons_folder = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
static menuitem_t OP_DiscordOptionsMenu[] =
 | 
			
		||||
{
 | 
			
		||||
	{IT_STRING | IT_CVAR,		NULL, "Rich Presence",			&cv_discordrp,			 10},
 | 
			
		||||
 | 
			
		||||
	{IT_HEADER,					NULL, "Rich Presence Settings",	NULL,					 30},
 | 
			
		||||
	{IT_STRING | IT_CVAR,		NULL, "Streamer Mode",			&cv_discordstreamer,	 40},
 | 
			
		||||
 | 
			
		||||
	{IT_STRING | IT_CVAR,		NULL, "Allow Ask To Join",		&cv_discordasks,		 60},
 | 
			
		||||
	{IT_STRING | IT_CVAR,		NULL, "Allow Invites",			&cv_discordinvites,		 70},
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static menuitem_t OP_HUDOptionsMenu[] =
 | 
			
		||||
{
 | 
			
		||||
	{IT_STRING | IT_CVAR, NULL, "Show HUD (F3)",			&cv_showhud,			 10},
 | 
			
		||||
| 
						 | 
				
			
			@ -1649,6 +1696,19 @@ menu_t MAPauseDef = PAUSEMENUSTYLE(MAPauseMenu, 40, 72);
 | 
			
		|||
menu_t SPauseDef = PAUSEMENUSTYLE(SPauseMenu, 40, 72);
 | 
			
		||||
menu_t MPauseDef = PAUSEMENUSTYLE(MPauseMenu, 40, 72);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
menu_t MISC_DiscordRequestsDef = {
 | 
			
		||||
	NULL,
 | 
			
		||||
	sizeof (MISC_DiscordRequestsMenu)/sizeof (menuitem_t),
 | 
			
		||||
	&MPauseDef,
 | 
			
		||||
	MISC_DiscordRequestsMenu,
 | 
			
		||||
	M_DrawDiscordRequests,
 | 
			
		||||
	0, 0,
 | 
			
		||||
	0,
 | 
			
		||||
	NULL
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Misc Main Menu
 | 
			
		||||
menu_t MISC_ScrambleTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ScrambleTeamMenu, &MPauseDef, 27, 40);
 | 
			
		||||
menu_t MISC_ChangeTeamDef = DEFAULTMENUSTYLE(NULL, MISC_ChangeTeamMenu, &MPauseDef, 27, 40);
 | 
			
		||||
| 
						 | 
				
			
			@ -2075,6 +2135,9 @@ menu_t OP_OpenGLColorDef =
 | 
			
		|||
menu_t OP_DataOptionsDef = DEFAULTMENUSTYLE("M_DATA", OP_DataOptionsMenu, &OP_MainDef, 60, 30);
 | 
			
		||||
menu_t OP_ScreenshotOptionsDef = DEFAULTMENUSTYLE("M_SCSHOT", OP_ScreenshotOptionsMenu, &OP_DataOptionsDef, 30, 30);
 | 
			
		||||
menu_t OP_AddonsOptionsDef = DEFAULTMENUSTYLE("M_ADDONS", OP_AddonsOptionsMenu, &OP_DataOptionsDef, 30, 30);
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
menu_t OP_DiscordOptionsDef = DEFAULTMENUSTYLE(NULL, OP_DiscordOptionsMenu, &OP_DataOptionsDef, 30, 30);
 | 
			
		||||
#endif
 | 
			
		||||
menu_t OP_EraseDataDef = DEFAULTMENUSTYLE("M_DATA", OP_EraseDataMenu, &OP_DataOptionsDef, 30, 30);
 | 
			
		||||
 | 
			
		||||
// ==========================================================================
 | 
			
		||||
| 
						 | 
				
			
			@ -3194,12 +3257,18 @@ void M_StartControlPanel(void)
 | 
			
		|||
		MPauseMenu[mpause_psetup].status = IT_DISABLED;
 | 
			
		||||
		MISC_ChangeTeamMenu[0].status = IT_DISABLED;
 | 
			
		||||
		MISC_ChangeSpectateMenu[0].status = IT_DISABLED;
 | 
			
		||||
 | 
			
		||||
		// Reset these in case splitscreen messes things up
 | 
			
		||||
		MPauseMenu[mpause_addons].alphaKey = 8;
 | 
			
		||||
		MPauseMenu[mpause_scramble].alphaKey = 8;
 | 
			
		||||
		MPauseMenu[mpause_switchmap].alphaKey = 24;
 | 
			
		||||
 | 
			
		||||
		MPauseMenu[mpause_switchteam].alphaKey = 48;
 | 
			
		||||
		MPauseMenu[mpause_switchspectate].alphaKey = 48;
 | 
			
		||||
		MPauseMenu[mpause_options].alphaKey = 64;
 | 
			
		||||
		MPauseMenu[mpause_title].alphaKey = 80;
 | 
			
		||||
		MPauseMenu[mpause_quit].alphaKey = 88;
 | 
			
		||||
 | 
			
		||||
		Dummymenuplayer_OnChange();
 | 
			
		||||
 | 
			
		||||
		if ((server || IsPlayerAdmin(consoleplayer)))
 | 
			
		||||
| 
						 | 
				
			
			@ -3271,6 +3340,19 @@ void M_StartControlPanel(void)
 | 
			
		|||
				MPauseMenu[mpause_spectate].status = IT_GRAYEDOUT;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
		{
 | 
			
		||||
			UINT8 i;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < mpause_discordrequests; i++)
 | 
			
		||||
				MPauseMenu[i].alphaKey -= 8;
 | 
			
		||||
 | 
			
		||||
			MPauseMenu[mpause_discordrequests].alphaKey = MPauseMenu[i].alphaKey;
 | 
			
		||||
 | 
			
		||||
			M_RefreshPauseMenu();
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		currentMenu = &MPauseDef;
 | 
			
		||||
		itemOn = mpause_continue;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -4098,6 +4180,25 @@ static void M_DrawPauseMenu(void)
 | 
			
		|||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	// kind of hackily baked in here
 | 
			
		||||
	if (currentMenu == &MPauseDef && discordRequestList != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		const tic_t freq = TICRATE/2;
 | 
			
		||||
 | 
			
		||||
		if ((leveltime % freq) >= freq/2)
 | 
			
		||||
		{
 | 
			
		||||
			V_DrawFixedPatch(204 * FRACUNIT,
 | 
			
		||||
				(currentMenu->y + MPauseMenu[mpause_discordrequests].alphaKey - 1) * FRACUNIT,
 | 
			
		||||
				FRACUNIT,
 | 
			
		||||
				0,
 | 
			
		||||
				W_CachePatchName("K_REQUE2", PU_CACHE),
 | 
			
		||||
				NULL
 | 
			
		||||
			);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	M_DrawGenericMenu();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6221,7 +6322,12 @@ static void M_Options(INT32 choice)
 | 
			
		|||
	OP_MainMenu[4].status = OP_MainMenu[5].status = (Playing() && !(server || IsPlayerAdmin(consoleplayer))) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU);
 | 
			
		||||
 | 
			
		||||
	OP_MainMenu[8].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_CALL); // Play credits
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	OP_DataOptionsMenu[4].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data
 | 
			
		||||
#else
 | 
			
		||||
	OP_DataOptionsMenu[3].status = (Playing()) ? (IT_GRAYEDOUT) : (IT_STRING|IT_SUBMENU); // Erase data
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	OP_GameOptionsMenu[3].status =
 | 
			
		||||
		(M_SecretUnlocked(SECRET_ENCORE)) ? (IT_CVAR|IT_STRING) : IT_SECRET; // cv_kartencore
 | 
			
		||||
| 
						 | 
				
			
			@ -6262,6 +6368,20 @@ static void M_SelectableClearMenus(INT32 choice)
 | 
			
		|||
	M_ClearMenus(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void M_RefreshPauseMenu(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	if (discordRequestList != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		MPauseMenu[mpause_discordrequests].status = IT_STRING | IT_SUBMENU;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		MPauseMenu[mpause_discordrequests].status = IT_GRAYEDOUT;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ======
 | 
			
		||||
// CHEATS
 | 
			
		||||
// ======
 | 
			
		||||
| 
						 | 
				
			
			@ -7460,7 +7580,7 @@ static void M_DrawStatsMaps(int location)
 | 
			
		|||
		else
 | 
			
		||||
			V_DrawString(20, y, 0, va("%s %s %s",
 | 
			
		||||
				mapheaderinfo[mnum]->lvlttl,
 | 
			
		||||
				(mapheaderinfo[mnum]->zonttl[0] ? mapheaderinfo[mnum]->zonttl : "ZONE"),
 | 
			
		||||
				(mapheaderinfo[mnum]->zonttl[0] ? mapheaderinfo[mnum]->zonttl : "Zone"),
 | 
			
		||||
				mapheaderinfo[mnum]->actnum));
 | 
			
		||||
 | 
			
		||||
		y += 8;
 | 
			
		||||
| 
						 | 
				
			
			@ -11263,3 +11383,161 @@ static void M_OGL_DrawColorMenu(void)
 | 
			
		|||
		highlightflags, "Gamma correction");
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
static const tic_t confirmLength = 3*TICRATE/4;
 | 
			
		||||
static tic_t confirmDelay = 0;
 | 
			
		||||
static boolean confirmAccept = false;
 | 
			
		||||
 | 
			
		||||
static void M_HandleDiscordRequests(INT32 choice)
 | 
			
		||||
{
 | 
			
		||||
	if (confirmDelay > 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	switch (choice)
 | 
			
		||||
	{
 | 
			
		||||
		case KEY_ENTER:
 | 
			
		||||
			Discord_Respond(discordRequestList->userID, DISCORD_REPLY_YES);
 | 
			
		||||
			confirmAccept = true;
 | 
			
		||||
			confirmDelay = confirmLength;
 | 
			
		||||
			S_StartSound(NULL, sfx_s3k63);
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case KEY_ESCAPE:
 | 
			
		||||
			Discord_Respond(discordRequestList->userID, DISCORD_REPLY_NO);
 | 
			
		||||
			confirmAccept = false;
 | 
			
		||||
			confirmDelay = confirmLength;
 | 
			
		||||
			S_StartSound(NULL, sfx_s3kb2);
 | 
			
		||||
			break;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *M_GetDiscordName(discordRequest_t *r)
 | 
			
		||||
{
 | 
			
		||||
	if (r == NULL)
 | 
			
		||||
		return "";
 | 
			
		||||
 | 
			
		||||
	if (cv_discordstreamer.value)
 | 
			
		||||
		return r->username;
 | 
			
		||||
 | 
			
		||||
	return va("%s#%s", r->username, r->discriminator);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// (this goes in k_hud.c when merged into v2)
 | 
			
		||||
static void M_DrawSticker(INT32 x, INT32 y, INT32 width, INT32 flags, boolean small)
 | 
			
		||||
{
 | 
			
		||||
	patch_t *stickerEnd;
 | 
			
		||||
	INT32 height;
 | 
			
		||||
	
 | 
			
		||||
	if (small == true)
 | 
			
		||||
	{
 | 
			
		||||
		stickerEnd = W_CachePatchName("K_STIKE2", PU_CACHE);
 | 
			
		||||
		height = 6;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		stickerEnd = W_CachePatchName("K_STIKEN", PU_CACHE);
 | 
			
		||||
		height = 11;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	V_DrawFixedPatch(x*FRACUNIT, y*FRACUNIT, FRACUNIT, flags, stickerEnd, NULL);
 | 
			
		||||
	V_DrawFill(x, y, width, height, 24|flags);
 | 
			
		||||
	V_DrawFixedPatch((x + width)*FRACUNIT, y*FRACUNIT, FRACUNIT, flags|V_FLIP, stickerEnd, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void M_DrawDiscordRequests(void)
 | 
			
		||||
{
 | 
			
		||||
	discordRequest_t *curRequest = discordRequestList;
 | 
			
		||||
	UINT8 *colormap;
 | 
			
		||||
	patch_t *hand = NULL;
 | 
			
		||||
	boolean removeRequest = false;
 | 
			
		||||
 | 
			
		||||
	const char *wantText = "...would like to join!";
 | 
			
		||||
	const char *controlText = "\x82" "ENTER" "\x80" " - Accept    " "\x82" "ESC" "\x80" " - Decline";
 | 
			
		||||
 | 
			
		||||
	INT32 x = 100;
 | 
			
		||||
	INT32 y = 133;
 | 
			
		||||
 | 
			
		||||
	INT32 slide = 0;
 | 
			
		||||
	INT32 maxYSlide = 18;
 | 
			
		||||
 | 
			
		||||
	if (confirmDelay > 0)
 | 
			
		||||
	{
 | 
			
		||||
		if (confirmAccept == true)
 | 
			
		||||
		{
 | 
			
		||||
			colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GREEN, GTC_MENUCACHE);
 | 
			
		||||
			hand = W_CachePatchName("K_LAPH02", PU_CACHE);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_RED, GTC_MENUCACHE);
 | 
			
		||||
			hand = W_CachePatchName("K_LAPH03", PU_CACHE);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		slide = confirmLength - confirmDelay;
 | 
			
		||||
 | 
			
		||||
		confirmDelay--;
 | 
			
		||||
 | 
			
		||||
		if (confirmDelay == 0)
 | 
			
		||||
			removeRequest = true;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_GREY, GTC_MENUCACHE);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	V_DrawFixedPatch(56*FRACUNIT, 150*FRACUNIT, FRACUNIT, 0, W_CachePatchName("K_LAPE01", PU_CACHE), colormap);
 | 
			
		||||
 | 
			
		||||
	if (hand != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		fixed_t handoffset = (4 - abs((signed)(skullAnimCounter - 4))) * FRACUNIT;
 | 
			
		||||
		V_DrawFixedPatch(56*FRACUNIT, 150*FRACUNIT + handoffset, FRACUNIT, 0, hand, NULL);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	M_DrawSticker(x + (slide * 32), y - 1, V_ThinStringWidth(M_GetDiscordName(curRequest), V_ALLOWLOWERCASE|V_6WIDTHSPACE), 0, false);
 | 
			
		||||
	V_DrawThinString(x + (slide * 32), y, V_ALLOWLOWERCASE|V_6WIDTHSPACE|V_YELLOWMAP, M_GetDiscordName(curRequest));
 | 
			
		||||
 | 
			
		||||
	M_DrawSticker(x, y + 12, V_ThinStringWidth(wantText, V_ALLOWLOWERCASE|V_6WIDTHSPACE), 0, true);
 | 
			
		||||
	V_DrawThinString(x, y + 10, V_ALLOWLOWERCASE|V_6WIDTHSPACE, wantText);
 | 
			
		||||
 | 
			
		||||
	M_DrawSticker(x, y + 26, V_ThinStringWidth(controlText, V_ALLOWLOWERCASE|V_6WIDTHSPACE), 0, true);
 | 
			
		||||
	V_DrawThinString(x, y + 24, V_ALLOWLOWERCASE|V_6WIDTHSPACE, controlText);
 | 
			
		||||
 | 
			
		||||
	y -= 18;
 | 
			
		||||
 | 
			
		||||
	while (curRequest->next != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		INT32 ySlide = min(slide * 4, maxYSlide);
 | 
			
		||||
 | 
			
		||||
		curRequest = curRequest->next;
 | 
			
		||||
 | 
			
		||||
		M_DrawSticker(x, y - 1 + ySlide, V_ThinStringWidth(M_GetDiscordName(curRequest), V_ALLOWLOWERCASE|V_6WIDTHSPACE), 0, false);
 | 
			
		||||
		V_DrawThinString(x, y + ySlide, V_ALLOWLOWERCASE|V_6WIDTHSPACE, M_GetDiscordName(curRequest));
 | 
			
		||||
 | 
			
		||||
		y -= 12;
 | 
			
		||||
		maxYSlide = 12;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (removeRequest == true)
 | 
			
		||||
	{
 | 
			
		||||
		DRPC_RemoveRequest(discordRequestList);
 | 
			
		||||
 | 
			
		||||
		if (discordRequestList == NULL)
 | 
			
		||||
		{
 | 
			
		||||
			// No other requests
 | 
			
		||||
			MPauseMenu[mpause_discordrequests].status = IT_GRAYEDOUT;
 | 
			
		||||
 | 
			
		||||
			if (currentMenu->prevMenu)
 | 
			
		||||
			{
 | 
			
		||||
				M_SetupNextMenu(currentMenu->prevMenu);
 | 
			
		||||
				if (currentMenu == &MPauseDef)
 | 
			
		||||
					itemOn = mpause_continue;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				M_ClearMenus(true);
 | 
			
		||||
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -267,6 +267,8 @@ void Addons_option_Onchange(void);
 | 
			
		|||
void M_ReplayHut(INT32 choice);
 | 
			
		||||
void M_SetPlaybackMenuPointer(void);
 | 
			
		||||
 | 
			
		||||
void M_RefreshPauseMenu(void);
 | 
			
		||||
 | 
			
		||||
INT32 HU_GetHighlightColor(void);
 | 
			
		||||
 | 
			
		||||
// These defines make it a little easier to make menus
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								src/mserv.c
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								src/mserv.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -23,6 +23,10 @@
 | 
			
		|||
#include "m_menu.h"
 | 
			
		||||
#include "z_zone.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef MASTERSERVER
 | 
			
		||||
 | 
			
		||||
static int     MSId;
 | 
			
		||||
| 
						 | 
				
			
			@ -266,6 +270,10 @@ Finish_update (void)
 | 
			
		|||
 | 
			
		||||
	if (! done)
 | 
			
		||||
		Finish_update();
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	else
 | 
			
		||||
		DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -303,6 +311,10 @@ Finish_unlist (void)
 | 
			
		|||
			MSId++;
 | 
			
		||||
	}
 | 
			
		||||
	Unlock_state();
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	DRPC_UpdatePresence();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_THREADS
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2962,7 +2962,7 @@ boolean P_SetupLevel(boolean skipprecip)
 | 
			
		|||
		snprintf(tx, 63, "%s%s%s",
 | 
			
		||||
			mapheaderinfo[gamemap-1]->lvlttl,
 | 
			
		||||
			(strlen(mapheaderinfo[gamemap-1]->zonttl) > 0) ? va(" %s",mapheaderinfo[gamemap-1]->zonttl) : // SRB2kart
 | 
			
		||||
			((mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " ZONE"),
 | 
			
		||||
			((mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone"),
 | 
			
		||||
			(strlen(mapheaderinfo[gamemap-1]->actnum) > 0) ? va(", Act %s",mapheaderinfo[gamemap-1]->actnum) : "");
 | 
			
		||||
		V_DrawSmallString(1, 195, V_ALLOWLOWERCASE, tx);
 | 
			
		||||
		I_UpdateNoVsync();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,6 +70,8 @@ if(${SDL2_FOUND})
 | 
			
		|||
	set(SRB2_SDL2_TOTAL_SOURCES
 | 
			
		||||
		${SRB2_CORE_SOURCES}
 | 
			
		||||
		${SRB2_CORE_HEADERS}
 | 
			
		||||
		${SRB2_DISCORDRPC_SOURCES}
 | 
			
		||||
		${SRB2_DISCORDRPC_HEADERS}
 | 
			
		||||
		${SRB2_PNG_SOURCES}
 | 
			
		||||
		${SRB2_PNG_HEADERS}
 | 
			
		||||
		${SRB2_CORE_RENDER_SOURCES}
 | 
			
		||||
| 
						 | 
				
			
			@ -86,9 +88,11 @@ if(${SDL2_FOUND})
 | 
			
		|||
		${SRB2_PNG_SOURCES} ${SRB2_PNG_HEADERS})
 | 
			
		||||
	source_group("Renderer" FILES ${SRB2_CORE_RENDER_SOURCES})
 | 
			
		||||
	source_group("Game" FILES ${SRB2_CORE_GAME_SOURCES})
 | 
			
		||||
	source_group("Discord Rich Presence" FILES ${SRB2_DISCORDRPC_SOURCES} ${SRB2_DISCORDRPC_HEADERS})
 | 
			
		||||
	source_group("Assembly" FILES ${SRB2_ASM_SOURCES} ${SRB2_NASM_SOURCES})
 | 
			
		||||
	source_group("LUA" FILES ${SRB2_LUA_SOURCES} ${SRB2_LUA_HEADERS})
 | 
			
		||||
	source_group("LUA\\Interpreter" FILES ${SRB2_BLUA_SOURCES} ${SRB2_BLUA_HEADERS})
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	if(${SRB2_CONFIG_HWRENDER})
 | 
			
		||||
		set(SRB2_SDL2_TOTAL_SOURCES ${SRB2_SDL2_TOTAL_SOURCES}
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +157,7 @@ if(${SDL2_FOUND})
 | 
			
		|||
			${ZLIB_LIBRARIES}
 | 
			
		||||
			${OPENGL_LIBRARIES}
 | 
			
		||||
			${CURL_LIBRARIES}
 | 
			
		||||
			${DISCORDRPC_LIBRARIES}
 | 
			
		||||
		)
 | 
			
		||||
		set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
 | 
			
		||||
	else()
 | 
			
		||||
| 
						 | 
				
			
			@ -164,6 +169,7 @@ if(${SDL2_FOUND})
 | 
			
		|||
			${ZLIB_LIBRARIES}
 | 
			
		||||
			${OPENGL_LIBRARIES}
 | 
			
		||||
			${CURL_LIBRARIES}
 | 
			
		||||
			${DISCORDRPC_LIBRARIES}
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
		if(${CMAKE_SYSTEM} MATCHES Linux)
 | 
			
		||||
| 
						 | 
				
			
			@ -244,6 +250,7 @@ if(${SDL2_FOUND})
 | 
			
		|||
		${ZLIB_INCLUDE_DIRS}
 | 
			
		||||
		${OPENGL_INCLUDE_DIRS}
 | 
			
		||||
		${CURL_INCLUDE_DIRS}
 | 
			
		||||
		${DISCORDRPC_INCLUDE_DIRS}
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if(${SRB2_HAVE_MIXER})
 | 
			
		||||
| 
						 | 
				
			
			@ -328,6 +335,10 @@ if(${SDL2_FOUND})
 | 
			
		|||
			getwinlib(libgme "libgme.dll")
 | 
			
		||||
		endif()
 | 
			
		||||
 | 
			
		||||
		if(${SRB2_CONFIG_HAVE_DISCORDRPC})
 | 
			
		||||
			getwinlib(discord-rpc "discord-rpc.dll")
 | 
			
		||||
		endif()
 | 
			
		||||
 | 
			
		||||
		install(PROGRAMS
 | 
			
		||||
			${win_extra_dll_list}
 | 
			
		||||
			DESTINATION .
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
#ifdef _WIN32
 | 
			
		||||
#define RPC_NO_WINDOWS_H
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#include <shlobj.h>
 | 
			
		||||
#include "../doomtype.h"
 | 
			
		||||
typedef BOOL (WINAPI *p_GetDiskFreeSpaceExA)(LPCSTR, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
 | 
			
		||||
typedef BOOL (WINAPI *p_IsProcessorFeaturePresent) (DWORD);
 | 
			
		||||
| 
						 | 
				
			
			@ -3770,6 +3771,65 @@ static const char *locateWad(void)
 | 
			
		|||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
static FILE * openAppDataFile(const char *filename, const char *mode)
 | 
			
		||||
{
 | 
			
		||||
	FILE * file = NULL;
 | 
			
		||||
	char   kdir[MAX_PATH];
 | 
			
		||||
 | 
			
		||||
	if (SHGetFolderPathAndSubDirA(NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
 | 
			
		||||
				NULL, 0, "SRB2Kart", kdir) == S_OK)
 | 
			
		||||
	{
 | 
			
		||||
		strcat(kdir, "\\");
 | 
			
		||||
		strcat(kdir, filename);
 | 
			
		||||
		file = fopen(kdir, mode);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return file;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void I_SaveCurrentWadDirectory(void)
 | 
			
		||||
{
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	char   path[MAX_PATH];
 | 
			
		||||
	FILE * file = openAppDataFile("lastwaddir", "w");
 | 
			
		||||
	if (file != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		if (strcmp(srb2path, ".") == 0)
 | 
			
		||||
		{
 | 
			
		||||
			GetCurrentDirectoryA(sizeof path, path);
 | 
			
		||||
			fputs(path, file);
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			fputs(srb2path, file);
 | 
			
		||||
		}
 | 
			
		||||
		fclose(file);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
boolean I_UseSavedWadDirectory(void)
 | 
			
		||||
{
 | 
			
		||||
	boolean ok = false;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
	FILE * file = openAppDataFile("lastwaddir", "r");
 | 
			
		||||
	if (file != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		if (fgets(srb2path, sizeof srb2path, file) != NULL)
 | 
			
		||||
		{
 | 
			
		||||
			I_OutputMsg(
 | 
			
		||||
					"Going to the last known directory with srb2.srb: %s\n",
 | 
			
		||||
					srb2path);
 | 
			
		||||
			ok = SetCurrentDirectoryA(srb2path);
 | 
			
		||||
		}
 | 
			
		||||
		fclose(file);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *I_LocateWad(void)
 | 
			
		||||
{
 | 
			
		||||
	const char *waddir;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,6 +81,10 @@
 | 
			
		|||
#include "ogl_sdl.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
#include "../discord.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// maximum number of windowed modes (see windowedModes[][])
 | 
			
		||||
#define MAXWINMODES (18)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1387,6 +1391,11 @@ void I_FinishUpdate(void)
 | 
			
		|||
	if (cv_showping.value && netgame && consoleplayer != serverplayer)
 | 
			
		||||
		SCR_DisplayLocalPing();
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	if (discordRequestList != NULL)
 | 
			
		||||
		ST_AskToJoinEnvelope();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (rendermode == render_soft && screens[0])
 | 
			
		||||
	{
 | 
			
		||||
		SDL_Rect rect;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -816,6 +816,10 @@ sfxinfo_t S_sfx[NUMSFX] =
 | 
			
		|||
  {"mkuma",  false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Trigger Happy Havoc Monokuma
 | 
			
		||||
  {"toada",  false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Arid Sands Toad scream
 | 
			
		||||
  {"bsnipe", false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Banana sniping
 | 
			
		||||
  {"join",   false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Player joined server
 | 
			
		||||
  {"leave",  false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Player left server
 | 
			
		||||
  {"requst", false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Got a Discord join request
 | 
			
		||||
  {"syfail", false,  96,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Funny sync failure
 | 
			
		||||
  {"itfree", false,  64,  0, -1, NULL, 0,        -1,  -1, LUMPERROR}, // :shitsfree:
 | 
			
		||||
  {"dbgsal", false, 255,  8, -1, NULL, 0,        -1,  -1, LUMPERROR}, // Debug notification
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -891,6 +891,10 @@ typedef enum
 | 
			
		|||
	sfx_mkuma,
 | 
			
		||||
	sfx_toada,
 | 
			
		||||
	sfx_bsnipe,
 | 
			
		||||
	sfx_join,
 | 
			
		||||
	sfx_leave,
 | 
			
		||||
	sfx_requst,
 | 
			
		||||
	sfx_syfail,
 | 
			
		||||
	sfx_itfree,
 | 
			
		||||
	sfx_dbgsal,
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -129,6 +129,11 @@ static patch_t *gotbflag;
 | 
			
		|||
static patch_t *hud_tv1;
 | 
			
		||||
static patch_t *hud_tv2;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
// Discord Rich Presence
 | 
			
		||||
static patch_t *envelope;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// SRB2kart
 | 
			
		||||
 | 
			
		||||
hudinfo_t hudinfo[NUMHUDITEMS] =
 | 
			
		||||
| 
						 | 
				
			
			@ -349,6 +354,11 @@ void ST_LoadGraphics(void)
 | 
			
		|||
	// Midnight Channel:
 | 
			
		||||
	hud_tv1 = W_CachePatchName("HUD_TV1", PU_HUDGFX);
 | 
			
		||||
	hud_tv2 = W_CachePatchName("HUD_TV2", PU_HUDGFX);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
	// Discord Rich Presence
 | 
			
		||||
	envelope = W_CachePatchName("K_REQUES", PU_HUDGFX);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// made separate so that skins code can reload custom face graphics
 | 
			
		||||
| 
						 | 
				
			
			@ -776,7 +786,7 @@ static void ST_drawLevelTitle(void)
 | 
			
		|||
		if (zonttl[0])
 | 
			
		||||
			zonexpos -= V_LevelNameWidth(zonttl); // SRB2kart
 | 
			
		||||
		else
 | 
			
		||||
			zonexpos -= V_LevelNameWidth(M_GetText("ZONE"));
 | 
			
		||||
			zonexpos -= V_LevelNameWidth(M_GetText("Zone"));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (lvlttlxpos < 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -813,7 +823,7 @@ static void ST_drawLevelTitle(void)
 | 
			
		|||
	if (strlen(zonttl) > 0)
 | 
			
		||||
		V_DrawLevelTitle(zonexpos, bary+6, 0, zonttl);
 | 
			
		||||
	else if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE))
 | 
			
		||||
		V_DrawLevelTitle(zonexpos, bary+6, 0, M_GetText("ZONE"));
 | 
			
		||||
		V_DrawLevelTitle(zonexpos, bary+6, 0, M_GetText("Zone"));
 | 
			
		||||
 | 
			
		||||
	if (actnum[0])
 | 
			
		||||
		V_DrawLevelTitle(ttlnumxpos+12, bary+6, 0, actnum);
 | 
			
		||||
| 
						 | 
				
			
			@ -2080,6 +2090,22 @@ static void ST_MayonakaStatic(void)
 | 
			
		|||
	V_DrawFixedPatch(320<<FRACBITS, 142<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_FLIP|flag, hud_tv2, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
void ST_AskToJoinEnvelope(void)
 | 
			
		||||
{
 | 
			
		||||
	const tic_t freq = TICRATE/2;
 | 
			
		||||
 | 
			
		||||
	if (menuactive)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if ((leveltime % freq) < freq/2)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	V_DrawFixedPatch(296*FRACUNIT, 2*FRACUNIT, FRACUNIT, V_SNAPTOTOP|V_SNAPTORIGHT, envelope, NULL);
 | 
			
		||||
	// maybe draw number of requests with V_DrawPingNum ?
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void ST_Drawer(void)
 | 
			
		||||
{
 | 
			
		||||
	UINT8 i;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,11 @@ void ST_Ticker(void);
 | 
			
		|||
// Called when naming a replay.
 | 
			
		||||
void ST_DrawDemoTitleEntry(void);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DISCORDRPC
 | 
			
		||||
// Called when you have Discord asks
 | 
			
		||||
void ST_AskToJoinEnvelope(void);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// Called by main loop.
 | 
			
		||||
void ST_Drawer(void);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,8 @@ ifndef MINGW64 #miniupnc is broken with MINGW64
 | 
			
		|||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
	HAVE_DISCORDRPC=1
 | 
			
		||||
 | 
			
		||||
	OPTS=-DSTDC_HEADERS
 | 
			
		||||
 | 
			
		||||
ifndef GCC44
 | 
			
		||||
| 
						 | 
				
			
			@ -142,4 +144,15 @@ ifdef MINGW64
 | 
			
		|||
else
 | 
			
		||||
	CURL_LDFLAGS+=-L../libs/curl/lib32 -lcurl
 | 
			
		||||
endif #MINGW64
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
ifdef HAVE_DISCORDRPC
 | 
			
		||||
ifdef MINGW64
 | 
			
		||||
	CPPFLAGS+=-I../libs/discord-rpc/win64-dynamic/include
 | 
			
		||||
	LDFLAGS+=-L../libs/discord-rpc/win64-dynamic/lib
 | 
			
		||||
else
 | 
			
		||||
	CPPFLAGS+=-I../libs/discord-rpc/win32-dynamic/include
 | 
			
		||||
	LDFLAGS+=-L../libs/discord-rpc/win32-dynamic/lib
 | 
			
		||||
endif
 | 
			
		||||
	LIBS+=-ldiscord-rpc
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -233,7 +233,7 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32))
 | 
			
		|||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			const char *zonttl = (mapheaderinfo[prevmap]->zonttl[0] ? mapheaderinfo[prevmap]->zonttl : "ZONE");
 | 
			
		||||
			const char *zonttl = (mapheaderinfo[prevmap]->zonttl[0] ? mapheaderinfo[prevmap]->zonttl : "Zone");
 | 
			
		||||
			if (mapheaderinfo[prevmap]->actnum[0])
 | 
			
		||||
				snprintf(data.match.levelstring,
 | 
			
		||||
					sizeof data.match.levelstring,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +0,0 @@
 | 
			
		|||
SRB2Kart Install Instructions
 | 
			
		||||
 | 
			
		||||
1. Move every file from the "new-install" folder to this main install folder.
 | 
			
		||||
 | 
			
		||||
2. DELETE "staging.bat" and "staging.txt"! These can mess up your installation if run by accident!
 | 
			
		||||
 | 
			
		||||
3. Optionally, create a folder in your user profile named "SRB2Kart". This is where your game data and addons may live. For example,
 | 
			
		||||
 | 
			
		||||
	C:\Users\[User]\SRB2Kart
 | 
			
		||||
 | 
			
		||||
4. Run the game! Double-click srb2kart.exe -- or see if you have Start Menu icons under "SRB2Kart".
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue