mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Compare commits
140 commits
daa6dbd667
...
c8f986db4d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f986db4d | ||
|
|
0734ffc201 | ||
|
|
fa787c4e8f | ||
|
|
511d9b083b | ||
|
|
6f61cfaefa | ||
|
|
932deb0b3f | ||
|
|
2309d11274 | ||
|
|
a9fe850eda | ||
|
|
210ec5ee63 | ||
|
|
cbb99ca79b | ||
|
|
4ff1f38877 | ||
|
|
78b11e8306 | ||
|
|
eb90b28c12 | ||
|
|
8bf15ef6f1 | ||
|
|
ef4ef91fed | ||
|
|
abbc6b03d4 | ||
|
|
50f007b653 | ||
|
|
11acb78875 | ||
|
|
8363ead346 | ||
|
|
32d03ccb1e | ||
|
|
d5c4534d31 | ||
|
|
2d3e7ce049 | ||
|
|
14201c65aa | ||
|
|
093cdb1043 | ||
|
|
350cd423e4 | ||
|
|
1d1e7d1741 | ||
|
|
59c4cfb2be | ||
|
|
d3ac1a6c5e | ||
|
|
60e65133e6 | ||
|
|
0badaed11d | ||
|
|
53d71225b8 | ||
|
|
80c0db9546 | ||
|
|
06626c9b0d | ||
|
|
0e46138a14 | ||
|
|
ae0100ba05 | ||
|
|
ab39175430 | ||
|
|
9bdd01f5a6 | ||
|
|
69e23ad50a | ||
|
|
e3067e8a09 | ||
|
|
3d16ecd7e9 | ||
|
|
bf901fddb3 | ||
|
|
140f9846aa | ||
|
|
9297e3cdcb | ||
|
|
7b10e4e2bd | ||
|
|
667ad18339 | ||
|
|
5e44040ae8 | ||
|
|
55192eaf39 | ||
|
|
d157076326 | ||
|
|
8b86622218 | ||
|
|
5ead1e5964 | ||
|
|
d5fc805cbd | ||
|
|
fbe2f9fd56 | ||
|
|
7b4cf9a07c | ||
|
|
d060df9bfe | ||
|
|
a05a82de7b | ||
|
|
cd038addd5 | ||
|
|
8f4a698a35 | ||
|
|
e7ee7ec9ce | ||
|
|
8b71cd9e82 | ||
|
|
3f8ee05db8 | ||
|
|
d55eab9748 | ||
|
|
997f995ce9 | ||
|
|
bd4b3336bf | ||
|
|
a428811884 | ||
|
|
74ae7abd4c | ||
|
|
8649a66e08 | ||
|
|
0c3906690d | ||
|
|
8e4b690387 | ||
|
|
cfd8260762 | ||
|
|
f2ab528062 | ||
|
|
bf330bafcc | ||
|
|
48e1ed5779 | ||
|
|
5950298ac6 | ||
|
|
77768b5a68 | ||
|
|
c1a80e4b1b | ||
|
|
65cf6edb93 | ||
|
|
b746b1a0e4 | ||
|
|
b587b4b574 | ||
|
|
ddd48b72d7 | ||
|
|
94ef03dcd2 | ||
|
|
a6f27a39e3 | ||
|
|
22e7b5e8ad | ||
|
|
a31b4a2682 | ||
|
|
c96e3b3cca | ||
|
|
766f34d4f5 | ||
|
|
b7f8afd5ef | ||
|
|
6507984c22 | ||
|
|
3cc58d93f2 | ||
|
|
39c2779fb2 | ||
|
|
c1b22c0c73 | ||
|
|
dc1c3bec0f | ||
|
|
e9906915b0 | ||
|
|
8f213c7e1b | ||
|
|
cef307816d | ||
|
|
d69e667835 | ||
|
|
b52e1cb61f | ||
|
|
fc4a2e9f80 | ||
|
|
01bcf6116e | ||
|
|
15bac24b8d | ||
|
|
c7fcf34a8a | ||
|
|
d5f131dcc2 | ||
|
|
2be14316cf | ||
|
|
60fca5210d | ||
|
|
7109cd8c13 | ||
|
|
e0fd5b43c5 | ||
|
|
51cc299e40 | ||
|
|
84917e36f1 | ||
|
|
5d30a46728 | ||
|
|
d0ef4cdfaf | ||
|
|
220f8b035d | ||
|
|
51e22892ac | ||
|
|
eb90dcd047 | ||
|
|
4337618342 | ||
|
|
2a72e0a855 | ||
|
|
6bd6c91077 | ||
|
|
aee332fa9b | ||
|
|
f7bc6e303e | ||
|
|
4aa3309885 | ||
|
|
595874f4e5 | ||
|
|
3f5f9825a8 | ||
|
|
4478fce917 | ||
|
|
f78ae582d4 | ||
|
|
55b333e01f | ||
|
|
867dfb49f2 | ||
|
|
3d5f0e9d73 | ||
|
|
587eddeb70 | ||
|
|
4b94f06186 | ||
|
|
38be6953e7 | ||
|
|
a13735822e | ||
|
|
b3a2cc2ea9 | ||
|
|
0373a23d72 | ||
|
|
27b9a46f0c | ||
|
|
944c13993b | ||
|
|
0dad1aa918 | ||
|
|
f674778097 | ||
|
|
9411ce5387 | ||
|
|
a01300cd54 | ||
|
|
1517ba4d89 | ||
|
|
4b81be037a | ||
|
|
75fe652dd5 |
67 changed files with 2279 additions and 436 deletions
|
|
@ -125,6 +125,9 @@ find_package(PNG REQUIRED)
|
|||
find_package(SDL2 CONFIG REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
if(WIN32 AND NOT MINGW)
|
||||
find_package(cpptrace CONFIG REQUIRED)
|
||||
endif()
|
||||
# Use the one in thirdparty/fmt to guarantee a minimum version
|
||||
#find_package(FMT CONFIG REQUIRED)
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@
|
|||
"name": "__develop-cl",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
|
||||
"SRB2_CONFIG_DEV_BUILD": "ON",
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
|
|
@ -64,8 +64,8 @@
|
|||
"name": "__release-cl",
|
||||
"hidden": true,
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_C_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
|
||||
"CMAKE_CXX_FLAGS_RELWITHDEBINFO": "/MD /Zi /O2 /Ob2 /DNDEBUG",
|
||||
"SRB2_CONFIG_DEV_BUILD": "OFF",
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,41 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32
|
|||
p_deepcopy.cpp
|
||||
)
|
||||
|
||||
# Always compile some files with optimizations in Debug config.
|
||||
# This is to make the debugging experience less slow for the majority of cases.
|
||||
set(always_optimize_options "")
|
||||
if(MSVC)
|
||||
set(always_optimize_options "$<$<CONFIG:Debug>:/O2;/Ob2>")
|
||||
else()
|
||||
set(always_optimize_options "$<$<CONFIG:Debug>:-O3>")
|
||||
endif()
|
||||
set_source_files_properties(
|
||||
r_bsp.cpp
|
||||
r_data.c
|
||||
r_debug.cpp
|
||||
r_debug_parser.cpp
|
||||
r_debug_printer.cpp
|
||||
r_draw.cpp
|
||||
r_fps.cpp
|
||||
r_main.cpp
|
||||
r_plane.cpp
|
||||
r_segs.cpp
|
||||
r_skins.c
|
||||
r_sky.c
|
||||
r_splats.c
|
||||
r_spritefx.cpp
|
||||
r_things.cpp
|
||||
r_bbox.c
|
||||
r_textures.cpp
|
||||
r_textures_dups.cpp
|
||||
r_patch.cpp
|
||||
r_patchrotation.c
|
||||
r_picformats.c
|
||||
r_portal.c
|
||||
PROPERTIES
|
||||
COMPILE_OPTIONS "${always_optimize_options}"
|
||||
)
|
||||
|
||||
set_target_properties(SRB2SDL2 PROPERTIES MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/sdl/macosx/MacOSXBundleInfo.plist.in")
|
||||
|
||||
if(SRB2_CONFIG_ENABLE_WEBM_MOVIES)
|
||||
|
|
@ -210,7 +245,7 @@ add_custom_target(_SRB2_reconf ALL
|
|||
)
|
||||
add_dependencies(SRB2SDL2 _SRB2_reconf)
|
||||
|
||||
if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
|
||||
if(("${CMAKE_COMPILER_IS_GNUCC}") AND "${CMAKE_SYSTEM_NAME}" MATCHES "Windows")
|
||||
target_link_options(SRB2SDL2 PRIVATE "-Wl,--disable-dynamicbase")
|
||||
if("${SRB2_CONFIG_STATIC_STDLIB}")
|
||||
# On MinGW with internal libraries, link the standard library statically
|
||||
|
|
@ -224,8 +259,19 @@ if(("${CMAKE_COMPILER_IS_GNUCC}" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link.exe")
|
||||
if(MSVC OR CMAKE_CXX_LINK_EXECUTABLE MATCHES "lld-link\\.exe")
|
||||
target_link_options(SRB2SDL2 PRIVATE /MANIFEST:NO)
|
||||
target_link_libraries(SRB2SDL2 PRIVATE "dbghelp")
|
||||
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND MSVC)
|
||||
# Stuff to make paths not include the builder's file system paths on clang-cl
|
||||
string(REPLACE "/" "\\" backslashes_cmake_source_dir "${CMAKE_SOURCE_DIR}")
|
||||
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${CMAKE_SOURCE_DIR}=X:/ringracers>")
|
||||
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-prefix-map=${backslashes_cmake_source_dir}=X:/ringracers>")
|
||||
target_compile_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/clang:-fdebug-compilation-dir=${CMAKE_SOURCE_DIR}>")
|
||||
target_link_options(SRB2SDL2 PRIVATE "$<$<CONFIG:RelWithDebInfo,Release>:/pdbaltpath:%_PDB%>")
|
||||
endif()
|
||||
|
||||
target_compile_features(SRB2SDL2 PRIVATE c_std_11 cxx_std_17)
|
||||
|
|
@ -283,6 +329,10 @@ target_link_libraries(SRB2SDL2 PRIVATE ZLIB::ZLIB)
|
|||
target_link_libraries(SRB2SDL2 PRIVATE PNG::PNG)
|
||||
target_link_libraries(SRB2SDL2 PRIVATE CURL::libcurl)
|
||||
target_link_libraries(SRB2SDL2 PRIVATE Opus::opus)
|
||||
if(WIN32 AND NOT MINGW)
|
||||
target_link_libraries(SRB2SDL2 PRIVATE cpptrace::cpptrace)
|
||||
target_compile_definitions(SRB2SDL2 PRIVATE HAVE_CPPTRACE)
|
||||
endif()
|
||||
target_link_libraries(SRB2SDL2 PRIVATE ReNameNoise::renamenoise)
|
||||
if("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
|
||||
target_link_libraries(SRB2SDL2 PRIVATE -lexecinfo)
|
||||
|
|
@ -461,6 +511,7 @@ target_compile_options(SRB2SDL2 PRIVATE
|
|||
# This is a direct translation from versions.mk
|
||||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<C_COMPILER_ID:GNU>>:
|
||||
-Wall
|
||||
-Werror-implicit-function-declaration
|
||||
-Wno-trigraphs
|
||||
-W # Was controlled by RELAXWARNINGS
|
||||
-pedantic
|
||||
|
|
@ -545,6 +596,7 @@ target_compile_options(SRB2SDL2 PRIVATE
|
|||
$<$<AND:$<COMPILE_LANGUAGE:C>,$<OR:$<C_COMPILER_ID:AppleClang>,$<C_COMPILER_ID:Clang>>>:
|
||||
#-Wall
|
||||
-Werror=microsoft
|
||||
-Werror=implicit-function-declaration
|
||||
-Wreturn-type # Missing returns in non-void function
|
||||
-Wduplicate-decl-specifier
|
||||
-Wsometimes-uninitialized
|
||||
|
|
@ -570,9 +622,13 @@ target_compile_options(SRB2SDL2 PRIVATE
|
|||
# C++, GNU
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:GNU>>:
|
||||
-Wall
|
||||
-Wno-c++11-compat
|
||||
-Wno-c++14-compat # No C++14 compat needed
|
||||
-Wc++20-extensions
|
||||
-Wc++23-extensions # Disallow newer language features entirely
|
||||
>
|
||||
|
||||
# C++, GNU, Clang and Apple Clang
|
||||
# C++, Clang and Apple Clang
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<OR:$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:Clang>>>:
|
||||
#-Wall
|
||||
-Werror=microsoft
|
||||
|
|
@ -584,6 +640,8 @@ target_compile_options(SRB2SDL2 PRIVATE
|
|||
-Wno-c++98-compat
|
||||
-Wno-c++11-compat
|
||||
-Wno-c++14-compat # No C++14 compat needed
|
||||
-Werror=c++20-extensions
|
||||
-Werror=c++23-extensions # Disallow newer language features entirely
|
||||
-Wno-unused-but-set-variable # Setting unread variables is fine (nontrivial C++ types issue)
|
||||
-Wno-misleading-indentation # Some cases in code currently
|
||||
-Wno-deprecated-non-prototype # We have no intention of using C23 yet.
|
||||
|
|
@ -594,6 +652,8 @@ target_compile_options(SRB2SDL2 PRIVATE
|
|||
-Wno-unused-function
|
||||
>
|
||||
|
||||
# C++, Clang and Apple Clang
|
||||
|
||||
# C++, MSVC
|
||||
$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:MSVC>>:
|
||||
/Wv:19.20.27004.0
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "Script.hpp"
|
||||
#include "Serial.hpp"
|
||||
#include "Thread.hpp"
|
||||
#include "../../../w_wad.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
|
@ -596,7 +597,12 @@ namespace ACSVM
|
|||
ModuleName Environment::readModuleName(Serial &in) const
|
||||
{
|
||||
auto s = readString(in);
|
||||
auto i = ReadVLN<std::size_t>(in);
|
||||
size_t i = ReadVLN<std::size_t>(in);
|
||||
|
||||
if ((i = W_LumpFromNetSave(i)) == LUMPERROR)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "lumpnum not found for ACS module '%s'\n", s->str);
|
||||
}
|
||||
|
||||
return {s, nullptr, i};
|
||||
}
|
||||
|
|
@ -768,7 +774,7 @@ namespace ACSVM
|
|||
void Environment::writeModuleName(Serial &out, ModuleName const &in) const
|
||||
{
|
||||
writeString(out, in.s);
|
||||
WriteVLN(out, in.i);
|
||||
WriteVLN<std::size_t>(out, W_LumpIntoNetSave(in.i));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
|||
|
|
@ -829,6 +829,7 @@ void ForceSkin_OnChange(void);
|
|||
consvar_t cv_forceskin = OnlineCheat("forcecharacter", "None").onchange(ForceSkin_OnChange).description("Force all players to use one character");
|
||||
|
||||
consvar_t cv_fuzz = OnlineCheat("fuzz", "Off").on_off().description("Human players spam random inputs, get random items");
|
||||
consvar_t cv_skiprender = OnlineCheat("skiprender", "1").values(CV_Natural).description("Only render every X frames");
|
||||
|
||||
consvar_t cv_kartdebugamount = OnlineCheat("debugitemamount", "1").min_max(1, 255).description("If debugitem, give multiple copies of an item");
|
||||
consvar_t cv_kartdebugbots = OnlineCheat("debugbots", "Off").on_off().description("Bot AI debugger");
|
||||
|
|
|
|||
130
src/d_clisrv.c
130
src/d_clisrv.c
|
|
@ -206,8 +206,11 @@ static UINT32 g_player_voice_frames_this_tic[MAXPLAYERS];
|
|||
static OpusEncoder *g_local_opus_encoder;
|
||||
static ReNameNoiseDenoiseState *g_local_renamenoise_state;
|
||||
static UINT64 g_local_opus_frame = 0;
|
||||
#define SRB2_VOICE_OPUS_FRAME_SIZE 960
|
||||
static float g_local_voice_buffer[SRB2_VOICE_OPUS_FRAME_SIZE];
|
||||
#define SRB2_VOICE_OPUS_FRAME_SIZE (20 * 48)
|
||||
#define SRB2_VOICE_MAX_FRAMES 8
|
||||
#define SRB2_VOICE_MAX_DEQUEUE_SAMPLES (SRB2_VOICE_MAX_FRAMES * SRB2_VOICE_OPUS_FRAME_SIZE)
|
||||
#define SRB2_VOICE_MAX_DEQUEUE_BYTES (SRB2_VOICE_MAX_DEQUEUE_SAMPLES * sizeof(float))
|
||||
static float g_local_voice_buffer[SRB2_VOICE_MAX_DEQUEUE_SAMPLES];
|
||||
static INT32 g_local_voice_buffer_len = 0;
|
||||
static INT32 g_local_voice_threshold_time = 0;
|
||||
float g_local_voice_last_peak = 0;
|
||||
|
|
@ -3742,8 +3745,6 @@ static void InitializeLocalVoiceEncoder(void)
|
|||
CONS_Alert(CONS_WARNING, "Failed to create Opus voice encoder: opus error %d\n", error);
|
||||
encoder = NULL;
|
||||
}
|
||||
opus_encoder_ctl(encoder, OPUS_SET_VBR(0));
|
||||
opus_encoder_ctl(encoder, OPUS_SET_BITRATE(28000));
|
||||
g_local_opus_encoder = encoder;
|
||||
g_local_opus_frame = 0;
|
||||
}
|
||||
|
|
@ -3811,6 +3812,12 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
|
|||
newplayer->availabilities[i] = READUINT8(*p);
|
||||
}
|
||||
|
||||
if (server)
|
||||
{
|
||||
for (i = 0; i < G_LocalSplitscreenPartySize(newplayernum); ++i)
|
||||
playerdelaytable[G_LocalSplitscreenPartyMember(newplayernum, i)] = mindelay;
|
||||
}
|
||||
|
||||
// the server is creating my player
|
||||
if (node == mynode)
|
||||
{
|
||||
|
|
@ -3838,12 +3845,6 @@ static void Got_AddPlayer(const UINT8 **p, INT32 playernum)
|
|||
|
||||
P_ForceLocalAngle(newplayer, newplayer->angleturn);
|
||||
addedtogame = true;
|
||||
|
||||
if (server)
|
||||
{
|
||||
for (i = 0; i < G_LocalSplitscreenPartySize(newplayernum); ++i)
|
||||
playerdelaytable[G_LocalSplitscreenPartyMember(newplayernum, i)] = mindelay;
|
||||
}
|
||||
}
|
||||
|
||||
newplayer->splitscreenindex = splitscreenplayer;
|
||||
|
|
@ -5379,7 +5380,7 @@ static void PT_HandleVoiceClient(SINT8 node, boolean isserver)
|
|||
{
|
||||
return;
|
||||
}
|
||||
float *decoded_out = Z_Malloc(sizeof(float) * SRB2_VOICE_OPUS_FRAME_SIZE, PU_STATIC, NULL);
|
||||
float *decoded_out = Z_Malloc(sizeof(float) * 1920, PU_STATIC, NULL);
|
||||
|
||||
INT32 decoded_samples = 0;
|
||||
UINT64 missedframes = 0;
|
||||
|
|
@ -5390,7 +5391,7 @@ static void PT_HandleVoiceClient(SINT8 node, boolean isserver)
|
|||
|
||||
for (UINT64 i = 0; i < missedframes; i++)
|
||||
{
|
||||
decoded_samples = opus_decode_float(decoder, NULL, 0, decoded_out, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
|
||||
decoded_samples = opus_decode_float(decoder, NULL, 0, decoded_out, 1920, 0);
|
||||
if (decoded_samples < 0)
|
||||
{
|
||||
continue;
|
||||
|
|
@ -5402,7 +5403,7 @@ static void PT_HandleVoiceClient(SINT8 node, boolean isserver)
|
|||
}
|
||||
g_player_opus_lastframe[playernum] = framenum;
|
||||
|
||||
decoded_samples = opus_decode_float(decoder, frame, framesize, decoded_out, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
|
||||
decoded_samples = opus_decode_float(decoder, frame, framesize, decoded_out, 1920, 0);
|
||||
if (decoded_samples < 0)
|
||||
{
|
||||
Z_Free(decoded_out);
|
||||
|
|
@ -7566,9 +7567,19 @@ void NetUpdate(void)
|
|||
FileSendTicker();
|
||||
}
|
||||
|
||||
static INT32 BiggestOpusFrameLength(INT32 samples)
|
||||
{
|
||||
if (samples >= 1920) return 1920;
|
||||
if (samples >= 960) return 960;
|
||||
if (samples >= 480) return 480;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetVoiceUpdate(void)
|
||||
{
|
||||
UINT8 *encoded = NULL;
|
||||
float *subframe_buffer = NULL;
|
||||
float *denoise_buffer = NULL;
|
||||
|
||||
if (dedicated)
|
||||
{
|
||||
|
|
@ -7576,42 +7587,25 @@ void NetVoiceUpdate(void)
|
|||
}
|
||||
|
||||
UINT32 bytes_dequed = 0;
|
||||
do
|
||||
|
||||
bytes_dequed = S_SoundInputDequeueSamples((void*)(g_local_voice_buffer + g_local_voice_buffer_len), SRB2_VOICE_MAX_DEQUEUE_BYTES - (g_local_voice_buffer_len * sizeof(float)));
|
||||
g_local_voice_buffer_len += bytes_dequed / 4;
|
||||
|
||||
INT32 buffer_offset = 0;
|
||||
INT32 frame_length = 0;
|
||||
for (
|
||||
;
|
||||
(frame_length = BiggestOpusFrameLength(g_local_voice_buffer_len - buffer_offset)) > 0 && (buffer_offset + frame_length) < g_local_voice_buffer_len;
|
||||
buffer_offset += frame_length
|
||||
)
|
||||
{
|
||||
// We need to drain the input queue completely, so do this in a full loop
|
||||
|
||||
UINT32 to_read = (SRB2_VOICE_OPUS_FRAME_SIZE - g_local_voice_buffer_len) * sizeof(float);
|
||||
|
||||
if (to_read > 0)
|
||||
{
|
||||
// Attempt to fill the voice frame buffer
|
||||
|
||||
bytes_dequed = S_SoundInputDequeueSamples((void*)(g_local_voice_buffer + g_local_voice_buffer_len), to_read);
|
||||
g_local_voice_buffer_len += bytes_dequed / 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_dequed = 0;
|
||||
}
|
||||
|
||||
if (g_local_voice_buffer_len < SRB2_VOICE_OPUS_FRAME_SIZE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (S_SoundInputRemainingSamples() > 5 * SRB2_VOICE_OPUS_FRAME_SIZE)
|
||||
{
|
||||
// If there are too many frames worth of samples to dequeue (100ms), skip this frame instead of encoding.
|
||||
// This is so we drain the queue without sending too many packets that might queue up on the network driver.
|
||||
g_local_voice_buffer_len = 0;
|
||||
continue;
|
||||
}
|
||||
float *frame_buffer = g_local_voice_buffer + buffer_offset;
|
||||
|
||||
// Amp of +10 dB is appromiately "twice as loud"
|
||||
float ampfactor = powf(10, (float) cv_voice_inputamp.value / 20.f);
|
||||
for (int i = 0; i < g_local_voice_buffer_len; i++)
|
||||
for (int i = 0; i < frame_length; i++)
|
||||
{
|
||||
g_local_voice_buffer[i] *= ampfactor;
|
||||
frame_buffer[i] *= ampfactor;
|
||||
}
|
||||
|
||||
if (cv_voice_denoise.value)
|
||||
|
|
@ -7620,30 +7614,34 @@ void NetVoiceUpdate(void)
|
|||
{
|
||||
InitializeLocalVoiceDenoiser();
|
||||
}
|
||||
int rnnoise_size = renamenoise_get_frame_size();
|
||||
float *subframe_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
|
||||
float *denoise_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
|
||||
int rnnoise_size = renamenoise_get_frame_size(); // this is always 480
|
||||
if (subframe_buffer == NULL)
|
||||
{
|
||||
subframe_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
|
||||
}
|
||||
if (denoise_buffer == NULL)
|
||||
{
|
||||
denoise_buffer = (float*) Z_Malloc(rnnoise_size * sizeof(float), PU_STATIC, NULL);
|
||||
}
|
||||
|
||||
// rnnoise frames are smaller than opus, but we should not expect the opus frame to be an exact multiple of rnnoise
|
||||
for (int denoise_position = 0; denoise_position < SRB2_VOICE_OPUS_FRAME_SIZE; denoise_position += rnnoise_size)
|
||||
for (int denoise_position = 0; denoise_position < frame_length; denoise_position += rnnoise_size)
|
||||
{
|
||||
memset(subframe_buffer, 0, rnnoise_size * sizeof(float));
|
||||
memcpy(subframe_buffer, g_local_voice_buffer + denoise_position, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
|
||||
memcpy(subframe_buffer, frame_buffer + denoise_position, min(rnnoise_size * sizeof(float), (frame_length - denoise_position) * sizeof(float)));
|
||||
renamenoise_process_frame(g_local_renamenoise_state, denoise_buffer, subframe_buffer);
|
||||
memcpy(g_local_voice_buffer + denoise_position, denoise_buffer, min(rnnoise_size * sizeof(float), (SRB2_VOICE_OPUS_FRAME_SIZE - denoise_position) * sizeof(float)));
|
||||
memcpy(frame_buffer + denoise_position, denoise_buffer, min(rnnoise_size * sizeof(float), (frame_length - denoise_position) * sizeof(float)));
|
||||
}
|
||||
Z_Free(denoise_buffer);
|
||||
Z_Free(subframe_buffer);
|
||||
}
|
||||
|
||||
float softmem = 0.f;
|
||||
opus_pcm_soft_clip(g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 1, &softmem);
|
||||
opus_pcm_soft_clip(frame_buffer, frame_length, 1, &softmem);
|
||||
|
||||
// Voice detection gate open/close
|
||||
float maxamplitude = 0.f;
|
||||
for (int i = 0; i < g_local_voice_buffer_len; i++)
|
||||
for (int i = 0; i < frame_length; i++)
|
||||
{
|
||||
maxamplitude = max(fabsf(g_local_voice_buffer[i]), maxamplitude);
|
||||
maxamplitude = max(fabsf(frame_buffer[i]), maxamplitude);
|
||||
}
|
||||
// 20. * log_10(amplitude) -> decibels (up to 0)
|
||||
// lower than -30 dB is usually inaudible
|
||||
|
|
@ -7660,7 +7658,6 @@ void NetVoiceUpdate(void)
|
|||
case 0:
|
||||
if (I_GetTime() - g_local_voice_threshold_time > 15)
|
||||
{
|
||||
g_local_voice_buffer_len = 0;
|
||||
g_local_voice_detected = false;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -7668,20 +7665,17 @@ void NetVoiceUpdate(void)
|
|||
case 1:
|
||||
if (!g_voicepushtotalk_on)
|
||||
{
|
||||
g_local_voice_buffer_len = 0;
|
||||
g_local_voice_detected = false;
|
||||
continue;
|
||||
}
|
||||
g_local_voice_detected = true;
|
||||
break;
|
||||
default:
|
||||
g_local_voice_buffer_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cv_voice_selfdeafen.value == 1)
|
||||
{
|
||||
g_local_voice_buffer_len = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -7696,7 +7690,7 @@ void NetVoiceUpdate(void)
|
|||
}
|
||||
OpusEncoder *encoder = g_local_opus_encoder;
|
||||
|
||||
INT32 result = opus_encode_float(encoder, g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, encoded, 1400);
|
||||
INT32 result = opus_encode_float(encoder, frame_buffer, frame_length, encoded, 1400);
|
||||
if (result < 0)
|
||||
{
|
||||
continue;
|
||||
|
|
@ -7718,14 +7712,20 @@ void NetVoiceUpdate(void)
|
|||
{
|
||||
RecreatePlayerOpusDecoder(consoleplayer);
|
||||
}
|
||||
result = opus_decode_float(g_player_opus_decoders[consoleplayer], encoded, result, g_local_voice_buffer, SRB2_VOICE_OPUS_FRAME_SIZE, 0);
|
||||
S_QueueVoiceFrameFromPlayer(consoleplayer, g_local_voice_buffer, result * sizeof(float), false);
|
||||
result = opus_decode_float(g_player_opus_decoders[consoleplayer], encoded, result, frame_buffer, frame_length, 0);
|
||||
S_QueueVoiceFrameFromPlayer(consoleplayer, frame_buffer, result * sizeof(float), false);
|
||||
}
|
||||
|
||||
g_local_voice_buffer_len = 0;
|
||||
g_local_opus_frame += 1;
|
||||
} while (bytes_dequed > 0);
|
||||
}
|
||||
|
||||
if (buffer_offset > 0)
|
||||
{
|
||||
memmove(g_local_voice_buffer, g_local_voice_buffer + buffer_offset, (g_local_voice_buffer_len - buffer_offset) * sizeof(float));
|
||||
g_local_voice_buffer_len -= buffer_offset;
|
||||
}
|
||||
|
||||
if (denoise_buffer) Z_Free(denoise_buffer);
|
||||
if (subframe_buffer) Z_Free(subframe_buffer);
|
||||
if (encoded) Z_Free(encoded);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,17 +107,17 @@ extern "C" consvar_t cv_lua_profile, cv_menuframeskip;
|
|||
/* Manually defined asset hashes
|
||||
*/
|
||||
|
||||
#define ASSET_HASH_BIOS_PK3 "70ad11d77048078ee0adb7891068bf38"
|
||||
#define ASSET_HASH_BIOS_PK3 "5f9093a5c6abfb77ab518ac530312564"
|
||||
#define ASSET_HASH_SCRIPTS_PK3 "c3440a9ee57b4d9a81145a09afa0c0d6"
|
||||
#define ASSET_HASH_GFX_PK3 "314e88e73c0a629df9c2851dd7c21baf"
|
||||
#define ASSET_HASH_GFX_PK3 "24a59ebaa74f253dbec55b00328accb9"
|
||||
#define ASSET_HASH_TEXTURES_GENERAL_PK3 "609b683d3efc291ea28dd4e50d731f34"
|
||||
#define ASSET_HASH_TEXTURES_SEGAZONES_PK3 "61a19cb324e66b84e0fbc07abb659c64"
|
||||
#define ASSET_HASH_TEXTURES_SEGAZONES_PK3 "7ef635c2a5495dad031acf5f0b090045"
|
||||
#define ASSET_HASH_TEXTURES_ORIGINALZONES_PK3 "2f3aa120be2dfb1f4fe3e7090fbb0948"
|
||||
#define ASSET_HASH_CHARS_PK3 "5c8c34c5623acf984e3f654da4509126"
|
||||
#define ASSET_HASH_FOLLOWERS_PK3 "4b61428e5f2ec806de398de8a5fba5f0"
|
||||
#define ASSET_HASH_MAPS_PK3 "84503a914248842b3e88db4f1080b8e6"
|
||||
#define ASSET_HASH_MAPS_PK3 "b5af5f4f8bb4380dbf87f91014fca028"
|
||||
#define ASSET_HASH_UNLOCKS_PK3 "a4de35ba9f83829ced44dfc1316ba33e"
|
||||
#define ASSET_HASH_STAFFGHOSTS_PK3 "f2ea75218c9b8ef479a75f287cc32d11"
|
||||
#define ASSET_HASH_STAFFGHOSTS_PK3 "04a6ac1e67c95fa356aac8b505749a4a"
|
||||
#define ASSET_HASH_SHADERS_PK3 "bc0b47744d457956db2ee9ea00f59eff"
|
||||
#ifdef USE_PATCH_FILE
|
||||
#define ASSET_HASH_PATCH_PK3 "00000000000000000000000000000000"
|
||||
|
|
@ -843,6 +843,8 @@ static bool D_Display(bool world)
|
|||
|
||||
tic_t rendergametic;
|
||||
|
||||
extern "C" consvar_t cv_skiprender;
|
||||
|
||||
void D_SRB2Loop(void)
|
||||
{
|
||||
tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS;
|
||||
|
|
@ -1123,6 +1125,13 @@ void D_SRB2Loop(void)
|
|||
else
|
||||
frameskip = 0;
|
||||
}
|
||||
else if (cv_skiprender.value > 1)
|
||||
{
|
||||
if (frameskip < cv_skiprender.value)
|
||||
frameskip++;
|
||||
else
|
||||
frameskip = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ranwipe && frameskip < 3 && deltatics > 1.0)
|
||||
|
|
|
|||
|
|
@ -4639,10 +4639,10 @@ static void Command_ListWADS_f(void)
|
|||
nameonly(tempname = va("%s", wadfiles[i]->filename));
|
||||
if (!i)
|
||||
CONS_Printf("\x82 IWAD\x80: %s\n", tempname);
|
||||
else if (i <= mainwads)
|
||||
else if (i < mainwads)
|
||||
CONS_Printf("\x82 * %.2d\x80: %s\n", i, tempname);
|
||||
else if (!wadfiles[i]->important)
|
||||
CONS_Printf("\x86 %c %.2d: %s\n", ((i <= mainwads + musicwads) ? '*' : ' '), i, tempname);
|
||||
CONS_Printf("\x86 %c %.2d: %s\n", ((i < mainwads + musicwads) ? '*' : ' '), i, tempname);
|
||||
else
|
||||
CONS_Printf(" %.2d: %s\n", i, tempname);
|
||||
}
|
||||
|
|
@ -6876,6 +6876,7 @@ static void Command_Staffsync(void)
|
|||
demostarttime = I_GetTime();
|
||||
|
||||
staffbrief = mapheader->ghostBrief[staffsync_ghost];
|
||||
|
||||
G_DoPlayDemoEx("", (staffbrief->wad << 16) | staffbrief->lump);
|
||||
|
||||
staffsync_ghost++;
|
||||
|
|
@ -6923,6 +6924,28 @@ static void Command_Staffsync(void)
|
|||
|
||||
CONS_Printf("\n");
|
||||
|
||||
CONS_Printf(" %d syncs (%d error)\n", result->numerror, result->totalerror/FRACUNIT);
|
||||
|
||||
CONS_Printf(" presync: ");
|
||||
|
||||
for (UINT32 j = 0; j < PRNUMSYNCED; j++)
|
||||
{
|
||||
if (result->rngerror_presync[j] > 0)
|
||||
CONS_Printf("%s %d ", rng_class_names[j], result->rngerror_presync[j]);
|
||||
}
|
||||
|
||||
CONS_Printf("\n");
|
||||
|
||||
CONS_Printf(" postsync: ");
|
||||
|
||||
for (UINT32 j = 0; j < PRNUMSYNCED; j++)
|
||||
{
|
||||
if (result->rngerror_postsync[j] > 0)
|
||||
CONS_Printf("%s %d ", rng_class_names[j], result->rngerror_postsync[j]);
|
||||
}
|
||||
|
||||
CONS_Printf("\n");
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,10 +163,10 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
|
|||
#ifdef DEVELOP
|
||||
i = 0;
|
||||
#else
|
||||
i = mainwads + 1;
|
||||
i = mainwads + musicwads;
|
||||
#endif
|
||||
|
||||
for (; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
|
||||
for (; i < numwadfiles; i++) //mainwads+musicwads, 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)
|
||||
|
|
@ -197,7 +197,7 @@ UINT8 *PutFileNeeded(UINT16 firstfile)
|
|||
|
||||
/* don't send mainwads!! */
|
||||
#ifdef DEVELOP
|
||||
if (i <= mainwads)
|
||||
if (i < mainwads)
|
||||
filestatus += (2 << 4);
|
||||
#endif
|
||||
|
||||
|
|
@ -565,7 +565,7 @@ INT32 CL_CheckFiles(void)
|
|||
#ifdef DEVELOP
|
||||
j = 0;
|
||||
#else
|
||||
j = mainwads + 1;
|
||||
j = mainwads + musicwads;
|
||||
#endif
|
||||
for (i = 0; i < fileneedednum || j < numwadfiles;)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ typedef enum
|
|||
#define TUMBLEBOUNCES 3
|
||||
#define TUMBLEGRAVITY (4*FRACUNIT)
|
||||
|
||||
#define TRIPWIRETIME (15)
|
||||
#define TRIPWIRETIME (50)
|
||||
|
||||
#define BALLHOGINCREMENT (7)
|
||||
|
||||
|
|
@ -801,6 +801,8 @@ struct player_t
|
|||
fixed_t spindashspeed; // Spindash release speed
|
||||
UINT8 spindashboost; // Spindash release boost timer
|
||||
|
||||
UINT8 ringboostinprogress; // Ring overhead, don't sting!
|
||||
|
||||
fixed_t fastfall; // Fast fall momentum
|
||||
fixed_t fastfallBase; // Fast fall base speed multiplier
|
||||
|
||||
|
|
@ -821,6 +823,7 @@ struct player_t
|
|||
UINT16 tripwireLeniency; // When reaching a state that lets you go thru tripwire, you get an extra second leniency after it ends to still go through it.
|
||||
UINT8 tripwireAirLeniency; // Timer that elongates tripwire leniency when in midair.
|
||||
UINT8 fakeBoost; // Some items need to grant tripwire pass briefly, even when their effect is thrust/instathrust. This is a fake boost type to control that.
|
||||
UINT16 subsonicleniency; // Keep the subsonic visual for just a little bit when your sonic boom is visible
|
||||
|
||||
itemroulette_t itemRoulette; // Item roulette data
|
||||
|
||||
|
|
@ -1071,8 +1074,6 @@ struct player_t
|
|||
UINT16 wavedashboost; // The actual boost granted from wavedash.
|
||||
fixed_t wavedashpower; // Is this a bullshit "tap" wavedash? Weaken lower-charge wavedashes while keeping long sliptides fully rewarding.
|
||||
|
||||
UINT16 speedpunt;
|
||||
|
||||
UINT16 trickcharge; // Landed normally from a trick panel? Get the benefits package!
|
||||
|
||||
UINT16 infinitether; // Generic infinitether time, used for infinitether leniency.
|
||||
|
|
@ -1128,6 +1129,8 @@ struct player_t
|
|||
boolean dotrickfx;
|
||||
boolean stingfx;
|
||||
UINT8 bumperinflate;
|
||||
|
||||
boolean mfdfinish; // Did you cross the finish line while just about to explode?
|
||||
|
||||
UINT8 ringboxdelay; // Delay until Ring Box auto-activates
|
||||
UINT8 ringboxaward; // Where did we stop?
|
||||
|
|
|
|||
|
|
@ -1599,6 +1599,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
"S_AMPBURST",
|
||||
|
||||
// Tripwire VFX on player for bumping it or passing it
|
||||
|
||||
"S_SONICBOOM",
|
||||
"S_TRIPWIREOK",
|
||||
"S_TRIPWIRELOCKOUT",
|
||||
|
||||
|
|
@ -3597,6 +3599,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_AMPAURA",
|
||||
"MT_AMPBURST",
|
||||
|
||||
"MT_SONICBOOM",
|
||||
"MT_TRIPWIREOK",
|
||||
"MT_TRIPWIRELOCKOUT",
|
||||
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ enum {
|
|||
|
||||
|
||||
*/
|
||||
void I_Error(const char *error, ...) FUNCIERROR;
|
||||
FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...);
|
||||
|
||||
/** \brief write a message to stderr (use before I_Quit) for when you need to quit with a msg, but need
|
||||
the return code 0 of I_Quit();
|
||||
|
|
@ -757,8 +757,8 @@ extern int
|
|||
#define EXP_STABLERATE 3*FRACUNIT/10 // how low is your placement before losing XP? 4*FRACUNIT/10 = top 40% of race will gain
|
||||
#define EXP_POWER 3*FRACUNIT/100 // adjust to change overall xp volatility
|
||||
#define EXP_MIN 25 // The min value target
|
||||
#define EXP_TARGET 120 // Used for grading ...
|
||||
#define EXP_MAX 120 // The max value displayed by the hud and in the tally screen and GP results screen
|
||||
#define EXP_TARGET 150 // Used for grading ...
|
||||
#define EXP_MAX 150 // The max value displayed by the hud and in the tally screen and GP results screen
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -245,6 +245,10 @@ struct staffsync_t
|
|||
char name[MAXPLAYERNAME+1];
|
||||
UINT32 reason;
|
||||
UINT32 extra;
|
||||
fixed_t totalerror;
|
||||
UINT32 numerror;
|
||||
UINT32 rngerror_presync[32];
|
||||
UINT32 rngerror_postsync[32];
|
||||
};
|
||||
extern staffsync_t staffsync_results[1024];
|
||||
|
||||
|
|
|
|||
|
|
@ -1593,6 +1593,7 @@ void F_StartGameEnd(void)
|
|||
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
|
||||
F_WipeEndScreen();
|
||||
F_RunWipe(wipe_level_toblack, wipedefs[wipe_level_toblack], false, "FADEMAP0", false, false);
|
||||
Music_Stop("credits");
|
||||
|
||||
nextmap = NEXTMAP_TITLE;
|
||||
G_EndGame();
|
||||
|
|
|
|||
|
|
@ -303,18 +303,39 @@ boolean G_ConsiderEndingDemoRead(void)
|
|||
}
|
||||
|
||||
// Demo failed sync during a sync test! Log the failure to be reported later.
|
||||
static void G_FailStaffSync(staffsync_reason_t reason, UINT32 extra)
|
||||
static boolean G_FailStaffSync(staffsync_reason_t reason, UINT32 extra)
|
||||
{
|
||||
if (demo.attract != DEMO_ATTRACT_OFF) // Don't shout about RNG desyncs in titledemos
|
||||
return false;
|
||||
|
||||
if (!staffsync)
|
||||
return;
|
||||
return true;
|
||||
|
||||
if (staffsync_results[staffsync_failed].reason != 0)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (reason == SYNC_RNG)
|
||||
{
|
||||
switch (extra)
|
||||
{
|
||||
case PR_ITEM_DEBRIS:
|
||||
case PR_RANDOMAUDIENCE:
|
||||
case PR_VOICES:
|
||||
case PR_DECORATION:
|
||||
case PR_RANDOMANIM:
|
||||
CONS_Printf("[!] Ignored desync from RNG class %d\n", extra);
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
staffsync_results[staffsync_failed].map = gamemap;
|
||||
memcpy(&staffsync_results[staffsync_failed].name, player_names[consoleplayer], sizeof(player_names[consoleplayer]));
|
||||
staffsync_results[staffsync_failed].reason = reason;
|
||||
staffsync_results[staffsync_failed].extra = extra;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void G_ReadDemoExtraData(void)
|
||||
|
|
@ -484,13 +505,26 @@ void G_ReadDemoExtraData(void)
|
|||
{
|
||||
P_SetRandSeed(static_cast<pr_class_t>(i), rng);
|
||||
|
||||
if (demosynced)
|
||||
if (staffsync)
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d)!\n", i);
|
||||
G_FailStaffSync(SYNC_RNG, i);
|
||||
if (demosynced)
|
||||
staffsync_results[staffsync_failed].rngerror_presync[i]++;
|
||||
else
|
||||
staffsync_results[staffsync_failed].rngerror_postsync[i]++;
|
||||
}
|
||||
|
||||
storesynced = false;
|
||||
if (demosynced)
|
||||
{
|
||||
if (G_FailStaffSync(SYNC_RNG, i))
|
||||
{
|
||||
CONS_Alert(CONS_WARNING, "Demo playback has desynced (RNG class %d - %s)!\n", i, rng_class_names[i]);
|
||||
storesynced = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
storesynced = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
demosynced = storesynced;
|
||||
|
|
@ -1242,6 +1276,12 @@ void G_ConsGhostTic(INT32 playernum)
|
|||
}
|
||||
demosynced = false;
|
||||
|
||||
if (staffsync)
|
||||
{
|
||||
staffsync_results[staffsync_failed].numerror++;
|
||||
staffsync_results[staffsync_failed].totalerror += abs(testmo->x - oldghost[playernum].x) + abs(testmo->y - oldghost[playernum].y) + abs(testmo->z - oldghost[playernum].z);
|
||||
}
|
||||
|
||||
P_UnsetThingPosition(testmo);
|
||||
testmo->x = oldghost[playernum].x;
|
||||
testmo->y = oldghost[playernum].y;
|
||||
|
|
@ -3269,6 +3309,8 @@ void G_DoPlayDemoEx(const char *defdemoname, lumpnum_t deflumpnum)
|
|||
|
||||
// net var data
|
||||
demobuf.p += CV_LoadDemoVars(demobuf.p);
|
||||
// Dumb hack for team play desyncs - https://gitlab.com/kart-krew-dev/ring-racers/-/issues/210
|
||||
g_teamplay = cv_teamplay.value ? 1 : 0;
|
||||
|
||||
memset(&grandprixinfo, 0, sizeof grandprixinfo);
|
||||
if ((demoflags & DF_GRANDPRIX))
|
||||
|
|
|
|||
|
|
@ -1885,7 +1885,7 @@ void G_Ticker(boolean run)
|
|||
|
||||
P_MapStart();
|
||||
|
||||
if (demo.playback && staffsync && !demosynced)
|
||||
if (demo.playback && staffsync && !demosynced && false) // We want to assess the magnitude of position desync, don't bail early!
|
||||
{
|
||||
G_ClearRetryFlag();
|
||||
G_StopDemo();
|
||||
|
|
@ -2312,6 +2312,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
UINT16 bigwaypointgap;
|
||||
|
||||
INT16 duelscore;
|
||||
|
||||
boolean mfdfinish;
|
||||
|
||||
roundconditions_t roundconditions;
|
||||
boolean saveroundconditions;
|
||||
|
|
@ -2406,6 +2408,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
|
||||
totalring = players[player].totalring;
|
||||
xtralife = players[player].xtralife;
|
||||
|
||||
mfdfinish = players[player].mfdfinish;
|
||||
|
||||
pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE|PF_AUTOROULETTE|PF_ANALOGSTICK|PF_AUTORING));
|
||||
pflags2 = (players[player].pflags2 & (PF2_SELFMUTE | PF2_SELFDEAFEN | PF2_SERVERTEMPMUTE | PF2_SERVERMUTE | PF2_SERVERDEAFEN | PF2_STRICTFASTFALL));
|
||||
|
|
@ -2483,6 +2487,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
lastsafecheatcheck = 0;
|
||||
bigwaypointgap = 0;
|
||||
duelscore = 0;
|
||||
mfdfinish = 0;
|
||||
|
||||
finalized = false;
|
||||
|
||||
|
|
@ -2675,6 +2680,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
|
|||
p->xtralife = xtralife;
|
||||
|
||||
p->finalized = finalized;
|
||||
|
||||
p->mfdfinish = mfdfinish;
|
||||
|
||||
// SRB2kart
|
||||
p->itemtype = itemtype;
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ void I_OsPolling(void);
|
|||
|
||||
/** \brief Called by M_Responder when quit is selected, return exit code 0
|
||||
*/
|
||||
void I_Quit(void) FUNCNORETURN;
|
||||
FUNCNORETURN void ATTRNORETURN I_Quit(void);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
|
|
|||
29
src/info.c
29
src/info.c
|
|
@ -614,6 +614,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
|
||||
"EXPC",
|
||||
|
||||
"TWBB",
|
||||
"TWOK",
|
||||
"TW_L",
|
||||
|
||||
|
|
@ -2225,6 +2226,7 @@ state_t states[NUMSTATES] =
|
|||
{SPR_AMPD, FF_FULLBRIGHT|FF_ANIMATE|0, -1, {NULL}, 4, 2, S_NULL}, // S_AMPAURA
|
||||
{SPR_AMPB, FF_FULLBRIGHT|FF_ADD|FF_PAPERSPRITE|2, -1, {NULL}, 4, 2, S_NULL}, // S_AMPBURST
|
||||
|
||||
{SPR_TWBB, FF_ADD|FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SONICBOOM
|
||||
{SPR_TWOK, FF_FULLBRIGHT|FF_ANIMATE|0, 56, {NULL}, 55, 1, S_NULL}, // S_TRIPWIREOK
|
||||
{SPR_TW_L, FF_FULLBRIGHT|FF_ANIMATE|0, 56, {NULL}, 55, 1, S_NULL}, // S_TRIPWIRELOCKOUT
|
||||
|
||||
|
|
@ -13998,6 +14000,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_SONICBOOM
|
||||
-1, // doomednum
|
||||
S_SONICBOOM, // spawnstate
|
||||
1000, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_NULL, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_NULL, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
67*FRACUNIT, // radius
|
||||
67*FRACUNIT, // height
|
||||
1, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOCLIPHEIGHT, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_TRIPWIREOK
|
||||
-1, // doomednum
|
||||
S_TRIPWIREOK, // spawnstate
|
||||
|
|
|
|||
|
|
@ -1155,6 +1155,7 @@ typedef enum sprite
|
|||
|
||||
SPR_EXPC,
|
||||
|
||||
SPR_TWBB, // Sonic Boom
|
||||
SPR_TWOK, // Tripwire OK
|
||||
SPR_TW_L, // Tripwire Lockout
|
||||
|
||||
|
|
@ -2681,6 +2682,7 @@ typedef enum state
|
|||
S_AMPAURA,
|
||||
S_AMPBURST,
|
||||
|
||||
S_SONICBOOM,
|
||||
S_TRIPWIREOK,
|
||||
S_TRIPWIRELOCKOUT,
|
||||
|
||||
|
|
@ -4706,6 +4708,7 @@ typedef enum mobj_type
|
|||
MT_AMPAURA,
|
||||
MT_AMPBURST,
|
||||
|
||||
MT_SONICBOOM,
|
||||
MT_TRIPWIREOK,
|
||||
MT_TRIPWIRELOCKOUT,
|
||||
|
||||
|
|
|
|||
|
|
@ -133,8 +133,12 @@ void K_CheckBumpers(void)
|
|||
{
|
||||
UINT8 i;
|
||||
UINT8 numingame = 0;
|
||||
UINT8 rednumingame = 0;
|
||||
UINT8 bluenumingame = 0;
|
||||
UINT8 nobumpers = 0;
|
||||
UINT8 eliminated = 0;
|
||||
UINT8 redeliminated = 0;
|
||||
UINT8 blueeliminated = 0;
|
||||
SINT8 kingofthehill = -1;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
|
|
@ -143,6 +147,8 @@ void K_CheckBumpers(void)
|
|||
if (gameaction == ga_completed)
|
||||
return;
|
||||
|
||||
boolean team = G_GametypeHasTeams();
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator) // not even in-game
|
||||
|
|
@ -152,6 +158,11 @@ void K_CheckBumpers(void)
|
|||
return;
|
||||
|
||||
numingame++;
|
||||
if (team)
|
||||
{
|
||||
if (players[i].team == 1) rednumingame++;
|
||||
if (players[i].team == 2) bluenumingame++;
|
||||
}
|
||||
|
||||
if (!P_MobjWasRemoved(players[i].mo) && players[i].mo->health <= 0) // if you don't have any bumpers, you're probably not a winner
|
||||
{
|
||||
|
|
@ -161,6 +172,11 @@ void K_CheckBumpers(void)
|
|||
if (players[i].pflags & PF_ELIMINATED)
|
||||
{
|
||||
eliminated++;
|
||||
if (team)
|
||||
{
|
||||
if (players[i].team == 1) redeliminated++;
|
||||
else if (players[i].team == 2) blueeliminated++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -168,6 +184,12 @@ void K_CheckBumpers(void)
|
|||
}
|
||||
}
|
||||
|
||||
boolean teamwin = false;
|
||||
if (team && (rednumingame - redeliminated == 0 || bluenumingame - blueeliminated == 0))
|
||||
{
|
||||
teamwin = true;
|
||||
}
|
||||
|
||||
if (numingame - eliminated == 2 && battleovertime.enabled && battleovertime.radius <= BARRIER_MIN_RADIUS)
|
||||
{
|
||||
Music_Stop("battle_overtime");
|
||||
|
|
@ -186,9 +208,28 @@ void K_CheckBumpers(void)
|
|||
{
|
||||
// If every other player is eliminated, the
|
||||
// last player standing wins by default.
|
||||
if (eliminated >= numingame - 1)
|
||||
// Or, if an entire team is eliminated.
|
||||
if (eliminated >= numingame - 1 || teamwin)
|
||||
{
|
||||
K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL);
|
||||
if (teamwin)
|
||||
{
|
||||
// Find the player with the highest individual score
|
||||
UINT32 highestscore = 0;
|
||||
UINT32 highestplayer = 0;
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] && players[i].score > highestscore)
|
||||
{
|
||||
highestplayer = i;
|
||||
highestscore = players[i].score;
|
||||
}
|
||||
}
|
||||
K_EndBattleRound(&players[highestplayer]);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1034,10 +1034,6 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
|
|||
}
|
||||
|
||||
// if you're here, you're getting hit
|
||||
// Damage is a bit hacky, we want only a small loss-of-control
|
||||
// while still behaving as if it's a "real" hit.
|
||||
P_PlayRinglossSound(victim);
|
||||
P_PlayerRingBurst(victimPlayer, 5);
|
||||
P_DamageMobj(victim, shield, attacker, 1, DMG_WHUMBLE);
|
||||
|
||||
K_DropPowerUps(victimPlayer);
|
||||
|
|
@ -1293,8 +1289,15 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
auto doStumble = [](mobj_t *t1, mobj_t *t2)
|
||||
{
|
||||
K_StumblePlayer(t2->player);
|
||||
K_SpawnAmps(t1->player, K_PvPAmpReward(20, t1->player, t2->player), t2);
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
K_StumblePlayer(t2->player);
|
||||
K_SpawnAmps(t1->player, K_PvPAmpReward(20, t1->player, t2->player), t2);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1, 1, DMG_WHUMBLE);
|
||||
}
|
||||
};
|
||||
|
||||
if (forEither(shouldStumble, doStumble))
|
||||
|
|
@ -1325,7 +1328,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
|
|||
|
||||
bool stung = false;
|
||||
|
||||
if (RINGTOTAL(t2->player) <= 0 && t2->health == 1 && !(t2->player->pflags2 & PF2_UNSTINGABLE))
|
||||
if (RINGTOTAL(t2->player) <= 0 && t2->player->ringboostinprogress == 0 && t2->health == 1 && !(t2->player->pflags2 & PF2_UNSTINGABLE))
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1, 1, DMG_STING|DMG_WOMBO);
|
||||
// CONS_Printf("T2 stung\n");
|
||||
|
|
|
|||
|
|
@ -22,6 +22,26 @@
|
|||
#include "s_sound.h"
|
||||
#include "m_easing.h"
|
||||
|
||||
// Use for adding hitlag that should be mostly ignored by impervious players.
|
||||
// (Currently only called in power clash, but in the future...?)
|
||||
void K_AddHitLagFromCollision(mobj_t *mo, INT32 tics)
|
||||
{
|
||||
boolean doAnything = true;
|
||||
|
||||
if (mo->player == NULL || mo->type != MT_PLAYER)
|
||||
doAnything = false;
|
||||
else if (!K_PlayerCanPunt(mo->player))
|
||||
doAnything = false;
|
||||
|
||||
if (!doAnything)
|
||||
{
|
||||
K_AddHitLag(mo, tics, false);
|
||||
return;
|
||||
}
|
||||
|
||||
K_AddHitLag(mo, min(tics, 2), false);
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage)
|
||||
|
||||
|
|
@ -34,9 +54,6 @@ void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mo->player && mo->player->overshield)
|
||||
tics = min(tics, 3);
|
||||
|
||||
mo->hitlag += tics;
|
||||
mo->hitlag = min(mo->hitlag, MAXHITLAGTICS);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ extern "C" {
|
|||
#define NUM_HITLAG_STATES (9)
|
||||
#define NUM_HITLAG_SOUNDS (4)
|
||||
|
||||
void K_AddHitLagFromCollision(mobj_t *mo, INT32 tics);
|
||||
|
||||
/*--------------------------------------------------
|
||||
void K_AddHitLag(mobj_t *mo, INT32 tics, boolean fromDamage);
|
||||
|
||||
|
|
|
|||
|
|
@ -3307,19 +3307,13 @@ static void K_drawKartEmeralds(void)
|
|||
|
||||
INT32 K_GetTransFlagFromFixed(fixed_t value, boolean midrace)
|
||||
{
|
||||
fixed_t base = midrace ? GRADINGFACTORSOFTCAP : FRACUNIT;
|
||||
fixed_t base = FRACUNIT;
|
||||
|
||||
value = std::clamp(value, base - FRACUNIT/2, base + FRACUNIT/2);
|
||||
|
||||
// Calculate distance from "base""
|
||||
fixed_t distance = abs(base - value);
|
||||
|
||||
if (midrace)
|
||||
{
|
||||
if (value > base)
|
||||
distance = FixedMul(distance, GRADINGFACTORCAPSTRENGTH);
|
||||
}
|
||||
|
||||
distance = std::clamp(distance, 0, FRACUNIT/2);
|
||||
|
||||
// Map the distance to 0-10 range (10 = closest to 1.0, 0 = farthest from 1.0)
|
||||
|
|
@ -5189,7 +5183,7 @@ static void K_drawKartPlayerCheck(void)
|
|||
continue;
|
||||
}
|
||||
|
||||
if ((checkplayer->invincibilitytimer <= 0) && (leveltime & 2))
|
||||
if ((checkplayer->invincibilitytimer <= 0) && (leveltime & 2) && !(cv_reducevfx.value))
|
||||
{
|
||||
pnum++; // white frames
|
||||
}
|
||||
|
|
@ -7172,11 +7166,13 @@ static void K_drawLapStartAnim(void)
|
|||
oldval = (188 + (32 * std::max(0, progressOld - 76))) * FRACUNIT;
|
||||
interpx = R_InterpolateFixed(oldval, newval);
|
||||
|
||||
UINT32 sanitizedlaps = std::min((UINT32)99, (UINT32)stplyr->latestlap);
|
||||
|
||||
V_DrawFixedPatch(
|
||||
interpx, // 194
|
||||
30*FRACUNIT, // 24
|
||||
FRACUNIT, V_SNAPTOTOP|hudtransflags,
|
||||
kp_lapanim_number[(((UINT32)stplyr->latestlap) / 10)][std::min(progress/2-8, 2)], NULL);
|
||||
kp_lapanim_number[(sanitizedlaps / 10)][std::min(progress/2-8, 2)], NULL);
|
||||
|
||||
if (progress/2-10 >= 0)
|
||||
{
|
||||
|
|
@ -7188,7 +7184,7 @@ static void K_drawLapStartAnim(void)
|
|||
interpx, // 221
|
||||
30*FRACUNIT, // 24
|
||||
FRACUNIT, V_SNAPTOTOP|hudtransflags,
|
||||
kp_lapanim_number[(((UINT32)stplyr->latestlap) % 10)][std::min(progress/2-10, 2)], NULL);
|
||||
kp_lapanim_number[(sanitizedlaps % 10)][std::min(progress/2-10, 2)], NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7311,7 +7307,21 @@ static void K_drawDistributionDebugger(void)
|
|||
return;
|
||||
}
|
||||
|
||||
K_FillItemRouletteData(stplyr, &rouletteData, false, true);
|
||||
{
|
||||
// GROSS GROSS GROSS GROSS copypaste from K_FillItemRoulette
|
||||
// but without the potential for Lua side-effects etc.
|
||||
// This sucks the ass.
|
||||
K_InitRoulette(&rouletteData);
|
||||
|
||||
rouletteData.baseDist = K_UndoMapScaling(stplyr->distancetofinish);
|
||||
|
||||
if (stplyr->pflags & PF_AUTOROULETTE)
|
||||
rouletteData.autoroulette = true;
|
||||
|
||||
K_CalculateRouletteSpeed(&rouletteData);
|
||||
|
||||
K_FillItemRouletteData(stplyr, &rouletteData, false, true);
|
||||
}
|
||||
|
||||
if (cv_kartdebugdistribution.value <= 1)
|
||||
return;
|
||||
|
|
@ -7772,7 +7782,7 @@ void K_drawKartHUD(void)
|
|||
return;
|
||||
}
|
||||
|
||||
if (staffsync)
|
||||
if (staffsync && staffsync_total)
|
||||
{
|
||||
V_DrawFadeScreen(31, 8);
|
||||
V_DrawCenteredGamemodeString(BASEVIDWIDTH/2, BASEVIDHEIGHT/2 - 30, 0, 0, "Staff Ghost Sync Test");
|
||||
|
|
|
|||
264
src/k_kart.c
264
src/k_kart.c
|
|
@ -158,9 +158,8 @@ fixed_t K_EffectiveGradingFactor(const player_t *player)
|
|||
return min;
|
||||
|
||||
fixed_t gf = player->gradingfactor;
|
||||
|
||||
if (gf > GRADINGFACTORSOFTCAP && !K_PlayerUsesBotMovement(player))
|
||||
gf = GRADINGFACTORSOFTCAP + FixedDiv(gf - GRADINGFACTORSOFTCAP, GRADINGFACTORCAPSTRENGTH);
|
||||
if (franticitems)
|
||||
gf = (gf + FRACUNIT)/2;
|
||||
|
||||
return max(min, gf);
|
||||
}
|
||||
|
|
@ -508,7 +507,7 @@ boolean K_IsPlayerLosing(player_t *player)
|
|||
}
|
||||
|
||||
// Some behavior should change if the player approaches the frontrunner unusually fast.
|
||||
fixed_t K_PlayerScamPercentage(const player_t *player, UINT8 mult)
|
||||
fixed_t K_PlayerScamPercentage(const player_t *player, fixed_t mult)
|
||||
{
|
||||
if (!M_NotFreePlay())
|
||||
return 0;
|
||||
|
|
@ -523,7 +522,7 @@ fixed_t K_PlayerScamPercentage(const player_t *player, UINT8 mult)
|
|||
// "Why 2000?" Vibes
|
||||
|
||||
UINT32 distance = K_GetItemRouletteDistance(player, 8);
|
||||
UINT32 scamdistance = mult * SCAMDIST;
|
||||
UINT32 scamdistance = FixedMul(mult, SCAMDIST*FRACUNIT)/FRACUNIT;
|
||||
|
||||
if (distance >= scamdistance)
|
||||
return 0;
|
||||
|
|
@ -3172,26 +3171,70 @@ boolean K_SlopeResistance(const player_t *player)
|
|||
|
||||
fixed_t K_PlayerTripwireSpeedThreshold(const player_t *player)
|
||||
{
|
||||
fixed_t required_speed = 2 * K_GetKartSpeed(player, false, false); // 200%
|
||||
fixed_t base_speed = K_GetKartSpeed(player, false, false);
|
||||
fixed_t required_speed = 9 * base_speed / 4; // 225%
|
||||
|
||||
// 200% in Easy / Tutorial
|
||||
if (gamespeed == KARTSPEED_EASY)
|
||||
required_speed = 2 * base_speed;
|
||||
|
||||
if (K_LegacyRingboost(player))
|
||||
return required_speed;
|
||||
return 2 * base_speed;
|
||||
|
||||
// 150% in special
|
||||
if (specialstageinfo.valid)
|
||||
required_speed = 3 * K_GetKartSpeed(player, false, false) / 2; // 150%
|
||||
required_speed = 3 * base_speed / 2;
|
||||
|
||||
// 400% in Time Attack
|
||||
if (modeattacking && !(gametyperules & GTR_CATCHER))
|
||||
required_speed = 4 * K_GetKartSpeed(player, false, false);
|
||||
required_speed = 4 * base_speed;
|
||||
|
||||
// Race
|
||||
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative() && M_NotFreePlay() && !modeattacking)
|
||||
{
|
||||
required_speed += FixedMul(required_speed, K_PlayerScamPercentage(player, 2)); // Proration: Players near 1st need more speed!
|
||||
}
|
||||
/*
|
||||
All of this will be for making Sonic Boom easier when you're drowning in the back, like a "reverse" proration
|
||||
*/
|
||||
|
||||
if (player->offroad && K_ApplyOffroad(player))
|
||||
{
|
||||
// Increase to 300% if you're lawnmowering.
|
||||
required_speed = (required_speed * 3) / 2;
|
||||
#define REVERSED_SONICBOOM_PRORATION (30000)
|
||||
#define MAX_SONICBOOM_REDUCTION (8*FRACUNIT/10)
|
||||
|
||||
UINT32 dist = K_GetItemRouletteDistance(player, D_NumPlayersInRace());
|
||||
|
||||
if (dist > REVERSED_SONICBOOM_PRORATION)
|
||||
{
|
||||
dist = REVERSED_SONICBOOM_PRORATION;
|
||||
}
|
||||
|
||||
fixed_t distfactor = FixedDiv(dist, REVERSED_SONICBOOM_PRORATION); //
|
||||
fixed_t sonicboom_aid = Easing_InCubic(distfactor, FRACUNIT, MAX_SONICBOOM_REDUCTION);
|
||||
|
||||
required_speed = FixedMul(sonicboom_aid, required_speed);
|
||||
|
||||
/*
|
||||
And then all of this will be for making it harder when you're in scam range, actual proration
|
||||
*/
|
||||
|
||||
fixed_t scamcheck_in_2p = 3*FRACUNIT/2; // Lower values = need to be closer to be scamming
|
||||
fixed_t scamcheck_in_16p = 5*FRACUNIT/2; // Higher values = tripwire threshold goes up when further away
|
||||
fixed_t scamscaler = FixedRescale(D_NumPlayersInRace(), 2, 16, Easing_Linear, scamcheck_in_2p, scamcheck_in_16p);
|
||||
required_speed += FixedMul(required_speed, K_PlayerScamPercentage(player, scamscaler));
|
||||
|
||||
if (player->position == 1)
|
||||
{
|
||||
required_speed = 9 * K_GetKartSpeed(player, false, false); // Seek employment
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!K_PlayerUsesBotMovement(player)) // Sonic Boom debug
|
||||
{
|
||||
//CONS_Printf("Sonic Boom threshold: %d percent, IN FRACUNIT: %d \n", ((required_speed *100) / K_GetKartSpeed(player, false, false)), required_speed);
|
||||
CONS_Printf("D=%d DF=%d SBA=%d SCAM=%d RRS=%d\n", dist, distfactor, sonicboom_aid, K_PlayerScamPercentage(player, scamscaler), required_speed * 100 / base_speed);
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef REVERSED_SONICBOOM_PRORATION
|
||||
#undef MAX_SONICBOOM_REDUCTION
|
||||
}
|
||||
|
||||
if (player->botvars.rubberband > FRACUNIT && K_PlayerUsesBotMovement(player) == true)
|
||||
|
|
@ -3670,7 +3713,7 @@ static void K_GetKartBoostPower(player_t *player)
|
|||
boostpower = (4*boostpower)/5;
|
||||
|
||||
if (player->stonedrag)
|
||||
boostpower = (4*boostpower)/5;
|
||||
boostpower = (70*boostpower)/100;
|
||||
|
||||
// Note: Handling will ONLY stack when sliptiding!
|
||||
// > (NB 2023-03-06: This was previously unintentionally applied while drifting as well.)
|
||||
|
|
@ -4498,6 +4541,15 @@ void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact)
|
|||
if (exp == 0)
|
||||
return;
|
||||
|
||||
boolean special = false;
|
||||
|
||||
if (player->gradingpointnum == K_GetNumGradingPoints())
|
||||
{
|
||||
exp *= 3;
|
||||
special = true;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < exp; i++)
|
||||
{
|
||||
mobj_t *pickup = P_SpawnMobj(impact->x, impact->y, impact->z, MT_EXP);
|
||||
|
|
@ -4508,6 +4560,14 @@ void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact)
|
|||
pickup->momy += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale);
|
||||
pickup->momz += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale);
|
||||
// pickup->color = player->skincolor;
|
||||
|
||||
if (special)
|
||||
{
|
||||
P_InstaScale(pickup, 3*pickup->scale/2);
|
||||
pickup->color = SKINCOLOR_SAPPHIRE;
|
||||
pickup->colorized = true;
|
||||
}
|
||||
|
||||
P_SetTarget(&pickup->target, player->mo);
|
||||
}
|
||||
}
|
||||
|
|
@ -4717,7 +4777,7 @@ void K_CheckpointCrossAward(player_t *player)
|
|||
K_HandleRaceSplits(player, leveltime - starttime, player->gradingpointnum);
|
||||
}
|
||||
|
||||
player->gradingfactor += K_GetGradingFactorAdjustment(player);
|
||||
player->gradingfactor += K_GetGradingFactorAdjustment(player, player->gradingpointnum);
|
||||
player->gradingpointnum++;
|
||||
player->exp = K_GetEXP(player);
|
||||
//CONS_Printf("player: %s factor: %.2f exp: %d\n", player_names[player-players], FIXED_TO_FLOAT(player->gradingfactor), player->exp);
|
||||
|
|
@ -4908,8 +4968,10 @@ void K_DoInstashield(player_t *player)
|
|||
|
||||
void K_DoPowerClash(mobj_t *t1, mobj_t *t2) {
|
||||
mobj_t *clash;
|
||||
UINT8 lag1 = 5;
|
||||
UINT8 lag2 = 5;
|
||||
UINT8 lag1 = 10; // Base value used for kartitem-to-player collision.
|
||||
UINT8 lag2 = 10; // We want to preserve shooting invinc players to hinder them!
|
||||
boolean slow1 = false; // If we _are_ hitting a kartitem, keep that value.
|
||||
boolean slow2 = false; // Otherwise, route to K_AddHitLagFromCollision.
|
||||
|
||||
boolean stripbubble = (gametyperules & GTR_BUMPERS);
|
||||
|
||||
|
|
@ -4917,24 +4979,32 @@ void K_DoPowerClash(mobj_t *t1, mobj_t *t2) {
|
|||
if (t1->player)
|
||||
{
|
||||
t1->player->instashield = 1;
|
||||
t1->player->speedpunt += 20;
|
||||
lag1 -= min(lag1, t1->player->speedpunt/10);
|
||||
if (stripbubble && t1->player->curshield == KSHIELD_BUBBLE)
|
||||
K_PopBubbleShield(t1->player);
|
||||
if (P_IsKartFieldItem(t2->type))
|
||||
slow1 = true;
|
||||
}
|
||||
|
||||
if (t2->player)
|
||||
{
|
||||
t2->player->instashield = 1;
|
||||
t2->player->speedpunt += 20;
|
||||
lag2 -= min(lag1, t2->player->speedpunt/10);
|
||||
if (stripbubble && t2->player->curshield == KSHIELD_BUBBLE)
|
||||
K_PopBubbleShield(t2->player);
|
||||
if (P_IsKartFieldItem(t1->type))
|
||||
slow2 = true;
|
||||
}
|
||||
|
||||
S_StartSound(t1, sfx_parry);
|
||||
K_AddHitLag(t1, lag1+1, false);
|
||||
K_AddHitLag(t2, lag2+1, false);
|
||||
|
||||
if (slow1)
|
||||
K_AddHitLag(t1, lag1, false);
|
||||
else
|
||||
K_AddHitLagFromCollision(t1, lag1);
|
||||
|
||||
if (slow2)
|
||||
K_AddHitLag(t2, lag2, false);
|
||||
else
|
||||
K_AddHitLagFromCollision(t2, lag2);
|
||||
|
||||
clash = P_SpawnMobj((t1->x/2) + (t2->x/2), (t1->y/2) + (t2->y/2), (t1->z/2) + (t2->z/2), MT_POWERCLASH);
|
||||
|
||||
|
|
@ -5848,7 +5918,7 @@ void K_ApplyTripWire(player_t *player, tripwirestate_t state)
|
|||
|
||||
if (player->hyudorotimer <= 0)
|
||||
{
|
||||
K_AddHitLag(player->mo, 10, false);
|
||||
K_AddHitLag(player->mo, (state == TRIPSTATE_PASSED) ? 2 : 10, false);
|
||||
player->mo->hitlag -= min(player->mo->hitlag, player->tripwireUnstuck/4);
|
||||
}
|
||||
|
||||
|
|
@ -9672,7 +9742,7 @@ static void K_UpdateTripwire(player_t *player)
|
|||
tripwirepass_t triplevel = K_TripwirePassConditions(player);
|
||||
boolean mightplaysound = false;
|
||||
|
||||
if (triplevel != TRIPWIRE_NONE)
|
||||
if (triplevel != TRIPWIRE_NONE) // Sonic Boom, able to pass tripwire
|
||||
{
|
||||
if (!boostExists)
|
||||
{
|
||||
|
|
@ -9767,7 +9837,7 @@ boolean K_PressingEBrake(const player_t *player)
|
|||
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
||||
{
|
||||
const boolean onground = P_IsObjectOnGround(player->mo);
|
||||
const fixed_t scamming = K_PlayerScamPercentage(player, 1);
|
||||
const fixed_t scamming = K_PlayerScamPercentage(player, FRACUNIT);
|
||||
|
||||
/* reset sprite offsets :) */
|
||||
player->mo->sprxoff = 0;
|
||||
|
|
@ -9878,7 +9948,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
{
|
||||
mobj_t *ghost;
|
||||
ghost = P_SpawnGhostMobj(player->mo);
|
||||
ghost->extravalue1 = player->numboosts+1;
|
||||
ghost->extravalue1 = player->numboosts;
|
||||
ghost->extravalue2 = (leveltime % ghost->extravalue1);
|
||||
ghost->fuse = ghost->extravalue1;
|
||||
ghost->renderflags |= RF_FULLBRIGHT;
|
||||
|
|
@ -9915,7 +9985,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
// Race: spawn ring debt indicator
|
||||
// Battle: spawn zero-bumpers indicator
|
||||
if (!(player->pflags2 & PF2_UNSTINGABLE) && ((gametyperules & GTR_SPHERES) ? player->mo->health <= 1 : RINGTOTAL(player) <= 0))
|
||||
if (!(player->pflags2 & PF2_UNSTINGABLE) && player->ringboostinprogress == 0 && ((gametyperules & GTR_SPHERES) ? player->mo->health <= 1 : RINGTOTAL(player) <= 0))
|
||||
{
|
||||
UINT8 doubler;
|
||||
|
||||
|
|
@ -10446,7 +10516,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->tricklock = 0;
|
||||
}
|
||||
|
||||
if (P_PlayerInPain(player) || player->respawn.state != RESPAWNST_NONE)
|
||||
if ((P_PlayerInPain(player) && G_CompatLevel(0x0010)) || player->respawn.state != RESPAWNST_NONE)
|
||||
{
|
||||
player->ringboost = 0;
|
||||
}
|
||||
|
|
@ -10474,6 +10544,11 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// CONS_Printf("%d - %d\n", player->ringboost, oldringboost - player->ringboost);
|
||||
}
|
||||
|
||||
if (!G_CompatLevel(0x0010) && player->superring == 0 && player->ringboxdelay == 0 && player->ringboost < player->lastringboost)
|
||||
{
|
||||
player->lastringboost = player->ringboost;
|
||||
}
|
||||
|
||||
if (player->sneakertimer)
|
||||
{
|
||||
player->sneakertimer--;
|
||||
|
|
@ -10507,10 +10582,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
if (player->trickboost)
|
||||
player->trickboost--;
|
||||
|
||||
/*
|
||||
if (K_PlayerUsesBotMovement(player) && player->botvars.bumpslow && player->incontrol)
|
||||
player->botvars.bumpslow--;
|
||||
*/
|
||||
|
||||
// WHOOPS! 2.4 bots were tuned around a bugged version of bumpslow that NEVER decayed
|
||||
// if the player in slot 0 was a human. People seem to like this tuning, but the dampened
|
||||
|
|
@ -10520,8 +10591,17 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
// I'd like to retune this later, but for now, just set bumpslow on every bot, as if they all
|
||||
// contact a wall instantly—consistently giving them the softer rubberband advancement.
|
||||
// What the fuck making games is hard.
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
player->botvars.bumpslow = TICRATE*2;
|
||||
if (G_CompatLevel(0x0010))
|
||||
{
|
||||
// Backwards compatibility for bot takeover in staff ghosts.
|
||||
if (K_PlayerUsesBotMovement(player) && player->botvars.bumpslow && player->incontrol)
|
||||
player->botvars.bumpslow--;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
player->botvars.bumpslow = TICRATE*2;
|
||||
}
|
||||
|
||||
|
||||
if (player->flamedash)
|
||||
|
|
@ -10639,13 +10719,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
player->wavedashpower = FRACUNIT; // Safety
|
||||
}
|
||||
|
||||
if (player->speedpunt)
|
||||
player->speedpunt--;
|
||||
|
||||
// This timer can get out of control fast, clamp to match player expectations about "new" hazards
|
||||
if (player->speedpunt > TICRATE*4)
|
||||
player->speedpunt = TICRATE*4;
|
||||
|
||||
if (player->trickcharge > 0 && onground == true)
|
||||
{
|
||||
player->trickcharge--;
|
||||
|
|
@ -10685,6 +10758,9 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->ringboostinprogress)
|
||||
player->ringboostinprogress--;
|
||||
|
||||
if (player->baildrop)
|
||||
{
|
||||
// freeze the stunned timer while baildrop is active
|
||||
|
|
@ -10791,6 +10867,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
player->itemamount = 0;
|
||||
player->itemtype = 0;
|
||||
player->rocketsneakertimer = 0;
|
||||
|
||||
/*
|
||||
if (player->itemamount)
|
||||
|
|
@ -10814,7 +10891,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
|
||||
INT32 fls = K_GetEffectiveFollowerSkin(player);
|
||||
if (player->follower && fls >= 0 && fls < numfollowers)
|
||||
if (player->follower && fls >= 0 && fls < numfollowers && cv_karthorns.value)
|
||||
{
|
||||
const follower_t *fl = &followers[fls];
|
||||
S_StartSound(player->follower, fl->hornsound);
|
||||
|
|
@ -13565,7 +13642,7 @@ static INT32 K_FlameShieldMax(player_t *player)
|
|||
|
||||
disttofinish = K_GetItemRouletteDistance(player, 8);
|
||||
|
||||
if (D_NumPlayersInRace() <= 1)
|
||||
if (D_NumPlayersInRace() <= 1 || (gametyperules & GTR_CATCHER) || (gametype == GT_TUTORIAL))
|
||||
{
|
||||
return FLAMESHIELD_MAX; // max when alone, for testing
|
||||
// and when in battle, for chaos
|
||||
|
|
@ -14049,12 +14126,19 @@ static void K_KartSpindash(player_t *player)
|
|||
}
|
||||
else if (!G_CompatLevel(0x0010))
|
||||
{
|
||||
boolean ebrakelasttic = ((player->oldcmd.buttons & BT_EBRAKEMASK) == BT_EBRAKEMASK);
|
||||
if (player->pflags2 & PF2_STRICTFASTFALL)
|
||||
ebrakelasttic = (player->oldcmd.buttons & BT_SPINDASH);
|
||||
UINT16 oldbuttons = player->oldcmd.buttons;
|
||||
UINT16 nowbuttons = K_GetKartButtons(player);
|
||||
|
||||
if (K_KartKickstart(player))
|
||||
oldbuttons |= BT_ACCELERATE; // Not strictly correct, but better than nothing.
|
||||
// Kickstart needs substantial attention if we want this sort of thing to be clean.
|
||||
|
||||
boolean ebrakelasttic = ((oldbuttons & BT_EBRAKEMASK) == BT_EBRAKEMASK);
|
||||
if (player->pflags2 & PF2_STRICTFASTFALL && !(oldbuttons & BT_SPINDASH))
|
||||
ebrakelasttic = false;
|
||||
|
||||
boolean ebrakenow = K_PressingEBrake(player);
|
||||
if (player->pflags2 & PF2_STRICTFASTFALL && !(player->cmd.buttons & BT_SPINDASH))
|
||||
if (player->pflags2 & PF2_STRICTFASTFALL && !(nowbuttons & BT_SPINDASH))
|
||||
ebrakenow = false;
|
||||
|
||||
if (!ebrakelasttic && ebrakenow && player->fastfall && player->transfer)
|
||||
|
|
@ -14844,7 +14928,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
if (player->cmd.buttons & BT_BAIL && (player->cmd.buttons & BT_RESPAWNMASK) != BT_RESPAWNMASK)
|
||||
{
|
||||
if (leveltime < introtime || (gametyperules & GTR_SPHERES) || modeattacking || player->markedfordeath
|
||||
|| player->respawn.state != RESPAWNST_NONE)
|
||||
|| player->respawn.state != RESPAWNST_NONE || player->baildrop)
|
||||
{
|
||||
// No bailing in GTR_SPHERES because I cannot be fucked to do manual Last Chance right now.
|
||||
// Maybe someday!
|
||||
|
|
@ -14971,6 +15055,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
P_SetOrigin(ring, ring->x, ring->y, ring->z);
|
||||
ring->extravalue1 = 1;
|
||||
player->ringboostinprogress = 25;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -15498,7 +15583,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
}
|
||||
|
||||
player->growshrinktimer = max(0, player->growshrinktimer);
|
||||
player->growshrinktimer += ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE;
|
||||
player->growshrinktimer = max(player->growshrinktimer + 5*TICRATE, ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE);
|
||||
|
||||
S_StartSound(player->mo, sfx_kc5a);
|
||||
|
||||
|
|
@ -17028,6 +17113,16 @@ boolean K_PlayerCanPunt(player_t *player)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (player->overshield > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->lightningcharge > 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (player->tripwirePass >= TRIPWIRE_BLASTER && player->speed >= K_PlayerTripwireSpeedThreshold(player))
|
||||
{
|
||||
return true;
|
||||
|
|
@ -17083,7 +17178,19 @@ static UINT8 K_Opponents(player_t *player)
|
|||
return opponents;
|
||||
}
|
||||
|
||||
static fixed_t K_GradingFactorPower(player_t *player)
|
||||
fixed_t K_FinalCheckpointPower(void)
|
||||
{
|
||||
// How much of the final total is given out as a bonus for the last check?
|
||||
fixed_t FINAL_CHECK_PERCENT = 25*FRACUNIT/100;
|
||||
|
||||
fixed_t theentirerace = K_GetNumGradingPoints()*FRACUNIT;
|
||||
fixed_t theentireraceplusbonus = FixedDiv(theentirerace, FRACUNIT - FINAL_CHECK_PERCENT);
|
||||
fixed_t bonusonly = theentireraceplusbonus - theentirerace;
|
||||
|
||||
return bonusonly;
|
||||
}
|
||||
|
||||
static fixed_t K_GradingFactorPower(player_t *player, UINT32 gradingpoint)
|
||||
{
|
||||
fixed_t power = EXP_POWER; // adjust to change overall exp volatility
|
||||
UINT8 opponents = K_Opponents(player);
|
||||
|
|
@ -17097,23 +17204,30 @@ static fixed_t K_GradingFactorPower(player_t *player)
|
|||
if (opponents > 8)
|
||||
power -= (opponents - 8) * (power/24);
|
||||
|
||||
UINT32 gp = K_GetNumGradingPoints();
|
||||
|
||||
if (gradingpoint-1 == gp)
|
||||
{
|
||||
power += FixedMul(power, K_FinalCheckpointPower());
|
||||
}
|
||||
|
||||
return power;
|
||||
}
|
||||
|
||||
static fixed_t K_GradingFactorGainPerWin(player_t *player)
|
||||
static fixed_t K_GradingFactorGainPerWin(player_t *player, UINT32 gradingpoint)
|
||||
{
|
||||
return K_GradingFactorPower(player);
|
||||
return K_GradingFactorPower(player, gradingpoint);
|
||||
}
|
||||
|
||||
static fixed_t K_GradingFactorDrainPerCheckpoint(player_t *player)
|
||||
static fixed_t K_GradingFactorDrainPerCheckpoint(player_t *player, UINT32 gradingpoint)
|
||||
{
|
||||
// EXP_STABLERATE: How low do you have to place before losing gradingfactor? 4*FRACUNIT/10 = top 40% of race gains, 60% loses.
|
||||
UINT8 opponents = K_Opponents(player);
|
||||
fixed_t power = K_GradingFactorPower(player);
|
||||
fixed_t power = K_GradingFactorPower(player, gradingpoint);
|
||||
return FixedMul(power, FixedMul(opponents*FRACUNIT, FRACUNIT - EXP_STABLERATE));
|
||||
}
|
||||
|
||||
fixed_t K_GetGradingFactorAdjustment(player_t *player)
|
||||
fixed_t K_GetGradingFactorAdjustment(player_t *player, UINT32 gradingpoint)
|
||||
{
|
||||
fixed_t result = 0;
|
||||
|
||||
|
|
@ -17124,13 +17238,13 @@ fixed_t K_GetGradingFactorAdjustment(player_t *player)
|
|||
continue;
|
||||
|
||||
if (player->position < players[i].position)
|
||||
result += K_GradingFactorGainPerWin(player);
|
||||
result += K_GradingFactorGainPerWin(player, gradingpoint);
|
||||
}
|
||||
|
||||
// ...then take all of the gradingfactor you could possibly have earned,
|
||||
// and lose it proportional to the stable rate. If you're below
|
||||
// the stable threshold, this results in you losing gradingfactor
|
||||
result -= K_GradingFactorDrainPerCheckpoint(player);
|
||||
result -= K_GradingFactorDrainPerCheckpoint(player, gradingpoint);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -17144,8 +17258,8 @@ fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max)
|
|||
for (UINT8 i = 0; i < player->gradingpointnum; i++) // For each gradingpoint you've reached...
|
||||
{
|
||||
for (UINT8 j = 0; j < winning; j++)
|
||||
factor += K_GradingFactorGainPerWin(player); // If max, increase gradingfactor for each player you could have been beating.
|
||||
factor -= K_GradingFactorDrainPerCheckpoint(player); // Then, drain like usual.
|
||||
factor += K_GradingFactorGainPerWin(player, i); // If max, increase gradingfactor for each player you could have been beating.
|
||||
factor -= K_GradingFactorDrainPerCheckpoint(player, i); // Then, drain like usual.
|
||||
}
|
||||
|
||||
return factor;
|
||||
|
|
@ -17153,19 +17267,33 @@ fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max)
|
|||
|
||||
UINT16 K_GetEXP(player_t *player)
|
||||
{
|
||||
fixed_t gradingpointnum = FRACUNIT * player->gradingpointnum;
|
||||
|
||||
UINT32 numgradingpoints = K_GetNumGradingPoints();
|
||||
fixed_t targetminexp = (EXP_MIN*player->gradingpointnum<<FRACBITS) / max(1,numgradingpoints); // about what a last place player should be at this stage of the race
|
||||
fixed_t targetmaxexp = (EXP_MAX*player->gradingpointnum<<FRACBITS) / max(1,numgradingpoints); // about what a 1.0 factor should be at this stage of the race
|
||||
fixed_t fixedgradingpoints = numgradingpoints * FRACUNIT;
|
||||
fixed_t effgradingpoints = fixedgradingpoints + K_FinalCheckpointPower();
|
||||
|
||||
// Account for Final Check bonus
|
||||
if (player->gradingpointnum == numgradingpoints)
|
||||
gradingpointnum = effgradingpoints;
|
||||
|
||||
// fixed_t targetminexp = (EXP_MIN*gpn<<FRACBITS) / max(1,effgradingpoints); // about what a last place player should be at this stage of the race
|
||||
// fixed_t targetmaxexp = (EXP_MAX*gpn<<FRACBITS) / max(1,effgradingpoints); // about what a 1.0 factor should be at this stage of the race
|
||||
fixed_t targetminexp = FixedDiv(EXP_MIN * gradingpointnum, max(FRACUNIT, effgradingpoints));
|
||||
fixed_t targetmaxexp = FixedDiv(EXP_MAX * gradingpointnum, max(FRACUNIT, effgradingpoints));
|
||||
fixed_t factormin = K_GetGradingFactorMinMax(player, false);
|
||||
fixed_t factormax = K_GetGradingFactorMinMax(player, true);
|
||||
|
||||
UINT16 exp = FixedRescale(player->gradingfactor, factormin, factormax, Easing_Linear, targetminexp, targetmaxexp)>>FRACBITS;
|
||||
|
||||
if (modeattacking)
|
||||
exp = 100 * player->gradingpointnum / numgradingpoints;
|
||||
exp = EXP_MAX * player->gradingpointnum / max(1, numgradingpoints); // No Final Check here, just a linear slide
|
||||
|
||||
// CONS_Printf("Player %s numgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
|
||||
// player_names[player - players], numgradingpoints, player->gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
|
||||
/*
|
||||
if (!player->bot)
|
||||
CONS_Printf("Player %s fcp=%d effgradingpoints=%d gradingpoint=%d targetminexp=%d targetmaxexp=%d factor=%.2f factormin=%.2f factormax=%.2f exp=%d\n",
|
||||
player_names[player - players], K_FinalCheckpointPower(), effgradingpoints, gradingpointnum, targetminexp, targetmaxexp, FIXED_TO_FLOAT(player->gradingfactor), FIXED_TO_FLOAT(factormin), FIXED_TO_FLOAT(factormax), exp);
|
||||
*/
|
||||
|
||||
return exp;
|
||||
}
|
||||
|
|
@ -17414,7 +17542,7 @@ fixed_t K_TeamComebackMultiplier(player_t *player)
|
|||
void K_ApplyStun(player_t *player, mobj_t *inflictor, mobj_t *source, ATTRUNUSED INT32 damage, ATTRUNUSED UINT8 damagetype)
|
||||
{
|
||||
#define BASE_STUN_TICS_MIN (4 * TICRATE)
|
||||
#define BASE_STUN_TICS_MAX (10 * TICRATE)
|
||||
#define BASE_STUN_TICS_MAX (8 * TICRATE)
|
||||
#define MAX_STUN_REDUCTION (FRACUNIT/2)
|
||||
#define STUN_REDUCTION_DISTANCE (20000)
|
||||
INT32 stunTics = 0;
|
||||
|
|
|
|||
13
src/k_kart.h
13
src/k_kart.h
|
|
@ -42,7 +42,7 @@ Make sure this matches the actual number of states
|
|||
#define INSTAWHIP_HOLD_DELAY (TICRATE*2)
|
||||
// MUST be longer or equal to INSTAWHIP_CHARGETIME.
|
||||
#define INSTAWHIP_TETHERBLOCK (TICRATE*4)
|
||||
#define PUNISHWINDOW (10*TICRATE/10)
|
||||
#define PUNISHWINDOW (G_CompatLevel(0x0010) ? 7*TICRATE/10 : 10*TICRATE/10)
|
||||
|
||||
#define BAIL_MAXCHARGE (84) // tics to bail when in painstate nad in air, on ground is half, if you touch this, also update Obj_BailChargeThink synced animation logic
|
||||
#define BAIL_DROP (FRACUNIT) // How many rings it has to drop before stun starts
|
||||
|
|
@ -76,7 +76,7 @@ Make sure this matches the actual number of states
|
|||
|
||||
#define EARLY_ITEM_FLICKER (NUMTRANSMAPS)
|
||||
|
||||
#define TRIPWIRE_OK_SOUND (sfx_s3k40)
|
||||
#define TRIPWIRE_OK_SOUND (sfx_sonbo2)
|
||||
#define TRIPWIRE_NG_SOUND (sfx_gshaf)
|
||||
|
||||
// 2023-08-26 +ang20 to Sal's OG values to make them friendlier - Tyron
|
||||
|
|
@ -105,7 +105,7 @@ Make sure this matches the actual number of states
|
|||
#define MAXTOPACCEL (12*FRACUNIT)
|
||||
#define TOPACCELREGEN (FRACUNIT/16)
|
||||
|
||||
#define BUBBLESCAM (4)
|
||||
#define BUBBLESCAM (4*FRACUNIT)
|
||||
|
||||
// Handling boosts and sliptide conditions got weird.
|
||||
// You must be under a handling boost of at least SLIPTIDEHANDLING to sliptide.
|
||||
|
|
@ -132,11 +132,10 @@ boolean K_DuelItemAlwaysSpawns(mapthing_t *mt);
|
|||
boolean K_InRaceDuel(void);
|
||||
player_t *K_DuelOpponent(player_t *player);
|
||||
|
||||
fixed_t K_FinalCheckpointPower(void);
|
||||
fixed_t K_EffectiveGradingFactor(const player_t *player);
|
||||
#define MINGRADINGFACTOR (FRACUNIT/2)
|
||||
#define MINFRANTICFACTOR (8*FRACUNIT/10)
|
||||
#define GRADINGFACTORSOFTCAP (FRACUNIT)
|
||||
#define GRADINGFACTORCAPSTRENGTH (3*FRACUNIT)
|
||||
|
||||
void K_TimerReset(void);
|
||||
void K_TimerInit(void);
|
||||
|
|
@ -145,7 +144,7 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player);
|
|||
void K_ReduceVFXForEveryone(mobj_t *mo);
|
||||
|
||||
boolean K_IsPlayerLosing(player_t *player);
|
||||
fixed_t K_PlayerScamPercentage(const player_t *player, UINT8 mult);
|
||||
fixed_t K_PlayerScamPercentage(const player_t *player, fixed_t mult);
|
||||
fixed_t K_GetKartGameSpeedScalar(SINT8 value);
|
||||
|
||||
INT32 K_GetShieldFromItem(INT32 item);
|
||||
|
|
@ -347,7 +346,7 @@ boolean K_ThunderDome(void);
|
|||
|
||||
boolean K_PlayerCanUseItem(player_t *player);
|
||||
|
||||
fixed_t K_GetGradingFactorAdjustment(player_t *player);
|
||||
fixed_t K_GetGradingFactorAdjustment(player_t *player, UINT32 gradingpoint);
|
||||
fixed_t K_GetGradingFactorMinMax(player_t *player, boolean max);
|
||||
UINT16 K_GetEXP(player_t *player);
|
||||
|
||||
|
|
|
|||
|
|
@ -661,7 +661,7 @@ typedef enum
|
|||
MA_NO
|
||||
} manswer_e;
|
||||
|
||||
#define MAXMENUMESSAGE 256
|
||||
#define MAXMENUMESSAGE 448
|
||||
#define MENUMESSAGECLOSE 2
|
||||
extern struct menumessage_s
|
||||
{
|
||||
|
|
@ -769,6 +769,7 @@ void M_StartControlPanel(void);
|
|||
void M_ValidateRestoreMenu(void);
|
||||
menu_t *M_SpecificMenuRestore(menu_t *torestore);
|
||||
void M_ClearMenus(boolean callexitmenufunc);
|
||||
void M_ClearMenusNoTitle(boolean callexitmenufunc);
|
||||
void M_SelectableClearMenus(INT32 choice);
|
||||
void M_SetupNextMenu(menu_t *menudef, boolean nofade);
|
||||
void M_GoBack(INT32 choice);
|
||||
|
|
|
|||
|
|
@ -912,10 +912,6 @@ void M_ClearMenus(boolean callexitmenufunc)
|
|||
if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine())
|
||||
return; // we can't quit this menu (also used to set parameter from the menu)
|
||||
|
||||
#ifndef DC // Save the config file. I'm sick of crashing the game later and losing all my changes!
|
||||
COM_BufAddText(va("saveconfig \"%s\" -silent\n", configfile));
|
||||
#endif //Alam: But not on the Dreamcast's VMUs
|
||||
|
||||
currentMenu->lastOn = itemOn;
|
||||
|
||||
if (gamestate == GS_MENU) // Back to title screen
|
||||
|
|
@ -934,6 +930,24 @@ void M_ClearMenus(boolean callexitmenufunc)
|
|||
menuactive = false;
|
||||
}
|
||||
|
||||
void M_ClearMenusNoTitle(boolean callexitmenufunc)
|
||||
{
|
||||
if (!menuactive)
|
||||
return;
|
||||
|
||||
CON_ClearHUD();
|
||||
|
||||
if (currentMenu->quitroutine && callexitmenufunc && !currentMenu->quitroutine())
|
||||
return; // we can't quit this menu (also used to set parameter from the menu)
|
||||
|
||||
currentMenu->lastOn = itemOn;
|
||||
|
||||
M_AbortVirtualKeyboard();
|
||||
menumessage.active = false;
|
||||
|
||||
menuactive = false;
|
||||
}
|
||||
|
||||
void M_SelectableClearMenus(INT32 choice)
|
||||
{
|
||||
(void)choice;
|
||||
|
|
|
|||
|
|
@ -384,14 +384,20 @@ void K_UpdatePowerLevels(player_t *player, UINT8 gradingpoint, boolean forfeit)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (exitBonus == false)
|
||||
fixed_t prevInc = ourinc;
|
||||
|
||||
INT16 dvs = max(K_GetNumGradingPoints(), 1);
|
||||
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
|
||||
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
|
||||
|
||||
if (exitBonus)
|
||||
{
|
||||
ourinc = FixedMul(ourinc, FRACUNIT + K_FinalCheckpointPower());
|
||||
theirinc = FixedMul(theirinc, FRACUNIT + K_FinalCheckpointPower());
|
||||
CONS_Debug(DBG_PWRLV, "Final check bonus (%d / %d * %d = %d)\n", prevInc/FRACUNIT, dvs, K_FinalCheckpointPower(), ourinc/FRACUNIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed_t prevInc = ourinc;
|
||||
|
||||
INT16 dvs = max(K_GetNumGradingPoints(), 1);
|
||||
ourinc = FixedDiv(ourinc, dvs*FRACUNIT);
|
||||
theirinc = FixedDiv(theirinc, dvs*FRACUNIT);
|
||||
|
||||
CONS_Debug(DBG_PWRLV, "Reduced (%d / %d = %d) because it's not the end of the race\n", prevInc/FRACUNIT, dvs, ourinc/FRACUNIT);
|
||||
}
|
||||
}
|
||||
|
|
@ -432,6 +438,8 @@ void K_UpdatePowerLevelsFinalize(player_t *player, boolean onForfeit)
|
|||
|
||||
if (checksleft <= 0)
|
||||
{
|
||||
if (!(gametyperules & GTR_CHECKPOINTS)) // We should probably do at least _one_ PWR update.
|
||||
K_UpdatePowerLevels(player, player->gradingpointnum, onForfeit);
|
||||
// We've done every checkpoint already.
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -423,8 +423,8 @@ static void K_DrawFinishLineBeamForLine(fixed_t offset, angle_t aiming, line_t *
|
|||
--------------------------------------------------*/
|
||||
|
||||
void K_RunFinishLineBeam(void)
|
||||
{
|
||||
if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true))
|
||||
{
|
||||
if ((gametyperules & GTR_ROLLINGSTART) || !(leveltime < starttime || rainbowstartavailable == true) || P_LevelIsFrozen())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,12 @@ void K_DoIngameRespawn(player_t *player)
|
|||
K_DoFault(player);
|
||||
}
|
||||
|
||||
if (player->rings <= -20 && !player->respawn.fromRingShooter)
|
||||
{
|
||||
P_KillMobj(player->mo, NULL, NULL, DMG_INSTAKILL);
|
||||
return;
|
||||
}
|
||||
|
||||
player->ringboost = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
|
|
@ -740,7 +746,7 @@ static void K_DropDashWait(player_t *player)
|
|||
player->respawn.timer--;
|
||||
|
||||
if (player->pflags & PF_FAULT)
|
||||
return;
|
||||
return;
|
||||
|
||||
if (leveltime % 8 == 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@
|
|||
static UINT32 K_DynamicItemOddsRace[NUMKARTRESULTS-1][2] =
|
||||
{
|
||||
// distance, duplication tolerance
|
||||
{20, 10}, // sneaker
|
||||
{25, 10}, // sneaker
|
||||
{63, 12}, // rocketsneaker
|
||||
{60, 19}, // invincibility
|
||||
{8, 4}, // banana
|
||||
|
|
@ -491,12 +491,7 @@ UINT32 K_ScaleItemDistance(INT32 distance, UINT8 numPlayers)
|
|||
return distance;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
||||
static UINT32 K_GetUnscaledFirstDistance(const player_t *player)
|
||||
{
|
||||
UINT32 pdis = 0;
|
||||
|
||||
|
|
@ -546,6 +541,19 @@ UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
|||
}
|
||||
|
||||
pdis = K_UndoMapScaling(pdis);
|
||||
|
||||
return pdis;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------
|
||||
static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
||||
|
||||
See header file for description.
|
||||
--------------------------------------------------*/
|
||||
UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers)
|
||||
{
|
||||
UINT32 pdis = K_GetUnscaledFirstDistance(player);
|
||||
pdis = K_ScaleItemDistance(pdis, numPlayers);
|
||||
|
||||
if (player->bot && (player->botvars.rival || cv_levelskull.value))
|
||||
|
|
@ -735,7 +743,7 @@ boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulette)
|
|||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
static void K_InitRoulette(itemroulette_t *const roulette)
|
||||
void K_InitRoulette(itemroulette_t *const roulette)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
|
@ -1047,7 +1055,7 @@ ATTRUNUSED static boolean K_IsItemUselessAlone(kartitems_t item)
|
|||
}
|
||||
}
|
||||
|
||||
ATTRUNUSED static boolean K_IsItemSpeed(kartitems_t item)
|
||||
static boolean K_IsItemSpeed(kartitems_t item)
|
||||
{
|
||||
switch (item)
|
||||
{
|
||||
|
|
@ -1059,6 +1067,7 @@ ATTRUNUSED static boolean K_IsItemSpeed(kartitems_t item)
|
|||
case KRITEM_TRIPLESNEAKER:
|
||||
case KITEM_FLAMESHIELD:
|
||||
case KITEM_SHRINK:
|
||||
case KITEM_SUPERRING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
@ -1411,11 +1420,6 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
roulette->preexpdist = K_GetItemRouletteDistance(player, roulette->playing);
|
||||
roulette->dist = roulette->preexpdist;
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative())
|
||||
{
|
||||
roulette->dist = FixedMul(roulette->preexpdist, K_EffectiveGradingFactor(player));
|
||||
}
|
||||
|
||||
// ===============================================================================
|
||||
// Dynamic Roulette. Oh boy!
|
||||
// Alright, here's the broad plan:
|
||||
|
|
@ -1426,15 +1430,41 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
// 5: Skim any items that are much weaker than the reel's average out of the roulette
|
||||
// 6: Cram it all in
|
||||
|
||||
fixed_t largegamescaler = roulette->playing * 14 + 100; // Spread out item odds in large games for a less insane experience.
|
||||
UINT32 targetpower = 100 * roulette->dist / largegamescaler; // fill roulette with items around this value!
|
||||
|
||||
UINT32 powers[NUMKARTRESULTS]; // how strong is each item? think of this as a "target distance" for this item to spawn at
|
||||
UINT32 deltas[NUMKARTRESULTS]; // how different is that strength from target?
|
||||
UINT32 candidates[NUMKARTRESULTS]; // how many of this item should we try to insert?
|
||||
UINT32 dupetolerance[NUMKARTRESULTS]; // how willing are we to select this item after already selecting it? higher values = lower dupe penalty
|
||||
boolean permit[NUMKARTRESULTS]; // is this item allowed?
|
||||
|
||||
UINT32 lonelinessSuppressor = DISTVAR; // This close to 1st? Dampen loneliness (you have a target!)
|
||||
UINT32 maxEXPDistanceCut = 3*DISTVAR; // The maximum amount you can be displaced by EXP
|
||||
|
||||
// If we're too close to 1st in absolute units, crush our top-end item odds down.
|
||||
fixed_t crowdingFirst = 0;
|
||||
if (player->position != 1)
|
||||
crowdingFirst = FixedRescale(K_GetUnscaledFirstDistance(player), 0, 4*DISTVAR, Easing_InCubic, FRACUNIT, 0);
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT) && !K_Cooperative())
|
||||
{
|
||||
roulette->dist = FixedMul(roulette->preexpdist, K_EffectiveGradingFactor(player));
|
||||
|
||||
if (roulette->dist < roulette->preexpdist)
|
||||
{
|
||||
if (roulette->preexpdist - roulette->dist > maxEXPDistanceCut)
|
||||
{
|
||||
roulette->dist = roulette->preexpdist - maxEXPDistanceCut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixed_t largegamescaler = roulette->playing * 11 + 115; // Spread out item odds in large games for a less insane experience.
|
||||
if (franticitems)
|
||||
largegamescaler = 100; // Except in Frantic, where you know what you're getting
|
||||
|
||||
UINT32 targetpower = 100 * roulette->dist / largegamescaler; // fill roulette with items around this value!
|
||||
if (!(specialstageinfo.valid))
|
||||
targetpower = Easing_Linear(crowdingFirst, targetpower, targetpower/2);
|
||||
|
||||
boolean rival = (player->bot && (player->botvars.rival || cv_levelskull.value));
|
||||
boolean filterweakitems = true; // strip unusually weak items from reel?
|
||||
UINT8 reelsize = 15; // How many items to attempt to add in prepass?
|
||||
|
|
@ -1488,6 +1518,10 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
{
|
||||
powers[i] = humanscaler * K_DynamicItemOddsRace[i-1][0];
|
||||
dupetolerance[i] = K_DynamicItemOddsRace[i-1][1];
|
||||
|
||||
// Bias towards attack items when close to the leader, gotta work for the slingshot pass!
|
||||
if (K_IsItemSpeed(i) && i != KITEM_SUPERRING)
|
||||
powers[i] = Easing_Linear(crowdingFirst, powers[i], 2*powers[i]);
|
||||
}
|
||||
|
||||
maxpower = max(maxpower, powers[i]);
|
||||
|
|
@ -1586,6 +1620,12 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
|
||||
loneliness = Easing_InCubic(loneliness, 0, FRACUNIT);
|
||||
|
||||
// You are not lonely if you're super close to 1st, even if 3nd is far away.
|
||||
if (roulette->preexpdist < lonelinessSuppressor)
|
||||
{
|
||||
loneliness = FixedRescale(roulette->preexpdist, 0, lonelinessSuppressor, Easing_InCubic, 0, loneliness);
|
||||
}
|
||||
|
||||
// Give interaction items a nudge against initial selection if you're lonely..
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
|
|
@ -1621,6 +1661,13 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
UINT8 added = 0; // How many items added so far?
|
||||
UINT32 totalreelpower = 0; // How much total item power in the reel? Used for an average later.
|
||||
|
||||
UINT32 basepenalty = 4*DISTVAR; // How much to penalize repicked items, to ensure item variety.
|
||||
// BUT, keep the item distribution tighter if we're close to the frontrunner...
|
||||
UINT32 penalty = Easing_Linear(crowdingFirst, basepenalty, basepenalty/2);
|
||||
if (player->position == 1) // ...unless we ARE the frontrunner.
|
||||
penalty = basepenalty;
|
||||
|
||||
|
||||
for (i = 0; i < reelsize; i++)
|
||||
{
|
||||
UINT32 lowestdelta = INT32_MAX;
|
||||
|
|
@ -1647,7 +1694,7 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
// Impose a penalty to this item's delta, to bias against selecting it again.
|
||||
// This is naively slashed by an item's "duplicate tolerance":
|
||||
// lower tolerance means that an item is less likely to be reselected (it's "rarer").
|
||||
UINT32 deltapenalty = 4*DISTVAR*(1+candidates[bestitem])/dupetolerance[bestitem];
|
||||
UINT32 deltapenalty = penalty*(1+candidates[bestitem])/dupetolerance[bestitem];
|
||||
|
||||
// Power items get better odds in frantic, or if you're the rival.
|
||||
// (For the rival, this is way more likely to matter at lower skills, where they're
|
||||
|
|
@ -1731,10 +1778,10 @@ void K_FillItemRouletteData(player_t *player, itemroulette_t *const roulette, bo
|
|||
UINT16 BASE_X = 280;
|
||||
UINT16 BASE_Y = 5+12*debugcount;
|
||||
INT32 FLAGS = V_SNAPTOTOP|V_SNAPTORIGHT;
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5, FLAGS, va("%d", targetpower/humanscaler));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+12, FLAGS, va("%d", toFront));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+24, FLAGS, va("%d", toBack));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+36, FLAGS, va("%d", loneliness));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5, FLAGS, va("TP %d", targetpower/humanscaler));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+12, FLAGS, va("FB %d / %d", toFront, toBack));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+24, FLAGS, va("L %d / CF %d", loneliness, crowdingFirst));
|
||||
V_DrawRightAlignedThinString(BASE_X - 12, 5+36, FLAGS, va("D %d / %d", roulette->preexpdist, roulette->dist));
|
||||
for(UINT8 k = 0; k < candidates[i]; k++)
|
||||
V_DrawFixedPatch((BASE_X + 3*k)*FRACUNIT, (BASE_Y-7)*FRACUNIT, (FRACUNIT >> 1), FLAGS, K_GetSmallStaticCachedItemPatch(i), NULL);
|
||||
UINT8 amount = K_ItemResultToAmount(i, roulette);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,19 @@ UINT32 K_UndoMapScaling(UINT32 distance);
|
|||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_InitRoulette(itemroulette_t *const roulette);
|
||||
/*--------------------------------------------------
|
||||
static void K_InitRoulette(itemroulette_t *const roulette)
|
||||
|
||||
Initializes the data for a new item roulette.
|
||||
|
||||
Input Arguments:-
|
||||
roulette - The item roulette data to initialize.
|
||||
|
||||
Return:-
|
||||
N/A
|
||||
--------------------------------------------------*/
|
||||
|
||||
void K_PushToRouletteItemList(itemroulette_t *const roulette, INT32 item);
|
||||
|
||||
/*--------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ INT32 level_tally_t::CalculateGrade(void)
|
|||
}
|
||||
}
|
||||
|
||||
const INT32 positionWeight = (position > 0 && numPlayers > 2) ? 50 : 0;
|
||||
const INT32 positionWeight = 0; // (position > 0 && numPlayers > 2) ? 50 : 0;
|
||||
const INT32 total = positionWeight + bonusWeights[0] + bonusWeights[1];
|
||||
|
||||
INT32 ours = 0;
|
||||
|
|
|
|||
|
|
@ -501,7 +501,21 @@ void K_ProcessTerrainEffect(mobj_t *mo)
|
|||
if (terrain->damageType > 0)
|
||||
{
|
||||
UINT8 dmg = (terrain->damageType & 0xFF);
|
||||
P_DamageMobj(mo, NULL, NULL, 1, dmg);
|
||||
|
||||
if ((dmg == DMG_STUMBLE) && !G_CompatLevel(0x0010))
|
||||
{
|
||||
if (player->mo->hitlag == 0 &&
|
||||
(player->mo->momz == 0 || (player->mo->momz > 0) != (P_MobjFlip(player->mo) > 0)))
|
||||
{
|
||||
player->pflags2 |= PF2_ALWAYSDAMAGED;
|
||||
P_DamageMobj(mo, NULL, NULL, 1, dmg);
|
||||
player->pflags2 &= ~PF2_ALWAYSDAMAGED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(mo, NULL, NULL, 1, dmg);
|
||||
}
|
||||
}
|
||||
|
||||
// Sneaker panel
|
||||
|
|
@ -2011,7 +2025,7 @@ static boolean K_TERRAINLumpParser(char *data, size_t size)
|
|||
Z_Free(tkn);
|
||||
tkn = M_GetToken(NULL);
|
||||
pos = M_GetTokenPos();
|
||||
|
||||
|
||||
if (tkn && pos <= size)
|
||||
{
|
||||
if (stricmp(tkn, "optional") == 0)
|
||||
|
|
|
|||
|
|
@ -269,6 +269,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushboolean(L, plr->transfer);
|
||||
else if (fastcmp(field,"markedfordeath"))
|
||||
lua_pushboolean(L, plr->markedfordeath);
|
||||
else if (fastcmp(field,"mfdfinish"))
|
||||
lua_pushboolean(L, plr->mfdfinish);
|
||||
else if (fastcmp(field,"incontrol"))
|
||||
lua_pushboolean(L, plr->incontrol);
|
||||
else if (fastcmp(field,"progressivethrust"))
|
||||
|
|
@ -347,6 +349,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->spindashspeed);
|
||||
else if (fastcmp(field,"spindashboost"))
|
||||
lua_pushinteger(L, plr->spindashboost);
|
||||
else if (fastcmp(field,"ringboostinprogress"))
|
||||
lua_pushinteger(L, plr->ringboostinprogress);
|
||||
else if (fastcmp(field,"fastfall"))
|
||||
lua_pushfixed(L, plr->fastfall);
|
||||
else if (fastcmp(field,"fastfallbase"))
|
||||
|
|
@ -375,6 +379,8 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->tripwirePass);
|
||||
else if (fastcmp(field,"fakeboost"))
|
||||
lua_pushinteger(L, plr->fakeBoost);
|
||||
else if (fastcmp(field,"subsonicleniency"))
|
||||
lua_pushinteger(L, plr->subsonicleniency);
|
||||
else if (fastcmp(field,"tripwireleniency"))
|
||||
lua_pushinteger(L, plr->tripwireLeniency);
|
||||
else if (fastcmp(field,"tripwireairleniency"))
|
||||
|
|
@ -405,8 +411,6 @@ static int player_get(lua_State *L)
|
|||
lua_pushinteger(L, plr->overdriveready);
|
||||
else if (fastcmp(field,"overdrivelenient"))
|
||||
lua_pushinteger(L, plr->overdrivelenient);
|
||||
else if (fastcmp(field,"speedpunt"))
|
||||
lua_pushinteger(L, plr->speedpunt);
|
||||
else if (fastcmp(field,"trickcharge"))
|
||||
lua_pushinteger(L, plr->trickcharge);
|
||||
else if (fastcmp(field,"infinitether"))
|
||||
|
|
@ -948,6 +952,8 @@ static int player_set(lua_State *L)
|
|||
plr->transfer = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"markedfordeath"))
|
||||
plr->markedfordeath = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"mfdfinish"))
|
||||
plr->mfdfinish = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"dotrickfx"))
|
||||
plr->dotrickfx = luaL_checkboolean(L, 3);
|
||||
else if (fastcmp(field,"stingfx"))
|
||||
|
|
@ -1012,6 +1018,8 @@ static int player_set(lua_State *L)
|
|||
plr->spindashspeed = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"spindashboost"))
|
||||
plr->spindashboost = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"ringboostinprogress"))
|
||||
plr->ringboostinprogress = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"fastfall"))
|
||||
plr->fastfall = luaL_checkfixed(L, 3);
|
||||
else if (fastcmp(field,"fastfallbase"))
|
||||
|
|
@ -1040,6 +1048,8 @@ static int player_set(lua_State *L)
|
|||
plr->tripwirePass = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"fakeboost"))
|
||||
plr->fakeBoost = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"subsonicleniency"))
|
||||
plr->subsonicleniency = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"tripwireleniency"))
|
||||
plr->tripwireLeniency = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"tripwireairleniency"))
|
||||
|
|
@ -1070,8 +1080,6 @@ static int player_set(lua_State *L)
|
|||
plr->overdriveready = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"overdrivelenient"))
|
||||
plr->overdrivelenient = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"speedpunt"))
|
||||
plr->speedpunt = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"trickcharge"))
|
||||
plr->trickcharge = luaL_checkinteger(L, 3);
|
||||
else if (fastcmp(field,"infinitether"))
|
||||
|
|
|
|||
|
|
@ -1797,7 +1797,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
case UCRP_PREFIX_BONUSROUND:
|
||||
return ((grandprixinfo.gp == true) && (grandprixinfo.eventmode == GPEVENT_BONUS));
|
||||
case UCRP_PREFIX_TIMEATTACK:
|
||||
return (modeattacking != ATTACKING_NONE);
|
||||
return (modeattacking != ATTACKING_NONE && !(skins[player->skin]->flags & SF_HIVOLT));
|
||||
case UCRP_PREFIX_PRISONBREAK:
|
||||
return ((gametyperules & GTR_PRISONS) && battleprisons);
|
||||
case UCRP_PREFIX_SEALEDSTAR:
|
||||
|
|
@ -1843,8 +1843,7 @@ boolean M_CheckCondition(condition_t *cn, player_t *player)
|
|||
if (cn->extrainfo2 != 0)
|
||||
return (K_PodiumGrade() >= cn->extrainfo1);
|
||||
if (cn->extrainfo1 != 0)
|
||||
return (player->position != 0
|
||||
&& player->position <= cn->extrainfo1);
|
||||
return K_GetPodiumPosition(player) <= cn->extrainfo1;
|
||||
return true;
|
||||
case UCRP_PODIUMEMERALD:
|
||||
case UCRP_PODIUMPRIZE:
|
||||
|
|
|
|||
107
src/m_pw.cpp
107
src/m_pw.cpp
|
|
@ -32,6 +32,7 @@
|
|||
#include "g_game.h"
|
||||
#include "k_menu.h"
|
||||
#include "m_cheat.h"
|
||||
#include "m_random.h"
|
||||
#include "m_cond.h"
|
||||
#include "m_pw.h"
|
||||
#include "m_pw_hash.h"
|
||||
|
|
@ -364,6 +365,111 @@ void f_maps()
|
|||
}
|
||||
}
|
||||
|
||||
void f_tutorials()
|
||||
{
|
||||
UINT16 i;
|
||||
boolean success = false;
|
||||
|
||||
for (i = 0; i < MAXUNLOCKABLES; i++)
|
||||
{
|
||||
if (!unlockables[i].conditionset)
|
||||
continue;
|
||||
if (unlockables[i].conditionset == CH_FURYBIKE)
|
||||
continue;
|
||||
if (gamedata->unlocked[i])
|
||||
continue;
|
||||
if (unlockables[i].type != SECRET_MAP)
|
||||
continue;
|
||||
|
||||
UINT16 mapnum = M_UnlockableMapNum(&unlockables[i]);
|
||||
if (mapnum >= nummapheaders || !mapheaderinfo[mapnum])
|
||||
continue;
|
||||
|
||||
if (G_GuessGametypeByTOL(mapheaderinfo[mapnum]->typeoflevel) != GT_TUTORIAL)
|
||||
continue;
|
||||
|
||||
gamedata->unlocked[i] = true;
|
||||
success = true;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
S_StartSound(0, sfx_kc42);
|
||||
G_SaveGameData();
|
||||
}
|
||||
|
||||
const char *knucklesrap;
|
||||
const UINT8 numsections = 5;
|
||||
static UINT8 section = numsections;
|
||||
if (section == numsections)
|
||||
section = M_RandomKey(numsections);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
default:
|
||||
knucklesrap =
|
||||
"\x85""So here's what I'm thinkin', \n"
|
||||
"\x85"" last time smart guys got together,\n"
|
||||
"\x85""In a tough sandy place \n"
|
||||
"\x85"" with a lot of hot weather,\n"
|
||||
"\x85""Playin' fundamental forces \n"
|
||||
"\x85"" at the top of their class,\n"
|
||||
"\x85""They made the sky so much hotter \n"
|
||||
"\x85"" and that sand into glass!\x80";
|
||||
break;
|
||||
case 1:
|
||||
knucklesrap =
|
||||
"\x85""But somethin's different, see? \n"
|
||||
"\x85""My homie right there, I trust him trustin'\n"
|
||||
"\x85"" the Eggman like it's nothin',\n"
|
||||
"\x85""A smart little guy \n"
|
||||
"\x85"" with a brother I like fightin',\n"
|
||||
"\x85""If there's somethin' cooking \n"
|
||||
"\x85"" I'm sure he'll do the right thing.\x80";
|
||||
break;
|
||||
case 2:
|
||||
knucklesrap =
|
||||
"\x85""I watched a space station fall, \n"
|
||||
"\x85"" straight down, fast fall, into the ground,\n"
|
||||
"\x85""Pieces of fire, shooting stars, \n"
|
||||
"\x85"" don't make a wish, kids\n"
|
||||
"\x85""Last second it's, gone, I ask how, \n"
|
||||
"\x85"" behold, they call it chaos control,\n"
|
||||
"\x85""I don't know it, never heard it, seen it, felt it, \n"
|
||||
"\x85"" sensed it. Even to me, these powers are a mystery.\x80";
|
||||
break;
|
||||
case 3:
|
||||
knucklesrap =
|
||||
"\x85""The tide goes out, it carries time away, \n"
|
||||
"\x85"" we call it yesterday,\n"
|
||||
"\x85""The tide comes in, it rings, it sings, \n"
|
||||
"\x85"" it brings a new age,\n"
|
||||
"\x85""But right now it's just me and the water, \n"
|
||||
"\x85"" thoughts clear, future lookin' hotter,\n"
|
||||
"\x85""I let myself sink in, feel the waves, \n"
|
||||
"\x85"" feel my body get lighter.\x80";
|
||||
break;
|
||||
case 4:
|
||||
knucklesrap =
|
||||
"\x85""Somethin' brewin' at the edges, \n"
|
||||
"\x85"" that's what a ring is, nothin' but edges,\n"
|
||||
"\x85""Circled light in a band, \n"
|
||||
"\x85"" hold 'em in in your hand,\n"
|
||||
"\x85""But it's a miracle a thousand times over,\n"
|
||||
"\x85""Small gasps of potential\n"
|
||||
"\x85"" floatin' over the sand.\x80";
|
||||
break;
|
||||
}
|
||||
|
||||
section = (section + 1) % numsections;
|
||||
|
||||
M_StartMessage("\"Broken Arrow\" ...for Sunbeam Paradise",
|
||||
va("\"%s\"\n\n%s",
|
||||
knucklesrap,
|
||||
(success ? "Unlocked all Tutorials." : "There are no more Tutorials to unlock.")),
|
||||
NULL, MM_NOTHING, NULL, NULL);
|
||||
}
|
||||
|
||||
void f_characters()
|
||||
{
|
||||
UINT16 i;
|
||||
|
|
@ -779,6 +885,7 @@ void M_PasswordInit(void)
|
|||
passwords.emplace_back(f_colors, "aSk8dw6FzJtTEmovh8fVEtUBpu6lj3QlRT/B5lwiEhAw8dAhRBQLdvtYlPaQcZISWI4wneAfAo6w5d6uf5r++g==");
|
||||
passwords.emplace_back(f_followers, "zYCIZw2qcnUbtF0P2ybLNHajdl8zrje0hzGex7yuMFe7fj4mvx4AegoMmvir28YvAbfAqkz/ekQRzr+RhrycHw==");
|
||||
passwords.emplace_back(f_maps, "u/Svaf+DCnCpJ8xmP3AVP4CK6X6X4O3fY73cmIq88ZJEygwz+n+L66q4Vhlv13vWgld1PEyRszFErzflQt9WZw==");
|
||||
passwords.emplace_back(f_tutorials, "G2FMttJpJ+lI/DeQu8tthL5i7AB4dk8uuksZR1c2N08Zrmpj3vTqWpbhxuSzSrhH10wJfWahR7QOgQdBkDbTdQ==");
|
||||
passwords.emplace_back(f_characters, "MohmPqpaGSd3MEHLfQKUFl/Yg8pHE+12X1LHEP59Gs/5w1u8mPtGUXNv1GYTF+c8gQqT5hXpZ3FeZ/EfCxo34g==");
|
||||
passwords.emplace_back(f_altmusic, "dZgxKNagOtB9F7wXqUUPzsuq4tfQlfK8ZqEeFXdI3Hd+k5tYfRm3ToLgbqawaNmwuLVrJ8PB+QnH4gT3ojnTMw==");
|
||||
passwords.emplace_back(f_timeattack, "mFu5OB9d6jnc2kth7HE66wJ42F/GHDzSvuciK1Qw++6iGnpBccxcKjpoxgOvD3eIoqR606ruBINuXi23proXHQ==");
|
||||
|
|
|
|||
|
|
@ -21,7 +21,42 @@
|
|||
#include "m_random.h"
|
||||
#include "m_fixed.h"
|
||||
|
||||
|
||||
char rng_class_names[34][30] = {
|
||||
"UNDEFINED",
|
||||
"EXECUTOR",
|
||||
"ACS",
|
||||
"DECORATION",
|
||||
"TERRAIN",
|
||||
"BUBBLE",
|
||||
"RANDOMANIM",
|
||||
"PLAYERSTARTS",
|
||||
"VOICES",
|
||||
"RANDOMSKIN",
|
||||
"RANDOMAUDIENCE",
|
||||
"RULESCRAMBLE",
|
||||
"MUSICSELECT",
|
||||
"ITEM_ROULETTE",
|
||||
"ITEM_RINGS",
|
||||
"ITEM_SHRINK",
|
||||
"ITEM_BUBBLE",
|
||||
"ITEM_DEBRIS",
|
||||
"ITEM_BOOST",
|
||||
"EXPLOSION",
|
||||
"SMOLDERING",
|
||||
"SPARKLE",
|
||||
"MOVINGTARGET",
|
||||
"TRACKHAZARDD",
|
||||
"BATTLEUFO",
|
||||
"BOTS",
|
||||
"AUTOROULETTE",
|
||||
"FUZZ",
|
||||
"FROSTTHROWERS",
|
||||
"ITEM_SPAWNER",
|
||||
"TEAMS",
|
||||
"DUMMY",
|
||||
"INTERPHUDRANDOM",
|
||||
"NUISANCE"
|
||||
};
|
||||
|
||||
// ---------------------------
|
||||
// RNG functions (not synched)
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ typedef enum
|
|||
PRNUMCLASS
|
||||
} pr_class_t;
|
||||
|
||||
extern char rng_class_names[34][30];
|
||||
// M_Random functions pull random numbers of various types that aren't network synced.
|
||||
// P_Random functions pulls random bytes from a PRNG that is network synced.
|
||||
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ void EggTV::watch() const
|
|||
{
|
||||
restoreMenu = currentMenu;
|
||||
|
||||
M_ClearMenus(false);
|
||||
M_ClearMenusNoTitle(false);
|
||||
|
||||
demo.loadfiles = true;
|
||||
demo.ignorefiles = false;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ menuitem_t OPTIONS_Voice[] =
|
|||
NULL, srb2::itemaction(&cv_voice_inputamp), 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Input Noise Suppression", "Suppress background noise from your voice.",
|
||||
NULL, {.cvar = &cv_voice_denoise}, 0, 0},
|
||||
NULL, srb2::itemaction(&cv_voice_denoise), 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Input Sensitivity", "Voice higher than this threshold will transmit, in decibels.",
|
||||
NULL, srb2::itemaction(&cv_voice_activationthreshold), 0, 0 },
|
||||
|
|
|
|||
|
|
@ -440,7 +440,7 @@ void M_HandleStaffReplay(INT32 choice)
|
|||
staffbrief_t *staffbrief;
|
||||
restoreMenu = &PLAY_TAReplayDef;
|
||||
|
||||
M_ClearMenus(true);
|
||||
M_ClearMenusNoTitle(true);
|
||||
demo.loadfiles = false;
|
||||
demo.ignorefiles = true; // Just assume that record attack replays have the files needed
|
||||
|
||||
|
|
@ -507,7 +507,7 @@ void M_ReplayTimeAttack(INT32 choice)
|
|||
|
||||
restoreMenu = &PLAY_TAReplayDef;
|
||||
|
||||
M_ClearMenus(true);
|
||||
M_ClearMenusNoTitle(true);
|
||||
demo.loadfiles = false;
|
||||
demo.ignorefiles = true; // Just assume that record attack replays have the files needed
|
||||
|
||||
|
|
@ -692,7 +692,7 @@ void M_StartTimeAttack(INT32 choice)
|
|||
false
|
||||
);
|
||||
|
||||
M_ClearMenus(true);
|
||||
M_ClearMenusNoTitle(true);
|
||||
|
||||
G_UpdateTimeStickerMedals(levellist.choosemap, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ void Obj_BulbTouched(mobj_t *special, mobj_t *toucher)
|
|||
P_MoveOrigin(toucher, special->x, special->y, special->z);
|
||||
toucher->player->nocontrol = 1;
|
||||
P_SetTarget(&toucher->tracer, special);
|
||||
toucher->flags &= ~MF_SHOOTABLE;
|
||||
toucher->flags &= ~(MF_SHOOTABLE|MF_NOGRAVITY);
|
||||
toucher->renderflags |= RF_DONTDRAW;
|
||||
P_SetTarget(&special->target, toucher);
|
||||
special->extravalue1 = spd;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../g_game.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_state.h"
|
||||
|
|
|
|||
|
|
@ -215,18 +215,12 @@ boolean Obj_OrbinautJawzCollide(mobj_t *t1, mobj_t *t2)
|
|||
else
|
||||
{
|
||||
// Player Damage
|
||||
if ((t1->type == MT_ORBINAUT_SHIELD || t1->type == MT_JAWZ_SHIELD)
|
||||
&& !t2->player->invincibilitytimer && !K_IsBigger(t2, t1)) // UGH. Stumble ignores invinc. Fix this damage type someday.
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO | DMG_STUMBLE);
|
||||
}
|
||||
else
|
||||
{
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
|
||||
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
|
||||
if (tumbleitem || (gametyperules & GTR_SPHERES) || !t2->player->tripwireLeniency)
|
||||
P_DamageMobj(t2, t1, t1->target, 1, DMG_WOMBO |
|
||||
(tumbleitem ? DMG_TUMBLE : DMG_WIPEOUT));
|
||||
|
||||
if (tumbleitem || !t2->player->tripwireLeniency)
|
||||
if ((gametyperules & GTR_SPHERES) || (t1->type != MT_ORBINAUT_SHIELD && t1->type != MT_JAWZ_SHIELD))
|
||||
K_KartBouncing(t2, t1);
|
||||
}
|
||||
|
||||
S_StartSound(t2, sfx_s3k7b);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,6 +220,7 @@ void Obj_playerWPZTurbine(player_t *p)
|
|||
}
|
||||
|
||||
mt = t->spawnpoint;
|
||||
pmo->flags &= ~MF_NOGRAVITY;
|
||||
|
||||
opt1 = (mt->thing_args[0] != 0);
|
||||
|
||||
|
|
|
|||
889
src/p_inter.c
889
src/p_inter.c
|
|
@ -408,8 +408,15 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
case MT_FLOATINGITEM: // SRB2Kart
|
||||
if (special->extravalue1 > 0 && toucher != special->tracer)
|
||||
{
|
||||
player->pflags |= PF_CASTSHADOW;
|
||||
return;
|
||||
if (special->tracer && !P_MobjWasRemoved(special->tracer) && special->tracer->player)
|
||||
{
|
||||
if (!G_SameTeam(special->tracer->player, player))
|
||||
{
|
||||
player->pflags |= PF_CASTSHADOW;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (special->threshold >= FIRSTPOWERUP)
|
||||
|
|
@ -489,7 +496,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
if (special->fuse) // This box is respawning, but was broken very recently (see P_FuseThink)
|
||||
{
|
||||
// What was this box broken as?
|
||||
if (!K_ThunderDome() && special->cvmem && !(special->flags2 & MF2_BOSSDEAD))
|
||||
if (!K_ThunderDome() && special->cusval && !(special->flags2 & MF2_BOSSDEAD))
|
||||
K_StartItemRoulette(player, false);
|
||||
else
|
||||
K_StartItemRoulette(player, true);
|
||||
|
|
@ -497,12 +504,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
else if (specialstate >= S_RANDOMITEM1 && specialstate <= S_RANDOMITEM12)
|
||||
{
|
||||
K_StartItemRoulette(player, false);
|
||||
special->cvmem = 1; // Lenient pickup should be ITEM
|
||||
special->cusval = 1; // Lenient pickup should be ITEM
|
||||
}
|
||||
else
|
||||
{
|
||||
K_StartItemRoulette(player, true);
|
||||
special->cvmem = 0; // Lenient pickup should be RING
|
||||
special->cusval = 0; // Lenient pickup should be RING
|
||||
}
|
||||
|
||||
P_ItemPop(special);
|
||||
|
|
@ -2855,24 +2862,9 @@ static boolean P_FlashingException(const player_t *player, const mobj_t *inflict
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Damages an object, which may or may not be a player.
|
||||
* For melee attacks, source and inflictor are the same.
|
||||
*
|
||||
* \param target The object being damaged.
|
||||
* \param inflictor The thing that caused the damage: creature, missile,
|
||||
* gargoyle, and so forth. Can be NULL in the case of
|
||||
* environmental damage, such as slime or crushing.
|
||||
* \param source The creature or person responsible. For example, if a
|
||||
* player is hit by a ring, the player who shot it. In some
|
||||
* cases, the target will go after this object after
|
||||
* receiving damage. This can be NULL.
|
||||
* \param damage Amount of damage to be dealt.
|
||||
* \param damagetype Type of damage to be dealt. If bit 7 (0x80) is set, this is an instant-kill.
|
||||
* \return True if the target sustained damage, otherwise false.
|
||||
* \todo Clean up this mess, split into multiple functions.
|
||||
* \sa P_KillMobj
|
||||
*/
|
||||
boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
// P_DamageMobj for 0x0010 compat.
|
||||
// I know this sucks ass, but this function is legitimately too complicated to add more behavior switches.
|
||||
static boolean P_DamageMobjCompat(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
player_t *player;
|
||||
player_t *playerInflictor;
|
||||
|
|
@ -3671,6 +3663,857 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
return true;
|
||||
}
|
||||
|
||||
/** Damages an object, which may or may not be a player.
|
||||
* For melee attacks, source and inflictor are the same.
|
||||
*
|
||||
* \param target The object being damaged.
|
||||
* \param inflictor The thing that caused the damage: creature, missile,
|
||||
* gargoyle, and so forth. Can be NULL in the case of
|
||||
* environmental damage, such as slime or crushing.
|
||||
* \param source The creature or person responsible. For example, if a
|
||||
* player is hit by a ring, the player who shot it. In some
|
||||
* cases, the target will go after this object after
|
||||
* receiving damage. This can be NULL.
|
||||
* \param damage Amount of damage to be dealt.
|
||||
* \param damagetype Type of damage to be dealt. If bit 7 (0x80) is set, this is an instant-kill.
|
||||
* \return True if the target sustained damage, otherwise false.
|
||||
* \todo Clean up this mess, split into multiple functions.
|
||||
* \sa P_KillMobj
|
||||
*/
|
||||
boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 damage, UINT8 damagetype)
|
||||
{
|
||||
if (G_CompatLevel(0x0010))
|
||||
return P_DamageMobjCompat(target, inflictor, source, damage, damagetype);
|
||||
|
||||
player_t *player;
|
||||
player_t *playerInflictor;
|
||||
boolean force = false;
|
||||
boolean spbpop = false;
|
||||
ATTRUNUSED boolean downgraded = false;
|
||||
boolean truewhumble = false; // Invincibility-ignoring DMG_WHUMBLE from the Insta-Whip itself.
|
||||
|
||||
INT32 laglength = 6;
|
||||
|
||||
if (objectplacing)
|
||||
return false;
|
||||
|
||||
if (target->health <= 0)
|
||||
return false;
|
||||
|
||||
// Spectator handling
|
||||
if (damagetype != DMG_SPECTATOR && target->player && target->player->spectator)
|
||||
return false;
|
||||
|
||||
// source is checked without a removal guard in so many places that it's genuinely less work to do it here.
|
||||
if (source && P_MobjWasRemoved(source))
|
||||
source = NULL;
|
||||
|
||||
if (source && source->player && source->player->spectator)
|
||||
return false;
|
||||
|
||||
if (((damagetype & DMG_TYPEMASK) == DMG_STING)
|
||||
|| ((inflictor && !P_MobjWasRemoved(inflictor)) && inflictor->type == MT_BANANA && inflictor->health <= 1))
|
||||
{
|
||||
laglength = 2;
|
||||
}
|
||||
else if (target->type == MT_DROPTARGET || target->type == MT_DROPTARGET_SHIELD)
|
||||
{
|
||||
laglength = 0; // handled elsewhere
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_MONITOR:
|
||||
damage = Obj_MonitorGetDamage(target, inflictor, damagetype);
|
||||
Obj_MonitorOnDamage(target, inflictor, damage);
|
||||
break;
|
||||
case MT_CDUFO:
|
||||
// Make it possible to pick them up during race
|
||||
if (inflictor->type == MT_ORBINAUT_SHIELD || inflictor->type == MT_JAWZ_SHIELD)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case MT_SPB:
|
||||
spbpop = (damagetype & DMG_TYPEMASK) == DMG_VOLTAGE;
|
||||
if (spbpop && source && source->player
|
||||
&& source->player->roundconditions.spb_neuter == false)
|
||||
{
|
||||
source->player->roundconditions.spb_neuter = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything above here can't be forced.
|
||||
{
|
||||
UINT8 shouldForce = LUA_HookShouldDamage(target, inflictor, source, damage, damagetype);
|
||||
if (P_MobjWasRemoved(target))
|
||||
return (shouldForce == 1); // mobj was removed
|
||||
if (shouldForce == 1)
|
||||
force = true;
|
||||
else if (shouldForce == 2)
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_BALLSWITCH_BALL:
|
||||
Obj_BallSwitchDamaged(target, inflictor, source);
|
||||
return false;
|
||||
|
||||
case MT_SA2_CRATE:
|
||||
case MT_ICECAPBLOCK:
|
||||
return Obj_TryCrateDamage(target, inflictor);
|
||||
|
||||
case MT_KART_LEFTOVER:
|
||||
// intangible (do not let instawhip shred damage)
|
||||
if (Obj_DestroyKart(target))
|
||||
return false;
|
||||
|
||||
P_SetObjectMomZ(target, 12*FRACUNIT, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if (!spbpop)
|
||||
{
|
||||
if (!(target->flags & MF_SHOOTABLE))
|
||||
return false; // shouldn't happen...
|
||||
}
|
||||
}
|
||||
|
||||
if (target->flags2 & MF2_SKULLFLY)
|
||||
target->momx = target->momy = target->momz = 0;
|
||||
|
||||
if (target->flags & (MF_ENEMY|MF_BOSS))
|
||||
{
|
||||
if (!force && target->flags2 & MF2_FRET) // Currently flashing from being hit
|
||||
return false;
|
||||
|
||||
if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype) || P_MobjWasRemoved(target))
|
||||
return true;
|
||||
|
||||
if (target->health > 1)
|
||||
target->flags2 |= MF2_FRET;
|
||||
}
|
||||
|
||||
player = target->player;
|
||||
playerInflictor = inflictor ? inflictor->player : NULL;
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
AddTimesHit(playerInflictor);
|
||||
}
|
||||
|
||||
if (player) // Player is the target
|
||||
{
|
||||
AddTimesHit(player);
|
||||
|
||||
if (player->pflags & PF_GODMODE)
|
||||
return false;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
// Player hits another player
|
||||
if (source && source->player)
|
||||
{
|
||||
if (!P_PlayerHitsPlayer(target, inflictor, source, damage, damagetype))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (source && source->player)
|
||||
{
|
||||
if (source->player->roundconditions.hit_midair == false
|
||||
&& source != target
|
||||
&& inflictor
|
||||
&& K_IsMissileOrKartItem(inflictor)
|
||||
&& target->player->airtime > TICRATE/2
|
||||
&& source->player->airtime > TICRATE/2)
|
||||
{
|
||||
source->player->roundconditions.hit_midair = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source->player->roundconditions.hit_drafter_lookback == false
|
||||
&& source != target
|
||||
&& target->player->lastdraft == (source->player - players)
|
||||
&& (K_GetKartButtons(source->player) & BT_LOOKBACK) == BT_LOOKBACK
|
||||
/*&& (AngleDelta(K_MomentumAngle(source), R_PointToAngle2(source->x, source->y, target->x, target->y)) > ANGLE_90)*/)
|
||||
{
|
||||
source->player->roundconditions.hit_drafter_lookback = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source->player->roundconditions.giant_foe_shrunken_orbi == false
|
||||
&& source != target
|
||||
&& player->growshrinktimer > 0
|
||||
&& !P_MobjWasRemoved(inflictor)
|
||||
&& inflictor->type == MT_ORBINAUT
|
||||
&& inflictor->scale < FixedMul((FRACUNIT + SHRINK_SCALE), mapobjectscale * 2)) // halfway between base scale and shrink scale, a little bit of leeway
|
||||
{
|
||||
source->player->roundconditions.giant_foe_shrunken_orbi = true;
|
||||
source->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
|
||||
if (source == target
|
||||
&& !P_MobjWasRemoved(inflictor)
|
||||
&& inflictor->type == MT_SPBEXPLOSION
|
||||
&& inflictor->threshold == KITEM_EGGMAN
|
||||
&& !P_MobjWasRemoved(inflictor->tracer)
|
||||
&& inflictor->tracer != source
|
||||
&& inflictor->tracer->player
|
||||
&& inflictor->tracer->player->roundconditions.returntosender_mark == false)
|
||||
{
|
||||
inflictor->tracer->player->roundconditions.returntosender_mark = true;
|
||||
inflictor->tracer->player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
}
|
||||
else if (!(inflictor && inflictor->player)
|
||||
&& !(player->exiting || player->laps > numlaps)
|
||||
&& damagetype != DMG_DEATHPIT)
|
||||
{
|
||||
// laps will never increment outside of GTR_CIRCUIT, so this is still fine
|
||||
const UINT8 requiredbit = 1<<(player->laps & 7);
|
||||
|
||||
if (!(player->roundconditions.hittrackhazard[player->laps/8] & requiredbit))
|
||||
{
|
||||
player->roundconditions.hittrackhazard[player->laps/8] |= requiredbit;
|
||||
player->roundconditions.checkthisframe = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Instant-Death
|
||||
if ((damagetype & DMG_DEATHMASK))
|
||||
{
|
||||
if (!P_KillPlayer(player, inflictor, source, damagetype))
|
||||
return false;
|
||||
}
|
||||
else if (LUA_HookMobjDamage(target, inflictor, source, damage, damagetype))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 type = (damagetype & DMG_TYPEMASK);
|
||||
const boolean hardhit = (type == DMG_EXPLODE || type == DMG_KARMA || type == DMG_TUMBLE); // This damage type can do evil stuff like ALWAYS combo
|
||||
INT16 ringburst = 5;
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->type == MT_INSTAWHIP && type == DMG_WHUMBLE)
|
||||
truewhumble = true;
|
||||
|
||||
// Check if the player is allowed to be damaged!
|
||||
// If not, then spawn the instashield effect instead.
|
||||
if (!force)
|
||||
{
|
||||
boolean invincible = true;
|
||||
boolean clash = true; // This effect is cool and reads well, why not
|
||||
sfxenum_t sfx = sfx_None;
|
||||
|
||||
if (!(gametyperules & GTR_BUMPERS))
|
||||
{
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Gametype does not have bumpers, steal damage is intended to not do anything
|
||||
// (No instashield is intentional)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
sfx = sfx_invind;
|
||||
}
|
||||
else if (K_IsBigger(target, inflictor) == true &&
|
||||
// SPB bypasses grow (K_IsBigger handles NULL check)
|
||||
(type != DMG_EXPLODE || inflictor->type != MT_SPBEXPLOSION || !inflictor->movefactor))
|
||||
{
|
||||
sfx = sfx_grownd;
|
||||
}
|
||||
else if (K_PlayerGuard(player))
|
||||
{
|
||||
sfx = sfx_s3k3a;
|
||||
}
|
||||
else if (player->overshield &&
|
||||
(type != DMG_EXPLODE || inflictor->type != MT_SPBEXPLOSION || !inflictor->movefactor))
|
||||
{
|
||||
;
|
||||
}
|
||||
else if (player->lightningcharge &&
|
||||
(type != DMG_EXPLODE || inflictor->type != MT_SPBEXPLOSION || !inflictor->movefactor))
|
||||
{
|
||||
;
|
||||
sfx = sfx_s3k45;
|
||||
}
|
||||
else if (player->hyudorotimer > 0)
|
||||
;
|
||||
else
|
||||
{
|
||||
invincible = false;
|
||||
}
|
||||
|
||||
// Hack for instawhip-guard counter, lets invincible players lose to guard
|
||||
if (inflictor == target)
|
||||
{
|
||||
invincible = false;
|
||||
}
|
||||
|
||||
if (player->pflags2 & PF2_ALWAYSDAMAGED)
|
||||
{
|
||||
invincible = false;
|
||||
clash = false;
|
||||
}
|
||||
|
||||
// TODO: doing this from P_DamageMobj limits punting to objects that damage the player.
|
||||
// And it may be kind of yucky.
|
||||
// But this is easier than accounting for every condition in PIT_CheckThing!
|
||||
if (inflictor && K_PuntCollide(inflictor, target))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (invincible && !truewhumble)
|
||||
{
|
||||
const INT32 oldHitlag = target->hitlag;
|
||||
const INT32 oldHitlagInflictor = inflictor ? inflictor->hitlag : 0;
|
||||
|
||||
// Damage during hitlag should be a no-op
|
||||
// for invincibility states because there
|
||||
// are no flashing tics. If the damage is
|
||||
// from a constant source, a deadlock
|
||||
// would occur.
|
||||
|
||||
if (target->eflags & MFE_PAUSED)
|
||||
{
|
||||
player->timeshit--; // doesn't count
|
||||
|
||||
if (playerInflictor)
|
||||
{
|
||||
playerInflictor->timeshit--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!clash) // Currently a no-op, damage floor hitlag kinda sucked ass
|
||||
{
|
||||
laglength = max(laglength / 2, 1);
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, false);
|
||||
|
||||
AddNullHitlag(player, oldHitlag);
|
||||
AddNullHitlag(playerInflictor, oldHitlagInflictor);
|
||||
}
|
||||
|
||||
if (player->timeshit > player->timeshitprev)
|
||||
{
|
||||
S_StartSound(target, sfx);
|
||||
}
|
||||
|
||||
if (clash)
|
||||
{
|
||||
player->spheres = max(player->spheres - 5, 0);
|
||||
|
||||
if (inflictor)
|
||||
{
|
||||
K_DoPowerClash(target, inflictor);
|
||||
|
||||
if (player->lightningcharge)
|
||||
{
|
||||
K_SpawnDriftElectricSparks(player, SKINCOLOR_PURPLE, true);
|
||||
}
|
||||
|
||||
if (inflictor->type == MT_SUPER_FLICKY)
|
||||
{
|
||||
Obj_BlockSuperFlicky(inflictor);
|
||||
}
|
||||
|
||||
S_StartSound(target, sfx);
|
||||
}
|
||||
else if (source)
|
||||
{
|
||||
K_DoPowerClash(target, source);
|
||||
S_StartSound(target, sfx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Full invulnerability
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
{
|
||||
// Check if we should allow wombo combos (hard hits by default, inverted by the presence of DMG_WOMBO).
|
||||
boolean allowcombo = ((hardhit || (type == DMG_STUMBLE || type == DMG_WHUMBLE)) == !(damagetype & DMG_WOMBO));
|
||||
|
||||
// Tumble/stumble is a special case.
|
||||
if (type == DMG_TUMBLE)
|
||||
{
|
||||
// don't allow constant combo
|
||||
if (player->tumbleBounces == 1 && (P_MobjFlip(target)*target->momz > 0))
|
||||
allowcombo = false;
|
||||
}
|
||||
else if (type == DMG_STUMBLE || type == DMG_WHUMBLE)
|
||||
{
|
||||
// don't allow constant combo
|
||||
if (player->tumbleBounces == TUMBLEBOUNCES-1 && (P_MobjFlip(target)*target->momz > 0))
|
||||
{
|
||||
if (type == DMG_STUMBLE)
|
||||
return false; // No-sell strings of stumble
|
||||
|
||||
allowcombo = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->momx == 0 && inflictor->momy == 0 && inflictor->momz == 0 && inflictor->type != MT_SPBEXPLOSION)
|
||||
{
|
||||
// Probably a map hazard.
|
||||
allowcombo = false;
|
||||
}
|
||||
|
||||
if (allowcombo == false && (target->eflags & MFE_PAUSED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// DMG_EXPLODE excluded from flashtic checks to prevent dodging eggbox/SPB with weak spinout
|
||||
if ((target->hitlag == 0 || allowcombo == false) &&
|
||||
player->flashing > 0 &&
|
||||
type != DMG_EXPLODE &&
|
||||
type != DMG_STUMBLE &&
|
||||
type != DMG_WHUMBLE &&
|
||||
P_FlashingException(player, inflictor) == false)
|
||||
{
|
||||
// Post-hit invincibility
|
||||
K_DoInstashield(player);
|
||||
return false;
|
||||
}
|
||||
else if (target->flags2 & MF2_ALREADYHIT) // do not deal extra damage in the same tic
|
||||
{
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Steals 2 bumpers
|
||||
damage = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not die from damage outside of bumpers health system
|
||||
damage = 0;
|
||||
}
|
||||
|
||||
boolean softenTumble = false;
|
||||
|
||||
// Sting and stumble shouldn't be rewarding Battle hits.
|
||||
if (type == DMG_STING || type == DMG_STUMBLE)
|
||||
{
|
||||
damage = 0;
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
if (!P_PlayerInPain(player) && (player->defenseLockout || player->instaWhipCharge))
|
||||
{
|
||||
K_SpawnAmps(source->player, 20, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// We successfully damaged them! Give 'em some bumpers!
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
// Stone Shoe handles amps on its own, but this is also a good place to set soften tumble for it
|
||||
if (inflictor->type == MT_STONESHOE || inflictor->type == MT_STONESHOE_CHAIN)
|
||||
softenTumble = true;
|
||||
else
|
||||
K_SpawnAmps(source->player, K_PvPAmpReward((truewhumble) ? 30 : 20, source->player, player), target);
|
||||
|
||||
|
||||
K_BotHitPenalty(player);
|
||||
|
||||
if (G_SameTeam(source->player, player))
|
||||
{
|
||||
if (type != DMG_EXPLODE)
|
||||
{
|
||||
type = DMG_STUMBLE;
|
||||
downgraded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (UINT8 i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || players[i].spectator || !players[i].mo || P_MobjWasRemoved(players[i].mo))
|
||||
continue;
|
||||
if (!G_SameTeam(source->player, &players[i]))
|
||||
continue;
|
||||
if (source->player == &players[i])
|
||||
continue;
|
||||
K_SpawnAmps(&players[i], FixedInt(FixedMul(5, K_TeamComebackMultiplier(player))), target);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extend the invincibility if the hit was a direct hit.
|
||||
if (inflictor == source && source->player->invincibilitytimer &&
|
||||
!K_PowerUpRemaining(source->player, POWERUP_SMONITOR))
|
||||
{
|
||||
tic_t kinvextend;
|
||||
|
||||
softenTumble = true;
|
||||
|
||||
if (gametyperules & GTR_CLOSERPLAYERS)
|
||||
kinvextend = 2*TICRATE;
|
||||
else
|
||||
kinvextend = 3*TICRATE;
|
||||
|
||||
// Reduce the value of subsequent invinc extensions
|
||||
kinvextend = kinvextend / (1 + source->player->invincibilityextensions); // 50%, 33%, 25%[...]
|
||||
kinvextend = max(kinvextend, TICRATE);
|
||||
|
||||
source->player->invincibilityextensions++;
|
||||
|
||||
source->player->invincibilitytimer += kinvextend;
|
||||
|
||||
if (P_IsDisplayPlayer(source->player))
|
||||
S_StartSound(NULL, sfx_gsha7);
|
||||
}
|
||||
|
||||
// if the inflictor is a landmine, its reactiontime will be non-zero if it is still moving
|
||||
if (inflictor->type == MT_LANDMINE && inflictor->reactiontime > 0)
|
||||
{
|
||||
// reduce tumble severity to account for getting beaned point blank sometimes
|
||||
softenTumble = true;
|
||||
// make it more consistent with set landmines
|
||||
inflictor->momx = 0;
|
||||
inflictor->momy = 0;
|
||||
}
|
||||
|
||||
K_TryHurtSoundExchange(target, source);
|
||||
|
||||
if (K_Cooperative() == false)
|
||||
{
|
||||
K_BattleAwardHit(source->player, player, inflictor, damage);
|
||||
}
|
||||
|
||||
if (K_Bumpers(source->player) < K_StartingBumperCount() || (damagetype & DMG_STEAL))
|
||||
{
|
||||
K_TakeBumpersFromPlayer(source->player, player, damage);
|
||||
}
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Give them ALL of your emeralds instantly :)
|
||||
source->player->emeralds |= player->emeralds;
|
||||
player->emeralds = 0;
|
||||
K_CheckEmeralds(source->player);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(damagetype & DMG_STEAL))
|
||||
{
|
||||
// Drop all of your emeralds
|
||||
K_DropEmeraldsFromPlayer(player, player->emeralds);
|
||||
}
|
||||
}
|
||||
|
||||
if (source && source != player->mo && source->player)
|
||||
{
|
||||
if (damagetype != DMG_DEATHPIT)
|
||||
{
|
||||
player->pitblame = source->player - players;
|
||||
}
|
||||
}
|
||||
|
||||
player->sneakertimer = player->numsneakers = 0;
|
||||
player->panelsneakertimer = player->numpanelsneakers = 0;
|
||||
player->weaksneakertimer = player->numweaksneakers = 0;
|
||||
player->driftboost = player->strongdriftboost = 0;
|
||||
player->gateBoost = 0;
|
||||
player->fastfall = 0;
|
||||
player->ringboost = 0;
|
||||
player->glanceDir = 0;
|
||||
player->preventfailsafe = TICRATE*3;
|
||||
player->pflags &= ~PF_GAINAX;
|
||||
Obj_EndBungee(player);
|
||||
K_BumperInflate(target->player);
|
||||
|
||||
UINT32 hurtskinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[(player-players)]].flags
|
||||
: skins[player->skin]->flags;
|
||||
if (hurtskinflags & SF_IRONMAN)
|
||||
{
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
SetRandomFakePlayerSkin(player, false, true);
|
||||
}
|
||||
|
||||
// Explosions are explicit combo setups.
|
||||
if (damagetype & DMG_EXPLODE)
|
||||
player->bumperinflate = 0;
|
||||
|
||||
if (player->spectator == false && !(player->charflags & SF_IRONMAN))
|
||||
{
|
||||
UINT32 skinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[(player-players)]].flags
|
||||
: skins[player->skin]->flags;
|
||||
|
||||
if (skinflags & SF_IRONMAN)
|
||||
{
|
||||
player->mo->skin = skins[player->skin];
|
||||
player->charflags = skinflags;
|
||||
K_SpawnMagicianParticles(player->mo, 5);
|
||||
}
|
||||
}
|
||||
|
||||
if (player->rings <= -20)
|
||||
{
|
||||
player->markedfordeath = true;
|
||||
damagetype = DMG_TUMBLE;
|
||||
type = DMG_TUMBLE;
|
||||
P_StartQuakeFromMobj(5, 44 * player->mo->scale, 2560 * player->mo->scale, player->mo);
|
||||
//P_KillPlayer(player, inflictor, source, damagetype);
|
||||
}
|
||||
|
||||
// Death save! On your last hit, no matter what, demote to weakest damage type for one last escape chance.
|
||||
if (player->mo->health == 2 && damage && gametyperules & GTR_BUMPERS)
|
||||
{
|
||||
K_AddMessageForPlayer(player, "\x8DLast Chance!", false, false);
|
||||
S_StartSound(target, sfx_gshc7);
|
||||
player->flashing = TICRATE;
|
||||
type = DMG_STUMBLE;
|
||||
downgraded = true;
|
||||
}
|
||||
|
||||
// Downgrade backthrown items that are not dedicated traps.
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && P_IsKartItem(inflictor->type) && inflictor->cvmem
|
||||
&& inflictor->type != MT_BANANA)
|
||||
{
|
||||
type = DMG_WHUMBLE;
|
||||
downgraded = true;
|
||||
}
|
||||
|
||||
// Downgrade orbital items.
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && (inflictor->type == MT_ORBINAUT_SHIELD || inflictor->type == MT_JAWZ_SHIELD))
|
||||
{
|
||||
type = DMG_WHUMBLE;
|
||||
downgraded = true;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_SPHERES) && player->tripwireLeniency && !P_PlayerInPain(player))
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DMG_EXPLODE:
|
||||
type = DMG_TUMBLE;
|
||||
downgraded = true;
|
||||
softenTumble = true;
|
||||
break;
|
||||
case DMG_TUMBLE:
|
||||
softenTumble = true;
|
||||
break;
|
||||
case DMG_NORMAL:
|
||||
case DMG_WIPEOUT:
|
||||
downgraded = true;
|
||||
type = DMG_WHUMBLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DMG_STING:
|
||||
K_DebtStingPlayer(player, source);
|
||||
K_KartPainEnergyFling(player);
|
||||
ringburst = 0;
|
||||
break;
|
||||
case DMG_STUMBLE:
|
||||
case DMG_WHUMBLE:
|
||||
K_StumblePlayer(player);
|
||||
ringburst = (type == DMG_WHUMBLE) ? 5 : 0;
|
||||
break;
|
||||
case DMG_TUMBLE:
|
||||
K_TumblePlayer(player, inflictor, source, softenTumble);
|
||||
ringburst = 10;
|
||||
break;
|
||||
case DMG_EXPLODE:
|
||||
case DMG_KARMA:
|
||||
ringburst = K_ExplodePlayer(player, inflictor, source);
|
||||
break;
|
||||
case DMG_WIPEOUT:
|
||||
K_SpinPlayer(player, inflictor, source, KSPIN_WIPEOUT);
|
||||
K_KartPainEnergyFling(player);
|
||||
break;
|
||||
case DMG_VOLTAGE:
|
||||
case DMG_NORMAL:
|
||||
default:
|
||||
K_SpinPlayer(player, inflictor, source, KSPIN_SPINOUT);
|
||||
break;
|
||||
}
|
||||
|
||||
// Have a shield? You get hit, but don't lose your rings!
|
||||
if (player->curshield != KSHIELD_NONE)
|
||||
{
|
||||
ringburst = 0;
|
||||
}
|
||||
|
||||
player->ringburst += ringburst;
|
||||
|
||||
if (type != DMG_STUMBLE)
|
||||
{
|
||||
if (type != DMG_STING)
|
||||
player->flashing = K_GetKartFlashing(player);
|
||||
|
||||
K_PopPlayerShield(player);
|
||||
player->instashield = 15;
|
||||
K_PlayPainSound(target, source);
|
||||
player->ringboost = 0;
|
||||
}
|
||||
|
||||
if (gametyperules & GTR_BUMPERS)
|
||||
player->spheres = min(player->spheres + 10, 40);
|
||||
|
||||
if ((hardhit == true && !softenTumble) || cv_kartdebughuddrop.value)
|
||||
{
|
||||
K_DropItems(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
K_DropHnextList(player);
|
||||
}
|
||||
|
||||
if (inflictor && !P_MobjWasRemoved(inflictor) && inflictor->type == MT_BANANA)
|
||||
{
|
||||
player->flipDI = true;
|
||||
}
|
||||
|
||||
// Apply stun!
|
||||
if (type != DMG_STING)
|
||||
{
|
||||
K_ApplyStun(player, inflictor, source, damage, damagetype);
|
||||
}
|
||||
|
||||
K_DefensiveOverdrive(target->player);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target->type == MT_SPECIAL_UFO)
|
||||
{
|
||||
return Obj_SpecialUFODamage(target, inflictor, source, damagetype);
|
||||
}
|
||||
else if (target->type == MT_BLENDEYE_MAIN)
|
||||
{
|
||||
VS_BlendEye_Damage(target, inflictor, source, damage);
|
||||
}
|
||||
|
||||
if (damagetype & DMG_STEAL)
|
||||
{
|
||||
// Not a player, steal damage is intended to not do anything
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((target->flags & MF_BOSS) == MF_BOSS)
|
||||
{
|
||||
targetdamaging_t targetdamaging = UFOD_GENERIC;
|
||||
if (P_MobjWasRemoved(inflictor) == true)
|
||||
;
|
||||
else switch (inflictor->type)
|
||||
{
|
||||
case MT_GACHABOM:
|
||||
targetdamaging = UFOD_GACHABOM;
|
||||
break;
|
||||
case MT_ORBINAUT:
|
||||
case MT_ORBINAUT_SHIELD:
|
||||
targetdamaging = UFOD_ORBINAUT;
|
||||
break;
|
||||
case MT_BANANA:
|
||||
targetdamaging = UFOD_BANANA;
|
||||
break;
|
||||
case MT_INSTAWHIP:
|
||||
inflictor->extravalue2 = 1; // Disable whip collision
|
||||
targetdamaging = UFOD_WHIP;
|
||||
break;
|
||||
case MT_PLAYER:
|
||||
targetdamaging = UFOD_BOOST;
|
||||
break;
|
||||
case MT_JAWZ:
|
||||
case MT_JAWZ_SHIELD:
|
||||
targetdamaging = UFOD_JAWZ;
|
||||
break;
|
||||
case MT_SPB:
|
||||
targetdamaging = UFOD_SPB;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
P_TrackRoundConditionTargetDamage(targetdamaging);
|
||||
}
|
||||
}
|
||||
|
||||
// do the damage
|
||||
if (damagetype & DMG_DEATHMASK)
|
||||
target->health = 0;
|
||||
else
|
||||
target->health -= damage;
|
||||
|
||||
if (source && source->player && target)
|
||||
G_GhostAddHit((INT32) (source->player - players), target);
|
||||
|
||||
// Insta-Whip (DMG_WHUMBLE): do not reduce hitlag because
|
||||
// this can leave room for double-damage.
|
||||
if (truewhumble && (gametyperules & GTR_BUMPERS) && !battleprisons)
|
||||
laglength /= 2;
|
||||
|
||||
if (target->type == MT_PLAYER && inflictor && !P_MobjWasRemoved(inflictor)
|
||||
&& inflictor->type == MT_PLAYER && K_PlayerCanPunt(inflictor->player))
|
||||
laglength = max(laglength / 2, 2);
|
||||
|
||||
if (!(target->player && (damagetype & DMG_DEATHMASK)))
|
||||
K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
|
||||
target->flags2 |= MF2_ALREADYHIT;
|
||||
|
||||
if (target->health <= 0)
|
||||
{
|
||||
P_KillMobj(target, inflictor, source, damagetype);
|
||||
return true;
|
||||
}
|
||||
|
||||
//K_SetHitLagForObjects(target, inflictor, source, laglength, true);
|
||||
|
||||
if (!player)
|
||||
{
|
||||
P_SetMobjState(target, target->info->painstate);
|
||||
|
||||
if (!P_MobjWasRemoved(target))
|
||||
{
|
||||
// if not intent on another player,
|
||||
// chase after this one
|
||||
P_SetTarget(&target->target, source);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define RING_LAYER_SIDE_SIZE (3)
|
||||
#define RING_LAYER_SIZE (RING_LAYER_SIDE_SIZE * 2)
|
||||
|
||||
|
|
|
|||
|
|
@ -533,8 +533,8 @@ struct BasicFF_t
|
|||
#define DMG_STING 0x04
|
||||
#define DMG_KARMA 0x05 // Karma Bomb explosion -- works like DMG_EXPLODE, but steals half of their bumpers & deletes the rest
|
||||
#define DMG_VOLTAGE 0x06
|
||||
#define DMG_STUMBLE 0x07 // Does not award points in Battle
|
||||
#define DMG_WHUMBLE 0x08 // <-- But this one DOES!
|
||||
#define DMG_STUMBLE 0x07 // Harmless disruption.
|
||||
#define DMG_WHUMBLE 0x08 // Harmful disruption. (Awards points, strips rings, pops shields, etc)
|
||||
//// Death types - cannot be combined with damage types
|
||||
#define DMG_INSTAKILL 0x80
|
||||
#define DMG_DEATHPIT 0x81
|
||||
|
|
|
|||
20
src/p_map.c
20
src/p_map.c
|
|
@ -4104,8 +4104,6 @@ papercollision:
|
|||
|
||||
static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
||||
{
|
||||
extern consvar_t cv_showgremlins;
|
||||
|
||||
fixed_t mmomx = 0, mmomy = 0;
|
||||
fixed_t oldmomx = mo->momx, oldmomy = mo->momy;
|
||||
|
||||
|
|
@ -4130,24 +4128,6 @@ static void P_BouncePlayerMove(mobj_t *mo, TryMoveResult_t *result)
|
|||
slidemo = mo;
|
||||
bestslideline = result->line;
|
||||
|
||||
if (bestslideline == NULL && cv_showgremlins.value)
|
||||
{
|
||||
// debug
|
||||
mobj_t*x = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
|
||||
x->frame = FF_FULLBRIGHT | FF_ADD;
|
||||
x->renderflags = RF_ALWAYSONTOP;
|
||||
x->color = SKINCOLOR_RED;
|
||||
|
||||
CONS_Printf(
|
||||
"GREMLIN: leveltime=%u x=%f y=%f z=%f angle=%f\n",
|
||||
leveltime,
|
||||
FixedToFloat(mo->x),
|
||||
FixedToFloat(mo->y),
|
||||
FixedToFloat(mo->z),
|
||||
AngleToFloat(R_PointToAngle2(0, 0, oldmomx, oldmomy))
|
||||
);
|
||||
}
|
||||
|
||||
if (mo->health <= 0)
|
||||
{
|
||||
tmxmove = mo->momx;
|
||||
|
|
|
|||
103
src/p_mobj.c
103
src/p_mobj.c
|
|
@ -7997,7 +7997,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
break;
|
||||
case MT_TRIPWIREAPPROACH: {
|
||||
case MT_TRIPWIREAPPROACH: { // Subsonic Visuals
|
||||
if (!mobj->target || !mobj->target->health || !mobj->target->player)
|
||||
{
|
||||
P_RemoveMobj(mobj);
|
||||
|
|
@ -8007,17 +8007,53 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj_t *target = mobj->target;
|
||||
player_t *player = target->player;
|
||||
fixed_t myspeed = (player->speed);
|
||||
|
||||
boolean In_A_Race = ((gametyperules & GTR_CIRCUIT) && !K_Cooperative() && M_NotFreePlay() && !modeattacking); // If you're in a real race.
|
||||
boolean prorated_sonicboom_alert = (K_PlayerTripwireSpeedThreshold(player) > 2 * K_GetKartSpeed(player, false, false)) ; // If you're being prorated.
|
||||
fixed_t maxspeed = K_PlayerTripwireSpeedThreshold(player); // Centered at this speed.
|
||||
fixed_t minspeed = max(2 * maxspeed / 4, 16 * K_GetKartSpeed(player, false, false) / 10); // Starts appearing at this speed.
|
||||
fixed_t minspeed = max(2 * maxspeed / 4, 7 * K_GetKartSpeed(player, false, false) / 5); // Starts appearing at this speed.
|
||||
fixed_t alertspeed = 9 * maxspeed / 10; // When to flash?
|
||||
fixed_t frontoffset = 5*target->scale; // How far in front?
|
||||
|
||||
|
||||
fixed_t percentvisible = 0;
|
||||
|
||||
if (myspeed > minspeed)
|
||||
{
|
||||
percentvisible = min(FRACUNIT, FixedDiv(myspeed - minspeed, maxspeed - minspeed));
|
||||
}
|
||||
|
||||
if (myspeed >= maxspeed || player->tripwireLeniency)
|
||||
percentvisible = 0;
|
||||
{
|
||||
player->subsonicleniency++; // Subsonic visual stays for a bit during tripwire leniency
|
||||
|
||||
if(player->subsonicleniency == 1 && player->tripwireLeniency && myspeed >= maxspeed && !S_SoundPlaying(player->mo, sfx_gsha7)) // Don't play during superring too
|
||||
{
|
||||
mobj_t *boost = P_SpawnMobjFromMobj(player->mo, 0, 0, player->mo->height/2, MT_SONICBOOM);
|
||||
boost->momx = player->mo->momx/2;
|
||||
boost->momy = player->mo->momy/2;
|
||||
boost->momz = player->mo->momz/2;
|
||||
boost->angle = player->mo->angle + ANGLE_90;
|
||||
boost->scalespeed = boost->scale;
|
||||
boost->destscale = boost->scale*8;
|
||||
//sonicboom->color = SKINCOLOR_WHITE;
|
||||
boost->fuse = 8;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
player->subsonicleniency = 0; // Goes back down otherwise
|
||||
}
|
||||
|
||||
if (player->subsonicleniency >= (3*TICRATE))
|
||||
{
|
||||
percentvisible = 0; // Once it stays long enough, no longer visible
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
CONS_Printf("SSL=%d, PV=%d\n", player->subsonicleniency, percentvisible);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
fixed_t hang = 85*FRACUNIT/100; // Dampen inward movement past a certain point
|
||||
|
|
@ -8045,8 +8081,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
P_InstaScale(mobj, FixedMul(target->scale, easedscale));
|
||||
K_MatchGenericExtraFlagsNoInterp(mobj, target);
|
||||
|
||||
UINT8 maxtranslevel = NUMTRANSMAPS - 2;
|
||||
UINT8 maxtranslevel = NUMTRANSMAPS;
|
||||
UINT8 trans = FixedInt(FixedMul(percentvisible, FRACUNIT*(maxtranslevel+1)));
|
||||
//UINT8 trans = FixedInt(FixedMul(percentvisible - player->subsonicleniency * FRACUNIT/100, FRACUNIT*(maxtranslevel+1)));
|
||||
|
||||
if (trans > maxtranslevel)
|
||||
trans = maxtranslevel;
|
||||
trans = NUMTRANSMAPS - trans;
|
||||
|
|
@ -8060,13 +8098,52 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj->renderflags |= RF_PAPERSPRITE;
|
||||
|
||||
mobj->colorized = true;
|
||||
if (myspeed > alertspeed)
|
||||
mobj->color = (leveltime & 1) ? SKINCOLOR_LILAC : SKINCOLOR_JAWZ;
|
||||
else
|
||||
mobj->color = SKINCOLOR_WHITE;
|
||||
|
||||
/*
|
||||
if (!K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
CONS_Printf("In_A_Race=%d, Prorated_SonicBoom_Alert=%d\n", In_A_Race, prorated_sonicboom_alert);
|
||||
}
|
||||
*/
|
||||
if (In_A_Race == true && prorated_sonicboom_alert == true)
|
||||
{
|
||||
mobj->color = (leveltime & 1) ? SKINCOLOR_KETCHUP : SKINCOLOR_RED; // If you're being prorated we flash red
|
||||
trans = trans*2;
|
||||
}
|
||||
else if (myspeed > alertspeed)
|
||||
mobj->color = (leveltime & 1) ? SKINCOLOR_LILAC : SKINCOLOR_JAWZ; // If the Subsonic lines meet we flash tripwire colors
|
||||
else
|
||||
mobj->color = SKINCOLOR_WHITE; // Default
|
||||
|
||||
mobj->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player));
|
||||
|
||||
// Alright, let's just handle all the sfx down here
|
||||
|
||||
if (P_IsDisplayPlayer(player))
|
||||
{
|
||||
UINT8 MIN_VOLUME = 25;
|
||||
UINT8 MAX_VOLUME = 75;
|
||||
UINT8 volume = FixedRescale(myspeed, minspeed, maxspeed, Easing_Linear, MIN_VOLUME, MAX_VOLUME);
|
||||
|
||||
if (myspeed >= minspeed && myspeed < maxspeed)
|
||||
{
|
||||
S_StopSoundByID(mobj, sfx_sonbo1);
|
||||
if(!S_SoundPlaying(mobj, sfx_sonbo3))
|
||||
S_StartSoundAtVolume(mobj, sfx_sonbo3, volume); // Subsonic SFX
|
||||
}
|
||||
else if (myspeed >= maxspeed || player->tripwireLeniency)
|
||||
{
|
||||
S_StopSoundByID(mobj, sfx_sonbo3);
|
||||
if(!S_SoundPlaying(mobj, sfx_sonbo1))
|
||||
S_StartSoundAtVolume(mobj, sfx_sonbo1, MAX_VOLUME); // SonicBoom lingering SFX
|
||||
}
|
||||
else
|
||||
{
|
||||
S_StopSoundByID(mobj, sfx_sonbo1);
|
||||
S_StopSoundByID(mobj, sfx_sonbo3);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case MT_TRIPWIREBOOST: {
|
||||
|
|
@ -9476,8 +9553,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
// it's still necessary to refresh SPR2 on skin changes.
|
||||
P_SetMobjState(cur, (newperfect == true) ? S_KART_SIGL : S_KART_SIGN);
|
||||
|
||||
if (cv_shittysigns.value && cur->state != &states[S_KART_SIGL])
|
||||
cur->sprite2 = P_GetSkinSprite2(skins[newplayer->skin], SPR2_SSIG, NULL);;
|
||||
if ((cv_shittysigns.value || newplayer->mfdfinish) && cur->state != &states[S_KART_SIGL])
|
||||
{
|
||||
cur->sprite2 = P_GetSkinSprite2(skins[newplayer->skin], SPR2_SSIG, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (cur->state == &states[S_SIGN_ERROR])
|
||||
|
|
|
|||
|
|
@ -512,6 +512,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT16(save->p, players[i].spindash);
|
||||
WRITEFIXED(save->p, players[i].spindashspeed);
|
||||
WRITEUINT8(save->p, players[i].spindashboost);
|
||||
WRITEUINT8(save->p, players[i].ringboostinprogress);
|
||||
|
||||
WRITEFIXED(save->p, players[i].fastfall);
|
||||
WRITEFIXED(save->p, players[i].fastfallBase);
|
||||
|
|
@ -533,6 +534,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT16(save->p, players[i].tripwireLeniency);
|
||||
WRITEUINT8(save->p, players[i].tripwireAirLeniency);
|
||||
WRITEUINT8(save->p, players[i].fakeBoost);
|
||||
WRITEUINT16(save->p, players[i].subsonicleniency);
|
||||
|
||||
WRITESINT8(save->p, players[i].itemtype);
|
||||
WRITEUINT8(save->p, players[i].itemamount);
|
||||
|
|
@ -653,7 +655,6 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEFIXED(save->p, players[i].overdrivepower);
|
||||
WRITEUINT8(save->p, players[i].overdriveready);
|
||||
WRITEUINT8(save->p, players[i].overdrivelenient);
|
||||
WRITEUINT16(save->p, players[i].speedpunt);
|
||||
WRITEUINT16(save->p, players[i].trickcharge);
|
||||
|
||||
WRITEUINT16(save->p, players[i].infinitether);
|
||||
|
|
@ -700,6 +701,7 @@ static void P_NetArchivePlayers(savebuffer_t *save)
|
|||
WRITEUINT8(save->p, players[i].analoginput);
|
||||
|
||||
WRITEUINT8(save->p, players[i].markedfordeath);
|
||||
WRITEUINT8(save->p, players[i].mfdfinish);
|
||||
WRITEUINT8(save->p, players[i].dotrickfx);
|
||||
WRITEUINT8(save->p, players[i].stingfx);
|
||||
WRITEUINT8(save->p, players[i].bumperinflate);
|
||||
|
|
@ -1191,6 +1193,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].spindash = READUINT16(save->p);
|
||||
players[i].spindashspeed = READFIXED(save->p);
|
||||
players[i].spindashboost = READUINT8(save->p);
|
||||
players[i].ringboostinprogress = READUINT8(save->p);
|
||||
|
||||
players[i].fastfall = READFIXED(save->p);
|
||||
players[i].fastfallBase = READFIXED(save->p);
|
||||
|
|
@ -1212,6 +1215,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].tripwireLeniency = READUINT16(save->p);
|
||||
players[i].tripwireAirLeniency = READUINT8(save->p);
|
||||
players[i].fakeBoost = READUINT8(save->p);
|
||||
players[i].subsonicleniency = READUINT16(save->p);
|
||||
|
||||
players[i].itemtype = READSINT8(save->p);
|
||||
players[i].itemamount = READUINT8(save->p);
|
||||
|
|
@ -1331,7 +1335,6 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].overdrivepower = READFIXED(save->p);
|
||||
players[i].overdriveready = READUINT8(save->p);
|
||||
players[i].overdrivelenient = READUINT8(save->p);
|
||||
players[i].speedpunt = READUINT16(save->p);
|
||||
players[i].trickcharge = READUINT16(save->p);
|
||||
|
||||
players[i].infinitether = READUINT16(save->p);
|
||||
|
|
@ -1377,6 +1380,7 @@ static void P_NetUnArchivePlayers(savebuffer_t *save)
|
|||
players[i].analoginput = READUINT8(save->p);
|
||||
|
||||
players[i].markedfordeath = READUINT8(save->p);
|
||||
players[i].mfdfinish = READUINT8(save->p);
|
||||
players[i].dotrickfx = READUINT8(save->p);
|
||||
players[i].stingfx = READUINT8(save->p);
|
||||
players[i].bumperinflate = READUINT8(save->p);
|
||||
|
|
|
|||
17
src/p_spec.c
17
src/p_spec.c
|
|
@ -1964,7 +1964,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
if (!G_TimeAttackStart() && leveltime < starttime && !(gametyperules & GTR_ROLLINGSTART))
|
||||
{
|
||||
// freeze 'em until fault penalty is over
|
||||
player->mo->hitlag = starttime - leveltime + TICRATE;
|
||||
player->mo->hitlag = starttime - leveltime + 2*TICRATE;
|
||||
P_ResetPlayer(player);
|
||||
player->pflags |= PF_VOID;
|
||||
player->mo->renderflags |= RF_DONTDRAW;
|
||||
|
|
@ -2020,7 +2020,7 @@ static void K_HandleLapIncrement(player_t *player)
|
|||
}
|
||||
|
||||
// finished race exit setup
|
||||
if (player->laps > numlaps && !K_InRaceDuel())
|
||||
if (player->laps > numlaps)
|
||||
{
|
||||
pflags_t applyflags = 0;
|
||||
if (specialstageinfo.valid == true)
|
||||
|
|
@ -5421,11 +5421,22 @@ static void P_EvaluateDamageType(player_t *player, sector_t *sector, boolean isT
|
|||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
|
||||
break;
|
||||
case SD_STUMBLE:
|
||||
if (isTouching)
|
||||
if (isTouching && G_CompatLevel(0x0010))
|
||||
{
|
||||
player->pflags2 |= PF2_ALWAYSDAMAGED;
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_STUMBLE);
|
||||
player->pflags2 &= ~PF2_ALWAYSDAMAGED;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isTouching && player->mo->hitlag == 0 &&
|
||||
(player->mo->momz == 0 || (player->mo->momz > 0) != (P_MobjFlip(player->mo) > 0)))
|
||||
{
|
||||
player->pflags2 |= PF2_ALWAYSDAMAGED;
|
||||
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_STUMBLE);
|
||||
player->pflags2 &= ~PF2_ALWAYSDAMAGED;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
#include "p_sweep.hpp"
|
||||
|
||||
#include "p_local.h"
|
||||
#include "g_demo.h"
|
||||
#include "r_main.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -30,6 +32,8 @@ void P_TestLine(line_t* ld)
|
|||
|
||||
line_t* P_SweepTestLines(fixed_t ax, fixed_t ay, fixed_t bx, fixed_t by, fixed_t r, vector2_t* return_normal)
|
||||
{
|
||||
extern consvar_t cv_showgremlins;
|
||||
|
||||
using namespace srb2::math;
|
||||
using namespace srb2::sweep;
|
||||
|
||||
|
|
@ -60,13 +64,65 @@ line_t* P_SweepTestLines(fixed_t ax, fixed_t ay, fixed_t bx, fixed_t by, fixed_t
|
|||
}
|
||||
}
|
||||
|
||||
g_lines.clear();
|
||||
|
||||
if (!collision)
|
||||
{
|
||||
return nullptr;
|
||||
line_t *line = nullptr;
|
||||
|
||||
if (!g_lines.empty() && !G_CompatLevel(0x000E))
|
||||
{
|
||||
// FIXME: This condition is a failsafe!
|
||||
// SlopeAABBvsLine::vs_slope can sometimes report
|
||||
// no collision despite P_CheckPosition saying otherwise.
|
||||
// (Generally related to infinitesimal numbers or overflows.)
|
||||
// When it reports no collision, that means no line and
|
||||
// no normals to base the collision off of.
|
||||
// Here we provide the last line checked and normals based on
|
||||
// the line and the player's momentum angle.
|
||||
// But the proper fix would be to make vs_slope work!!
|
||||
|
||||
line = g_lines.back();
|
||||
|
||||
angle_t lineangle = line->angle;
|
||||
angle_t mobjangle = R_PointToAngle2(ax, ay, bx, by);
|
||||
angle_t diff = lineangle - mobjangle;
|
||||
|
||||
lineangle += diff > ANGLE_180 ? -ANGLE_90 : ANGLE_90;
|
||||
|
||||
return_normal->x = FINECOSINE((lineangle >> ANGLETOFINESHIFT) & FINEMASK);
|
||||
return_normal->y = FINESINE((lineangle >> ANGLETOFINESHIFT) & FINEMASK);
|
||||
|
||||
// Moving the gremlin debug here so that it
|
||||
// still fires even when the workaround is used.
|
||||
if (cv_showgremlins.value)
|
||||
{
|
||||
mobj_t *mo = g_tm.thing;
|
||||
|
||||
if (mo)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobj(mo->x, mo->y, mo->z, MT_THOK);
|
||||
x->frame = FF_FULLBRIGHT | FF_ADD;
|
||||
x->renderflags = RF_ALWAYSONTOP;
|
||||
x->color = SKINCOLOR_RED;
|
||||
|
||||
CONS_Printf(
|
||||
"GREMLIN: leveltime=%u x=%f y=%f z=%f momx=%f momy=%f momz=%f\n",
|
||||
leveltime,
|
||||
FixedToFloat(mo->x),
|
||||
FixedToFloat(mo->y),
|
||||
FixedToFloat(mo->z),
|
||||
FixedToFloat(mo->momx),
|
||||
FixedToFloat(mo->momy),
|
||||
FixedToFloat(mo->momz)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_lines.clear();
|
||||
return line;
|
||||
}
|
||||
|
||||
g_lines.clear();
|
||||
return_normal->x = Fixed {collision->normal.x};
|
||||
return_normal->y = Fixed {collision->normal.y};
|
||||
|
||||
|
|
|
|||
|
|
@ -1272,6 +1272,7 @@ void P_DoPlayerExit(player_t *player, pflags_t flags)
|
|||
if (!player->spectator && (gametyperules & GTR_CIRCUIT)) // Special Race-like handling
|
||||
{
|
||||
K_UpdateAllPlayerPositions();
|
||||
player->mfdfinish = player->markedfordeath;
|
||||
}
|
||||
|
||||
if (!(gametyperules & GTR_SPHERES) && (player->pflags & PF_RINGLOCK) && grandprixinfo.gp)
|
||||
|
|
|
|||
|
|
@ -732,8 +732,7 @@ void R_RenderMaskedSegRange(drawseg_t *drawseg, INT32 x1, INT32 x2)
|
|||
template <typename T>
|
||||
static constexpr T saturating_add(T x, T y) noexcept
|
||||
{
|
||||
INT64 z;
|
||||
z = static_cast<INT64>(x) + static_cast<INT64>(y);
|
||||
INT64 z = static_cast<INT64>(x) + static_cast<INT64>(y);
|
||||
if (z > static_cast<INT64>(std::numeric_limits<T>::max()))
|
||||
{
|
||||
z = static_cast<INT64>(std::numeric_limits<T>::max());
|
||||
|
|
@ -748,8 +747,7 @@ static constexpr T saturating_add(T x, T y) noexcept
|
|||
template <typename T>
|
||||
static constexpr T saturating_mul(T x, T y) noexcept
|
||||
{
|
||||
INT64 z;
|
||||
z = static_cast<INT64>(x) * static_cast<INT64>(y);
|
||||
INT64 z = static_cast<INT64>(x) * static_cast<INT64>(y);
|
||||
if (z > static_cast<INT64>(std::numeric_limits<T>::max()))
|
||||
{
|
||||
z = static_cast<INT64>(std::numeric_limits<T>::max());
|
||||
|
|
|
|||
|
|
@ -1293,7 +1293,7 @@ Rloadtextures (INT32 i, INT32 w)
|
|||
}
|
||||
|
||||
INT32 sizeLimit = 2048;
|
||||
if (w <= mainwads)
|
||||
if (w < mainwads)
|
||||
{
|
||||
// TODO: we ran out of time to do this properly.
|
||||
// 4096 limit on textures may be incompatible with some older graphics cards (circa 2005-2008?).
|
||||
|
|
|
|||
|
|
@ -970,7 +970,7 @@ void S_UpdateVoicePositionalProperties(void)
|
|||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (!playeringame[i] || !voice_proximity_enabled)
|
||||
if (!playeringame[i])
|
||||
{
|
||||
I_SetPlayerVoiceProperties(i, speakingplayerattenuation, 0.0f);
|
||||
continue;
|
||||
|
|
@ -1025,7 +1025,7 @@ void S_UpdateVoicePositionalProperties(void)
|
|||
attenuation_distance = voice_distanceattenuation_teamdistance;
|
||||
}
|
||||
|
||||
if (attenuation_distance > 0 && voice_distanceattenuation_factor >= 0 && voice_distanceattenuation_factor <= 1.0f)
|
||||
if (voice_proximity_enabled && attenuation_distance > 0 && voice_distanceattenuation_factor >= 0 && voice_distanceattenuation_factor <= 1.0f)
|
||||
{
|
||||
float invfactor = 1.0f - voice_distanceattenuation_factor;
|
||||
float distfactor = max(0.f, min(attenuation_distance, pdistance)) / attenuation_distance;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "../core/string.h"
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <tracy/tracy/Tracy.hpp>
|
||||
|
||||
|
|
@ -32,11 +31,7 @@
|
|||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "time.h" // For log timestamps
|
||||
}
|
||||
|
||||
#ifdef HAVE_SDL
|
||||
|
||||
#ifdef HAVE_TTF
|
||||
#include "SDL.h"
|
||||
|
|
@ -68,46 +63,6 @@ char logfilename[1024];
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined (_WIN32)
|
||||
extern "C" {
|
||||
#include "../win32/win_dbg.h"
|
||||
}
|
||||
typedef BOOL (WINAPI *p_IsDebuggerPresent)(VOID);
|
||||
#endif
|
||||
|
||||
#if defined (_WIN32)
|
||||
static inline VOID MakeCodeWritable(VOID)
|
||||
{
|
||||
#ifdef USEASM // Disable write-protection of code segment
|
||||
DWORD OldRights;
|
||||
const DWORD NewRights = PAGE_EXECUTE_READWRITE;
|
||||
PBYTE pBaseOfImage = (PBYTE)GetModuleHandle(NULL);
|
||||
PIMAGE_DOS_HEADER dosH =(PIMAGE_DOS_HEADER)pBaseOfImage;
|
||||
PIMAGE_NT_HEADERS ntH = (PIMAGE_NT_HEADERS)(pBaseOfImage + dosH->e_lfanew);
|
||||
PIMAGE_OPTIONAL_HEADER oH = (PIMAGE_OPTIONAL_HEADER)
|
||||
((PBYTE)ntH + sizeof (IMAGE_NT_SIGNATURE) + sizeof (IMAGE_FILE_HEADER));
|
||||
LPVOID pA = pBaseOfImage+oH->BaseOfCode;
|
||||
SIZE_T pS = oH->SizeOfCode;
|
||||
#if 1 // try to find the text section
|
||||
PIMAGE_SECTION_HEADER ntS = IMAGE_FIRST_SECTION (ntH);
|
||||
WORD s;
|
||||
for (s = 0; s < ntH->FileHeader.NumberOfSections; s++)
|
||||
{
|
||||
if (memcmp (ntS[s].Name, ".text\0\0", 8) == 0)
|
||||
{
|
||||
pA = pBaseOfImage+ntS[s].VirtualAddress;
|
||||
pS = ntS[s].Misc.VirtualSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!VirtualProtect(pA,pS,NewRights,&OldRights))
|
||||
I_Error("Could not make code writable\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LOGMESSAGES
|
||||
static void InitLogging(void)
|
||||
{
|
||||
|
|
@ -212,10 +167,6 @@ static void init_exchndl()
|
|||
if (pfnExcHndlInit != NULL)
|
||||
(pfnExcHndlInit)();
|
||||
}
|
||||
#else
|
||||
static void init_exchndl()
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -300,25 +251,12 @@ int main(int argc, char **argv)
|
|||
|
||||
//I_OutputMsg("I_StartupSystem() ...\n");
|
||||
I_StartupSystem();
|
||||
#if defined (_WIN32)
|
||||
|
||||
#if defined (_WIN32) && !defined(_MSC_VER)
|
||||
if (!M_CheckParm("-noexchndl"))
|
||||
{
|
||||
#if 0 // just load the DLL
|
||||
p_IsDebuggerPresent pfnIsDebuggerPresent = (p_IsDebuggerPresent)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsDebuggerPresent");
|
||||
if ((!pfnIsDebuggerPresent || !pfnIsDebuggerPresent())
|
||||
#ifdef BUGTRAP
|
||||
&& !InitBugTrap()
|
||||
#endif
|
||||
)
|
||||
#endif
|
||||
{
|
||||
init_exchndl();
|
||||
}
|
||||
init_exchndl();
|
||||
}
|
||||
#ifndef __MINGW32__
|
||||
prevExceptionFilter = SetUnhandledExceptionFilter(RecordExceptionInfo);
|
||||
#endif
|
||||
MakeCodeWritable();
|
||||
#endif
|
||||
|
||||
try {
|
||||
|
|
@ -353,8 +291,6 @@ int main(int argc, char **argv)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
int WINAPI WinMain(HINSTANCE pInstance, HINSTANCE pPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ typedef DWORD (WINAPI *p_timeGetTime) (void);
|
|||
typedef UINT (WINAPI *p_timeEndPeriod) (UINT);
|
||||
typedef HANDLE (WINAPI *p_OpenFileMappingA) (DWORD, BOOL, LPCSTR);
|
||||
typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
|
||||
|
||||
#if defined(_WIN32) && !defined(__GNUC__)
|
||||
#define USE_DBGHELP
|
||||
#include <DbgHelp.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -141,6 +147,10 @@ typedef LPVOID (WINAPI *p_MapViewOfFile) (HANDLE, DWORD, DWORD, DWORD, SIZE_T);
|
|||
#define UNIXBACKTRACE
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CPPTRACE
|
||||
#include <cpptrace/cpptrace.hpp>
|
||||
#endif
|
||||
|
||||
// Locations for searching for bios.pk3
|
||||
#if defined (__unix__) || defined(__APPLE__) || defined (UNIXCOMMON)
|
||||
#define DEFAULTWADLOCATION1 "/usr/local/share/games/RingRacers"
|
||||
|
|
@ -302,8 +312,10 @@ static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dump
|
|||
dumpmade ?
|
||||
#if defined (UNIXBACKTRACE)
|
||||
"crash-log.txt"
|
||||
#elif defined (_WIN32)
|
||||
#elif defined (_WIN32) && defined(__GNUC__)
|
||||
".rpt crash dump"
|
||||
#elif defined (USE_DBGHELP)
|
||||
".dmp crash dump"
|
||||
#endif
|
||||
" (very important!) and " : "",
|
||||
#ifdef LOGMESSAGES
|
||||
|
|
@ -369,12 +381,83 @@ static void I_ShowErrorMessageBox(const char *messagefordevelopers, boolean dump
|
|||
// in case the fullscreen window blocks it for some absurd reason.
|
||||
}
|
||||
|
||||
static void I_ReportSignal(int num, int coredumped)
|
||||
static void I_ReportSignal(int num, int coredumped, void* tracefromcpptrace)
|
||||
{
|
||||
//static char msg[] = "oh no! back to reality!\r\n";
|
||||
const char * sigmsg;
|
||||
char msg[128];
|
||||
char msg[8192];
|
||||
|
||||
#ifdef USE_DBGHELP
|
||||
// The signal code is a WIN32 exception code, not a libc signal
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-exception_record
|
||||
switch (num)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
sigmsg = "EXCEPTION_ACCESS_VIOLATION";
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
sigmsg = "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
|
||||
break;
|
||||
case EXCEPTION_BREAKPOINT:
|
||||
sigmsg = "EXCEPTION_BREAKPOINT";
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
sigmsg = "EXCEPTION_DATATYPE_MISALIGNMENT";
|
||||
break;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
sigmsg = "EXCEPTION_FLT_DENORMAL_OPERAND";
|
||||
break;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
sigmsg = "EXCEPTION_FLT_DENORMAL_OPERAND";
|
||||
break;
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
sigmsg = "EXCEPTION_FLT_INEXACT_RESULT";
|
||||
break;
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
sigmsg = "EXCEPTION_FLT_INVALID_OPERATION";
|
||||
break;
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
sigmsg = "EXCEPTION_FLT_OVERFLOW";
|
||||
break;
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
sigmsg = "EXCEPTION_FLT_STACK_CHECK";
|
||||
break;
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
sigmsg = "EXCEPTION_FLT_UNDERFLOW";
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
sigmsg = "EXCEPTION_ILLEGAL_INSTRUCTION";
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
sigmsg = "EXCEPTION_IN_PAGE_ERROR";
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
sigmsg = "EXCEPTION_INT_DIVIDE_BY_ZERO";
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
sigmsg = "EXCEPTION_INT_OVERFLOW";
|
||||
break;
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
sigmsg = "EXCEPTION_INVALID_DISPOSITION";
|
||||
break;
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
sigmsg = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
sigmsg = "EXCEPTION_PRIV_INSTRUCTION";
|
||||
break;
|
||||
case EXCEPTION_SINGLE_STEP:
|
||||
sigmsg = "EXCEPTION_SINGLE_STEP";
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
sigmsg = "EXCEPTION_STACK_OVERFLOW";
|
||||
break;
|
||||
default:
|
||||
sigmsg = "";
|
||||
sprintf(msg, "unknown exception %d", num);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
switch (num)
|
||||
{
|
||||
// case SIGINT:
|
||||
|
|
@ -405,30 +488,132 @@ static void I_ReportSignal(int num, int coredumped)
|
|||
else
|
||||
sigmsg = msg;
|
||||
}
|
||||
#endif
|
||||
if (sigmsg)
|
||||
{
|
||||
strcpy(msg, sigmsg);
|
||||
}
|
||||
|
||||
if (coredumped)
|
||||
{
|
||||
if (sigmsg)
|
||||
strcpy(msg, sigmsg);
|
||||
strcat(msg, " (core dumped)");
|
||||
|
||||
sigmsg = msg;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CPPTRACE
|
||||
strncat(msg, "\n", sizeof(msg) - strlen(msg) - 1);
|
||||
|
||||
cpptrace::stacktrace const& trace = *(cpptrace::stacktrace*)tracefromcpptrace;
|
||||
bool firstfound = false;
|
||||
#ifndef _WIN32
|
||||
firstfound = true;
|
||||
#endif
|
||||
for (const auto& frame : trace)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// dumb hack, unsure if it works on anything other than windows 10-11
|
||||
if (!firstfound && frame.symbol == "KiUserExceptionDispatcher")
|
||||
{
|
||||
firstfound = true;
|
||||
continue;
|
||||
}
|
||||
if (!firstfound)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
srb2::String frame_str;
|
||||
if (!frame.filename.empty() && frame.line.has_value())
|
||||
{
|
||||
frame_str = srb2::format("{} at {}:{}\n", frame.symbol, frame.filename, frame.line.value_or(0));
|
||||
}
|
||||
else if (!frame.filename.empty() && !frame.line.has_value())
|
||||
{
|
||||
frame_str = srb2::format("{} at {}\n", frame.symbol, frame.filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
frame_str = srb2::format("{}\n", frame.symbol);
|
||||
}
|
||||
|
||||
strncat(msg, frame_str.c_str(), sizeof(msg) - strlen(msg) - 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
sigmsg = msg;
|
||||
|
||||
I_OutputMsg("\nProcess killed by signal: %s\n\n", sigmsg);
|
||||
|
||||
I_ShowErrorMessageBox(sigmsg,
|
||||
#if defined (UNIXBACKTRACE)
|
||||
true
|
||||
#elif defined (_WIN32)
|
||||
#elif defined (_WIN32) && defined (__GNUC__)
|
||||
!M_CheckParm("-noexchndl")
|
||||
#elif defined (USE_DBGHELP)
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
#ifndef NEWSIGNALHANDLER
|
||||
#if !defined(NEWSIGNALHANDLER) || defined(USE_DBGHELP)
|
||||
static void CommonSignalHandleCleanup(void)
|
||||
{
|
||||
D_QuitNetGame(); // Fix server freezes
|
||||
CL_AbortDownloadResume();
|
||||
G_DirtyGameData();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DBGHELP
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER g_previous_toplevelexceptionfilter;
|
||||
|
||||
static LONG WriteMinidumpExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo)
|
||||
{
|
||||
#ifdef HAVE_CPPTRACE
|
||||
// Fully aware this is completely signal unsafe. We don't ever try to recover from signals, so who cares.
|
||||
// If it breaks it breaks. We're not mission critical software.
|
||||
cpptrace::stacktrace trace = cpptrace::generate_trace(0, 30);
|
||||
#else
|
||||
int trace = 0;
|
||||
#endif
|
||||
|
||||
MINIDUMP_EXCEPTION_INFORMATION mei {};
|
||||
mei.ExceptionPointers = ExceptionInfo;
|
||||
mei.ClientPointers = TRUE;
|
||||
mei.ThreadId = GetCurrentThreadId();
|
||||
HANDLE outfile;
|
||||
|
||||
char outfilename[1024];
|
||||
GetModuleFileNameA(NULL, outfilename, sizeof(outfilename));
|
||||
strncat(outfilename, ".dmp", sizeof(outfilename) - strlen(outfilename) - 1);
|
||||
|
||||
outfile = CreateFileA(outfilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (outfile == NULL)
|
||||
{
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL result;
|
||||
result = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), outfile, MiniDumpNormal, &mei, NULL, NULL);
|
||||
if (result == FALSE)
|
||||
{
|
||||
CloseHandle(outfile);
|
||||
DeleteFileA("ringracers_minidump.dmp");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
CloseHandle(outfile);
|
||||
|
||||
exit:
|
||||
CommonSignalHandleCleanup();
|
||||
I_ReportSignal(ExceptionInfo->ExceptionRecord->ExceptionCode, 0, (void*)&trace);
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(NEWSIGNALHANDLER) && !defined(USE_DBGHELP)
|
||||
static ATTRNORETURN void signal_handler(INT32 num)
|
||||
{
|
||||
g_in_exiting_signal_handler = true;
|
||||
|
|
@ -441,18 +626,20 @@ static ATTRNORETURN void signal_handler(INT32 num)
|
|||
exit(-2);
|
||||
}
|
||||
|
||||
D_QuitNetGame(); // Fix server freezes
|
||||
CL_AbortDownloadResume();
|
||||
G_DirtyGameData();
|
||||
CommonSignalHandleCleanup();
|
||||
#ifdef UNIXBACKTRACE
|
||||
write_backtrace(num);
|
||||
#endif
|
||||
I_ReportSignal(num, 0);
|
||||
I_ReportSignal(num, 0, NULL);
|
||||
signal(num, SIG_DFL); //default signal action
|
||||
raise(num);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_DBGHELP
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER g_prevtoplevelexceptionfilter;
|
||||
#endif
|
||||
|
||||
FUNCNORETURN static ATTRNORETURN void quit_handler(int num)
|
||||
{
|
||||
signal(num, SIG_DFL); //default signal action
|
||||
|
|
@ -829,12 +1016,17 @@ static void I_RegisterSignals (void)
|
|||
|
||||
// If these defines don't exist,
|
||||
// then compilation would have failed above us...
|
||||
#ifndef NEWSIGNALHANDLER
|
||||
#if !defined(NEWSIGNALHANDLER) && !defined(USE_DBGHELP)
|
||||
signal(SIGILL , signal_handler);
|
||||
signal(SIGSEGV , signal_handler);
|
||||
signal(SIGABRT , signal_handler);
|
||||
signal(SIGFPE , signal_handler);
|
||||
#endif
|
||||
|
||||
#ifdef USE_DBGHELP
|
||||
// Initialize Windows SDK-specific crashdump handler (DbgHelp)
|
||||
g_previous_toplevelexceptionfilter = SetUnhandledExceptionFilter(WriteMinidumpExceptionFilter);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef NEWSIGNALHANDLER
|
||||
|
|
@ -1598,9 +1790,9 @@ static void I_Fork(void)
|
|||
{
|
||||
signum = WTERMSIG (status);
|
||||
#ifdef WCOREDUMP
|
||||
I_ReportSignal(signum, WCOREDUMP (status));
|
||||
I_ReportSignal(signum, WCOREDUMP (status), NULL);
|
||||
#else
|
||||
I_ReportSignal(signum, 0);
|
||||
I_ReportSignal(signum, 0, NULL);
|
||||
#endif
|
||||
status = 128 + signum;
|
||||
}
|
||||
|
|
@ -1656,7 +1848,7 @@ INT32 I_StartupSystem(void)
|
|||
//
|
||||
// I_Quit
|
||||
//
|
||||
void I_Quit(void)
|
||||
FUNCNORETURN void ATTRNORETURN I_Quit(void)
|
||||
{
|
||||
static SDL_bool quiting = SDL_FALSE;
|
||||
|
||||
|
|
@ -1732,7 +1924,7 @@ static boolean shutdowning = false;
|
|||
|
||||
extern "C" consvar_t cv_fuzz;
|
||||
|
||||
void I_Error(const char *error, ...)
|
||||
FUNCIERROR void ATTRNORETURN I_Error(const char *error, ...)
|
||||
{
|
||||
va_list argptr;
|
||||
char buffer[8192];
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ public:
|
|||
|
||||
float left_scale = std::cos(sep_pan);
|
||||
float right_scale = std::sin(sep_pan);
|
||||
buffer[i] = {buffer[i].amplitudes[0] * volume_ * left_scale, buffer[i].amplitudes[1] * volume_ * right_scale};
|
||||
buffer[i] = {std::clamp(buffer[i].amplitudes[0] * volume_ * left_scale, -1.f, 1.f), std::clamp(buffer[i].amplitudes[1] * volume_ * right_scale, -1.f, 1.f)};
|
||||
}
|
||||
|
||||
return buffer.size();
|
||||
|
|
@ -1046,13 +1046,8 @@ UINT32 I_SoundInputDequeueSamples(void *data, UINT32 len)
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
UINT32 avail = SDL_GetQueuedAudioSize(g_input_device_id);
|
||||
if (avail == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 ret = SDL_DequeueAudio(g_input_device_id, data, std::min(len, avail));
|
||||
UINT32 ret = SDL_DequeueAudio(g_input_device_id, data, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1164,12 +1164,18 @@ sfxinfo_t S_sfx[NUMSFX] =
|
|||
{"gate04", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"gate05", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Wavedash
|
||||
{"waved1", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved2", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved3", false, 32, 64, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved4", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"waved5", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Sonic Boom & Subsonic
|
||||
{"sonbo1", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"sonbo2", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"sonbo3", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
||||
// Passing sounds
|
||||
{"pass01", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
{"pass02", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, ""},
|
||||
|
|
|
|||
|
|
@ -1239,6 +1239,11 @@ typedef enum
|
|||
sfx_waved3,
|
||||
sfx_waved4,
|
||||
sfx_waved5,
|
||||
|
||||
// Sonic Boom & Subsonic
|
||||
sfx_sonbo1,
|
||||
sfx_sonbo2,
|
||||
sfx_sonbo3,
|
||||
|
||||
// Passing sounds
|
||||
sfx_pass01,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
// it's only for detection of the version the player is using so the MS can alert them of an update.
|
||||
// Only set it higher, not lower, obviously.
|
||||
// Note that we use this to help keep internal testing in check; this is why v2.0 is not version "2".
|
||||
#define MODVERSION 8
|
||||
#define MODVERSION 9
|
||||
|
||||
// Define this as a prerelease version suffix
|
||||
#define BETAVERSION "RC5"
|
||||
#define BETAVERSION "RC6"
|
||||
|
|
|
|||
|
|
@ -1397,7 +1397,7 @@ lumpnum_t W_CheckNumForName(const char *name)
|
|||
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
|
||||
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME);
|
||||
strncpy(lumpnumcache[lumpnumcacheindex].lumpname, name, 8);
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) | check;
|
||||
lumpnumcache[lumpnumcacheindex].lumphash = hash;
|
||||
|
||||
return lumpnumcache[lumpnumcacheindex].lumpnum;
|
||||
|
|
@ -1454,11 +1454,11 @@ lumpnum_t W_CheckNumForLongName(const char *name)
|
|||
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
|
||||
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME);
|
||||
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, LUMPNUMCACHENAME);
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) | check;
|
||||
lumpnumcache[lumpnumcacheindex].lumphash = hash;
|
||||
}
|
||||
|
||||
return (i << 16) + check;
|
||||
return (i << 16) | check;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1505,11 +1505,11 @@ lumpnum_t W_CheckNumForMap(const char *name, boolean checktofirst)
|
|||
lumpnumcacheindex = (lumpnumcacheindex + 1) & (LUMPNUMCACHESIZE - 1);
|
||||
memset(lumpnumcache[lumpnumcacheindex].lumpname, '\0', LUMPNUMCACHENAME);
|
||||
strlcpy(lumpnumcache[lumpnumcacheindex].lumpname, name, LUMPNUMCACHENAME);
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) + check;
|
||||
lumpnumcache[lumpnumcacheindex].lumpnum = (i << 16) | check;
|
||||
lumpnumcache[lumpnumcacheindex].lumphash = hash;
|
||||
}
|
||||
|
||||
return (i << 16) + check;
|
||||
return (i << 16) | check;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1608,7 +1608,7 @@ lumpnum_t W_CheckNumForNameInFolder(const char *lump, const char *folder)
|
|||
check = W_CheckNumForLongNamePwad(lump, (UINT16)i, fsid);
|
||||
if (check < feid)
|
||||
{
|
||||
return (i<<16) + check; // found it, in our constraints
|
||||
return (i<<16) | check; // found it, in our constraints
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1634,6 +1634,93 @@ UINT8 W_LumpExists(const char *name)
|
|||
return false;
|
||||
}
|
||||
|
||||
// Thanks to the introduction of "client side WAD files",
|
||||
// a notion which is insanity in any other branch of DOOM,
|
||||
// any direct wadnum ID is not a guaranteed index (and
|
||||
// lumpnum_t, which has it in their upper bits, suffer too)
|
||||
// We can do an O(n) conversion back and forth, which is
|
||||
// better than nothing, but still kind of annoying to do.
|
||||
// It was either this or killing musicwads lmao ~toast 180925
|
||||
|
||||
lumpnum_t W_LumpIntoNetSave(lumpnum_t lump)
|
||||
{
|
||||
UINT32 wad = (lump >> 16);
|
||||
if (lump == LUMPERROR // Bad already
|
||||
|| wad < mainwads) // Same between client/server
|
||||
{
|
||||
// Give what we get.
|
||||
return lump;
|
||||
}
|
||||
|
||||
if (wad >= numwadfiles // Outside of range
|
||||
|| !wadfiles[wad]->important) // Can't convert local lumpnum
|
||||
{
|
||||
// No good return result!
|
||||
return LUMPERROR;
|
||||
}
|
||||
|
||||
// Count previous local files the client might not have.
|
||||
UINT32 i = (mainwads + musicwads), localoffset = 0;
|
||||
for (; i < wad; i++)
|
||||
{
|
||||
if (wadfiles[i]->important)
|
||||
continue;
|
||||
|
||||
localoffset++;
|
||||
}
|
||||
|
||||
if (!localoffset)
|
||||
{
|
||||
// No local files, return unchanged.
|
||||
return lump;
|
||||
}
|
||||
|
||||
if (localoffset <= wad)
|
||||
{
|
||||
// Success, return with the conversion.
|
||||
return ((wad - localoffset) << 16) | (lump & UINT16_MAX);
|
||||
}
|
||||
|
||||
// Death!!
|
||||
return LUMPERROR;
|
||||
}
|
||||
|
||||
lumpnum_t W_LumpFromNetSave(lumpnum_t lump)
|
||||
{
|
||||
UINT32 netwad = (lump >> 16);
|
||||
if (lump == LUMPERROR // Bad already
|
||||
|| netwad < mainwads) // Same between client/server
|
||||
{
|
||||
// Give what we get.
|
||||
return lump;
|
||||
}
|
||||
|
||||
// Count previous local files the server would ignore.
|
||||
UINT32 i = (mainwads + musicwads), localoffset = 0;
|
||||
for (; (i - localoffset) <= netwad && i < numwadfiles; i++)
|
||||
{
|
||||
if (wadfiles[i]->important)
|
||||
continue;
|
||||
|
||||
localoffset++;
|
||||
}
|
||||
|
||||
if (!localoffset)
|
||||
{
|
||||
// No local files, return unchanged.
|
||||
return lump;
|
||||
}
|
||||
|
||||
if (netwad + localoffset < numwadfiles)
|
||||
{
|
||||
// Success, return with the conversion.
|
||||
return ((netwad + localoffset) << 16) | (lump & UINT16_MAX);
|
||||
}
|
||||
|
||||
// Death!!
|
||||
return LUMPERROR;
|
||||
}
|
||||
|
||||
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump)
|
||||
{
|
||||
if (!TestValidLump(wad, lump))
|
||||
|
|
|
|||
|
|
@ -188,6 +188,9 @@ lumpnum_t W_CheckNumForNameInBlock(const char *name, const char *blockstart, con
|
|||
lumpnum_t W_CheckNumForNameInFolder(const char *lump, const char *folder);
|
||||
UINT8 W_LumpExists(const char *name); // Lua uses this.
|
||||
|
||||
lumpnum_t W_LumpIntoNetSave(lumpnum_t lump);
|
||||
lumpnum_t W_LumpFromNetSave(lumpnum_t lump);
|
||||
|
||||
size_t W_LumpLengthPwad(UINT16 wad, UINT16 lump);
|
||||
size_t W_LumpLength(lumpnum_t lumpnum);
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@
|
|||
"version": "1.0.0",
|
||||
"builtin-baseline": "d5ec528843d29e3a52d745a64b469f810b2cedbf",
|
||||
"dependencies": [
|
||||
{
|
||||
"name": "cpptrace",
|
||||
"platform": "windows & !mingw"
|
||||
},
|
||||
"curl",
|
||||
"libogg",
|
||||
"libpng",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue