Merge master

Slopes in a few maps are really broken ... think it's anchors, I'm gonna leave that to jart :V
This commit is contained in:
Sally Coolatta 2020-09-25 12:00:50 -04:00
commit b5fcd74ef9
63 changed files with 3395 additions and 1163 deletions

View 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)

View file

@ -1,6 +1,6 @@
# SRB2Kart - Which DLLs do I need to bundle?
Updated 12/6/2019 (v2.2)
Updated 8/23/2020 (v1.3)
Here are the required DLLs, per build. For each architecture, copy all the binaries from these folders:
@ -15,6 +15,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\SDL2mixerX\i686-w64-mingw32\bin\*.dll (get everything)
@ -24,27 +25,8 @@ 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
<<<<<<< HEAD
* 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)
=======
* libs\SDL2mixerX\x86_64-w64-mingw32\bin\*.dll (get everything)
* libs\libopenmpt\x86_64\bin\mingw\libopenmpt.dll
>>>>>>> srb2/next

16
libs/discord-rpc.props Normal file
View 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>

View 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

View 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

Binary file not shown.

View 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

View 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,39 @@
/*
* Copyright 2002-2015 Jose Fonseca
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <windows.h>
// Set the unhandled exception handler.
// Must be called when exchndll.dll is statically loaded (as opposed to loaded
// dynamically via LoadLibrary)
EXTERN_C VOID APIENTRY
ExcHndlInit(void);
// Override the report file name.
//
// Default is prog_name.RPT, in the same directory as the main executable.
//
// You can also pass "-" for stderr.
EXTERN_C BOOL APIENTRY
ExcHndlSetLogFileNameA(const char *szLogFileName);

Binary file not shown.

Binary file not shown.

View file

@ -103,7 +103,6 @@ set(SRB2_CORE_HEADERS
m_swap.h
md5.h
mserv.h
http-mserv.h
p5prof.h
s_sound.h
screen.h
@ -253,6 +252,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_HAVE_OPENMPT ON CACHE BOOL
@ -369,7 +370,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")
@ -429,6 +430,32 @@ if(${SRB2_CONFIG_HAVE_MIXERX})
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)
@ -481,7 +508,7 @@ endif()
if(${SRB2_CONFIG_HAVE_CURL})
if(${SRB2_CONFIG_USE_INTERNAL_LIBRARIES})
set(CURL_FOUND ON)
set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl)
set(CURL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/libs/curl/include)
if(${SRB2_SYSTEM_BITS} EQUAL 64)
set(CURL_LIBRARIES "-L${CMAKE_SOURCE_DIR}/libs/curl/lib64 -lcurl")
else() # 32-bit

View file

@ -57,10 +57,10 @@
# Compile a profile version, add 'PROFILEMODE=1'
# Compile a debug version, add 'DEBUGMODE=1'
# Compile for the testers group (they don't get to play unless we're watching *wink*), add 'TESTERS=1'
# Compile with extra warnings, add 'WARNINGMODE=1'
# Compile with less warnings, add 'RELAXWARNINGS=1'
# Generate compiler errors for most compiler warnings, add 'ERRORMODE=1'
# Compile without NASM's tmap.nas, add 'NOASM=1'
# Compile without 3D hardware support, add 'NOHW=1'
# Compile without 3D sound support, add 'NOHS=1'
# Compile with GDBstubs, add 'RDB=1'
# Compile without PNG, add 'NOPNG=1'
# Compile without zlib, add 'NOZLIB=1'
@ -81,6 +81,58 @@
#
#############################################################################
ALL_SYSTEMS=\
PANDORA\
LINUX64\
MINGW64\
HAIKU\
DUMMY\
DJGPPDOS\
MINGW\
UNIX\
LINUX\
SOLARIS\
FREEBSD\
MACOSX\
SDL\
# check for user specified system
ifeq (,$(filter $(ALL_SYSTEMS),$(.VARIABLES)))
ifeq ($(OS),Windows_NT) # all windows are Windows_NT...
$(info Detected a Windows system, compiling for 32-bit MinGW SDL2...)
# go for a 32-bit sdl mingw exe by default
MINGW=1
SDL=1
WINDOWSHELL=1
else # if you on the *nix
system:=$(shell uname -s)
ifeq ($(system),Linux)
new_system=LINUX
else
$(error \
Could not automatically detect your system,\
try specifying a system manually)
endif
ifeq ($(shell getconf LONG_BIT),64)
system+=64-bit
new_system:=$(new_system)64
endif
$(info Detected $(system) ($(new_system))...)
$(new_system)=1
endif
endif
# SRB2 data files
D_DIR?=../bin/Resources
D_FILES=$(D_DIR)/main.kart \
@ -124,7 +176,6 @@ NOPNG=1
NOZLIB=1
NONET=1
NOHW=1
NOHS=1
NOASM=1
NOIPX=1
EXENAME?=srb2dummy
@ -146,7 +197,6 @@ endif
ifdef PANDORA
NONX86=1
NOHW=1
NOHS=1
endif
ifndef NOOPENMPT
@ -228,13 +278,6 @@ else
$(OBJDIR)/hw_md2load.o $(OBJDIR)/hw_md3load.o $(OBJDIR)/hw_model.o $(OBJDIR)/u_list.o $(OBJDIR)/hw_batching.o
endif
ifdef NOHS
OPTS+=-DNOHS
else
OPTS+=-DHW3SOUND
OBJS+=$(OBJDIR)/hw3sound.o
endif
OPTS += -DCOMPVERSION
ifndef NONX86
@ -348,6 +391,12 @@ CFLAGS+=-DHAVE_MINIUPNPC
endif
endif
ifdef HAVE_DISCORDRPC
LIBS+=-ldiscord-rpc
CFLAGS+=-DHAVE_DISCORDRPC
OBJS+=$(OBJDIR)/discord.o
endif
include blua/Makefile.cfg
ifdef NOMD5
@ -780,19 +829,6 @@ $(OBJDIR)/ogl_win.o: hardware/r_opengl/ogl_win.c hardware/r_opengl/r_opengl.h \
$(CC) $(CFLAGS) $(WFLAGS) -D_WINDOWS -mwindows -c $< -o $@
endif
ifndef NOHS
$(OBJDIR)/s_ds3d.o: hardware/s_ds3d/s_ds3d.c hardware/hw3dsdrv.h \
hardware/hw_dll.h
$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_ds3d.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_ds3d/s_ds3d.c
$(OBJDIR)/s_fmod.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \
hardware/hw_dll.h
$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_fmod.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_fmod/s_fmod.c
$(OBJDIR)/s_openal.o: hardware/s_openal/s_openal.c hardware/hw3dsdrv.h \
hardware/hw_dll.h
$(CC) $(ARCHOPTS) -Os -o $(OBJDIR)/s_openal.o $(WFLAGS) -D_WINDOWS -mwindows -c hardware/s_openal/s_openal.c
endif
endif
endif

View file

@ -210,10 +210,7 @@ WFLAGS=-Wall
ifndef GCC295
#WFLAGS+=-Wno-packed
endif
ifdef ERRORMODE
WARNINGMODE=1
endif
ifdef WARNINGMODE
ifndef RELAXWARNINGS
WFLAGS+=-W
#WFLAGS+=-Wno-sign-compare
ifndef GCC295

View file

@ -322,8 +322,8 @@ static void Arith (lua_State *L, StkId ra, TValue *rb,
case TM_ADD: setnvalue(ra, luai_numadd(nb, nc)); break;
case TM_SUB: setnvalue(ra, luai_numsub(nb, nc)); break;
case TM_MUL: setnvalue(ra, luai_nummul(nb, nc)); break;
case TM_DIV: if (nc == 0) { lua_pushliteral(L, "divide by zero error"); lua_error(L); } else setnvalue(ra, luai_numdiv(nb, nc)); break;
case TM_MOD: if (nc == 0) { lua_pushliteral(L, "modulo by zero error"); lua_error(L); } else setnvalue(ra, luai_nummod(nb, nc)); break;
case TM_DIV: if (nc == 0) { luaG_runerror(L, "divide by zero error"); } else setnvalue(ra, luai_numdiv(nb, nc)); break;
case TM_MOD: if (nc == 0) { luaG_runerror(L, "modulo by zero error"); } else setnvalue(ra, luai_nummod(nb, nc)); break;
case TM_POW: setnvalue(ra, luai_numpow(nb, nc)); break;
case TM_UNM: setnvalue(ra, luai_numunm(nb)); break;
case TM_AND: setnvalue(ra, luai_numand(nb, nc)); break;
@ -492,8 +492,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
if (ttisnumber(rb) && ttisnumber(rc)) {
lua_Number nb = nvalue(rb), nc = nvalue(rc);
if (nc == 0) {
lua_pushliteral(L, "divide by zero error");
lua_error(L);
luaG_runerror(L, "divide by zero error");
}
else
setnvalue(ra, luai_numdiv(nb, nc));
@ -508,8 +507,7 @@ void luaV_execute (lua_State *L, int nexeccalls) {
if (ttisnumber(rb) && ttisnumber(rc)) {
lua_Number nb = nvalue(rb), nc = nvalue(rc);
if (nc == 0) {
lua_pushliteral(L, "modulo by zero error");
lua_error(L);
luaG_runerror(L, "modulo by zero error");
}
else
setnvalue(ra, luai_nummod(nb, nc));

View file

@ -29,7 +29,7 @@
/* Manually defined asset hashes for non-CMake builds
* Last updated 2019 / 01 / 18 - Kart v1.0.2 - Main assets
* Last updated 2020 / 05 / 09 - Kart v1.2 - patch.kart
* Last updated 2020 / 08 / 30 - Kart v1.3 - patch.kart
*/
#define ASSET_HASH_MAIN_KART "00000000000000000000000000000000"

File diff suppressed because it is too large Load diff

View file

@ -367,6 +367,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;
@ -592,6 +597,10 @@ typedef enum
} kickreason_t;
/* the max number of name changes in some time period */
#define MAXNAMECHANGES (5)
#define NAMECHANGERATE (60*TICRATE)
extern boolean server;
extern boolean serverrunning;
#define client (!server)
@ -619,6 +628,8 @@ extern consvar_t cv_maxsend, cv_noticedownload, cv_downloadspeed;
extern consvar_t cv_joinnextround;
#endif
extern consvar_t cv_discordinvites;
// Used in d_net, the only dependence
tic_t ExpandTics(INT32 low, tic_t basetic);
void D_ClientServerInit(void);
@ -643,7 +654,7 @@ void CL_Reset(void);
void CL_ClearPlayer(INT32 playernum);
void CL_RemovePlayer(INT32 playernum, kickreason_t reason);
void CL_QueryServerList(msg_server_t *list);
void CL_UpdateServerList(boolean internetsearch, INT32 room);
void CL_UpdateServerList(void);
// Is there a game running
boolean Playing(void);

View file

@ -59,7 +59,6 @@
#include "m_cheat.h"
#include "y_inter.h"
#include "p_local.h" // chasecam
#include "mserv.h" // ms_RoomId
#include "m_misc.h" // screenshot functionality
#include "dehacked.h" // Dehacked list test
#include "m_cond.h" // condition initialization
@ -96,6 +95,10 @@
int VERSION;
int SUBVERSION;
#ifdef HAVE_DISCORDRPC
#include "discord.h"
#endif
// platform independant focus loss
UINT8 window_notinfocus = false;
@ -901,6 +904,13 @@ void D_SRB2Loop(void)
#endif
LUA_Step();
#ifdef HAVE_DISCORDRPC
if (! dedicated)
{
Discord_RunCallbacks();
}
#endif
}
}
@ -1078,9 +1088,23 @@ static void ChangeDirForUrlHandler(void)
// Identify the SRB2 version, and IWAD file to use.
// ==========================================================================
static boolean AddIWAD(void)
{
char * path = va(pandf,srb2path,"main.kart");
if (FIL_ReadFileOK(path))
{
D_AddFile(path, startupiwads);
return true;
}
else
{
return false;
}
}
static void IdentifyVersion(void)
{
char *mainresource;
const char *srb2waddir = NULL;
#if (defined (__unix__) && !defined (MSDOS)) || defined (UNIXCOMMON) || defined (HAVE_SDL)
@ -1098,36 +1122,19 @@ static void IdentifyVersion(void)
if (getcwd(srb2path, 256) != NULL)
srb2waddir = srb2path;
else
{
srb2waddir = ".";
}
}
#if defined (macintosh) && !defined (HAVE_SDL)
// cwd is always "/" when app is dbl-clicked
if (!stricmp(srb2waddir, "/"))
srb2waddir = I_GetWadDir();
#endif
// Commercial.
mainresource = malloc(strlen(srb2waddir)+1+9+1);
if (mainresource == NULL)
I_Error("No more free memory to look in %s", srb2waddir);
else
sprintf(mainresource, pandf, srb2waddir, "main.kart");
// Load the IWAD
if (! AddIWAD())
{
I_Error("MAIN.KART 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 (mainresource != NULL && FIL_ReadFileOK(mainresource))
D_AddFile(mainresource, startupiwads);
else
I_Error("main.kart not found! Expected in %s, ss file: %s \n", srb2waddir, mainresource);
if (mainresource)
free(mainresource);
// if you change the ordering of this or add/remove a file, be sure to update the md5
// checking in D_SRB2Main
@ -1662,17 +1669,6 @@ void D_SRB2Main(void)
CONS_Printf("ST_Init(): Init status bar.\n");
ST_Init();
if (M_CheckParm("-room"))
{
if (!M_IsNextParm())
I_Error("usage: -room <room_id>\nCheck the Master Server's webpage for room ID numbers.\n");
ms_RoomId = atoi(M_GetNextParm());
#ifdef UPDATE_ALERT
GetMODVersion_Console();
#endif
}
// Set up splitscreen players before joining!
if (!dedicated && (M_CheckParm("-splitscreen") && M_IsNextParm()))
{
@ -1890,6 +1886,13 @@ void D_SRB2Main(void)
if (!P_LoadLevel(false))
I_Quit(); // fail so reset game stuff
}
#ifdef HAVE_DISCORDRPC
if (! dedicated)
{
DRPC_Init();
}
#endif
}
const char *D_Home(void)

View file

@ -64,6 +64,10 @@
#define CV_RESTRICT 0
#endif
#ifdef HAVE_DISCORDRPC
#include "discord.h"
#endif
// ------
// protos
// ------
@ -89,6 +93,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);
@ -748,10 +753,13 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_showviewpointtext);
#ifdef SEENAMES
CV_RegisterVar(&cv_allowseenames);
CV_RegisterVar(&cv_allowseenames);
#endif
CV_RegisterVar(&cv_dummyconsvar);
CV_RegisterVar(&cv_discordinvites);
RegisterNetXCmd(XD_DISCORD, Got_DiscordInfo);
}
// =========================================================================
@ -1038,6 +1046,12 @@ void D_RegisterClientCommands(void)
#ifdef 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);
#endif
}
/** Checks if a name (as received from another player) is okay.
@ -1255,6 +1269,8 @@ static void SetPlayerName(INT32 playernum, char *newname)
if (netgame)
HU_AddChatText(va("\x82*%s renamed to %s", player_names[playernum], newname), false);
player_name_changes[playernum]++;
strcpy(player_names[playernum], newname);
demo_extradata[playernum] |= DXD_NAME;
}
@ -1455,7 +1471,12 @@ static void SendNameAndColor(UINT8 n)
snacpending[n]++;
// Don't change name if muted
if (cv_mute.value && !(server || IsPlayerAdmin(playernum)))
if (player_name_changes[playernum] >= MAXNAMECHANGES)
{
CV_StealthSet(&cv_playername[n], player_names[playernum]);
HU_AddChatText("\x85*You must wait to change your name again", false);
}
else if (cv_mute.value && !(server || IsPlayerAdmin(playernum)))
CV_StealthSet(&cv_playername[n], player_names[playernum]);
else // Cleanup name if changing it
CleanupPlayerName(playernum, cv_playername[n].zstring);
@ -1491,6 +1512,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
UINT16 color, followercolor;
UINT8 skin;
SINT8 follower;
SINT8 localplayer = -1;
UINT8 i;
#ifdef PARANOIA
@ -1509,7 +1531,7 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
I_Error("snacpending[%d] negative!", i);
#endif
// i is now player screen id
localplayer = i;
break;
}
}
@ -1590,8 +1612,8 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
const INT32 forcedskin = cv_forceskin.value;
SetPlayerSkinByNum(playernum, forcedskin);
if (playernum == g_localplayers[i])
CV_StealthSet(&cv_skin[i], skins[forcedskin].name);
if (localplayer != -1)
CV_StealthSet(&cv_skin[localplayer], skins[forcedskin].name);
}
else
SetPlayerSkinByNum(playernum, skin);
@ -1602,6 +1624,11 @@ static void Got_NameAndColor(UINT8 **cp, INT32 playernum)
// set follower
SetFollower(playernum, follower);
#ifdef HAVE_DISCORDRPC
if (playernum == consoleplayer)
DRPC_UpdatePresence();
#endif
}
void SendWeaponPref(UINT8 n)
@ -2865,6 +2892,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)
@ -3799,7 +3830,7 @@ static void Command_RunSOC(void)
static void Got_RunSOCcmd(UINT8 **cp, INT32 playernum)
{
char filename[256];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
if (playernum != serverplayer && !IsPlayerAdmin(playernum))
{
@ -3937,7 +3968,7 @@ static void Command_Addfile(void)
static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
boolean kick = false;
boolean toomany = false;
@ -3996,7 +4027,7 @@ static void Got_RequestAddfilecmd(UINT8 **cp, INT32 playernum)
static void Got_Addfilecmd(UINT8 **cp, INT32 playernum)
{
char filename[241];
filestatus_t ncs = FS_NOTFOUND;
filestatus_t ncs = FS_NOTCHECKED;
UINT8 md5sum[16];
READSTRINGN(*cp, filename, 240);
@ -4289,6 +4320,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.
@ -5603,3 +5638,26 @@ static void KartEliminateLast_OnChange(void)
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)
SendKick(playernum, KICK_MSG_CON_FAIL | KICK_MSG_KEEP_BODY);
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
}

View file

@ -161,6 +161,7 @@ typedef enum
XD_CANCELPARTYINVITE, // 31
XD_GIVEITEM, // 32
XD_ADDBOT, // 33
XD_DISCORD, // 34
MAXNETXCMD
} netxcmd_t;

View file

@ -118,6 +118,10 @@ static pauseddownload_t *pauseddownload = NULL;
#ifndef NONET
// for cl loading screen
INT32 lastfilenum = -1;
INT32 downloadcompletednum = 0;
UINT32 downloadcompletedsize = 0;
INT32 totalfilesrequestednum = 0;
UINT32 totalfilesrequestedsize = 0;
#endif
#ifdef HAVE_CURL
@ -156,7 +160,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
for (i = mainwads; i < numwadfiles; i++)
for (i = mainwads+1; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
{
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
@ -222,7 +226,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
p = (UINT8 *)fileneededstr;
for (i = firstfile; i < fileneedednum; i++)
{
fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
fileneeded[i].justdownloaded = false;
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].willsend = (UINT8)(filestatus >> 4);
@ -416,15 +420,17 @@ boolean PT_RequestFile(INT32 node)
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
* 3 too many files, over WADLIMIT
* 4 still checking, continuing next tic
*
*/
INT32 CL_CheckFiles(void)
{
INT32 i, j;
char wadfilename[MAX_WADPATH];
INT32 ret = 1;
size_t packetsize = 0;
size_t filestoget = 0;
size_t filestoload = 0;
boolean downloadrequired = false;
// if (M_CheckParm("-nofiles"))
// return 1;
@ -441,7 +447,7 @@ INT32 CL_CheckFiles(void)
if (modifiedgame)
{
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 0, j = mainwads; i < fileneedednum || j < numwadfiles;)
for (i = 0, j = mainwads+1; i < fileneedednum || j < numwadfiles;)
{
if (j < numwadfiles && !wadfiles[j]->important)
{
@ -470,10 +476,19 @@ INT32 CL_CheckFiles(void)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_FALLBACK)
downloadrequired = true;
if (fileneeded[i].status == FS_FOUND || fileneeded[i].status == FS_NOTFOUND)
filestoload++;
if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics
continue;
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
// Check in already loaded files
for (j = mainwads; wadfiles[j]; j++)
for (j = mainwads+1; wadfiles[j]; j++)
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) &&
@ -481,36 +496,35 @@ INT32 CL_CheckFiles(void)
{
CONS_Debug(DBG_NETPLAY, "already loaded\n");
fileneeded[i].status = FS_OPEN;
break;
return 4;
}
}
if (fileneeded[i].status != FS_NOTFOUND)
continue;
packetsize += nameonlylength(fileneeded[i].filename) + 22;
if (mainwads+filestoget >= MAX_WADFILES)
return 3;
filestoget++;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
if (fileneeded[i].status != FS_FOUND)
ret = 0;
return 4;
}
return ret;
//now making it here means we've checked the entire list and no FS_NOTCHECKED files remain
if (numwadfiles+filestoload > MAX_WADFILES)
return 3;
else if (downloadrequired)
return 0; //some stuff is FS_NOTFOUND, needs download
else
return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading
}
// Load it now
void CL_LoadServerFiles(void)
boolean CL_LoadServerFiles(void)
{
INT32 i;
// if (M_CheckParm("-nofiles"))
// return;
for (i = 1; i < fileneedednum; i++)
for (i = 0; i < fileneedednum; i++)
{
if (fileneeded[i].status == FS_OPEN)
continue; // Already loaded
@ -519,6 +533,7 @@ void CL_LoadServerFiles(void)
P_AddWadFile(fileneeded[i].filename);
G_SetGameModified(true, false);
fileneeded[i].status = FS_OPEN;
return false;
}
else if (fileneeded[i].status == FS_MD5SUMBAD)
I_Error("Wrong version of file %s", fileneeded[i].filename);
@ -544,6 +559,7 @@ void CL_LoadServerFiles(void)
fileneeded[i].status, s);
}
}
return true;
}
void AddLuaFileTransfer(const char *filename, const char *mode)
@ -1374,6 +1390,11 @@ void PT_FileFragment(void)
netbuffer->packettype = PT_HASLUAFILE;
HSendPacket(servernode, true, 0, 0);
}
#ifndef NONET
downloadcompletednum++;
downloadcompletedsize += file->totalsize;
#endif
}
}
else // Already received
@ -1732,6 +1753,8 @@ void CURLGetFile(void)
{
nameonly(curl_realname);
CONS_Printf(M_GetText("Finished downloading %s\n"), curl_realname);
downloadcompletednum++;
downloadcompletedsize += curl_curfile->totalsize;
curl_curfile->status = FS_FOUND;
fclose(curl_curfile->file);
}

View file

@ -27,6 +27,7 @@ typedef enum
typedef enum
{
FS_NOTCHECKED,
FS_NOTFOUND,
FS_FOUND,
FS_REQUESTED,
@ -61,6 +62,10 @@ extern char downloaddir[512];
#ifndef NONET
extern INT32 lastfilenum;
extern INT32 downloadcompletednum;
extern UINT32 downloadcompletedsize;
extern INT32 totalfilesrequestednum;
extern UINT32 totalfilesrequestedsize;
#endif
#ifdef HAVE_CURL
@ -74,7 +79,7 @@ void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 fi
void CL_PrepareDownloadSaveGame(const char *tmpsave);
INT32 CL_CheckFiles(void);
void CL_LoadServerFiles(void);
boolean CL_LoadServerFiles(void);
void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod,
UINT8 fileid);

View file

@ -10362,7 +10362,6 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_TWINKLECARTAMBIENCE",
"MT_EXPLODINGBARREL",
"MT_MERRYHORSE",
"MT_ARIDTOAD",
"MT_BLUEFRUIT",
"MT_ORANGEFRUIT",
"MT_REDFRUIT",
@ -10373,6 +10372,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_BOOSTPROMPT",
"MT_BOOSTOFF",
"MT_BOOSTON",
"MT_ARIDTOAD",
"MT_LIZARDMAN",
"MT_LIONMAN",
@ -12689,8 +12689,6 @@ static inline int lib_getenum(lua_State *L)
if (mathlib) return luaL_error(L, "constant '%s' could not be parsed.\n", word);
// DYNAMIC variables too!!
// Try not to add anything that would break netgames or timeattack replays here.
// You know, like consoleplayer, displayplayer, secondarydisplayplayer, or gametime.
return LUA_PushGlobals(L, word);
}

712
src/discord.c Normal file
View file

@ -0,0 +1,712 @@
// 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" // cv_advertise
#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 21
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};
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, 17, 18, 19, 20, 21};
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();
}
#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 (dedicated)
{
return;
}
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)
{
if (cv_advertise.value)
{
discordPresence.state = "Public";
}
else
{
discordPresence.state = "Private";
}
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 = ((gametype == GT_BATTLE) ? "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

80
src/discord.h Normal file
View file

@ -0,0 +1,80 @@
// 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 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_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__

View file

@ -220,4 +220,11 @@ typedef struct
#define NUMMAPS 1035
/* slope thing types */
enum
{
FLOOR_SLOPE_THING = 777,
CEILING_SLOPE_THING = 778,
};
#endif // __DOOMDATA__

View file

@ -29,7 +29,6 @@
// Use Mixer interface?
#ifdef HAVE_MIXER
#define SOUND SOUND_MIXER
#define NOHS // No HW3SOUND
#ifdef HW3SOUND
#undef HW3SOUND
#endif
@ -45,7 +44,6 @@
// Use FMOD?
#ifdef HAVE_FMOD
#define SOUND SOUND_FMOD
#define NOHS // No HW3SOUND
#ifdef HW3SOUND
#undef HW3SOUND
#endif
@ -62,10 +60,6 @@
#if !defined (HWRENDER) && !defined (NOHW)
#define HWRENDER
#endif
// judgecutor: 3D sound support
#if !defined(HW3SOUND) && !defined (NOHS)
#define HW3SOUND
#endif
#endif
#ifdef _WIN32
@ -165,32 +159,13 @@ extern char logfilename[1024];
// Please change to apply to your modification (we don't want everyone asking where your mod is on SRB2.org!).
#define UPDATE_ALERT_STRING \
"A new update is available for SRB2Kart.\n"\
"Please visit mb.srb2.org to download it.\n"\
"Please visit kartkrew.org to download it.\n"\
"\n"\
"You are using version: %s\n"\
"The newest version is: %s\n"\
"\n"\
"This update is required for online\n"\
"play using the Master Server.\n"\
"You will not be able to connect to\n"\
"the Master Server until you update to\n"\
"the newest version of the game.\n"\
"\n"\
"(Press a key)\n"
// The string used in the I_Error alert upon trying to host through command line parameters.
// Generally less filled with newlines, since Windows gives you lots more room to work with.
#define UPDATE_ALERT_STRING_CONSOLE \
"A new update is available for SRB2Kart.\n"\
"Please visit mb.srb2.org to download it.\n"\
"\n"\
"You are using version: %s\n"\
"The newest version is: %s\n"\
"\n"\
"This update is required for online play using the Master Server.\n"\
"You will not be able to connect to the Master Server\n"\
"until you update to the newest version of the game.\n"
// For future use, the codebase is the version of SRB2 that the modification is based on,
// and should not be changed unless you have merged changes between versions of SRB2
// (such as 2.0.4 to 2.0.5, etc) into your working copy.
@ -683,4 +658,10 @@ extern const char *compdate, *comptime, *comprevision, *compbranch;
/// MIDI support is really shitty -- we don't use it anyway, so lets throw it behind a define
#define NO_MIDI
#if defined (HAVE_CURL) && ! defined (NONET)
#define MASTERSERVER
#else
#undef UPDATE_ALERT
#endif
#endif // __DOOMDEF__

View file

@ -58,6 +58,10 @@
#include "k_grandprix.h"
#include "doomstat.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
#endif
gameaction_t gameaction;
gamestate_t gamestate = GS_NULL;
UINT8 ultimatemode = false;
@ -471,6 +475,7 @@ player_t *seenplayer; // player we're aiming at right now
// now automatically allocated in D_RegisterClientCommands
// so that it doesn't have to be updated depending on the value of MAXPLAYERS
char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
INT32 player_name_changes[MAXPLAYERS];
// Allocation for time and nights data
void G_AllocMainRecordData(INT16 i)
@ -1957,6 +1962,11 @@ void G_Ticker(boolean run)
if (camtoggledelay[i])
camtoggledelay[i]--;
}
if (gametic % NAMECHANGERATE == 0)
{
memset(player_name_changes, 0, sizeof player_name_changes);
}
}
}
@ -4744,6 +4754,9 @@ INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep)
void G_SetGamestate(gamestate_t newstate)
{
gamestate = newstate;
#ifdef HAVE_DISCORDRPC
DRPC_UpdatePresence();
#endif
}
/* These functions handle the exitgame flag. Before, when the user

View file

@ -27,7 +27,8 @@ extern char customversionstring[32];
#ifdef SEENAMES
extern player_t *seenplayer;
#endif
extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
extern char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
extern INT32 player_name_changes[MAXPLAYERS];
extern player_t players[MAXPLAYERS];
extern boolean playeringame[MAXPLAYERS];

View file

@ -11,10 +11,12 @@
/*
Documentation available here.
<http://mb.srb2.org/MS/tools/api/v1/>
<https://ms.kartkrew.org/tools/api/2/>
*/
#ifdef HAVE_CURL
#include <curl/curl.h>
#endif
#include "doomdef.h"
#include "d_clisrv.h"
@ -49,6 +51,8 @@ consvar_t cv_masterserver_token = {
NULL, 0, NULL, NULL, 0, 0, NULL/* C90 moment */
};
#ifdef MASTERSERVER
static int hms_started;
static char *hms_api;
@ -137,7 +141,7 @@ HMS_connect (const char *format, ...)
if (cv_masterserver_token.string[0])
{
quack_token = curl_easy_escape(curl, cv_masterserver_token.string, 0);
token_length = ( sizeof "?token="-1 )+ strlen(quack_token);
token_length = ( sizeof "&token="-1 )+ strlen(quack_token);
}
else
{
@ -152,7 +156,9 @@ HMS_connect (const char *format, ...)
seek = strlen(hms_api) + 1;/* + '/' */
va_start (ap, format);
url = malloc(seek + vsnprintf(0, 0, format, ap) + token_length + 1);
url = malloc(seek + vsnprintf(0, 0, format, ap) +
sizeof "?v=2" - 1 +
token_length + 1);
va_end (ap);
sprintf(url, "%s/", hms_api);
@ -165,8 +171,11 @@ HMS_connect (const char *format, ...)
seek += vsprintf(&url[seek], format, ap);
va_end (ap);
strcpy(&url[seek], "?v=2");
seek += sizeof "?v=2" - 1;
if (quack_token)
sprintf(&url[seek], "?token=%s", quack_token);
sprintf(&url[seek], "&token=%s", quack_token);
CONS_Printf("HMS: connecting '%s'...\n", url);
@ -254,117 +263,6 @@ HMS_end (struct HMS_buffer *buffer)
free(buffer);
}
int
HMS_fetch_rooms (int joining, int query_id)
{
struct HMS_buffer *hms;
int ok;
int doing_shit;
char *id;
char *title;
char *room_motd;
int id_no;
char *p;
char *end;
int i;
(void)query_id;
hms = HMS_connect("rooms");
if (! hms)
return 0;
if (HMS_do(hms))
{
doing_shit = 1;
p = hms->buffer;
for (i = 0; i < NUM_LIST_ROOMS && ( end = strstr(p, "\n\n\n") );)
{
*end = '\0';
id = strtok(p, "\n");
title = strtok(0, "\n");
room_motd = strtok(0, "");
if (id && title && room_motd)
{
id_no = atoi(id);
/*
Don't show the 'All' room if hosting. And it's a hack like this
because I'm way too lazy to add another feature to the MS.
*/
if (joining || id_no != 0)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
if (query_id != ms_QueryId)
doing_shit = 0;
}
I_unlock_mutex(ms_QueryId_mutex);
if (! doing_shit)
break;
#endif
room_list[i].header.buffer[0] = 1;
room_list[i].id = id_no;
strlcpy(room_list[i].name, title, sizeof room_list[i].name);
strlcpy(room_list[i].motd, room_motd, sizeof room_list[i].motd);
i++;
}
p = ( end + 3 );/* skip the three linefeeds */
}
else
break;
}
if (doing_shit)
room_list[i].header.buffer[0] = 0;
ok = 1;
if (doing_shit)
{
#ifdef HAVE_THREADS
I_lock_mutex(&m_menu_mutex);
#endif
{
for (i = 0; room_list[i].header.buffer[0]; i++)
{
if(*room_list[i].name != '\0')
{
MP_RoomMenu[i+1].text = room_list[i].name;
roomIds[i] = room_list[i].id;
MP_RoomMenu[i+1].status = IT_STRING|IT_CALL;
}
}
}
#ifdef HAVE_THREADS
I_unlock_mutex(m_menu_mutex);
#endif
}
}
else
ok = 0;
HMS_end(hms);
return ok;
}
int
HMS_register (void)
{
@ -373,28 +271,26 @@ HMS_register (void)
char post[256];
char *title;
char *contact;
hms = HMS_connect("rooms/%d/register", ms_RoomId);
hms = HMS_connect(
"games/%s/%d/servers/register", SRB2APPLICATION, MODVERSION);
if (! hms)
return 0;
title = curl_easy_escape(hms->curl, cv_servername.string, 0);
contact = curl_easy_escape(hms->curl, cv_server_contact.string, 0);
snprintf(post, sizeof post,
"port=%d&"
"title=%s&"
"version=%s",
"contact=%s",
current_port,
title,
SRB2VERSION
contact
);
curl_free(title);
curl_free(contact);
curl_easy_setopt(hms->curl, CURLOPT_POSTFIELDS, post);
@ -468,19 +364,13 @@ HMS_list_servers (void)
{
struct HMS_buffer *hms;
char *p;
hms = HMS_connect("servers");
hms = HMS_connect("games/%s/%d/servers", SRB2APPLICATION, MODVERSION);
if (! hms)
return;
if (HMS_do(hms))
{
p = &hms->buffer[strlen(hms->buffer)];
while (*--p == '\n')
;
CONS_Printf("%s\n", hms->buffer);
}
@ -488,35 +378,24 @@ HMS_list_servers (void)
}
msg_server_t *
HMS_fetch_servers (msg_server_t *list, int room_number, int query_id)
HMS_fetch_servers (msg_server_t *list, int query_id)
{
struct HMS_buffer *hms;
int doing_shit;
char local_version[9];
char *room;
char *address;
char *port;
char *title;
char *version;
char *contact;
char *end;
char *section_end;
char *p;
int i;
(void)query_id;
if (room_number > 0)
{
hms = HMS_connect("rooms/%d/servers", room_number);
}
else
hms = HMS_connect("servers");
hms = HMS_connect("games/%s/%d/servers", SRB2APPLICATION, MODVERSION);
if (! hms)
return NULL;
@ -525,80 +404,51 @@ HMS_fetch_servers (msg_server_t *list, int room_number, int query_id)
{
doing_shit = 1;
snprintf(local_version, sizeof local_version,
"%s",
SRB2VERSION
);
p = hms->buffer;
i = 0;
do
while (i < MAXSERVERLIST && ( end = strchr(p, '\n') ))
{
section_end = strstr(p, "\n\n");
*end = '\0';
room = strtok(p, "\n");
address = strtok(p, " ");
port = strtok(0, " ");
contact = strtok(0, "");
p = strtok(0, "");
if (! p)
break;
while (i < MAXSERVERLIST && ( end = strchr(p, '\n') ))
if (address && port)
{
*end = '\0';
address = strtok(p, " ");
port = strtok(0, " ");
title = strtok(0, " ");
version = strtok(0, "");
if (address && port && title && version)
{
#ifdef HAVE_THREADS
I_lock_mutex(&ms_QueryId_mutex);
{
if (query_id != ms_QueryId)
doing_shit = 0;
}
I_unlock_mutex(ms_QueryId_mutex);
I_lock_mutex(&ms_QueryId_mutex);
{
if (query_id != ms_QueryId)
doing_shit = 0;
}
I_unlock_mutex(ms_QueryId_mutex);
if (! doing_shit)
break;
if (! doing_shit)
break;
#endif
if (strcmp(version, local_version) == 0)
{
strlcpy(list[i].ip, address, sizeof list[i].ip);
strlcpy(list[i].port, port, sizeof list[i].port);
strlcpy(list[i].name, title, sizeof list[i].name);
strlcpy(list[i].version, version, sizeof list[i].version);
strlcpy(list[i].ip, address, sizeof list[i].ip);
strlcpy(list[i].port, port, sizeof list[i].port);
list[i].room = atoi(room);
list[i].header.buffer[0] = 1;
i++;
}
if (end == section_end)/* end of list for this room */
break;
else
p = ( end + 1 );/* skip server delimiter */
}
else
if (contact)
{
section_end = 0;/* malformed so quit the parsing */
break;
strlcpy(list[i].contact, contact, sizeof list[i].contact);
}
list[i].header.buffer[0] = 1;
i++;
p = ( end + 1 );/* skip server delimiter */
}
if (! doing_shit)
else
{
/* malformed so quit the parsing */
break;
p = ( section_end + 2 );
}
}
while (section_end) ;
if (doing_shit)
list[i].header.buffer[0] = 0;
@ -620,7 +470,7 @@ HMS_compare_mod_version (char *buffer, size_t buffer_size)
char *version;
char *version_name;
hms = HMS_connect("versions/%d", MODID);
hms = HMS_connect("games/%s/version", SRB2APPLICATION);
if (! hms)
return 0;
@ -649,6 +499,19 @@ HMS_compare_mod_version (char *buffer, size_t buffer_size)
return ok;
}
static char *
Strip_trailing_slashes (char *api)
{
char * p = &api[strlen(api)];
while (*--p == '/')
;
p[1] = '\0';
return api;
}
void
HMS_set_api (char *api)
{
@ -657,17 +520,21 @@ HMS_set_api (char *api)
#endif
{
free(hms_api);
hms_api = api;
hms_api = Strip_trailing_slashes(api);
}
#ifdef HAVE_THREADS
I_unlock_mutex(hms_api_mutex);
#endif
}
#endif/*MASTERSERVER*/
static void
MasterServer_Debug_OnChange (void)
{
#ifdef MASTERSERVER
/* TODO: change to 'latest-log.txt' for log files revision. */
if (cv_masterserver_debug.value)
CONS_Printf("Master server debug messages will appear in log.txt\n");
#endif
}

View file

@ -306,35 +306,35 @@ static INT32 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
/*Jawz x2*/ { 0, 0, 1, 2, 0, 0, 0, 0 } // Jawz x2
};
static INT32 K_KartItemOddsBattle[NUMKARTRESULTS-1][6] =
static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
{
//P-Odds 0 1 2 3 4 5
/*Sneaker*/ { 3, 2, 2, 2, 0, 2 }, // Sneaker
/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 0 }, // Rocket Sneaker
/*Invincibility*/ { 0, 1, 2, 3, 4, 2 }, // Invincibility
/*Banana*/ { 2, 1, 0, 0, 0, 0 }, // Banana
/*Eggman Monitor*/ { 1, 1, 0, 0, 0, 0 }, // Eggman Monitor
/*Orbinaut*/ { 6, 2, 1, 0, 0, 0 }, // Orbinaut
/*Jawz*/ { 3, 3, 3, 2, 0, 2 }, // Jawz
/*Mine*/ { 2, 3, 3, 1, 0, 2 }, // Mine
/*Ballhog*/ { 0, 1, 2, 1, 0, 2 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb
/*Grow*/ { 0, 0, 1, 2, 4, 2 }, // Grow
/*Shrink*/ { 0, 0, 0, 0, 0, 0 }, // Shrink
/*Thunder Shield*/ { 0, 0, 0, 0, 0, 0 }, // Thunder Shield
/*Bubble Shield*/ { 0, 0, 0, 0, 0, 0 }, // Bubble Shield
/*Flame Shield*/ { 0, 0, 0, 0, 0, 0 }, // Flame Shield
/*Hyudoro*/ { 1, 1, 0, 0, 0, 0 }, // Hyudoro
/*Pogo Spring*/ { 1, 1, 0, 0, 0, 0 }, // Pogo Spring
/*Super Ring*/ { 0, 0, 0, 0, 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
/*Sneaker x2*/ { 0, 0, 0, 0, 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 0, 0, 2, 4, 2 }, // Sneaker x3
/*Banana x3*/ { 1, 2, 1, 0, 0, 0 }, // Banana x3
/*Banana x10*/ { 0, 0, 1, 1, 0, 2 }, // Banana x10
/*Orbinaut x3*/ { 0, 1, 2, 1, 0, 0 }, // Orbinaut x3
/*Orbinaut x4*/ { 0, 0, 1, 3, 4, 2 }, // Orbinaut x4
/*Jawz x2*/ { 0, 0, 1, 2, 4, 2 } // Jawz x2
//P-Odds 0 1
/*Sneaker*/ { 2, 1 }, // Sneaker
/*Rocket Sneaker*/ { 0, 0 }, // Rocket Sneaker
/*Invincibility*/ { 2, 1 }, // Invincibility
/*Banana*/ { 1, 0 }, // Banana
/*Eggman Monitor*/ { 1, 0 }, // Eggman Monitor
/*Orbinaut*/ { 8, 0 }, // Orbinaut
/*Jawz*/ { 8, 1 }, // Jawz
/*Mine*/ { 4, 1 }, // Mine
/*Ballhog*/ { 2, 1 }, // Ballhog
/*Self-Propelled Bomb*/ { 0, 0 }, // Self-Propelled Bomb
/*Grow*/ { 2, 1 }, // Grow
/*Shrink*/ { 0, 0 }, // Shrink
/*Thunder Shield*/ { 0, 0 }, // Thunder Shield
/*Bubble Shield*/ { 0, 0 }, // Bubble Shield
/*Flame Shield*/ { 0, 0 }, // Flame Shield
/*Hyudoro*/ { 2, 0 }, // Hyudoro
/*Pogo Spring*/ { 2, 0 }, // Pogo Spring
/*Super Ring*/ { 0, 0 }, // Super Ring
/*Kitchen Sink*/ { 0, 0 }, // Kitchen Sink
/*Sneaker x2*/ { 0, 0 }, // Sneaker x2
/*Sneaker x3*/ { 0, 1 }, // Sneaker x3
/*Banana x3*/ { 1, 0 }, // Banana x3
/*Banana x10*/ { 0, 1 }, // Banana x10
/*Orbinaut x3*/ { 2, 0 }, // Orbinaut x3
/*Orbinaut x4*/ { 1, 1 }, // Orbinaut x4
/*Jawz x2*/ { 2, 1 } // Jawz x2
};
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
@ -620,19 +620,20 @@ INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed, boolean spbrush,
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush)
{
UINT8 i;
UINT8 n = 0;
UINT8 useodds = 0;
UINT8 disttable[14];
UINT8 totallen = 0;
UINT8 distlen = 0;
boolean oddsvalid[8];
// Unused now, oops :V
(void)bestbumper;
for (i = 0; i < 8; i++)
{
UINT8 j;
boolean available = false;
if (gametype == GT_BATTLE && i > 5)
if (gametype == GT_BATTLE && i > 1)
{
oddsvalid[i] = false;
break;
@ -653,30 +654,24 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum
#define SETUPDISTTABLE(odds, num) \
if (oddsvalid[odds]) \
for (i = num; i; --i) \
disttable[distlen++] = odds; \
totallen += num;
disttable[distlen++] = odds;
if (gametype == GT_BATTLE) // Battle Mode
{
SETUPDISTTABLE(0,1);
SETUPDISTTABLE(1,1);
SETUPDISTTABLE(2,1);
SETUPDISTTABLE(3,1);
SETUPDISTTABLE(4,1);
if (player->kartstuff[k_roulettetype] == 1 && oddsvalid[5]) // 5 is the extreme odds of player-controlled "Karma" items
useodds = 5;
if (player->kartstuff[k_roulettetype] == 1 && oddsvalid[1] == true)
{
// 1 is the extreme odds of player-controlled "Karma" items
useodds = 1;
}
else
{
SINT8 wantedpos = (bestbumper-player->kartstuff[k_bumper]); // 0 is the best player's bumper count, 1 is a bumper below best, 2 is two bumpers below, etc
if (K_IsPlayerWanted(player))
wantedpos++;
if (wantedpos > 4) // Don't run off into karma items
wantedpos = 4;
if (wantedpos < 0) // Don't go below somehow
wantedpos = 0;
n = (wantedpos * distlen) / totallen;
useodds = disttable[n];
useodds = 0;
if (oddsvalid[0] == false && oddsvalid[1] == true)
{
// try to use karma odds as a fallback
useodds = 1;
}
}
}
else
@ -1240,7 +1235,7 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
}
}
/** \brief Checks that the player is on an offroad subsector for realsies
/** \brief Checks that the player is on an offroad subsector for realsies. Also accounts for line riding to prevent cheese.
\param mo player mobj object
@ -1248,18 +1243,64 @@ void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
*/
static UINT8 K_CheckOffroadCollide(mobj_t *mo)
{
UINT8 i;
// Check for sectors in touching_sectorlist
UINT8 i; // special type iter
msecnode_t *node; // touching_sectorlist iter
sector_t *s; // main sector shortcut
sector_t *s2; // FOF sector shortcut
ffloor_t *rover; // FOF
fixed_t flr;
fixed_t cel; // floor & ceiling for height checks to make sure we're touching the offroad sector.
I_Assert(mo != NULL);
I_Assert(!P_MobjWasRemoved(mo));
for (i = 2; i < 5; i++)
for (node = mo->touching_sectorlist; node; node = node->m_sectorlist_next)
{
if (P_MobjTouchingSectorSpecial(mo, 1, i, true))
return i-1;
}
if (!node->m_sector)
break; // shouldn't happen.
return 0;
s = node->m_sector;
// 1: Check for the main sector, make sure we're on the floor of that sector and see if we can apply offroad.
// Make arbitrary Z checks because we want to check for 1 sector in particular, we don't want to affect the player if the offroad sector is way below them and they're lineriding a normal sector above.
flr = P_MobjFloorZ(mo, s, s, mo->x, mo->y, NULL, false, true);
cel = P_MobjCeilingZ(mo, s, s, mo->x, mo->y, NULL, true, true); // get Z coords of both floors and ceilings for this sector (this accounts for slopes properly.)
// NOTE: we don't use P_GetZAt with our x/y directly because the mobj won't have the same height because of its hitbox on the slope. Complex garbage but tldr it doesn't work.
if ( ((s->flags & SF_FLIPSPECIAL_FLOOR) && mo->z == flr) // floor check
|| ((mo->eflags & MFE_VERTICALFLIP && (s->flags & SF_FLIPSPECIAL_CEILING) && (mo->z + mo->height) == cel)) ) // ceiling check.
for (i = 2; i < 5; i++) // check for sector special
if (GETSECSPECIAL(s->special, 1) == i)
return i-1; // return offroad type
// 2: If we're here, we haven't found anything. So let's try looking for FOFs in the sectors using the same logic.
for (rover = s->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS)) // This FOF doesn't exist anymore.
continue;
s2 = &sectors[rover->secnum]; // makes things easier for us
flr = P_GetFOFBottomZ(mo, s, rover, mo->x, mo->y, NULL);
cel = P_GetFOFTopZ(mo, s, rover, mo->x, mo->y, NULL); // Z coords for fof top/bottom.
// we will do essentially the same checks as above instead of bothering with top/bottom height of the FOF.
// Reminder that an FOF's floor is its bottom, silly!
if ( ((s2->flags & SF_FLIPSPECIAL_FLOOR) && mo->z == cel) // "floor" check
|| ((s2->flags & SF_FLIPSPECIAL_CEILING) && (mo->z + mo->height) == flr) ) // "ceiling" check.
for (i = 2; i < 5; i++) // check for sector special
if (GETSECSPECIAL(s2->special, 1) == i)
return i-1; // return offroad type
}
}
return 0; // couldn't find any offroad
}
/** \brief Updates the Player's offroad value once per frame
@ -3680,13 +3721,13 @@ void K_PuntMine(mobj_t *thismine, mobj_t *punter)
mine->flags2 = thismine->flags2;
mine->floorz = thismine->floorz;
mine->ceilingz = thismine->ceilingz;
//Since we aren't using P_KillMobj, we need to clean up the hnext reference
{
P_SetTarget(&thismine->target->hnext, NULL); //target is the player who owns the mine
thismine->target->player->kartstuff[k_bananadrag] = 0;
thismine->target->player->kartstuff[k_itemheld] = 0;
if (--thismine->target->player->kartstuff[k_itemamount] <= 0)
thismine->target->player->kartstuff[k_itemtype] = KITEM_NONE;
}
@ -4340,7 +4381,7 @@ void K_DropRocketSneaker(player_t *player)
flingangle = -(ANG60);
else
flingangle = ANG60;
S_StartSound(shoe, shoe->info->deathsound);
P_SetObjectMomZ(shoe, 8*FRACUNIT, false);
P_InstaThrust(shoe, R_PointToAngle2(shoe->target->x, shoe->target->y, shoe->x, shoe->y)+flingangle, 16*FRACUNIT);
@ -4944,14 +4985,22 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source)
static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
{
const INT32 numsnds = 13;
const fixed_t closedist = 160*FRACUNIT;
const fixed_t fardist = 1536*FRACUNIT;
const UINT8 dampenval = 48; // 255 * 48 = close enough to FRACUNIT/6
INT32 class, s, w; // engine class number
UINT8 volume = 255;
fixed_t volumedampen = 0;
fixed_t volumedampen = FRACUNIT;
INT32 targetsnd = 0;
INT32 i;
s = (player->kartspeed-1)/3;
w = (player->kartweight-1)/3;
s = (player->kartspeed - 1) / 3;
w = (player->kartweight - 1) / 3;
#define LOCKSTAT(stat) \
if (stat < 0) { stat = 0; } \
@ -4960,83 +5009,119 @@ static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
LOCKSTAT(w);
#undef LOCKSTAT
class = s+(3*w);
class = s + (3*w);
// Silence the engines
if (leveltime < 8 || player->spectator)
{
player->karthud[khud_enginesnd] = 0; // Reset sound number
// Silence the engines, and reset sound number while we're at it.
player->karthud[khud_enginesnd] = 0;
return;
}
#if 0
if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct!
#else
if (leveltime % 8) // .25 seconds of wait time between engine sounds
if (leveltime % 8)
#endif
{
// .25 seconds of wait time between each engine sound playback
return;
}
if (player->respawn.state == RESPAWNST_DROP) // Dropdashing
{
// Dropdashing
targetsnd = ((cmd->buttons & BT_ACCELERATE) ? 12 : 0);
else if (K_PlayerEBrake(player) == true) // Spindashing
}
else if (K_PlayerEBrake(player) == true)
{
// Spindashing
targetsnd = ((cmd->buttons & BT_DRIFT) ? 12 : 0);
}
else
targetsnd = (((6*K_GetForwardMove(player))/25) + ((player->speed / mapobjectscale)/5))/2;
{
// Average out the value of forwardmove and the speed that you're moving at.
targetsnd = (((6 * cmd->forwardmove) / 25) + ((player->speed / mapobjectscale) / 5)) / 2;
}
if (targetsnd < 0)
targetsnd = 0;
if (targetsnd > 12)
targetsnd = 12;
if (targetsnd < 0) { targetsnd = 0; }
if (targetsnd > 12) { targetsnd = 12; }
if (player->karthud[khud_enginesnd] < targetsnd)
player->karthud[khud_enginesnd]++;
if (player->karthud[khud_enginesnd] > targetsnd)
player->karthud[khud_enginesnd]--;
if (player->karthud[khud_enginesnd] < targetsnd) { player->karthud[khud_enginesnd]++; }
if (player->karthud[khud_enginesnd] > targetsnd) { player->karthud[khud_enginesnd]--; }
if (player->karthud[khud_enginesnd] < 0)
player->karthud[khud_enginesnd] = 0;
if (player->karthud[khud_enginesnd] > 12)
player->karthud[khud_enginesnd] = 12;
if (player->karthud[khud_enginesnd] < 0) { player->karthud[khud_enginesnd] = 0; }
if (player->karthud[khud_enginesnd] > 12) { player->karthud[khud_enginesnd] = 12; }
// This code calculates how many players (and thus, how many engine sounds) are within ear shot,
// and rebalances the volume of your engine sound based on how far away they are.
// This results in multiple things:
// - When on your own, you will hear your own engine sound extremely clearly.
// - When you were alone but someone is gaining on you, yours will go quiet, and you can hear theirs more clearly.
// - When around tons of people, engine sounds will try to rebalance to not be as obnoxious.
for (i = 0; i < MAXPLAYERS; i++)
{
UINT8 thisvol = 0;
fixed_t dist;
if (!playeringame[i] || !players[i].mo || players[i].spectator || players[i].exiting)
continue;
if (P_IsDisplayPlayer(&players[i]))
if (!playeringame[i] || !players[i].mo)
{
volumedampen += FRACUNIT; // We already know what this is gonna be, let's not waste our time.
// This player doesn't exist.
continue;
}
dist = P_AproxDistance(P_AproxDistance(player->mo->x-players[i].mo->x,
player->mo->y-players[i].mo->y), player->mo->z-players[i].mo->z) / 2;
if (players[i].spectator)
{
// This player isn't playing an engine sound.
continue;
}
if (P_IsDisplayPlayer(&players[i]))
{
// Don't dampen yourself!
continue;
}
dist = P_AproxDistance(
P_AproxDistance(
player->mo->x - players[i].mo->x,
player->mo->y - players[i].mo->y),
player->mo->z - players[i].mo->z) / 2;
dist = FixedDiv(dist, mapobjectscale);
if (dist > 1536<<FRACBITS)
if (dist > fardist)
{
// ENEMY OUT OF RANGE !
continue;
else if (dist < 160<<FRACBITS) // engine sounds' approx. range
}
else if (dist < closedist)
{
// engine sounds' approx. range
thisvol = 255;
}
else
thisvol = (15 * (((160<<FRACBITS) - dist)>>FRACBITS)) / (((1536<<FRACBITS)-(160<<FRACBITS))>>(FRACBITS+4));
{
thisvol = (15 * ((closedist - dist) / FRACUNIT)) / ((fardist - closedist) >> (FRACBITS+4));
}
if (thisvol == 0)
continue;
volumedampen += (thisvol * 257); // 255 * 257 = FRACUNIT
volumedampen += (thisvol * dampenval);
}
if (volumedampen > FRACUNIT)
volume = FixedDiv(volume<<FRACBITS, volumedampen)>>FRACBITS;
{
volume = FixedDiv(volume * FRACUNIT, volumedampen) / FRACUNIT;
}
if (volume <= 0) // Might as well
if (volume <= 0)
{
// Don't need to play the sound at all.
return;
}
S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->karthud[khud_enginesnd]) + (class*numsnds), volume);
S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->karthud[khud_enginesnd]) + (class * numsnds), volume);
}
static void K_UpdateInvincibilitySounds(player_t *player)

View file

@ -3624,41 +3624,6 @@ static int lib_kGetItemPatch(lua_State *L)
return 1;
}
// sets the remaining time before players blow up
static int lib_kSetRaceCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
racecountdown = c;
return 0;
}
// sets the remaining time before the race ends after everyone finishes
static int lib_kSetExitCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
NOHUD
exitcountdown = c;
return 0;
}
// Sets the item cooldown before another shrink / SPB can be rolled
static int lib_kSetIndirectItemCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
NOHUD
indirectitemcooldown = c;
return 0;
}
// Sets the item cooldown before another shrink / SPB can be rolled
static int lib_kSetHyuCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
NOHUD
hyubgone = c;
return 0;
}
static luaL_Reg lib[] = {
{"print", lib_print},
{"chatprint", lib_chatprint},
@ -3920,10 +3885,6 @@ static luaL_Reg lib[] = {
{"K_GetKartAccel",lib_kGetKartAccel},
{"K_GetKartFlashing",lib_kGetKartFlashing},
{"K_GetItemPatch",lib_kGetItemPatch},
{"K_SetRaceCountdown",lib_kSetRaceCountdown},
{"K_SetExitCountdown",lib_kSetExitCountdown},
{"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown},
{"K_SetHyudoroCooldown",lib_kSetHyuCountdown},
{NULL, NULL}
};

View file

@ -370,7 +370,11 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"exitcountdown")) {
lua_pushinteger(L, exitcountdown); // This name is pretty dumb. Hence why we'll prefer more descriptive names at least in Lua...
return 1;
} else if (fastcmp(word,"replayplayback")) {
lua_pushboolean(L, demo.playback);
return 1;
}
return 0;
}
@ -381,6 +385,15 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
redscore = (UINT32)luaL_checkinteger(L, 2);
else if (fastcmp(word, "bluescore"))
bluescore = (UINT32)luaL_checkinteger(L, 2);
// SRB2Kart
else if (fastcmp(word,"racecountdown"))
racecountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"exitcountdown"))
exitcountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"indirectitemcooldown"))
indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"hyubgone"))
hyubgone = (tic_t)luaL_checkinteger(L, 2);
else
return 0;

File diff suppressed because it is too large Load diff

View file

@ -239,7 +239,6 @@ typedef enum
M_NOT_WAITING,
M_WAITING_VERSION,
M_WAITING_ROOMS,
M_WAITING_SERVERS,
}
M_waiting_mode_t;
@ -336,12 +335,6 @@ typedef struct menuitem_s
UINT8 alphaKey;
} menuitem_t;
extern menuitem_t MP_RoomMenu[];
extern UINT32 roomIds[NUM_LIST_ROOMS];
extern menuitem_t MP_RoomMenu[];
extern UINT32 roomIds[NUM_LIST_ROOMS];
typedef struct menu_s
{
UINT32 menuid; // ID to encode menu type and hierarchy
@ -478,6 +471,8 @@ void Addons_option_Onchange(void);
void M_ReplayHut(INT32 choice);
void M_SetPlaybackMenuPointer(void);
void M_RefreshPauseMenu(void);
INT32 HU_GetHighlightColor(void);
// Moviemode menu updating

View file

@ -23,6 +23,12 @@
#include "m_menu.h"
#include "z_zone.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
#endif
#ifdef MASTERSERVER
static int MSId;
static int MSRegisteredId = -1;
@ -43,27 +49,33 @@ static I_cond MSCond;
# define Unlock_state()
#endif/*HAVE_THREADS*/
static void Update_parameters (void);
#ifndef NONET
static void Command_Listserv_f(void);
#endif
#endif/*MASTERSERVER*/
static void Update_parameters (void);
static void MasterServer_OnChange(void);
static void Advertise_OnChange(void);
static CV_PossibleValue_t masterserver_update_rate_cons_t[] = {
{2, "MIN"},
{60, "MAX"},
{0}
{0, NULL}
};
consvar_t cv_masterserver = {"masterserver", "https://mb.srb2.org/MS/0", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_masterserver = {"masterserver", "https://ms.kartkrew.org/ms/api", CV_SAVE|CV_CALL, NULL, MasterServer_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_servername = {"servername", "SRB2Kart server", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_server_contact = {"server_contact", "", CV_SAVE|CV_CALL|CV_NOINIT, NULL, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_masterserver_update_rate = {"masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, Update_parameters, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_masterserver_update_rate = {"masterserver_update_rate", "15", CV_SAVE|CV_CALL|CV_NOINIT, masterserver_update_rate_cons_t, MasterClient_Ticker, 0, NULL, NULL, 0, 0, NULL};
INT16 ms_RoomId = -1;
consvar_t cv_advertise = {"advertise", "No", CV_NETVAR|CV_CALL|CV_NOINIT, CV_YesNo, Advertise_OnChange, 0, NULL, NULL, 0, 0, NULL};
#ifdef HAVE_THREADS
#if defined (MASTERSERVER) && defined (HAVE_THREADS)
int ms_QueryId;
I_mutex ms_QueryId_mutex;
@ -73,10 +85,6 @@ I_mutex ms_ServerList_mutex;
UINT16 current_port = 0;
// Room list is an external variable now.
// Avoiding having to get info ten thousand times...
msg_rooms_t room_list[NUM_LIST_ROOMS+1]; // +1 for easy test
/** Adds variables and commands relating to the master server.
*
* \sa cv_masterserver, cv_servername,
@ -90,11 +98,17 @@ void AddMServCommands(void)
CV_RegisterVar(&cv_masterserver_timeout);
CV_RegisterVar(&cv_masterserver_debug);
CV_RegisterVar(&cv_masterserver_token);
CV_RegisterVar(&cv_advertise);
CV_RegisterVar(&cv_servername);
CV_RegisterVar(&cv_server_contact);
#ifdef MASTERSERVER
COM_AddCommand("listserv", Command_Listserv_f);
#endif
#endif
}
#ifdef MASTERSERVER
static void WarnGUI (void)
{
#ifdef HAVE_THREADS
@ -107,14 +121,14 @@ static void WarnGUI (void)
}
#define NUM_LIST_SERVER MAXSERVERLIST
msg_server_t *GetShortServersList(INT32 room, int id)
msg_server_t *GetShortServersList(int id)
{
msg_server_t *server_list;
// +1 for easy test
server_list = malloc(( NUM_LIST_SERVER + 1 ) * sizeof *server_list);
if (HMS_fetch_servers(server_list, room, id))
if (HMS_fetch_servers(server_list, id))
return server_list;
else
{
@ -124,17 +138,6 @@ msg_server_t *GetShortServersList(INT32 room, int id)
}
}
INT32 GetRoomsList(boolean hosting, int id)
{
if (HMS_fetch_rooms( ! hosting, id))
return 1;
else
{
WarnGUI();
return -1;
}
}
#ifdef UPDATE_ALERT
char *GetMODVersion(int id)
{
@ -168,15 +171,6 @@ char *GetMODVersion(int id)
return NULL;
}
}
// Console only version of the above (used before game init)
void GetMODVersion_Console(void)
{
char buffer[16];
if (HMS_compare_mod_version(buffer, sizeof buffer) > 0)
I_Error(UPDATE_ALERT_STRING_CONSOLE, VERSIONSTRING, buffer);
}
#endif
#ifndef NONET
@ -267,6 +261,9 @@ Finish_unlist (void)
Lock_state();
{
registered = MSRegistered;
if (MSId == MSRegisteredId)
MSId++;
}
Unlock_state();
@ -287,13 +284,6 @@ Finish_unlist (void)
I_wake_all_cond(&MSCond);
#endif
}
Lock_state();
{
if (MSId == MSRegisteredId)
MSId++;
}
Unlock_state();
}
#ifdef HAVE_THREADS
@ -395,6 +385,7 @@ Change_masterserver_thread (char *api)
void RegisterServer(void)
{
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
I_spawn_thread(
"register-server",
@ -404,6 +395,7 @@ void RegisterServer(void)
#else
Finish_registration();
#endif
#endif/*MASTERSERVER*/
}
static void UpdateServer(void)
@ -421,6 +413,7 @@ static void UpdateServer(void)
void UnregisterServer(void)
{
#ifdef MASTERSERVER
#ifdef HAVE_THREADS
I_spawn_thread(
"unlist-server",
@ -430,12 +423,13 @@ void UnregisterServer(void)
#else
Finish_unlist();
#endif
#endif/*MASTERSERVER*/
}
static boolean
Online (void)
{
return ( serverrunning && ms_RoomId > 0 );
return ( serverrunning && cv_advertise.value );
}
static inline void SendPingToMasterServer(void)
@ -465,9 +459,33 @@ static inline void SendPingToMasterServer(void)
}
}
void MasterClient_Ticker(void)
{
#ifdef MASTERSERVER
SendPingToMasterServer();
#endif
}
static void
Set_api (const char *api)
{
#ifdef HAVE_THREADS
I_spawn_thread(
"change-masterserver",
(I_thread_fn)Change_masterserver_thread,
strdup(api)
);
#else
HMS_set_api(strdup(api));
#endif
}
#endif/*MASTERSERVER*/
static void
Update_parameters (void)
{
#ifdef MASTERSERVER
int registered;
int delayed;
@ -487,29 +505,12 @@ Update_parameters (void)
if (! delayed && registered)
UpdateServer();
}
}
void MasterClient_Ticker(void)
{
SendPingToMasterServer();
}
static void
Set_api (const char *api)
{
#ifdef HAVE_THREADS
I_spawn_thread(
"change-masterserver",
(I_thread_fn)Change_masterserver_thread,
strdup(api)
);
#else
HMS_set_api(strdup(api));
#endif
#endif/*MASTERSERVER*/
}
static void MasterServer_OnChange(void)
{
#ifdef MASTERSERVER
UnregisterServer();
/*
@ -527,4 +528,36 @@ static void MasterServer_OnChange(void)
if (Online())
RegisterServer();
#endif/*MASTERSERVER*/
}
static void
Advertise_OnChange(void)
{
int different;
if (cv_advertise.value)
{
if (serverrunning)
{
Lock_state();
{
different = ( MSId != MSRegisteredId );
}
Unlock_state();
if (different)
{
RegisterServer();
}
}
}
else
{
UnregisterServer();
}
#ifdef HAVE_DISCORDRPC
DRPC_UpdatePresence();
#endif
}

View file

@ -16,9 +16,6 @@
#include "i_threads.h"
// lowered from 32 due to menu changes
#define NUM_LIST_ROOMS 16
#if defined(_MSC_VER)
#pragma pack(1)
#endif
@ -35,19 +32,10 @@ typedef struct
msg_header_t header;
char ip[16];
char port[8];
char name[32];
INT32 room;
char contact[32];
char version[8]; // format is: x.yy.z (like 1.30.2 or 1.31)
} ATTRPACK msg_server_t;
typedef struct
{
msg_header_t header;
INT32 id;
char name[32];
char motd[255];
} ATTRPACK msg_rooms_t;
typedef struct
{
msg_header_t header;
@ -65,15 +53,13 @@ typedef struct
// ================================ GLOBALS ===============================
extern consvar_t cv_masterserver, cv_servername;
extern consvar_t cv_server_contact;
extern consvar_t cv_masterserver_update_rate;
extern consvar_t cv_masterserver_timeout;
extern consvar_t cv_masterserver_debug;
extern consvar_t cv_masterserver_token;
// < 0 to not connect (usually -1) (offline mode)
// == 0 to show all rooms, not a valid hosting room
// anything else is whatever room the MS assigns to that number (online mode)
extern INT16 ms_RoomId;
extern consvar_t cv_advertise;
#ifdef HAVE_THREADS
extern int ms_QueryId;
@ -88,24 +74,20 @@ void UnregisterServer(void);
void MasterClient_Ticker(void);
msg_server_t *GetShortServersList(INT32 room, int id);
INT32 GetRoomsList(boolean hosting, int id);
msg_server_t *GetShortServersList(int id);
#ifdef UPDATE_ALERT
char *GetMODVersion(int id);
void GetMODVersion_Console(void);
#endif
extern msg_rooms_t room_list[NUM_LIST_ROOMS+1];
void AddMServCommands(void);
/* HTTP */
void HMS_set_api (char *api);
int HMS_fetch_rooms (int joining, int id);
int HMS_register (void);
int HMS_unlist (void);
int HMS_update (void);
void HMS_list_servers (void);
msg_server_t * HMS_fetch_servers (msg_server_t *list, int room, int id);
msg_server_t * HMS_fetch_servers (msg_server_t *list, int id);
int HMS_compare_mod_version (char *buffer, size_t size_of_buffer);
#endif

View file

@ -432,8 +432,17 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
return;
}
front = linedef->frontsector;
back = linedef->backsector;
// Treat polyobjects kind of like 3D Floors
if (linedef->polyobj && (linedef->polyobj->flags & POF_TESTHEIGHT))
{
front = linedef->frontsector;
back = linedef->frontsector;
}
else
{
front = linedef->frontsector;
back = linedef->backsector;
}
I_Assert(front != NULL);
I_Assert(back != NULL);

View file

@ -10464,6 +10464,7 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
return true;
}
else if (mthing->type == 750 // Slope vertex point (formerly chaos spawn)
|| (mthing->type == 777 || mthing->type == 778) // Slope anchors
|| (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns
|| mthing->type == 1705 || mthing->type == 1713) // Hoops
{

View file

@ -2123,7 +2123,7 @@ static inline void SaveDynamicSlopeThinker(const thinker_t *th, const UINT8 type
WRITEFIXED(save_p, ht->extent);
WRITEMEM(save_p, ht->tags, sizeof(ht->tags));
WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
WRITEMEM(save_p, ht->vex, sizeof(ht->vex));
}
static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type)

View file

@ -3980,8 +3980,16 @@ boolean P_LoadLevel(boolean fromnetsave)
// init anything that P_SpawnSlopes/P_LoadThings needs to know
P_InitSpecials();
// set up world state
// jart: needs to be done here so anchored slopes know the attached list
P_SpawnSpecials(fromnetsave);
P_SpawnSlopes(fromnetsave);
P_RaiseThings();
P_SpawnSpecialsThatRequireObjects();
P_SpawnMapThings(!fromnetsave);
skyboxmo[0] = skyboxviewpnts[0];
skyboxmo[1] = skyboxcenterpnts[0];
@ -3990,8 +3998,6 @@ boolean P_LoadLevel(boolean fromnetsave)
if (!playerstarts[numcoopstarts])
break;
// set up world state
P_SpawnSpecials(fromnetsave);
K_AdjustWaypointsParameters();
if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)

View file

@ -27,6 +27,9 @@
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
static void P_BuildSlopeAnchorList (void);
static void P_SetupAnchoredSlopes (void);
// Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
@ -72,7 +75,7 @@ static void P_CalculateLineSlopeHighLow(pslope_t *slope, line_t *line, boolean c
}
/// Setup slope via 3 vertexes.
static void ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3)
void P_ReconfigureViaVertexes (pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3)
{
vector3_t vec1, vec2;
@ -185,7 +188,7 @@ void T_DynamicSlopeVert (dynplanethink_t* th)
th->vex[i].z = 0;
}
ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]);
P_ReconfigureViaVertexes(slope, th->vex[0], th->vex[1], th->vex[2]);
}
static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent, const INT16 tags[3], const vector3_t vx[3])
@ -492,7 +495,7 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
vx[i].z += R_PointInSubsector(vx[i].x, vx[i].y)->sector->floorheight;
}
ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
P_ReconfigureViaVertexes(ret, vx[0], vx[1], vx[2]);
if (spawnthinker && (flags & SL_DYNAMIC))
P_AddDynSlopeThinker(ret, DP_VERTEX, NULL, 0, tags, vx);
@ -574,7 +577,7 @@ static void SpawnVertexSlopes(void)
pslope_t *slop = Slope_Add(0);
sc->f_slope = slop;
sc->hasslope = true;
ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
P_ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
}
if (v1->ceilingzset || v2->ceilingzset || v3->ceilingzset)
@ -586,7 +589,7 @@ static void SpawnVertexSlopes(void)
pslope_t *slop = Slope_Add(0);
sc->c_slope = slop;
sc->hasslope = true;
ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
P_ReconfigureViaVertexes(slop, vtx[0], vtx[1], vtx[2]);
}
}
}
@ -709,6 +712,14 @@ void P_SpawnSlopes(const boolean fromsave) {
}
}
// jart
/// Build list of slope anchors--faster searching.
P_BuildSlopeAnchorList();
/// Setup anchor based slopes.
P_SetupAnchoredSlopes();
/// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers.
for (i = 0; i < numlines; i++)
@ -966,3 +977,6 @@ void P_ButteredSlope(mobj_t *mo)
P_Thrust(mo, mo->standingslope->xydirection, thrust);
}
// jart
#include "slope_anchors.c"

View file

@ -50,6 +50,7 @@ typedef enum
void P_LinkSlopeThinkers (void);
void P_CalculateSlopeNormal(pslope_t *slope);
void P_ReconfigureViaVertexes(pslope_t *slope, const vector3_t v1, const vector3_t v2, const vector3_t v3);
void P_SpawnSlopes(const boolean fromsave);
//

View file

@ -1081,7 +1081,6 @@ INT32 P_FindSpecialLineFromTag(INT16 special, INT16 tag, INT32 start)
}
}
// Parses arguments for parameterized polyobject door types
static boolean PolyDoor(line_t *line)
{
@ -1355,7 +1354,6 @@ static boolean PolyDisplace(line_t *line)
return EV_DoPolyObjDisplace(&pdd);
}
// Parses arguments for parameterized polyobject rotate-by-sector-heights specials
static boolean PolyRotDisplace(line_t *line)
{
@ -5547,6 +5545,26 @@ P_RaiseTaggedThingsToFakeFloor (
}
}
void
P_RaiseThings (void)
{
size_t i;
for (i = 0; i < numlines; ++i)
{
switch (lines[i].special)
{
case 80: // Raise tagged things by type to this FOF
P_RaiseTaggedThingsToFakeFloor(
( sides[lines[i].sidenum[0]].textureoffset >> FRACBITS ),
lines[i].tag,
lines[i].frontsector
);
break;
}
}
}
//
// SPECIAL SPAWNING
//
@ -6931,28 +6949,19 @@ void P_SpawnSpecials(boolean fromnetsave)
}
}
/* some things have to be done after FOF spawn */
for (i = 0; i < numlines; ++i)
{
switch (lines[i].special)
{
case 80: // Raise tagged things by type to this FOF
P_RaiseTaggedThingsToFakeFloor(
( sides[lines[i].sidenum[0]].textureoffset >> FRACBITS ),
lines[i].tag,
lines[i].frontsector
);
break;
}
}
// Allocate each list
for (i = 0; i < numsectors; i++)
if(secthinkers[i].thinkers)
Z_Free(secthinkers[i].thinkers);
Z_Free(secthinkers);
}
/** Fuck polyobjects
*/
void P_SpawnSpecialsThatRequireObjects(void)
{
size_t i;
// haleyjd 02/20/06: spawn polyobjects
Polyobj_InitLevel();

View file

@ -43,6 +43,8 @@ void P_SetupLevelFlatAnims(void);
// at map load
void P_InitSpecials(void);
void P_SpawnSpecials(boolean fromnetsave);
void P_RaiseThings(void);
void P_SpawnSpecialsThatRequireObjects(void);
// every tic
void P_UpdateSpecials(void);
@ -648,4 +650,12 @@ void P_CalcHeight(player_t *player);
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);
/* line specials */
enum
{
LT_SLOPE_ANCHORS_FLOOR = 777,
LT_SLOPE_ANCHORS_CEILING = 778,
LT_SLOPE_ANCHORS = 779,
};
#endif

View file

@ -536,6 +536,7 @@ void S_StartCaption(sfxenum_t sfx_id, INT32 cnum, UINT16 lifespan)
void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume)
{
const INT32 initial_volume = volume;
INT32 sep, pitch, priority, cnum;
const sfxenum_t actual_id = sfx_id;
sfxinfo_t *sfx;
@ -900,6 +901,7 @@ dontplay4:
// Assigns the handle to one of the channels in the
// mix/output buffer.
channels[cnum].volume = initial_volume;
channels[cnum].handle = I_StartSound(sfx_id, volume, sep, pitch, priority, cnum);
}
@ -1110,7 +1112,7 @@ void S_UpdateSounds(void)
if (I_SoundIsPlaying(c->handle))
{
// initialize parameters
volume = 255; // 8 bits internal volume precision
volume = c->volume; // 8 bits internal volume precision
pitch = NORM_PITCH;
sep = NORM_SEP;
@ -1444,15 +1446,12 @@ INT32 S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source, INT32 *v
}
// volume calculation
if (approx_dist < S_CLOSE_DIST)
{
// SfxVolume is now hardware volume
*vol = 255; // not snd_SfxVolume
}
else
/* not sure if it should be > (no =), but this matches the old behavior */
if (approx_dist >= S_CLOSE_DIST)
{
// distance effect
*vol = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS)) / S_ATTENUATOR;
INT32 n = (15 * ((S_CLIPPING_DIST - approx_dist)>>FRACBITS));
*vol = FixedMul(*vol * FRACUNIT / 255, n) / S_ATTENUATOR;
}
if (r_splitscreen)

View file

@ -88,6 +88,9 @@ typedef struct
// origin of sound
const void *origin;
// initial volume of sound, which is applied after distance and direction
INT32 volume;
// handle of the sound being played
INT32 handle;

View file

@ -75,6 +75,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}
@ -91,9 +93,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}
@ -166,6 +170,7 @@ if(${SDL2_FOUND})
${ZLIB_LIBRARIES}
${OPENGL_LIBRARIES}
${CURL_LIBRARIES}
${DISCORDRPC_LIBRARIES}
)
set_target_properties(SRB2SDL2 PROPERTIES OUTPUT_NAME "${CPACK_PACKAGE_DESCRIPTION_SUMMARY}")
else()
@ -179,6 +184,7 @@ if(${SDL2_FOUND})
${ZLIB_LIBRARIES}
${OPENGL_LIBRARIES}
${CURL_LIBRARIES}
${DISCORDRPC_LIBRARIES}
)
if(${CMAKE_SYSTEM} MATCHES Linux)
@ -261,6 +267,7 @@ if(${SDL2_FOUND})
${ZLIB_INCLUDE_DIRS}
${OPENGL_INCLUDE_DIRS}
${CURL_INCLUDE_DIRS}
${DISCORDRPC_INCLUDE_DIRS}
)
if((${SRB2_HAVE_MIXER}) OR (${SRB2_HAVE_MIXERX}))
@ -375,6 +382,10 @@ if(${SDL2_FOUND})
getwinlib(libstdc++-6 "libstdc++-6.dll")
endif()
if(${SRB2_CONFIG_HAVE_DISCORDRPC})
getwinlib(discord-rpc "discord-rpc.dll")
endif()
install(PROGRAMS
${win_extra_dll_list}
DESTINATION .

View file

@ -53,28 +53,6 @@ ifndef NOHW
OBJS+=$(OBJDIR)/r_opengl.o $(OBJDIR)/ogl_sdl.o
endif
ifndef NOHS
ifdef OPENAL
OBJS+=$(OBJDIR)/s_openal.o
OPTS+=-DSTATIC3DS
STATICHS=1
else
ifdef FMOD
OBJS+=$(OBJDIR)/s_fmod.o
OPTS+=-DSTATIC3DS
STATICHS=1
else
ifdef MINGW
ifdef DS3D
OBJS+=$(OBJDIR)/s_ds3d.o
OPTS+=-DSTATIC3DS
STATICHS=1
endif
endif
endif
endif
endif
ifdef NOMIXER
i_sound_o=$(OBJDIR)/sdl_sound.o
else

View file

@ -65,6 +65,10 @@ char logfilename[1024];
#endif
#endif
#if defined (_WIN32)
#include "exchndl.h"
#endif
#if defined (_WIN32)
#include "../win32/win_dbg.h"
typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID);
@ -191,6 +195,20 @@ static void InitLogging(void)
#endif
#ifdef _WIN32
static void
ChDirToExe (void)
{
CHAR path[MAX_PATH];
if (GetModuleFileNameA(NULL, path, MAX_PATH) > 0)
{
strrchr(path, '\\')[0] = '\0';
SetCurrentDirectoryA(path);
}
}
#endif
/** \brief The main function
\param argc number of arg
@ -219,6 +237,10 @@ int main(int argc, char **argv)
#endif
#endif
#ifdef _WIN32
ChDirToExe();
#endif
#ifdef LOGMESSAGES
if (!M_CheckParm("-nolog"))
InitLogging();
@ -237,7 +259,7 @@ int main(int argc, char **argv)
)
#endif
{
LoadLibraryA("exchndl.dll");
ExcHndlInit();
}
}
#ifndef __MINGW32__

View file

@ -152,11 +152,6 @@ int TimeFunction(int requested_frequency);
#define DEFAULTSEARCHPATH1 "/usr/local/games"
#define DEFAULTSEARCHPATH2 "/usr/games"
#define DEFAULTSEARCHPATH3 "/usr/local"
#elif defined (_WIN32)
#define DEFAULTWADLOCATION1 "c:\\games\\srb2kart"
#define DEFAULTWADLOCATION2 "\\games\\srb2kart"
#define DEFAULTSEARCHPATH1 "c:\\games"
#define DEFAULTSEARCHPATH2 "\\games"
#endif
/** \brief WAD file to look for
@ -2341,6 +2336,18 @@ static const char *locateWad(void)
#endif
#ifdef DEFAULTDIR
I_OutputMsg(",HOME/" DEFAULTDIR);
// examine user jart directory
if ((envstr = I_GetEnv("HOME")) != NULL)
{
sprintf(returnWadPath, "%s" PATHSEP DEFAULTDIR, envstr);
if (isWadPathOk(returnWadPath))
return returnWadPath;
}
#endif
#ifdef CMAKECONFIG
#ifndef NDEBUG
I_OutputMsg(","CMAKE_ASSETS_DIR);

View file

@ -20,6 +20,7 @@
/// \brief SRB2 graphics stuff for SDL
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
@ -85,6 +86,10 @@
#include "ogl_sdl.h"
#endif
#ifdef HAVE_DISCORDRPC
#include "../discord.h"
#endif
// maximum number of windowed modes (see windowedModes[][])
#define MAXWINMODES (18)
@ -1324,6 +1329,11 @@ void I_FinishUpdate(void)
if (cv_closedcaptioning.value)
SCR_ClosedCaptions();
#ifdef HAVE_DISCORDRPC
if (discordRequestList != NULL)
ST_AskToJoinEnvelope();
#endif
if (rendermode == render_soft && screens[0])
{
SDL_Rect rect;

492
src/slope_anchors.c Normal file
View file

@ -0,0 +1,492 @@
// SONIC ROBO BLAST 2 KART
//-----------------------------------------------------------------------------
// Copyright (C) 2020 by James R.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \brief Charyb's vertex slope anchors.
/// This file is self contained to avoid a Big Large merge conflict.
/*
FIXME
FIXME
FIXME
FIXME WHEN 2.2 MERGE IS OVER, REFACTOR A LOT OF THE CODE IN P_SLOPES.C AND
FIXME MAKE THIS NOT REDUNDANT.
FIXME
FIXME
FIXME
*/
struct anchor_list
{
mapthing_t ** anchors;
const vertex_t ** points;
fixed_t * closeness;
size_t count;
};
struct anchor_list floor_anchors;
struct anchor_list ceiling_anchors;
static void * new_list (size_t n) {
return Z_Malloc(n, PU_LEVEL, NULL);
}
static void make_new_anchor_list (struct anchor_list * list) {
list->anchors = new_list(list->count * sizeof *list->anchors);
list->points = new_list(list->count * sizeof *list->points);
list->closeness = new_list(list->count * sizeof *list->closeness);
}
static void allocate_anchors (void) {
size_t i;
floor_anchors.count = 0;
ceiling_anchors.count = 0;
for (i = 0; i < nummapthings; ++i)
{
switch (mapthings[i].type)
{
case FLOOR_SLOPE_THING:
floor_anchors.count++;
break;
case CEILING_SLOPE_THING:
ceiling_anchors.count++;
break;
}
}
make_new_anchor_list(&floor_anchors);
make_new_anchor_list(&ceiling_anchors);
}
static void
compare_vertex_distance
(
const vertex_t ** nearest,
fixed_t * nearest_distance,
const fixed_t origin_x,
const fixed_t origin_y,
const vertex_t * v
){
const fixed_t distance = abs(P_AproxDistance
(
origin_x - v->x,
origin_y - v->y
));
if (distance < (*nearest_distance))
{
(*nearest) = v;
(*nearest_distance) = distance;
}
}
static const vertex_t *
nearest_point
(
fixed_t * closeness,
mapthing_t * a,
const sector_t * sector
){
const fixed_t x = a->x << FRACBITS;
const fixed_t y = a->y << FRACBITS;
const vertex_t * v = NULL;/* shut compiler up, should never be NULL */
size_t i;
(*closeness) = INT32_MAX;
for (i = 0; i < sector->linecount; ++i)
{
compare_vertex_distance(&v, closeness, x, y, sector->lines[i]->v1);
compare_vertex_distance(&v, closeness, x, y, sector->lines[i]->v2);
}
return v;
}
static INT16
anchor_height
(
const mapthing_t * a,
const sector_t * s
){
{
INT16 z = ( a->options >> ZSHIFT );
if (a->options & MTF_OBJECTFLIP)
{
return ( s->ceilingheight >> FRACBITS ) - z;
}
else
{
return ( s->floorheight >> FRACBITS ) + z;
}
}
}
static void
set_anchor
(
struct anchor_list * list,
mapthing_t * a
){
const subsector_t * sub = R_PointInSubsector
(
a->x << FRACBITS,
a->y << FRACBITS
);
const vertex_t * v;
fixed_t closeness;
a->z = anchor_height(a, sub->sector);
v = nearest_point(&closeness, a, sub->sector);
a->x = ( v->x >> FRACBITS );
a->y = ( v->y >> FRACBITS );
list->anchors [list->count] = a;
list->points [list->count] = v;
list->closeness[list->count] = closeness;
list->count++;
}
static void build_anchors (void) {
size_t i;
floor_anchors.count = 0;
ceiling_anchors.count = 0;
for (i = 0; i < nummapthings; ++i)
{
switch (mapthings[i].type)
{
case FLOOR_SLOPE_THING:
set_anchor(&floor_anchors, &mapthings[i]);
break;
case CEILING_SLOPE_THING:
set_anchor(&ceiling_anchors, &mapthings[i]);
break;
}
}
}
static void
get_anchor
(
mapthing_t ** anchors,
fixed_t distances[3],
const struct anchor_list * list,
const INT16 tag,
const vertex_t * v
){
size_t i;
int k;
for (i = 0; i < list->count; ++i)
{
if (list->points[i] == v && list->anchors[i]->extrainfo == tag)
{
for (k = 0; k < 3; ++k)
{
if (list->closeness[i] < distances[k])
{
if (k == 0)
{
distances[2] = distances[1];
distances[1] = distances[0];
anchors [2] = anchors [1];
anchors [1] = anchors [0];
}
else if (k == 1)
{
distances[2] = distances[1];
anchors [2] = anchors [1];
}
distances[k] = list->closeness[i];
anchors[k] = list->anchors[i];
break;
}
else if (list->anchors[i] == anchors[k])
{
break;
}
}
}
}
}
static void
get_sector_anchors
(
mapthing_t ** anchors,
fixed_t distances[3],
const struct anchor_list * list,
const INT16 tag,
const sector_t * sector
){
size_t i;
for (i = 0; i < sector->linecount; ++i)
{
get_anchor(anchors, distances, list, tag, sector->lines[i]->v1);
get_anchor(anchors, distances, list, tag, sector->lines[i]->v2);
}
}
static mapthing_t **
find_closest_anchors
(
const sector_t * sector,
const struct anchor_list * list,
const INT16 tag
){
fixed_t distances[3] = { INT32_MAX, INT32_MAX, INT32_MAX };
mapthing_t ** anchors;
int last = 0;
size_t i;
if (list->count < 3)
{
I_Error("At least three slope anchors are required to make a slope.");
}
anchors = Z_Malloc(3 * sizeof *anchors, PU_LEVEL, NULL);
if (sector->numattached > 0)
{
for (i = 0; i < sector->numattached; ++i)
{
get_sector_anchors
(anchors, distances, list, tag, &sectors[sector->attached[i]]);
}
}
else
{
get_sector_anchors(anchors, distances, list, tag, sector);
}
if (distances[2] < INT32_MAX)
{
return anchors;
}
if (distances[1] < INT32_MAX)
last = 2;
else if (distances[0] < INT32_MAX)
last = 1;
else
last = 0;
if (sector->numattached > 0)
{
CONS_Printf("\nSearched for anchors in sectors...\n\n");
for (i = 0; i < sector->numattached; ++i)
{
CONS_Printf("#%s\n", sizeu1 (sector->attached[i]));
}
I_Error(
"(Control Sector #%s)"
" Slope requires anchors (with Parameter %d)"
" near 3 of its target sectors' vertices (%d found)"
"\n\nCheck the log to see which sectors were searched.",
sizeu1 (sector - sectors),
tag,
last
);
}
else
{
I_Error(
"(Sector #%s)"
" Slope requires anchors (with Parameter %d)"
" near 3 of its vertices (%d found)",
sizeu1 (sector - sectors),
tag,
last
);
}
}
static pslope_t *
new_vertex_slope
(
mapthing_t ** anchors,
const INT16 flags
){
pslope_t * slope = Z_Calloc(sizeof (pslope_t), PU_LEVEL, NULL);
const vector3_t anchorVertices[3] = {
{anchors[0]->x << FRACBITS, anchors[0]->y << FRACBITS, anchors[0]->z << FRACBITS},
{anchors[1]->x << FRACBITS, anchors[1]->y << FRACBITS, anchors[1]->z << FRACBITS},
{anchors[2]->x << FRACBITS, anchors[2]->y << FRACBITS, anchors[2]->z << FRACBITS}
};
if (flags & ML_NETONLY)
{
slope->flags |= SL_NOPHYSICS;
}
if (flags & ML_NONET)
{
slope->flags |= SL_DYNAMIC;
}
P_ReconfigureViaVertexes(slope, anchorVertices[0], anchorVertices[1], anchorVertices[2]);
//slope->refpos = 5;
// Add to the slope list
slope->next = slopelist;
slopelist = slope;
slopecount++;
slope->id = slopecount;
return slope;
}
static mapthing_t **
flip_slope
(
mapthing_t ** origin,
const sector_t * sector
){
mapthing_t * copy = Z_Malloc(3 * sizeof (mapthing_t), PU_LEVEL, NULL);
mapthing_t ** anchors = Z_Malloc(3 * sizeof (mapthing_t *), PU_LEVEL, NULL);
size_t i;
for (i = 0; i < 3; ++i)
{
memcpy(&copy[i], origin[i], sizeof copy[i]);
copy[i].options ^= MTF_OBJECTFLIP;
copy[i].z = anchor_height(&copy[i], sector);
anchors[i] = &copy[i];
}
return anchors;
}
static void
slope_sector
(
pslope_t ** slope,
pslope_t ** alt,
sector_t * sector,
const INT16 flags,
const struct anchor_list * list,
const INT16 tag
){
mapthing_t ** anchors = find_closest_anchors(sector, list, tag);
if (anchors != NULL)
{
(*slope) = new_vertex_slope(anchors, flags);
/* Effect 6 - invert slope to opposite side */
if (flags & ML_EFFECT6)
{
(*alt) = new_vertex_slope(flip_slope(anchors, sector), flags);
}
sector->hasslope = true;
}
}
static void
make_anchored_slope
(
const line_t * line,
const int plane
){
enum
{
FLOOR = 0x1,
CEILING = 0x2,
};
INT16 flags = line->flags;
const int side = ( flags & ML_NOCLIMB ) != 0;
sector_t * s;
if (side == 0 || flags & ML_TWOSIDED)
{
s = sides[line->sidenum[side]].sector;
if (plane == (FLOOR|CEILING))
{
flags &= ~ML_EFFECT6;
}
if (plane & FLOOR)
{
slope_sector
(&s->f_slope, &s->c_slope, s, flags, &floor_anchors, line->tag);
}
if (plane & CEILING)
{
slope_sector
(&s->c_slope, &s->f_slope, s, flags, &ceiling_anchors, line->tag);
}
}
}
static void P_BuildSlopeAnchorList (void) {
allocate_anchors();
build_anchors();
}
static void P_SetupAnchoredSlopes (void) {
enum
{
FLOOR = 0x1,
CEILING = 0x2,
};
size_t i;
for (i = 0; i < numlines; ++i)
{
if (lines[i].special == LT_SLOPE_ANCHORS_FLOOR)
{
make_anchored_slope(&lines[i], FLOOR);
}
else if (lines[i].special == LT_SLOPE_ANCHORS_CEILING)
{
make_anchored_slope(&lines[i], CEILING);
}
else if (lines[i].special == LT_SLOPE_ANCHORS)
{
make_anchored_slope(&lines[i], FLOOR|CEILING);
}
}
}

View file

@ -888,6 +888,10 @@ sfxinfo_t S_sfx[NUMSFX] =
{"bhurry", false, 255, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // v1.0.2 Battle overtime
{"bsnipe", false, 96, 8, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Banana sniping
{"sploss", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Down to yellow sparks
{"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
{"cock", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""}, // Hammer cocks, bang bang

View file

@ -952,6 +952,10 @@ typedef enum
sfx_bhurry,
sfx_bsnipe,
sfx_sploss,
sfx_join,
sfx_leave,
sfx_requst,
sfx_syfail,
sfx_itfree,
sfx_dbgsal,
sfx_cock,

View file

@ -136,6 +136,11 @@ static patch_t *fnshico;
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] =
@ -363,6 +368,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
@ -1009,6 +1019,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)
{
boolean stagetitle = false; // Decide whether to draw the stage title or not

View file

@ -32,6 +32,11 @@ void ST_Ticker(boolean run);
// 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);

View file

@ -50,6 +50,10 @@ ifndef MINGW64 #miniupnc is broken with MINGW64
endif
endif
ifndef NO_DISCORDRPC
HAVE_DISCORDRPC=1
endif
OPTS=-DSTDC_HEADERS
ifndef GCC44
@ -76,6 +80,12 @@ else
endif
endif
ifndef MINGW64
CPPFLAGS+=-I../libs/drmingw/include
LDFLAGS+=-L../libs/drmingw/lib/win32
LIBS+=-lmgwhelp -lexchndl
endif
# name of the exefile
ifdef SDL
EXENAME?=srb2kart.exe
@ -162,4 +172,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

View file

@ -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".