Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into break-through-them-all

This commit is contained in:
toaster 2023-10-07 12:42:07 +01:00
commit 8c734d3646
68 changed files with 1225 additions and 570 deletions

View file

@ -76,6 +76,8 @@ option(SRB2_CONFIG_HWRENDER "Enable hardware render (OpenGL) support" ON)
option(SRB2_CONFIG_STATIC_OPENGL "Enable static linking GL (do not do this)" OFF)
option(SRB2_CONFIG_ERRORMODE "Compile C code with warnings treated as errors." OFF)
option(SRB2_CONFIG_DEBUGMODE "Compile with PARANOIA, ZDEBUG, RANGECHECK and PACKETDROP defined." OFF)
option(SRB2_CONFIG_DEV_BUILD "Compile a development build." OFF)
option(SRB2_CONFIG_TESTERS "Compile a build for testers." OFF)
option(SRB2_CONFIG_MOBJCONSISTANCY "Compile with MOBJCONSISTANCY defined." OFF)
option(SRB2_CONFIG_PACKETDROP "Compile with PACKETDROP defined." OFF)
option(SRB2_CONFIG_ZDEBUG "Compile with ZDEBUG defined." OFF)
@ -202,6 +204,10 @@ if("${SRB2_SDL2_EXE_NAME}" STREQUAL "")
if(NOT "${SRB2_GIT_REVISION}" STREQUAL "master")
list(APPEND EXE_NAME_PARTS ${SRB2_GIT_REVISION})
endif()
if (SRB2_CONFIG_TESTERS)
list(APPEND EXE_NAME_PARTS "TESTERS")
endif()
else()
list(APPEND EXE_NAME_PARTS ${SRB2_SDL2_EXE_NAME})
endif()

View file

@ -33,14 +33,6 @@
"SRB2_CONFIG_TESTERS": "ON"
}
},
{
"name": "host-testers",
"description": "Build to use when hosting, to let testers join",
"inherits": "default",
"cacheVariables": {
"SRB2_CONFIG_HOSTTESTERS": "ON"
}
},
{
"name": "release",
"description": "Build for game's release",

View file

@ -205,12 +205,6 @@ set(SRB2_CONFIG_USEASM OFF CACHE BOOL
"Enable NASM tmap implementation for software mode speedup.")
set(SRB2_CONFIG_YASM OFF CACHE BOOL
"Use YASM in place of NASM.")
set(SRB2_CONFIG_DEV_BUILD OFF CACHE BOOL
"Compile a development build of Dr Robotnik's Ring Racers.")
set(SRB2_CONFIG_TESTERS OFF CACHE BOOL
"Compile a build for testers.")
set(SRB2_CONFIG_HOSTTESTERS OFF CACHE BOOL
"Compile a build to host netgames for testers builds.")
add_subdirectory(blua)
@ -556,9 +550,6 @@ endif()
if(SRB2_CONFIG_TESTERS)
target_compile_definitions(SRB2SDL2 PRIVATE -DTESTERS)
endif()
if(SRB2_CONFIG_HOSTTESTERS)
target_compile_definitions(SRB2SDL2 PRIVATE -DHOSTTESTERS)
endif()
if(SRB2_CONFIG_MOBJCONSISTANCY)
target_compile_definitions(SRB2SDL2 PRIVATE -DMOBJCONSISTANCY)
endif()

View file

@ -6,7 +6,7 @@ passthru_opts+=\
NO_IPV6 NOHW NOMD5 NOPOSTPROCESSING\
MOBJCONSISTANCY PACKETDROP ZDEBUG\
HAVE_MINIUPNPC\
HAVE_DISCORDRPC TESTERS HOSTTESTERS DEVELOP
HAVE_DISCORDRPC TESTERS DEVELOP
# build with debugging information
ifdef DEBUGMODE

View file

@ -2236,6 +2236,21 @@ bool CallFunc_MusicRemap(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::
return false;
}
/*--------------------------------------------------
bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
Updates level freeze.
--------------------------------------------------*/
bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)
{
(void)argV;
(void)argC;
P_SetFreezeLevel(argV[0] != 0);
return false;
}
/*--------------------------------------------------
bool CallFunc_Get/SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC)

View file

@ -103,6 +103,8 @@ bool CallFunc_DialogueSetSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV,
bool CallFunc_DialogueSetCustomSpeaker(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_DialogueNewText(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_Freeze(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_SetLineProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);
bool CallFunc_GetSideProperty(ACSVM::Thread *thread, const ACSVM::Word *argV, ACSVM::Word argC);

View file

@ -181,6 +181,7 @@ Environment::Environment()
addFuncDataACS0( 508, addCallFunc(CallFunc_MusicPlay));
addFuncDataACS0( 509, addCallFunc(CallFunc_MusicStopAll));
addFuncDataACS0( 510, addCallFunc(CallFunc_MusicRemap));
addFuncDataACS0( 511, addCallFunc(CallFunc_Freeze));
addFuncDataACS0( 600, addCallFunc(CallFunc_DialogueSetSpeaker));
addFuncDataACS0( 601, addCallFunc(CallFunc_DialogueSetCustomSpeaker));

View file

@ -421,6 +421,10 @@ consvar_t cv_scr_depth = Player("scr_depth", "16 bits").values({{8, "8 bits"}, {
consvar_t cv_scr_width = Player("scr_width", "640").values(CV_Unsigned);
consvar_t cv_scr_height = Player("scr_height", "400").values(CV_Unsigned);
consvar_t cv_scr_scale = Player("scr_scale", "1.0").floating_point();
consvar_t cv_scr_x = Player("scr_x", "0.0").floating_point();
consvar_t cv_scr_y = Player("scr_y", "0.0").floating_point();
consvar_t cv_seenames = Player("seenames", "On").on_off();
consvar_t cv_shadow = Player("shadow", "On").on_off();
consvar_t cv_shittyscreen = Player("televisionsignal", "Okay").flags(CV_NOSHOWHELP).values({{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}}).dont_save();

View file

@ -419,6 +419,9 @@ void D_RegisterServerCommands(void)
COM_AddDebugCommand("downloads", Command_Downloads_f);
COM_AddDebugCommand("give", Command_KartGiveItem_f);
COM_AddDebugCommand("give2", Command_KartGiveItem_f);
COM_AddDebugCommand("give3", Command_KartGiveItem_f);
COM_AddDebugCommand("give4", Command_KartGiveItem_f);
COM_AddCommand("schedule_add", Command_Schedule_Add);
COM_AddCommand("schedule_clear", Command_Schedule_Clear);
@ -534,6 +537,7 @@ void D_RegisterClientCommands(void)
// add cheats
COM_AddDebugCommand("noclip", Command_CheatNoClip_f);
COM_AddDebugCommand("god", Command_CheatGod_f);
COM_AddDebugCommand("freeze", Command_CheatFreeze_f);
COM_AddDebugCommand("setrings", Command_Setrings_f);
COM_AddDebugCommand("setspheres", Command_Setspheres_f);
COM_AddDebugCommand("setlives", Command_Setlives_f);
@ -1605,6 +1609,22 @@ static void GetViewablePlayerPlaceRange(INT32 *first, INT32 *last)
}
}
static int GetCommandViewNumber(void)
{
char c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */
switch (c)
{
default:
return 0;
case '2':
case '3':
case '4':
return c - '1';
}
}
#define PRINTVIEWPOINT( pre,suf ) \
CONS_Printf(pre"viewing \x84(%d) \x83%s\x80"suf".\n",\
(*displayplayerp), player_names[(*displayplayerp)]);
@ -1612,21 +1632,11 @@ static void Command_View_f(void)
{
INT32 *displayplayerp;
INT32 olddisplayplayer;
int viewnum;
int viewnum = 1 + GetCommandViewNumber();
const char *playerparam;
INT32 placenum;
INT32 playernum;
INT32 firstplace, lastplace;
char c;
/* easy peasy */
c = COM_Argv(0)[strlen(COM_Argv(0))-1];/* may be digit */
switch (c)
{
case '2': viewnum = 2; break;
case '3': viewnum = 3; break;
case '4': viewnum = 4; break;
default: viewnum = 1;
}
if (viewnum > 1 && !( multiplayer && demo.playback ))
{
@ -1709,13 +1719,6 @@ static void Command_SetViews_f(void)
UINT8 splits;
UINT8 newsplits;
if (!( demo.playback && multiplayer ))
{
CONS_Alert(CONS_NOTICE,
"You must be viewing a multiplayer replay to use this.\n");
return;
}
if (COM_Argc() != 2)
{
CONS_Printf("setviews <views>: set the number of split screens\n");
@ -1726,12 +1729,26 @@ static void Command_SetViews_f(void)
newsplits = atoi(COM_Argv(1));
newsplits = min(max(newsplits, 1), 4);
if (newsplits > splits)
if (newsplits > splits && demo.playback && multiplayer)
{
G_AdjustView(newsplits, 0, true);
}
else
{
// Even if the splits go beyond the real number of
// splitscreen players, displayplayers was filled
// with duplicates of P1 (see Got_AddPlayer).
r_splitscreen = newsplits-1;
R_ExecuteSetViewSize();
// If promoting (outside of replays), make sure the
// camera is in the correct position.
UINT8 i;
for (i = splits + 1; i <= newsplits; ++i)
{
G_FixCamera(i);
}
}
}
@ -3687,7 +3704,7 @@ static void Command_Login_f(void)
boolean IsPlayerAdmin(INT32 playernum)
{
#if defined(DEVELOP) && !(defined(HOSTTESTERS) || defined(TESTERS))
#if 0 // defined(DEVELOP)
return playernum != serverplayer;
#else
INT32 i;
@ -4642,8 +4659,6 @@ static void Command_Version_f(void)
// DEVELOP build
#if defined(TESTERS)
CONS_Printf("\x88" "TESTERS " "\x80");
#elif defined(HOSTTESTERS)
CONS_Printf("\x82" "HOSTTESTERS " "\x80");
#elif defined(DEVELOP)
CONS_Printf("\x87" "DEVELOP " "\x80");
#endif
@ -5737,6 +5752,13 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
break;
}
case CHEAT_FREEZE: {
const char *status = P_FreezeCheat() ? "off" : "on";
P_SetFreezeCheat( !P_FreezeCheat() );
CV_CheaterWarning(targetPlayer, va("freeze %s", status));
break;
}
case NUMBER_OF_CHEATS:
break;
}
@ -5911,6 +5933,8 @@ static void Command_Archivetest_f(void)
*/
static void Command_KartGiveItem_f(void)
{
UINT8 localplayer = g_localplayers[GetCommandViewNumber()];
int ac;
const char *name;
INT32 item;
@ -5966,7 +5990,7 @@ static void Command_KartGiveItem_f(void)
else
amt = BATTLE_POWERUP_TIME;
D_Cheat(consoleplayer, CHEAT_GIVEPOWERUP, item, amt);
D_Cheat(localplayer, CHEAT_GIVEPOWERUP, item, amt);
}
else if (item < NUMKARTITEMS)
{
@ -5977,7 +6001,7 @@ static void Command_KartGiveItem_f(void)
else
amt = (item != KITEM_NONE);/* default to one quantity, or zero, if KITEM_NONE */
D_Cheat(consoleplayer, CHEAT_GIVEITEM, item, amt);
D_Cheat(localplayer, CHEAT_GIVEITEM, item, amt);
}
else
{

View file

@ -289,6 +289,7 @@ actionpointer_t actionpointers[] =
{{A_SSMineFlash}, "A_SSMINEFLASH"},
{{A_LandMineExplode}, "A_LANDMINEEXPLODE"},
{{A_BallhogExplode}, "A_BALLHOGEXPLODE"},
{{A_SpecialStageBombExplode},"A_SPECIALSTAGEBOMBEXPLODE"},
{{A_LightningFollowPlayer}, "A_LIGHTNINGFOLLOWPLAYER"},
{{A_FZBoomFlash}, "A_FZBOOMFLASH"},
{{A_FZBoomSmoke}, "A_FZBOOMSMOKE"},
@ -4372,6 +4373,17 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_EERIEFOG4",
"S_EERIEFOG5",
// Chaos Chute
"S_SPECIALSTAGEARCH",
"S_SPECIALSTAGEBOMB",
"S_SPECIALSTAGEBOMB_DISARM",
"S_SPECIALSTAGEBOMB_EXPLODE",
"S_SPECIALSTAGEBOMB_DISAPPEAR",
"S_SPECIALSTAGEBOMB_FLICKER1",
"S_SPECIALSTAGEBOMB_FLICKER2",
"S_SPECIALSTAGEBOMB_FLICKERLOOP",
"S_SPECIALSTAGEBOMB_RESET",
// SMK ports
"S_SMK_PIPE1", // Generic pipes
"S_SMK_PIPE2",
@ -4674,6 +4686,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
"S_CHECKPOINT_SPARK9",
"S_CHECKPOINT_SPARK10",
"S_CHECKPOINT_SPARK11",
"S_BALLSWITCH_BALL",
"S_BALLSWITCH_BALL_ACTIVE",
"S_BALLSWITCH_PAD",
"S_BALLSWITCH_PAD_ACTIVE",
};
// RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1",
@ -5731,6 +5748,10 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_EERIEFOG",
"MT_EERIEFOGGEN",
// Chaos Chute
"MT_SPECIALSTAGEARCH",
"MT_SPECIALSTAGEBOMB",
// SMK ports
"MT_SMK_PIPE",
"MT_SMK_MOLESPAWNER",
@ -5827,6 +5848,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_CHECKPOINT_END",
"MT_SCRIPT_THING",
"MT_BALLSWITCH_BALL",
"MT_BALLSWITCH_PAD",
};
const char *const MOBJFLAG_LIST[] = {

View file

@ -1565,9 +1565,6 @@ void F_VersionDrawer(void)
#if defined(TESTERS)
addtext(V_SKYMAP, "Tester client");
addtext(V_TRANSLUCENT, va("%s", compdate));
#elif defined(HOSTTESTERS)
addtext(V_REDMAP, "Netgame host for testers");
addtext(V_TRANSLUCENT, va("%s", compdate));
#elif defined(DEVELOP)
addtext(V_TRANSLUCENT, va("%s %s", comprevision, compnote));
addtext(V_TRANSLUCENT, D_GetFancyBranchName());
@ -1711,8 +1708,6 @@ void F_TitleScreenDrawer(void)
#ifdef DEVELOP
#if defined(TESTERS)
V_DrawCenteredString(BASEVIDWIDTH/2, 96, V_SKYMAP, "Tester EXE");
#elif defined(HOSTTESTERS)
V_DrawCenteredThinString(BASEVIDWIDTH/2, 96, V_REDMAP, "Tester netgame host EXE");
#else
V_DrawCenteredString(BASEVIDWIDTH/2, 96, 0, "Development EXE");
#endif

View file

@ -432,7 +432,7 @@ void F_WipeEndScreen(void)
dst_region.h = std::min(dst_region.h, backbuf_deets.height);
rhi->copy_framebuffer_to_texture(ctx, hw_state->wipe_frames.end, dst_region, dst_region);
hw_state->blit_rect->set_output(dst_region.w, dst_region.h, false, true);
hw_state->blit_rect->set_output(0, 0, dst_region.w, dst_region.h, false, true);
rhi::TextureDetails start_deets = rhi->get_texture_details(hw_state->wipe_frames.start);
hw_state->blit_rect->set_texture(hw_state->wipe_frames.start, start_deets.width, start_deets.height);
hw_state->blit_rect->draw(*rhi, ctx);

View file

@ -206,7 +206,15 @@ class TiccmdBuilder
else
#endif
{
localangle[viewnum] += angleChange;
int p = g_localplayers[forplayer()];
for (int i = 0; i <= r_splitscreen; ++i)
{
if (displayplayers[i] == p)
{
localangle[i] += angleChange;
}
}
}
}
@ -237,7 +245,7 @@ class TiccmdBuilder
bool director_input()
{
if (demo.freecam || G_IsPartyLocal(displayplayers[forplayer()]) == true)
if (demo.freecam || !K_DirectorIsAvailable(viewnum))
{
return false;
}

View file

@ -89,7 +89,7 @@ JoyType_t Joystick[MAXSPLITSCREENPLAYERS];
// SRB2kart
char gamedatafilename[64] =
#if defined (TESTERS) || defined (HOSTTESTERS)
#if defined (TESTERS)
"test"
#elif defined(DEVELOP)
"develop"
@ -1494,13 +1494,15 @@ boolean G_CouldView(INT32 playernum)
//
boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive)
{
if (!playeringame[playernum] || players[playernum].spectator)
{
return false;
}
UINT8 splits;
UINT8 viewd;
INT32 *displayplayerp;
if (!(onlyactive ? G_CouldView(playernum) : (playeringame[playernum] && !players[playernum].spectator)))
return false;
splits = r_splitscreen+1;
if (viewnum > splits)
viewnum = splits;
@ -1509,15 +1511,18 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive)
{
displayplayerp = (&displayplayers[viewd-1]);
if ((*displayplayerp) == playernum)
return false;
return true;
}
for (viewd = viewnum + 1; viewd <= splits; ++viewd)
{
displayplayerp = (&displayplayers[viewd-1]);
if ((*displayplayerp) == playernum)
return false;
return true;
}
if (onlyactive && !G_CouldView(playernum))
return false;
return true;
}
@ -1567,7 +1572,6 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
UINT8 viewd;
INT32 *displayplayerp;
camera_t *camerap;
INT32 olddisplayplayer;
INT32 playersviewable;
@ -1618,22 +1622,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
(*displayplayerp) = playernum;
if ((*displayplayerp) != olddisplayplayer)
{
camerap = &camera[viewnum-1];
P_ResetCamera(&players[(*displayplayerp)], camerap);
R_ResetViewInterpolation(viewnum);
G_FixCamera(viewnum);
}
if (viewnum > splits)
{
for (viewd = splits+1; viewd < viewnum; ++viewd)
{
displayplayerp = (&displayplayers[viewd-1]);
camerap = &camera[viewd];
(*displayplayerp) = G_FindView(0, viewd, onlyactive, false);
P_ResetCamera(&players[(*displayplayerp)], camerap);
G_FixCamera(viewd);
}
}
@ -1695,6 +1691,26 @@ void G_ResetViews(void)
}
}
//
// G_FixCamera
// Reset camera position, angle and interpolation on a view
// after changing state.
//
void G_FixCamera(UINT8 view)
{
player_t *player = &players[displayplayers[view - 1]];
// The order of displayplayers can change, which would
// invalidate localangle.
localangle[view - 1] = player->angleturn;
P_ResetCamera(player, &camera[view - 1]);
// Make sure the viewport doesn't interpolate at all into
// its new position -- just snap instantly into place.
R_ResetViewInterpolation(view);
}
//
// G_Ticker
// Make ticcmd_ts for the players.

View file

@ -240,6 +240,7 @@ INT32 G_CountPlayersPotentiallyViewable(boolean active);
void G_ResetViews(void);
void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive);
void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive);
void G_FixCamera(UINT8 viewnum);
void G_AddPlayer(INT32 playernum);
void G_SpectatePlayerOnJoin(INT32 playernum);

View file

@ -19,7 +19,7 @@
#include "d_clisrv.h" // playerconsole
#include "doomdef.h" // MAXPLAYERS
#include "doomstat.h" // consoleplayer
#include "g_game.h" // localangle
#include "g_game.h" // G_FixCamera
#include "g_party.h"
#include "g_state.h"
#include "p_local.h"
@ -136,20 +136,8 @@ public:
for (std::size_t i = 0; i < size(); ++i)
{
const playernum_t player = at(i);
displayplayers[i] = player;
// The order of displayplayers can change, which
// would make localangle invalid now.
localangle[i] = players[player].angleturn;
P_ResetCamera(&players[player], &camera[i]);
// Make sure the viewport doesn't interpolate at
// all into its new position -- just snap
// instantly into place.
R_ResetViewInterpolation(1 + i);
displayplayers[i] = at(i);
G_FixCamera(1 + i);
}
r_splitscreen = size() - 1;

View file

@ -5398,17 +5398,7 @@ static void HWR_DrawSkyBackground(player_t *player)
{
FTransform dometransform;
const float fpov = FIXED_TO_FLOAT(cv_fov[viewssnum].value+player->fovadd);
postimg_t *type = &postimgtype[0];
SINT8 i;
for (i = r_splitscreen; i >= 0; i--)
{
if (player == &players[displayplayers[i]])
{
type = &postimgtype[i];
break;
}
}
postimg_t *type = &postimgtype[R_GetViewNumber()];
memset(&dometransform, 0x00, sizeof(FTransform));
@ -6104,20 +6094,10 @@ INT32 HWR_GetTextureUsed(void)
void HWR_DoPostProcessor(player_t *player)
{
postimg_t *type = &postimgtype[0];
SINT8 i;
postimg_t *type = &postimgtype[R_GetViewNumber()];
HWD.pfnUnSetShader();
for (i = r_splitscreen; i >= 0; i--)
{
if (player == &players[displayplayers[i]])
{
type = &postimgtype[i];
break;
}
}
// Armageddon Blast Flash!
// Could this even be considered postprocessor?
if (player->flashcount)

View file

@ -90,10 +90,10 @@ void K_drawKartPowerUps(void)
switch (r_splitscreen)
{
case 0:
return { make_drawer(307, 55, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 };
return { make_drawer(307, 58, Draw::Font::kZVote), "PWRU", -17, 7, -35, -1 };
case 1:
return { make_drawer(318, viewnum == 0 ? 55 : 155, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 };
return { make_drawer(318, viewnum == 0 ? 58 : 147, Draw::Font::kPing), "PWRS", -9, 6, -19, -1 };
}
// 3/4P

View file

@ -4,6 +4,7 @@
#include "../g_game.h"
#include "../k_hud.h"
#include "../p_local.h"
#include "../r_fps.h"
#include "../v_draw.hpp"
using srb2::Draw;
@ -24,13 +25,13 @@ void K_drawKart2PTimestamp(void)
{
auto get_row = []
{
if (stplyr == &players[displayplayers[0]])
if (R_GetViewNumber() == 0)
{
return Draw(286, 31).flags(V_SNAPTOTOP);
return Draw(287, 33).flags(V_SNAPTOTOP);
}
else
{
return Draw(286, 163).flags(V_SNAPTOBOTTOM);
return Draw(287, 156).flags(V_SNAPTOBOTTOM);
}
};

View file

@ -100,7 +100,7 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
if (output_correct_aspect_)
{
aspect = static_cast<float>(texture_width_) / static_cast<float>(texture_height_);
output_aspect = static_cast<float>(output_width_) / static_cast<float>(output_height_);
output_aspect = static_cast<float>(output_position_.w) / static_cast<float>(output_position_.h);
}
bool taller = aspect > output_aspect;
@ -137,7 +137,7 @@ void BlitRectPass::transfer(Rhi& rhi, Handle<GraphicsContext> ctx)
void BlitRectPass::graphics(Rhi& rhi, Handle<GraphicsContext> ctx)
{
rhi.bind_pipeline(ctx, pipeline_);
rhi.set_viewport(ctx, {0, 0, output_width_, output_height_});
rhi.set_viewport(ctx, output_position_);
rhi.bind_uniform_set(ctx, 0, uniform_sets_[0]);
rhi.bind_uniform_set(ctx, 1, uniform_sets_[1]);
rhi.bind_binding_set(ctx, binding_set_);

View file

@ -26,8 +26,7 @@ class BlitRectPass
uint32_t texture_width_ = 0;
uint32_t texture_height_ = 0;
rhi::Handle<rhi::Texture> output_;
uint32_t output_width_ = 0;
uint32_t output_height_ = 0;
rhi::Rect output_position_;
bool output_correct_aspect_ = false;
bool output_flip_ = false;
rhi::Handle<rhi::Buffer> quad_vbo_;
@ -63,14 +62,15 @@ public:
/// @param width texture width
/// @param height texture height
void set_output(
int32_t x,
int32_t y,
uint32_t width,
uint32_t height,
bool correct_aspect,
bool flip
) noexcept
{
output_width_ = width;
output_height_ = height;
output_position_ = {x, y, width, height};
output_correct_aspect_ = correct_aspect;
output_flip_ = flip;
}

View file

@ -37,6 +37,19 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle<GraphicsContext> ctx)
remake = true;
}
auto new_renderpass = [&rhi = rhi](AttachmentLoadOp load_op, AttachmentStoreOp store_op)
{
RenderPassDesc desc {};
desc.use_depth_stencil = true;
desc.color_load_op = load_op;
desc.color_store_op = store_op;
desc.depth_load_op = load_op;
desc.depth_store_op = store_op;
desc.stencil_load_op = load_op;
desc.stencil_store_op = store_op;
return rhi.create_render_pass(desc);
};
if (remake)
{
if (color_)
@ -63,23 +76,22 @@ void UpscaleBackbuffer::begin_pass(Rhi& rhi, Handle<GraphicsContext> ctx)
depth_tex.height = vid_height;
depth_ = rhi.create_renderbuffer(depth_tex);
}
if (!renderpass_)
if (!renderpass_clear_)
{
renderpass_clear_ = new_renderpass(AttachmentLoadOp::kClear, AttachmentStoreOp::kStore);
}
}
else
{
RenderPassDesc desc {};
desc.use_depth_stencil = true;
desc.color_load_op = AttachmentLoadOp::kLoad;
desc.color_store_op = AttachmentStoreOp::kStore;
desc.depth_load_op = AttachmentLoadOp::kLoad;
desc.depth_store_op = AttachmentStoreOp::kStore;
desc.stencil_load_op = AttachmentLoadOp::kLoad;
desc.stencil_store_op = AttachmentStoreOp::kStore;
renderpass_ = rhi.create_render_pass(desc);
if (!renderpass_)
{
renderpass_ = new_renderpass(AttachmentLoadOp::kLoad, AttachmentStoreOp::kStore);
}
}
RenderPassBeginInfo begin_info {};
begin_info.render_pass = renderpass_;
begin_info.render_pass = remake ? renderpass_clear_ : renderpass_;
begin_info.clear_color = {0, 0, 0, 1};
begin_info.color_attachment = color_;
begin_info.depth_stencil_attachment = depth_;

View file

@ -20,6 +20,7 @@ class UpscaleBackbuffer
rhi::Handle<rhi::Texture> color_;
rhi::Handle<rhi::Renderbuffer> depth_;
rhi::Handle<rhi::RenderPass> renderpass_;
rhi::Handle<rhi::RenderPass> renderpass_clear_;
public:
UpscaleBackbuffer();

View file

@ -16,8 +16,10 @@
#include <imgui.h>
#include <tracy/tracy/Tracy.hpp>
#include "command.h"
#include "cxxutil.hpp"
#include "f_finale.h"
#include "m_fixed.h"
#include "m_misc.h"
#include "hwr2/hardware_state.hpp"
#include "hwr2/patch_atlas.hpp"
@ -46,6 +48,8 @@
#include "st_stuff.h"
#include "v_video.h"
extern "C" consvar_t cv_scr_scale, cv_scr_x, cv_scr_y;
using namespace srb2;
using namespace srb2::hwr2;
using namespace srb2::rhi;
@ -103,62 +107,6 @@ static void postframe_update(Rhi& rhi)
g_hw_state.palette_manager->destroy_per_frame_resources(rhi);
}
#ifdef HWRENDER
static void finish_legacy_ogl_update()
{
int player;
SCR_CalculateFPS();
if (st_overlay)
{
if (cv_songcredits.value)
HU_DrawSongCredits();
if (cv_ticrate.value)
SCR_DisplayTicRate();
if (cv_showping.value && netgame && (consoleplayer != serverplayer || !server_lagless))
{
if (server_lagless)
{
if (consoleplayer != serverplayer)
SCR_DisplayLocalPing();
}
else
{
for (player = 1; player < MAXPLAYERS; player++)
{
if (D_IsPlayerHumanAndGaming(player))
{
SCR_DisplayLocalPing();
break;
}
}
}
}
if (cv_mindelay.value && consoleplayer == serverplayer && Playing())
SCR_DisplayLocalPing();
}
if (marathonmode)
SCR_DisplayMarathonInfo();
// draw captions if enabled
if (cv_closedcaptioning.value)
SCR_ClosedCaptions();
#ifdef HAVE_DISCORDRPC
if (discordRequestList != NULL)
ST_AskToJoinEnvelope();
#endif
ST_drawDebugInfo();
OglSdlFinishUpdate(cv_vidwait.value);
}
#endif
static void temp_legacy_finishupdate_draws()
{
SCR_CalculateFPS();
@ -211,6 +159,14 @@ static void temp_legacy_finishupdate_draws()
ST_drawDebugInfo();
}
#ifdef HWRENDER
static void finish_legacy_ogl_update()
{
temp_legacy_finishupdate_draws();
OglSdlFinishUpdate(cv_vidwait.value);
}
#endif
static void new_twodee_frame()
{
g_2d = Twodee();
@ -329,7 +285,20 @@ void I_FinishUpdate(void)
rhi->begin_default_render_pass(ctx, true);
// Upscale draw the backbuffer (with postprocessing maybe?)
g_hw_state.blit_rect->set_output(vid.realwidth, vid.realheight, true, true);
if (cv_scr_scale.value != FRACUNIT)
{
float f = std::max(FixedToFloat(cv_scr_scale.value), 0.f);
float w = vid.realwidth * f;
float h = vid.realheight * f;
float x = (vid.realwidth - w) * (0.5f + (FixedToFloat(cv_scr_x.value) * 0.5f));
float y = (vid.realheight - h) * (0.5f + (FixedToFloat(cv_scr_y.value) * 0.5f));
g_hw_state.blit_rect->set_output(x, y, w, h, true, true);
}
else
{
g_hw_state.blit_rect->set_output(0, 0, vid.realwidth, vid.realheight, true, true);
}
g_hw_state.blit_rect->set_texture(g_hw_state.backbuffer->color(), static_cast<uint32_t>(vid.width), static_cast<uint32_t>(vid.height));
g_hw_state.blit_rect->draw(*rhi, ctx);
rhi->end_render_pass(ctx);

View file

@ -798,6 +798,10 @@ char sprnames[NUMSPRITES + 1][5] =
// Eerie Grove
"EGFG",
// Chaos Chute
"SARC",
"SSBM",
// SMK ports
"SMKP",
"MTYM",
@ -893,6 +897,8 @@ char sprnames[NUMSPRITES + 1][5] =
"CPT2", // Checkpoint Stick
"CPT3", // Checkpoint Base
"SA2S", // SA2-style Ball Switch
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
"VIEW",
};
@ -5092,6 +5098,17 @@ state_t states[NUMSTATES] =
{SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|3, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG5}, // S_EERIEFOG4
{SPR_EGFG, FF_TRANS90|FF_FULLBRIGHT|4, 7, {A_SetRandomTics}, 5, 9, S_EERIEFOG1}, // S_EERIEFOG5
// Chaos Chute
{SPR_SARC, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIALSTAGEARCH
{SPR_SSBM, FF_GLOBALANIM|FF_ANIMATE|0, -1, {NULL}, 3, 3, S_NULL}, // S_SPECIALSTAGEBOMB
{SPR_SSBM, 0, 1, {A_SetObjectFlags}, MF_NOCLIPTHING, 2, S_SPECIALSTAGEBOMB_EXPLODE}, // S_SPECIALSTAGEBOMB_DISARM
{SPR_NULL, 0, 0, {A_SpecialStageBombExplode}, 0, 0, S_SPECIALSTAGEBOMB_DISAPPEAR}, // S_SPECIALSTAGEBOMB_EXPLODE
{SPR_NULL, 0, 28*TICRATE, {A_Pain}, 0, 0, S_SPECIALSTAGEBOMB_FLICKER1}, // S_SPECIALSTAGEBOMB_DISAPPEAR
{SPR_SSBM, FF_GLOBALANIM|FF_ANIMATE|0, 1, {NULL}, 3, 3, S_SPECIALSTAGEBOMB_FLICKER2}, // S_SPECIALSTAGEBOMB_FLICKER1
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_SPECIALSTAGEBOMB_FLICKERLOOP}, // S_SPECIALSTAGEBOMB_FLICKER2
{SPR_NULL, 0, 0, {A_Repeat}, TICRATE, S_SPECIALSTAGEBOMB_FLICKER1, S_SPECIALSTAGEBOMB_RESET}, // S_SPECIALSTAGEBOMB_FLICKERLOOP
{SPR_NULL, 0, 0, {A_SetObjectFlags}, MF_NOCLIPTHING, 1, S_SPECIALSTAGEBOMB}, // S_SPECIALSTAGEBOMB_RESET
// SMK ports
{SPR_SMKP, 0, -1, {NULL}, 0, 0, S_SMK_PIPE1}, // S_SMK_PIPE1
{SPR_SMKP, 1, -1, {NULL}, 0, 0, S_SMK_PIPE2}, // S_SMK_PIPE2
@ -5421,6 +5438,11 @@ state_t states[NUMSTATES] =
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|8, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK10}, // S_CHECKPOINT_SPARK9
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK11}, // S_CHECKPOINT_SPARK10
{SPR_SGNS, FF_ADD|FF_FULLBRIGHT|2, 1, {NULL}, 0, 0, S_CHECKPOINT_SPARK1}, // S_CHECKPOINT_SPARK11
{SPR_SA2S, FF_SEMIBRIGHT|3, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_BALL
{SPR_SA2S, FF_FULLBRIGHT|FF_ANIMATE|FF_GLOBALANIM|4, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_BALL_ACTIVE
{SPR_SA2S, FF_FLOORSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_BALLSWITCH_PAD
{SPR_SA2S, FF_FLOORSPRITE|FF_ANIMATE|FF_GLOBALANIM|1, -1, {NULL}, 1, 1, S_NULL}, // S_BALLSWITCH_PAD_ACTIVE
};
mobjinfo_t mobjinfo[NUMMOBJTYPES] =
@ -28331,6 +28353,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_SPECIALSTAGEARCH
3889, // doomednum
S_SPECIALSTAGEARCH, // 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
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // dispoffset
0, // mass
0, // damage
sfx_None, // activesound
MF_SCENERY|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_SPECIALSTAGEBOMB
3890, // doomednum
S_SPECIALSTAGEBOMB, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_SPECIALSTAGEBOMB_DISARM, // painstate
0, // painchance
sfx_s24b, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
60*FRACUNIT, // radius
100*FRACUNIT, // height
0, // dispoffset
7, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL, // flags
S_SPECIALSTAGEBOMB_EXPLODE // raisestate
},
{ // MT_SMK_PIPE
3970, // doomednum
S_SMK_PIPE1, // spawnstate
@ -29407,7 +29483,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING, // flags
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_DRAWFROMFARAWAY, // flags
S_NULL // raisestate
},
@ -29434,7 +29510,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT, // flags
MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_DRAWFROMFARAWAY, // flags
S_NULL // raisestate
},
@ -30412,6 +30488,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
{ // MT_BALLSWITCH_BALL
5000, // doomednum
S_BALLSWITCH_BALL, // 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
36*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL|MF_SHOOTABLE|MF_NOGRAVITY, // flags
S_NULL // raisestate
},
{ // MT_BALLSWITCH_PAD
-1, // doomednum
S_BALLSWITCH_PAD, // 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
64*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_SCENERY, // flags
S_NULL // raisestate
},
};
skincolor_t skincolors[MAXSKINCOLORS] = {

View file

@ -282,6 +282,7 @@ enum actionnum
A_SSMINEEXPLODE,
A_LANDMINEEXPLODE,
A_BALLHOGEXPLODE,
A_SPECIALSTAGEBOMBEXPLODE,
A_LIGHTNINGFOLLOWPLAYER,
A_FZBOOMFLASH,
A_FZBOOMSMOKE,
@ -557,6 +558,7 @@ void A_SSMineFlash();
void A_LandMineExplode();
void A_LandMineExplode();
void A_BallhogExplode();
void A_SpecialStageBombExplode();
void A_LightningFollowPlayer();
void A_FZBoomFlash();
void A_FZBoomSmoke();
@ -1352,6 +1354,10 @@ typedef enum sprite
// Eerie Grove
SPR_EGFG,
// Chaos Chute
SPR_SARC,
SPR_SSBM,
// SMK ports
SPR_SMKP,
SPR_MTYM,
@ -1447,6 +1453,8 @@ typedef enum sprite
SPR_CPT2, // Checkpoint Stick
SPR_CPT3, // Checkpoint Base
SPR_SA2S, // SA2-style Ball Switch
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
SPR_VIEW,
@ -5530,6 +5538,17 @@ typedef enum state
S_EERIEFOG4,
S_EERIEFOG5,
// Chaos Chute
S_SPECIALSTAGEARCH,
S_SPECIALSTAGEBOMB,
S_SPECIALSTAGEBOMB_DISARM,
S_SPECIALSTAGEBOMB_EXPLODE,
S_SPECIALSTAGEBOMB_DISAPPEAR,
S_SPECIALSTAGEBOMB_FLICKER1,
S_SPECIALSTAGEBOMB_FLICKER2,
S_SPECIALSTAGEBOMB_FLICKERLOOP,
S_SPECIALSTAGEBOMB_RESET,
// SMK ports
S_SMK_PIPE1, // Generic pipes
S_SMK_PIPE2,
@ -5849,6 +5868,11 @@ typedef enum state
S_CHECKPOINT_SPARK10,
S_CHECKPOINT_SPARK11,
S_BALLSWITCH_BALL,
S_BALLSWITCH_BALL_ACTIVE,
S_BALLSWITCH_PAD,
S_BALLSWITCH_PAD_ACTIVE,
S_FIRSTFREESLOT,
S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1,
NUMSTATES
@ -6924,6 +6948,10 @@ typedef enum mobj_type
MT_EERIEFOG,
MT_EERIEFOGGEN,
// Chaos Chute
MT_SPECIALSTAGEARCH,
MT_SPECIALSTAGEBOMB,
// SMK ports
MT_SMK_PIPE,
MT_SMK_MOLESPAWNER,
@ -7021,6 +7049,9 @@ typedef enum mobj_type
MT_CHECKPOINT_END,
MT_SCRIPT_THING,
MT_BALLSWITCH_BALL,
MT_BALLSWITCH_PAD,
MT_FIRSTFREESLOT,
MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1,
NUMMOBJTYPES

View file

@ -801,24 +801,6 @@ void K_BattleInit(boolean singleplayercontext)
battleprisons = true;
}
if (gametyperules & GTR_BUMPERS)
{
const INT32 startingHealth = K_BumpersToHealth(K_StartingBumperCount());
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (players[i].mo)
{
players[i].mo->health = startingHealth;
}
K_SpawnPlayerBattleBumpers(players+i);
}
}
g_battleufo.due = starttime;
g_battleufo.previousId = Obj_GetFirstBattleUFOSpawnerID();
}

View file

@ -458,6 +458,7 @@ static BlockItReturn_t K_FindObjectsForNudging(mobj_t *thing)
case MT_BUBBLESHIELDTRAP:
case MT_DUELBOMB:
case MT_GACHABOM:
case MT_SPECIALSTAGEBOMB:
K_AddDodgeObject(thing, side, 20);
break;
case MT_SHRINK_GUN:

View file

@ -929,16 +929,12 @@ boolean K_InstaWhipCollide(mobj_t *shield, mobj_t *victim)
}
else
{
if (victim->type == MT_ORBINAUT || victim->type == MT_JAWZ || victim->type == MT_GACHABOM
|| victim->type == MT_BANANA || victim->type == MT_EGGMANITEM || victim->type == MT_BALLHOG
|| victim->type == MT_SSMINE || victim->type == MT_LANDMINE || victim->type == MT_SINK
|| victim->type == MT_GARDENTOP || victim->type == MT_DROPTARGET || victim->type == MT_BATTLECAPSULE
|| victim->type == MT_MONITOR || victim->type == MT_SPECIAL_UFO || victim->type == MT_BATTLEUFO)
if (victim->flags & MF_SHOOTABLE)
{
// Monitor hack. We can hit monitors once per instawhip, no multihit shredding!
// Damage values in Obj_MonitorGetDamage.
// Apply to UFO also -- steelt 29062023
if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO)
if (victim->type == MT_MONITOR || victim->type == MT_BATTLEUFO || victim->type == MT_BALLSWITCH_BALL)
{
if (shield->extravalue1 == 1)
return false;

View file

@ -25,6 +25,8 @@ void K_UnsetDialogue(void);
void K_DrawDialogue(void);
void K_TickDialogue(void);
boolean K_DialogueFreeze(void);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -48,6 +48,7 @@ private:
bool syllable;
bool dismissable;
bool freeze;
void Init(void);
//void Unset(void);

View file

@ -11,6 +11,7 @@
#include "k_director.h"
#include "d_netcmd.h"
#include "p_local.h"
#include "g_party.h"
#define SWITCHTIME TICRATE * 5 // cooldown between unforced switches
#define BOREDOMTIME 3 * TICRATE / 2 // how long until players considered far apart?
@ -322,3 +323,9 @@ void K_ToggleDirector(boolean active)
directorinfo.active = active;
}
boolean K_DirectorIsAvailable(UINT8 viewnum)
{
return viewnum <= r_splitscreen && viewnum < G_PartySize(consoleplayer) &&
displayplayers[viewnum] != G_PartyMember(consoleplayer, viewnum);
}

View file

@ -28,6 +28,7 @@ void K_UpdateDirector(void);
void K_DrawDirectorDebugger(void);
void K_DirectorFollowAttack(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_ToggleDirector(boolean active);
boolean K_DirectorIsAvailable(UINT8 viewnum);
#ifdef __cplusplus
} // extern "C"

View file

@ -435,7 +435,7 @@ void K_HandleFollower(player_t *player)
}
else // follower exists, woo!
{
if (player->follower->hitlag != 0)
if (P_MobjIsFrozen(player->follower))
{
// Don't update frames in hitlag
return;

View file

@ -100,6 +100,7 @@ static patch_t *kp_speedometersticker;
static patch_t *kp_speedometerlabel[4];
static patch_t *kp_rankbumper;
static patch_t *kp_bigbumper;
static patch_t *kp_tinybumper[2];
static patch_t *kp_ranknobumpers;
static patch_t *kp_rankcapsule;
@ -439,6 +440,7 @@ void K_LoadKartHUDGraphics(void)
// Extra ranking icons
HU_UpdatePatch(&kp_rankbumper, "K_BLNICO");
HU_UpdatePatch(&kp_bigbumper, "K_BLNBIG");
HU_UpdatePatch(&kp_tinybumper[0], "K_BLNA");
HU_UpdatePatch(&kp_tinybumper[1], "K_BLNB");
HU_UpdatePatch(&kp_ranknobumpers, "K_NOBLNS");
@ -1481,7 +1483,7 @@ static void K_drawKartItem(void)
// pain and suffering defined below
if (offset)
{
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = ITEM_X;
fy = ITEM_Y;
@ -1507,6 +1509,11 @@ static void K_drawKartItem(void)
fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN;
}
if (r_splitscreen == 1)
{
fy -= 5;
}
V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg);
// Need to draw these in a particular order, for sorting.
@ -1622,7 +1629,7 @@ static void K_drawKartItem(void)
{
xo++;
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // Flip for P1 and P3 (yes, that's correct)
if (!(R_GetViewNumber() & 1)) // Flip for P1 and P3 (yes, that's correct)
{
xo -= 62;
flip = V_FLIP;
@ -1730,7 +1737,7 @@ static void K_drawKartSlotMachine(void)
if (offset)
{
boxoffx -= 4;
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = ITEM_X + 10;
fy = ITEM_Y + 10;
@ -1759,6 +1766,11 @@ static void K_drawKartSlotMachine(void)
fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN;
}
if (r_splitscreen == 1)
{
fy -= 5;
}
V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg);
V_SetClipRect(
@ -2052,7 +2064,7 @@ static void K_DrawKartPositionNum(UINT8 num)
{
fx = BASEVIDWIDTH << FRACBITS;
if (stplyr == &players[displayplayers[0]])
if (R_GetViewNumber() == 0)
{
// for player 1: display this at the top right, above the minimap.
fy = 0;
@ -2071,8 +2083,7 @@ static void K_DrawKartPositionNum(UINT8 num)
{
fy = BASEVIDHEIGHT << FRACBITS;
if (stplyr == &players[displayplayers[0]]
|| stplyr == &players[displayplayers[2]])
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
// If we are P1 or P3...
fx = 0;
@ -2128,7 +2139,7 @@ static void K_DrawKartPositionNum(UINT8 num)
color = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_POSNUM, GTC_CACHE);
}
if ((fflags & V_SNAPTORIGHT) == 0 && num > 9)
if ((fflags & V_SNAPTORIGHT) == 0)
{
const UINT8 splitIndex = (r_splitscreen > 0) ? 1 : 0;
UINT8 adjustNum = num;
@ -2512,7 +2523,7 @@ static void K_drawKartEmeralds(void)
if (r_splitscreen < 2)
{
startx -= 8;
if (r_splitscreen == 1 && stplyr == &players[displayplayers[0]])
if (r_splitscreen == 1 && R_GetViewNumber() == 0)
{
starty = 1;
}
@ -2522,7 +2533,7 @@ static void K_drawKartEmeralds(void)
{
xindex = 2;
starty -= 15;
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
startx = LAPS_X;
splitflags = V_SNAPTOLEFT|V_SNAPTOBOTTOM|V_SPLITSCREEN;
@ -2586,7 +2597,7 @@ static void K_drawKartLaps(void)
}
else
{
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = LAPS_X;
fy = LAPS_Y;
@ -2693,7 +2704,7 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
}
else
{
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = LAPS_X;
fy = LAPS_Y;
@ -2728,10 +2739,16 @@ static void K_drawRingCounter(boolean gametypeinfoshown)
V_DrawMappedPatch(fr+ringx, fy-3, V_HUDTRANS|V_SLIDEIN|splitflags|ringflip, kp_smallring[ringanim_realframe], (colorring ? ringmap : NULL));
if (stplyr->hudrings < 0) // Draw the minus for ring debt
V_DrawMappedPatch(fr+7, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminussmall, ringmap);
V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap);
V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap);
{
V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_ringdebtminussmall, ringmap);
V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap);
V_DrawMappedPatch(fr+19, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap);
}
else
{
V_DrawMappedPatch(fr+11, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[0]], ringmap);
V_DrawMappedPatch(fr+15, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[rn[1]], ringmap);
}
// SPB ring lock
if (stplyr->pflags & PF_RINGLOCK)
@ -2833,7 +2850,7 @@ static void K_drawKartAccessibilityIcons(boolean gametypeinfoshown, INT32 fx)
{
fx = LAPS_X+44;
fy = LAPS_Y;
if (!(stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]])) // If we are not P1 or P3...
if (R_GetViewNumber() & 1) // If we are not P1 or P3...
{
splitflags ^= (V_SNAPTOLEFT|V_SNAPTORIGHT);
fx = (BASEVIDWIDTH/2) - fx;
@ -2904,6 +2921,11 @@ static void K_drawKartSpeedometer(boolean gametypeinfoshown)
INT32 splitflags = V_SNAPTOBOTTOM|V_SNAPTOLEFT|V_SPLITSCREEN;
INT32 fy = LAPS_Y-14;
if (battleprisons)
{
fy -= 2;
}
if (!stplyr->exiting) // Keep the same speed value as when you crossed the finish line!
{
switch (cv_kartspeedometer.value)
@ -2976,7 +2998,23 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown)
if (r_splitscreen < 2) // don't change shit for THIS splitscreen.
{
fx = LAPS_X;
fy = LAPS_Y-7;
fy = LAPS_Y-4;
if (battleprisons)
{
if (r_splitscreen == 1)
{
fy -= 8;
}
else
{
fy -= 5;
}
}
else if (r_splitscreen == 1)
{
fy -= 5;
}
if (gametypeinfoshown)
{
@ -2992,7 +3030,7 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown)
else
{
xstep = 8;
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = LAPS_X-2;
fy = LAPS_Y;
@ -3006,6 +3044,11 @@ static void K_drawBlueSphereMeter(boolean gametypeinfoshown)
xstep = -xstep;
}
if (battleprisons)
{
fy -= 5;
}
if (gametypeinfoshown)
{
fy -= 16;
@ -3077,7 +3120,7 @@ static void K_drawKartBumpersOrKarma(void)
}
else
{
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
if (!(R_GetViewNumber() & 1)) // If we are P1 or P3...
{
fx = LAPS_X;
fy = LAPS_Y;
@ -3093,11 +3136,13 @@ static void K_drawKartBumpersOrKarma(void)
}
V_DrawScaledPatch(fx-2 + (flipflag ? (SHORT(kp_ringstickersplit[1]->width) - 3) : 0), fy, V_HUDTRANS|V_SLIDEIN|splitflags|flipflag, kp_ringstickersplit[0]);
V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash);
fx += 2;
if (battleprisons)
{
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankcapsule, NULL);
V_DrawScaledPatch(fx+22, fy, V_HUDTRANS|V_SLIDEIN|splitflags, frameslash);
V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankcapsule, NULL);
if (numtargets > 9 || maptargets > 9)
{
@ -3122,54 +3167,42 @@ static void K_drawKartBumpersOrKarma(void)
}
else
{
const INT32 maxbumper = K_StartingBumperCount();
const UINT8 bumpers = K_Bumpers(stplyr);
V_DrawMappedPatch(fx+1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
V_DrawMappedPatch(fx-1, fy-2, V_HUDTRANS|V_SLIDEIN|splitflags, kp_rankbumper, colormap);
if (bumpers > 9 || maxbumper > 9)
{
UINT8 ln[2];
ln[0] = (bumpers / 10 % 10);
ln[1] = (bumpers % 10);
UINT8 ln[2];
ln[0] = (bumpers / 10 % 10);
ln[1] = (bumpers % 10);
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+17, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
ln[0] = ((abs(maxbumper) / 10) % 10);
ln[1] = (abs(maxbumper) % 10);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[0]]);
V_DrawScaledPatch(fx+31, fy, V_HUDTRANS|V_SLIDEIN|splitflags, fontv[PINGNUM_FONT].font[ln[1]]);
}
else
{
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(bumpers) % 10]);
V_DrawScaledPatch(fx+27, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[(maxbumper) % 10]);
}
V_DrawScaledPatch(fx+13, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[0]]);
V_DrawScaledPatch(fx+19, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_facenum[ln[1]]);
}
}
else
{
INT32 fy = r_splitscreen == 1 ? LAPS_Y-3 : LAPS_Y;
if (battleprisons)
{
if (numtargets > 9 && maptargets > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulestickerwide, NULL);
V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulestickerwide, NULL);
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulesticker, NULL);
V_DrawTimerString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", numtargets, maptargets));
V_DrawMappedPatch(LAPS_X, fy, V_HUDTRANS|V_SLIDEIN|splitflags, kp_capsulesticker, NULL);
V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", numtargets, maptargets));
}
else
{
const INT32 maxbumper = K_StartingBumperCount();
const UINT8 bumpers = K_Bumpers(stplyr);
if (bumpers > 9 && maxbumper > 9)
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumperstickerwide, colormap);
else
V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bumpersticker, colormap);
if (r_splitscreen == 0)
{
fy += 2;
}
V_DrawTimerString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d/%d", bumpers, maxbumper));
K_DrawSticker(LAPS_X+12, fy+5, bumpers > 9 ? 64 : 52, V_HUDTRANS|V_SLIDEIN|splitflags, false);
V_DrawMappedPatch(LAPS_X+15, fy-5, V_HUDTRANS|V_SLIDEIN|splitflags, kp_bigbumper, colormap);
V_DrawTimerString(LAPS_X+47, fy+3, V_HUDTRANS|V_SLIDEIN|splitflags, va("%d", bumpers));
}
}
}
@ -3418,7 +3451,7 @@ static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p)
// Since there's no "V_DrawFixedFill", and I don't feel like making it,
// fuck it, we're gonna just V_NOSCALESTART hack it
if (cnum & 1)
if (r_splitscreen > 1 && cnum & 1)
{
x += (BASEVIDWIDTH/2) * FRACUNIT;
}
@ -3517,6 +3550,31 @@ static void K_drawKartNameTags(void)
return;
}
// Crop within splitscreen bounds
switch (r_splitscreen)
{
case 1:
V_SetClipRect(
0,
cnum == 1 ? (BASEVIDHEIGHT / 2) * FRACUNIT : 0,
BASEVIDWIDTH * FRACUNIT,
(BASEVIDHEIGHT / 2) * FRACUNIT,
0
);
break;
case 2:
case 3:
V_SetClipRect(
cnum & 1 ? (BASEVIDWIDTH / 2) * FRACUNIT : 0,
cnum > 1 ? (BASEVIDHEIGHT / 2) * FRACUNIT : 0,
(BASEVIDWIDTH / 2) * FRACUNIT,
(BASEVIDHEIGHT / 2) * FRACUNIT,
0
);
break;
}
c.x = viewx;
c.y = viewy;
c.z = viewz;
@ -3704,20 +3762,10 @@ static void K_drawKartNameTags(void)
if (result.onScreen == true)
{
if (!(demo.playback == true && demo.freecam == true))
if (!(demo.playback == true && demo.freecam == true) && P_IsDisplayPlayer(ntplayer) &&
ntplayer != &players[displayplayers[cnum]])
{
for (j = 0; j <= (unsigned)r_splitscreen; j++)
{
if (ntplayer == &players[displayplayers[j]])
{
break;
}
}
if (j <= (unsigned)r_splitscreen && j != cnum)
{
localindicator = j;
}
localindicator = G_PartyPosition(ntplayer - players);
}
if (localindicator >= 0)
@ -3742,6 +3790,8 @@ static void K_drawKartNameTags(void)
}
}
}
V_ClearClipRect();
}
#define PROGRESSION_BAR_WIDTH 120
@ -3896,7 +3946,7 @@ static void K_drawKartMinimap(void)
// Only draw for the first player
// Maybe move this somewhere else where this won't be a concern?
if (stplyr != &players[displayplayers[0]])
if (R_GetViewNumber() != 0)
return;
if (specialstageinfo.valid == true)
@ -4431,7 +4481,7 @@ static void K_drawKartFinish(boolean finish)
interpx = R_InterpolateFixed(ox, x);
if (r_splitscreen && stplyr == &players[displayplayers[1]])
if (r_splitscreen && R_GetViewNumber() == 1)
interpx = -interpx;
V_DrawFixedPatch(interpx + (STCD_X<<FRACBITS) - (pwidth / 2),
@ -4669,14 +4719,12 @@ static void K_drawKartFirstPerson(void)
if (stplyr->spectator || !stplyr->mo || (stplyr->mo->renderflags & RF_DONTDRAW))
return;
if (stplyr == &players[displayplayers[1]] && r_splitscreen)
{ pn = pnum[1]; tn = turn[1]; dr = drift[1]; }
else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1)
{ pn = pnum[2]; tn = turn[2]; dr = drift[2]; }
else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)
{ pn = pnum[3]; tn = turn[3]; dr = drift[3]; }
else
{ pn = pnum[0]; tn = turn[0]; dr = drift[0]; }
{
UINT8 view = R_GetViewNumber();
pn = pnum[view];
tn = turn[view];
dr = drift[view];
}
if (r_splitscreen)
{
@ -4805,14 +4853,12 @@ static void K_drawKartFirstPerson(void)
V_DrawFixedPatch(x, y, scale, splitflags, kp_fpview[target], colmap);
if (stplyr == &players[displayplayers[1]] && r_splitscreen)
{ pnum[1] = pn; turn[1] = tn; drift[1] = dr; }
else if (stplyr == &players[displayplayers[2]] && r_splitscreen > 1)
{ pnum[2] = pn; turn[2] = tn; drift[2] = dr; }
else if (stplyr == &players[displayplayers[3]] && r_splitscreen > 2)
{ pnum[3] = pn; turn[3] = tn; drift[3] = dr; }
else
{ pnum[0] = pn; turn[0] = tn; drift[0] = dr; }
{
UINT8 view = R_GetViewNumber();
pnum[view] = pn;
turn[view] = tn;
drift[view] = dr;
}
}
// doesn't need to ever support 4p
@ -5060,23 +5106,26 @@ void K_drawKartFreePlay(void)
if (((leveltime-lt_endtime) % TICRATE) < TICRATE/2)
return;
const fixed_t x = ((BASEVIDWIDTH - (LAPS_X+6)) * FRACUNIT) - \
V_StringScaledWidth(
INT32 h_snap = (r_splitscreen < 2 || R_GetViewNumber() & 1) ? V_SNAPTORIGHT : V_SNAPTOLEFT;
fixed_t x = ((r_splitscreen > 1 ? BASEVIDWIDTH/4 : BASEVIDWIDTH - (LAPS_X+6)) * FRACUNIT);
fixed_t y = ((r_splitscreen ? BASEVIDHEIGHT/2 : BASEVIDHEIGHT) - 20) * FRACUNIT;
x -= V_StringScaledWidth(
FRACUNIT,
FRACUNIT,
FRACUNIT,
V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN,
V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|h_snap|V_SPLITSCREEN,
KART_FONT,
"FREE PLAY"
);
) / (r_splitscreen > 1 ? 2 : 1);
V_DrawStringScaled(
x,
(LAPS_Y+3) * FRACUNIT,
y,
FRACUNIT,
FRACUNIT,
FRACUNIT,
V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN,
V_HUDTRANS|V_SLIDEIN|V_SNAPTOBOTTOM|h_snap|V_SPLITSCREEN,
NULL,
KART_FONT,
"FREE PLAY"
@ -5086,33 +5135,26 @@ void K_drawKartFreePlay(void)
static void
Draw_party_ping (int ss, INT32 snap)
{
HU_drawMiniPing(0, 0, playerpingtable[displayplayers[ss]], V_HUDTRANS|V_SPLITSCREEN|V_SNAPTOTOP|snap);
HU_drawMiniPing(0, 0, playerpingtable[displayplayers[ss]], V_SPLITSCREEN|V_SNAPTOTOP|snap);
}
static void
K_drawMiniPing (void)
{
UINT32 f = V_SNAPTORIGHT;
UINT8 i;
UINT8 i = R_GetViewNumber();
if (!cv_showping.value)
{
return;
}
for (i = 0; i <= r_splitscreen; i++)
if (r_splitscreen > 1 && !(i & 1))
{
if (stplyr == &players[displayplayers[i]])
{
if (r_splitscreen > 1 && !(i & 1))
{
f = V_SNAPTOLEFT;
}
Draw_party_ping(i, f);
break;
}
f = V_SNAPTOLEFT;
}
Draw_party_ping(i, f);
}
void K_drawButton(fixed_t x, fixed_t y, INT32 flags, patch_t *button[2], boolean pressed)
@ -5210,7 +5252,7 @@ static void K_drawDistributionDebugger(void)
fixed_t y = -pad;
size_t i;
if (stplyr != &players[displayplayers[0]]) // only for p1
if (R_GetViewNumber() != 0) // only for p1
{
return;
}
@ -5268,7 +5310,7 @@ static void K_DrawWaypointDebugger(void)
if (cv_kartdebugwaypoints.value == 0)
return;
if (stplyr != &players[displayplayers[0]]) // only for p1
if (R_GetViewNumber() != 0) // only for p1
return;
if (netgame)
@ -5298,7 +5340,7 @@ static void K_DrawBotDebugger(void)
return;
}
if (stplyr != &players[displayplayers[0]]) // only for p1
if (R_GetViewNumber() != 0) // only for p1
{
return;
}
@ -5368,7 +5410,7 @@ static void K_DrawGPRankDebugger(void)
return;
}
if (stplyr != &players[displayplayers[0]]) // only for p1
if (R_GetViewNumber() != 0) // only for p1
{
return;
}
@ -5425,7 +5467,7 @@ void K_drawKartHUD(void)
K_drawKartFirstPerson();
// Draw full screen stuff that turns off the rest of the HUD
if (mapreset && stplyr == &players[displayplayers[0]])
if (mapreset && R_GetViewNumber() == 0)
{
K_drawChallengerScreen();
return;
@ -5455,19 +5497,6 @@ void K_drawKartHUD(void)
K_drawKartMinimap();
}
// Draw the item window
if (LUA_HudEnabled(hud_item) && !freecam)
{
if (stplyr->itemRoulette.ringbox && stplyr->itemamount == 0 && stplyr->itemtype == 0)
{
K_drawKartSlotMachine();
}
else
{
K_drawKartItem();
}
}
if (demo.title)
;
else if (!r_splitscreen)
@ -5482,18 +5511,23 @@ void K_drawKartHUD(void)
islonesome = K_drawKartPositionFaces();
}
else if (r_splitscreen == 1)
else
{
if (LUA_HudEnabled(hud_time))
islonesome = M_NotFreePlay() == false;
if (r_splitscreen == 1)
{
K_drawKart2PTimestamp();
if (LUA_HudEnabled(hud_time))
{
K_drawKart2PTimestamp();
}
}
}
else if (viewnum == r_splitscreen)
{
if (LUA_HudEnabled(hud_time))
else if (viewnum == r_splitscreen)
{
K_drawKart4PTimestamp();
if (LUA_HudEnabled(hud_time))
{
K_drawKart4PTimestamp();
}
}
}
@ -5581,6 +5615,19 @@ void K_drawKartHUD(void)
if (LUA_HudEnabled(hud_position))
K_drawInput();
}
// Draw the item window
if (LUA_HudEnabled(hud_item) && !freecam)
{
if (stplyr->itemRoulette.ringbox && stplyr->itemamount == 0 && stplyr->itemtype == 0)
{
K_drawKartSlotMachine();
}
else
{
K_drawKartItem();
}
}
}
}
@ -5640,7 +5687,7 @@ void K_drawKartHUD(void)
K_drawKartPowerUps();
if (G_IsPartyLocal(displayplayers[viewnum]) == false)
if (K_DirectorIsAvailable(viewnum) == true)
{
K_drawDirectorHUD();
}

View file

@ -264,13 +264,13 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player)
return flag;
if (player == &players[displayplayers[0]])
flag = RF_DONTDRAWP1;
else if (r_splitscreen >= 1 && player == &players[displayplayers[1]])
flag = RF_DONTDRAWP2;
else if (r_splitscreen >= 2 && player == &players[displayplayers[2]])
flag = RF_DONTDRAWP3;
else if (r_splitscreen >= 3 && player == &players[displayplayers[3]])
flag = RF_DONTDRAWP4;
flag |= RF_DONTDRAWP1;
if (r_splitscreen >= 1 && player == &players[displayplayers[1]])
flag |= RF_DONTDRAWP2;
if (r_splitscreen >= 2 && player == &players[displayplayers[2]])
flag |= RF_DONTDRAWP3;
if (r_splitscreen >= 3 && player == &players[displayplayers[3]])
flag |= RF_DONTDRAWP4;
return flag;
}
@ -3809,13 +3809,33 @@ void K_RemoveGrowShrink(player_t *player)
boolean K_IsBigger(mobj_t *compare, mobj_t *other)
{
fixed_t compareScale, otherScale;
if ((compare == NULL || P_MobjWasRemoved(compare) == true)
|| (other == NULL || P_MobjWasRemoved(other) == true))
{
return false;
}
return (compare->scale > other->scale + (mapobjectscale / 4));
if ((compareScale = P_GetMobjDefaultScale(compare)) != FRACUNIT)
{
compareScale = FixedDiv(compare->scale, compareScale);
}
else
{
compareScale = compare->scale;
}
if ((otherScale = P_GetMobjDefaultScale(other)) != FRACUNIT)
{
otherScale = FixedDiv(other->scale, otherScale);
}
else
{
otherScale = other->scale;
}
return (compareScale > otherScale + (mapobjectscale / 4));
}
static fixed_t K_TumbleZ(mobj_t *mo, fixed_t input)
@ -4536,7 +4556,7 @@ void K_MineFlashScreen(mobj_t *source)
}
// Spawns the purely visual explosion
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay)
void K_SpawnMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay)
{
INT32 i, radius, height;
mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING);
@ -4626,6 +4646,38 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay)
#undef MINEQUAKEDIST
void K_SpawnLandMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay)
{
mobj_t *smoldering;
mobj_t *expl;
UINT8 i;
// Spawn smoke remains:
smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING);
P_SetScale(smoldering, source->scale);
smoldering->tics = TICRATE*3;
smoldering->hitlag = delay;
// spawn a few physics explosions
for (i = 0; i < 15; i++)
{
expl = P_SpawnMobj(source->x, source->y, source->z + source->scale, MT_BOOMEXPLODE);
expl->color = color;
expl->tics = (i+1);
expl->hitlag = delay;
expl->renderflags |= RF_DONTDRAW;
//K_MatchGenericExtraFlags(expl, actor);
P_SetScale(expl, source->scale*4);
expl->momx = P_RandomRange(PR_EXPLOSION, -3, 3)*source->scale/2;
expl->momy = P_RandomRange(PR_EXPLOSION, -3, 3)*source->scale/2;
// 100/45 = 2.22 fu/t
expl->momz = ((i+1)*source->scale*5/2)*P_MobjFlip(expl);
}
}
fixed_t K_ItemScaleForPlayer(player_t *player)
{
switch (player->itemscale)
@ -7882,8 +7934,6 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
debtflag->color = player->skincolor;
debtflag->fuse = 2;
debtflag->renderflags = K_GetPlayerDontDrawFlag(player);
}
if (player->springstars && (leveltime & 1))

View file

@ -120,7 +120,8 @@ void K_DebtStingPlayer(player_t *player, mobj_t *source);
void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount);
void K_MineFlashScreen(mobj_t *source);
void K_SpawnMineExplosion(mobj_t *source, UINT8 color, tic_t delay);
void K_SpawnMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay);
void K_SpawnLandMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay);
void K_RunFinishLineBeam(void);
UINT16 K_DriftSparkColor(player_t *player, INT32 charge);
void K_SpawnBoostTrail(player_t *player);

View file

@ -233,6 +233,12 @@ boolean Obj_GetCheckpointRespawnPosition(const mobj_t *checkpoint, vector3_t *re
angle_t Obj_GetCheckpointRespawnAngle(const mobj_t *checkpoint);
void Obj_ActivateCheckpointInstantly(mobj_t* mobj);
/* Ball Switch */
void Obj_BallSwitchInit(mobj_t *mobj);
void Obj_BallSwitchThink(mobj_t *mobj);
void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher);
void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -33,6 +33,7 @@
#include "m_easing.h"
#include "s_sound.h"
#include "st_stuff.h"
#include "r_fps.h"
boolean level_tally_t::UseBonuses(void)
{
@ -883,14 +884,14 @@ void level_tally_t::Draw(void)
SINT8 h_transition_sign = 1;
if (r_splitscreen > 1)
{
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]])
if (!(R_GetViewNumber() & 1))
{
h_transition_sign = -h_transition_sign;
}
}
else if (r_splitscreen > 0)
{
if (stplyr == &players[displayplayers[1]])
if (R_GetViewNumber() == 1)
{
h_transition_sign = -h_transition_sign;
}

View file

@ -662,7 +662,7 @@ static int libd_drawOnMinimap(lua_State *L)
if (gamestate != GS_LEVEL)
return 0;
if (stplyr != &players[displayplayers[0]])
if (R_GetViewNumber() != 0)
return 0;
AutomapPic = mapheaderinfo[gamemap-1]->minimapPic;

View file

@ -599,7 +599,6 @@ static int player_set(lua_State *L)
if (plr == &players[displayplayers[i]])
{
localaiming[i] = plr->aiming;
break;
}
}
}

View file

@ -303,6 +303,14 @@ void Command_CheatGod_f(void)
D_Cheat(consoleplayer, CHEAT_GOD);
}
void Command_CheatFreeze_f(void)
{
REQUIRE_CHEATS;
REQUIRE_INLEVEL;
D_Cheat(consoleplayer, CHEAT_FREEZE);
}
void Command_Scale_f(void)
{
const double scaled = atof(COM_Argv(1));

View file

@ -41,6 +41,7 @@ typedef enum {
CHEAT_RESPAWNAT,
CHEAT_GIVEPOWERUP,
CHEAT_SPHERES,
CHEAT_FREEZE,
NUMBER_OF_CHEATS
} cheat_t;
@ -74,6 +75,7 @@ void OP_ObjectplaceMovement(player_t *player);
//
void Command_CheatNoClip_f(void);
void Command_CheatGod_f(void);
void Command_CheatFreeze_f(void);
void Command_Savecheckpoint_f(void);
void Command_Setrings_f(void);
void Command_Setspheres_f(void);

View file

@ -78,7 +78,7 @@ menuitem_t PLAY_MP_OptSelect[] =
{IT_STRING_CALL_NOTESTERS, "Host Game", "Start your own online game!",
NULL, {.routine = M_PreMPHostInit}, 0, 0},
{IT_STRING_CALL_NOTESTERS, "Server Browser", "Search for game servers to play in.",
{IT_STRING | IT_CALL, "Server Browser", "Search for game servers to play in.",
NULL, {.routine = M_PreMPRoomSelectInit}, 0, 0},
{IT_STRING | IT_CALL, "Join by IP", "Join an online game by its IP address.",

View file

@ -75,11 +75,13 @@ void M_MPRoomSelectInit(INT32 choice)
mpmenu.scrolln = 0;
mpmenu.slide = 0;
#ifndef TESTERS
if ((modifiedgame == true) || (M_SecretUnlocked(SECRET_ADDONS, true) == false))
{
M_ServersMenu(0);
return;
}
#endif // TESTERS
M_SetupNextMenu(&PLAY_MP_RoomSelectDef, false);
}

View file

@ -30,4 +30,5 @@ target_sources(SRB2SDL2 PRIVATE
emerald.c
checkpoint.cpp
shadow.cpp
ball-switch.cpp
)

241
src/objects/ball-switch.cpp Normal file
View file

@ -0,0 +1,241 @@
#include "../k_objects.h"
#include "../doomdef.h"
#include "../info.h"
#include "../p_local.h"
#include "../r_main.h"
#include "../k_hitlag.h"
#define ball_pad(o) ((o)->target)
#define ball_instawhipped(o) ((o)->extravalue1) // see instawhip collide
#define ball_cooldown(o) ((o)->cvmem)
#define ball_activedefer(o) ((o)->extravalue2)
#define ball_activator(o) ((o)->tracer)
namespace
{
struct BallSwitch_Pad : mobj_t
{
statenum_t Anim() const { return static_cast<statenum_t>(this->state - states); }
void Anim(statenum_t n)
{
if (Anim() != n)
{
P_SetMobjState(this, n);
}
}
void Spawned()
{
renderflags |= RF_FLOORSPRITE|RF_NOSPLATBILLBOARD|RF_SLOPESPLAT|RF_NOSPLATROLLANGLE;
}
void Tick(boolean active)
{
if (active == true)
{
Anim(S_BALLSWITCH_PAD_ACTIVE);
}
else
{
Anim(S_BALLSWITCH_PAD);
}
}
};
struct BallSwitch_Ball : mobj_t
{
BallSwitch_Pad *Pad() const { return static_cast<BallSwitch_Pad *>( ball_pad(this) ); }
void Pad(BallSwitch_Pad *n) { P_SetTarget(&ball_pad(this), n); }
statenum_t Anim() const { return static_cast<statenum_t>(this->state - states); }
void Anim(statenum_t n)
{
if (Anim() != n)
{
P_SetMobjState(this, n);
}
}
INT32 Cooldown() const { return ball_cooldown(this); }
void Cooldown(INT32 n) { ball_cooldown(this) = n; }
boolean Active() const { return (ball_cooldown(this) != 0); }
boolean DeferActivation() const { return ball_activedefer(this); }
mobj_t *Activator() const { return ball_activator(this); }
void DeferActivation(boolean n, mobj_t *src)
{
ball_activedefer(this) = n;
P_SetTarget(&ball_activator(this), src);
}
SINT8 IntSign(int value) const
{
if (value > 0)
{
return 1;
}
if (value < 0)
{
return -1;
}
return 0;
}
void Spawned()
{
Pad( static_cast<BallSwitch_Pad *>( P_SpawnMobjFromMobj(this, 0, 0, 0, MT_BALLSWITCH_PAD) ) );
Pad()->Spawned();
this->z += Pad()->height * P_MobjFlip(this);
}
void Tick()
{
if (P_MobjWasRemoved(Pad()) == true)
{
P_RemoveMobj(this);
return;
}
ball_instawhipped(this) = 0;
if (DeferActivation() == true)
{
P_ActivateThingSpecial(this, Activator());
Cooldown(-1); // maybe later?
DeferActivation(false, nullptr);
}
fixed_t ourZ = P_GetMobjFeet(this);
fixed_t theirZ = P_GetMobjHead(Pad());
fixed_t dist = P_AproxDistance(P_AproxDistance(Pad()->x - this->x, Pad()->y - this->y), theirZ - ourZ);
fixed_t move = P_AproxDistance(P_AproxDistance(this->momx, this->momy), this->momz);
constexpr INT32 accelScale = 4;
if (dist < accelScale * this->scale && move < accelScale * this->scale)
{
P_SetOrigin(this, Pad()->x, Pad()->y, theirZ);
this->momx = this->momy = this->momz = 0;
}
else
{
static constexpr const INT32 accel[2] = { FRACUNIT*3/4, FRACUNIT*3/16 };
constexpr fixed_t frict = FRACUNIT*99/100;
this->momx = FixedMul(this->momx, frict);
this->momy = FixedMul(this->momy, frict);
this->momz = FixedMul(this->momz, frict);
SINT8 xSign = IntSign(Pad()->x - this->x);
SINT8 ySign = IntSign(Pad()->y - this->y);
SINT8 zSign = IntSign(theirZ - ourZ);
boolean xAway = (IntSign(this->momx) == xSign);
boolean yAway = (IntSign(this->momy) == ySign);
boolean zAway = (IntSign(this->momz) == zSign);
this->momx += FixedMul(accel[xAway], accelScale * this->scale) * xSign;
this->momy += FixedMul(accel[yAway], accelScale * this->scale) * ySign;
this->momz += FixedMul(accel[zAway], accelScale * this->scale) * zSign;
this->angle += FixedAngle(move * 2);
if (dist > this->radius * 2)
{
P_Thrust(this, this->angle, (move / accelScale) * 2 / 3);
}
}
if (Active() == true)
{
INT32 cool = Cooldown();
if (cool > 0)
{
Cooldown(cool - 1);
}
Anim(S_BALLSWITCH_BALL_ACTIVE);
}
else
{
Anim(S_BALLSWITCH_BALL);
}
Pad()->Tick(Active());
}
void Push(mobj_t *toucher, const fixed_t pushValue, const fixed_t repelValue)
{
fixed_t push = FixedMul(pushValue, toucher->scale);
fixed_t repel = FixedMul(repelValue, this->scale);
angle_t thrustAngle = R_PointToAngle2(toucher->x, toucher->y, this->x, this->y);
fixed_t thrustAngleCos = FINECOSINE(thrustAngle >> ANGLETOFINESHIFT);
fixed_t thrustAngleSin = FINESINE(thrustAngle >> ANGLETOFINESHIFT);
fixed_t thisZ = this->z + (this->height / 2);
fixed_t toucherZ = toucher->z + (toucher->height / 2);
angle_t thrustPitch = R_PointToAngle2(0, toucherZ, R_PointToDist2(toucher->x, toucher->y, this->x, this->y), thisZ);
fixed_t thrustPitchCos = FINECOSINE(thrustPitch >> ANGLETOFINESHIFT);
fixed_t thrustPitchSin = FINESINE(thrustPitch >> ANGLETOFINESHIFT);
this->momx += FixedMul(FixedMul(push, thrustAngleCos), thrustPitchCos);
this->momy += FixedMul(FixedMul(push, thrustAngleSin), thrustPitchCos);
this->momz += FixedMul(push, thrustPitchSin);
toucher->momx -= FixedMul(FixedMul(repel, thrustAngleCos), thrustPitchCos);
toucher->momy -= FixedMul(FixedMul(repel, thrustAngleSin), thrustPitchCos);
toucher->momz -= FixedMul(repel, thrustPitchSin);
}
void Touch(mobj_t *toucher)
{
Push(toucher, 4 << FRACBITS, 6 << FRACBITS);
}
void Hit(mobj_t *inflictor, mobj_t *source)
{
Push(inflictor, 64 << FRACBITS, 1 << FRACBITS);
K_SetHitLagForObjects(this, inflictor, source, 4, true);
if (Active() == false)
{
DeferActivation(true, source);
}
}
};
}; // namespace
void Obj_BallSwitchInit(mobj_t *mobj)
{
BallSwitch_Ball *ball = static_cast<BallSwitch_Ball *>(mobj);
ball->Spawned();
}
void Obj_BallSwitchThink(mobj_t *mobj)
{
BallSwitch_Ball *ball = static_cast<BallSwitch_Ball *>(mobj);
ball->Tick();
}
void Obj_BallSwitchTouched(mobj_t *mobj, mobj_t *toucher)
{
BallSwitch_Ball *ball = static_cast<BallSwitch_Ball *>(mobj);
ball->Touch(toucher);
}
void Obj_BallSwitchDamaged(mobj_t *mobj, mobj_t *inflictor, mobj_t *source)
{
BallSwitch_Ball *ball = static_cast<BallSwitch_Ball *>(mobj);
ball->Hit(inflictor, source);
}

View file

@ -314,6 +314,7 @@ void A_SSMineExplode(mobj_t *actor);
void A_SSMineFlash(mobj_t *actor);
void A_LandMineExplode(mobj_t *actor);
void A_BallhogExplode(mobj_t *actor);
void A_SpecialStageBombExplode(mobj_t *actor);
void A_LightningFollowPlayer(mobj_t *actor);
void A_FZBoomFlash(mobj_t *actor);
void A_FZBoomSmoke(mobj_t *actor);
@ -13064,11 +13065,7 @@ void A_SSMineFlash(mobj_t *actor)
void A_LandMineExplode(mobj_t *actor)
{
mobj_t *expl;
INT32 colour = SKINCOLOR_KETCHUP; // we spell words properly here
INT32 i;
mobj_t *smoldering;
skincolornum_t colour = SKINCOLOR_KETCHUP; // we spell words properly here
tic_t delay = actor->reactiontime;
if (LUA_CallAction(A_LANDMINEEXPLODE, actor))
@ -13085,33 +13082,10 @@ void A_LandMineExplode(mobj_t *actor)
if (actor->target && !P_MobjWasRemoved(actor->target))
colour = actor->target->color;
// Spawn smoke remains:
smoldering = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SMOLDERING);
P_SetScale(smoldering, actor->scale);
smoldering->tics = TICRATE*3;
smoldering->hitlag = delay;
K_SpawnLandMineExplosion(actor, colour, delay);
actor->fuse = actor->tics; // disappear when this state ends.
// spawn a few physics explosions
for (i = 0; i < 15; i++)
{
expl = P_SpawnMobj(actor->x, actor->y, actor->z + actor->scale, MT_BOOMEXPLODE);
expl->color = colour;
expl->tics = (i+1);
expl->hitlag = delay;
expl->renderflags |= RF_DONTDRAW;
//K_MatchGenericExtraFlags(expl, actor);
P_SetScale(expl, actor->scale*4);
expl->momx = P_RandomRange(PR_EXPLOSION, -3, 3)*actor->scale/2;
expl->momy = P_RandomRange(PR_EXPLOSION, -3, 3)*actor->scale/2;
// 100/45 = 2.22 fu/t
expl->momz = ((i+1)*actor->scale*5/2)*P_MobjFlip(expl);
}
Obj_SpawnBrolyKi(actor, delay);
}
@ -13129,6 +13103,15 @@ void A_BallhogExplode(mobj_t *actor)
return;
}
void A_SpecialStageBombExplode(mobj_t *actor)
{
if (LUA_CallAction(A_SPECIALSTAGEBOMBEXPLODE, actor))
return;
K_SpawnLandMineExplosion(actor, SKINCOLOR_KETCHUP, actor->hitlag);
P_StartQuakeFromMobj(TICRATE/6, 24 * actor->scale, 512 * mapobjectscale, actor);
}
// A_LightningFollowPlayer:
// Dumb simple function that gives a mobj its target's momentums without updating its angle.
void A_LightningFollowPlayer(mobj_t *actor)

View file

@ -565,6 +565,26 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_SetTarget(&special->target, toucher);
S_StartSound(special, sfx_s1a2);
return;
case MT_SPECIALSTAGEBOMB:
// only attempt to damage the player if they're not invincible
if (!(player->invincibilitytimer > 0
|| K_IsBigger(toucher, special) == true
|| K_PlayerGuard(player) == true
|| player->hyudorotimer > 0))
{
if (P_DamageMobj(toucher, special, special, 1, DMG_STUMBLE))
{
P_SetMobjState(special, special->info->painstate);
special->eflags |= MFE_DAMAGEHITLAG;
return;
}
}
// if we didn't damage the player, just explode
P_SetMobjState(special, special->info->painstate);
P_SetMobjState(special, special->info->raisestate); // immediately explode visually
return;
case MT_CDUFO: // SRB2kart
if (special->fuse || !P_CanPickupItem(player, 1))
return;
@ -832,6 +852,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
Obj_DashRingTouch(special, player);
return;
case MT_BALLSWITCH_BALL:
{
Obj_BallSwitchTouched(special, toucher);
return;
}
default: // SOC or script pickup
P_SetTarget(&special->target, toucher);
break;
@ -1428,7 +1454,6 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
if (target->player == &players[displayplayers[i]])
{
localaiming[i] = 0;
break;
}
}
@ -2413,6 +2438,12 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
return false;
}
if (target->type == MT_BALLSWITCH_BALL)
{
Obj_BallSwitchDamaged(target, inflictor, source);
return false;
}
if (!force)
{
if (!spbpop)

View file

@ -154,7 +154,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount);
void P_ResetCamera(player_t *player, camera_t *thiscam);
boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam);
void P_SlideCameraMove(camera_t *thiscam);
void P_DemoCameraMovement(camera_t *cam);
void P_DemoCameraMovement(camera_t *cam, UINT8 num);
boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcalled);
void P_ToggleDemoCamera(void);
@ -167,7 +167,6 @@ boolean P_IsMachineLocalPlayer(player_t *player);
boolean P_IsDisplayPlayer(player_t *player);
void P_SetPlayerAngle(player_t *player, angle_t angle);
angle_t P_GetLocalAngle(player_t *player);
void P_ForceLocalAngle(player_t *player, angle_t angle);
boolean P_PlayerFullbright(player_t *player);
@ -256,6 +255,7 @@ mobjtype_t P_GetMobjtype(UINT16 mthingtype);
void P_RespawnSpecials(void);
fixed_t P_GetMobjDefaultScale(mobj_t *mobj);
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type);
void P_CalculatePrecipFloor(precipmobj_t *mobj);
@ -333,6 +333,8 @@ void P_FlashPal(player_t *pl, UINT16 type, UINT16 duration);
#define PAL_RECYCLE 3
#define PAL_NUKE 4
boolean P_MobjIsFrozen(mobj_t *mobj);
//
// P_ENEMY
//

View file

@ -573,7 +573,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
return BMIT_CONTINUE;
// Ignore the collision if BOTH things are in hitlag.
if (thing->hitlag > 0 && tm.thing->hitlag > 0)
if (P_MobjIsFrozen(thing) && P_MobjIsFrozen(tm.thing))
return BMIT_CONTINUE;
if ((thing->flags & MF_NOCLIPTHING) || !(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))

View file

@ -9727,6 +9727,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
case MT_RAINBOWDASHRING:
Obj_RainbowDashRingThink(mobj);
break;
case MT_BALLSWITCH_BALL:
{
Obj_BallSwitchThink(mobj);
break;
}
default:
// check mobj against possible water content, before movement code
P_MobjCheckWater(mobj);
@ -10031,6 +10036,7 @@ void P_MobjThinker(mobj_t *mobj)
mobj->flags2 &= ~(MF2_ALREADYHIT);
// Don't run any thinker code while in hitlag
mobj->eflags &= ~(MFE_PAUSED);
if ((mobj->player ? mobj->hitlag - mobj->player->nullHitlag : mobj->hitlag) > 0)
{
mobj->eflags |= MFE_PAUSED;
@ -10073,11 +10079,14 @@ void P_MobjThinker(mobj_t *mobj)
if (mobj->type == MT_HITLAG && mobj->hitlag == 0)
mobj->renderflags &= ~RF_DONTDRAW;
*/
}
if (P_MobjIsFrozen(mobj))
{
return;
}
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED|MFE_PAUSED);
mobj->eflags &= ~(MFE_PUSHED|MFE_SPRUNG|MFE_JUSTBOUNCEDWALL|MFE_DAMAGEHITLAG|MFE_SLOPELAUNCHED);
// sal: what the hell? is there any reason this isn't done, like, literally ANYWHERE else?
P_SetTarget(&tm.floorthing, NULL);
@ -10528,6 +10537,20 @@ void P_SceneryThinker(mobj_t *mobj)
// GAME SPAWN FUNCTIONS
//
fixed_t P_GetMobjDefaultScale(mobj_t *mobj)
{
switch(mobj->type)
{
case MT_SPECIALSTAGEARCH:
return 5*FRACUNIT;
case MT_SPECIALSTAGEBOMB:
return 3*FRACUNIT/4;
default:
break;
}
return FRACUNIT;
}
static void P_DefaultMobjShadowScale(mobj_t *thing)
{
thing->shadowscale = 0;
@ -10628,6 +10651,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
SINT8 sc = -1;
state_t *st;
mobj_t *mobj;
fixed_t scale;
if (type == MT_NULL)
{
@ -10680,13 +10704,12 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
// All mobjs are created at 100% scale.
mobj->scale = FRACUNIT;
mobj->destscale = mobj->scale;
mobj->scalespeed = FRACUNIT/12;
mobj->destscale = mapobjectscale;
mobj->scalespeed = mapobjectscale/12;
if (mapobjectscale != FRACUNIT) //&& !(mobj->type == MT_BLACKEGGMAN)
if ((scale = P_GetMobjDefaultScale(mobj)) != FRACUNIT)
{
mobj->destscale = mapobjectscale;
mobj->scalespeed = mapobjectscale/12;
mobj->destscale = FixedMul(mobj->destscale, scale);
}
// Sprite rendering
@ -11174,6 +11197,9 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
case MT_SNEAKERPANELSPAWNER:
Obj_SneakerPanelSpawnerSpawn(mobj);
break;
case MT_BALLSWITCH_BALL:
Obj_BallSwitchInit(mobj);
break;
default:
break;
}
@ -11664,6 +11690,9 @@ static void P_SpawnPrecipitationAt(fixed_t basex, fixed_t basey)
for (j = 0; j < numparticles; j++)
{
INT32 floorz;
INT32 ceilingz;
rainmo = P_SpawnPrecipMobj(x, y, z, type);
if (randomstates > 0)
@ -11682,8 +11711,19 @@ static void P_SpawnPrecipitationAt(fixed_t basex, fixed_t basey)
}
}
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(rainmo->floorz >> FRACBITS, rainmo->ceilingz >> FRACBITS) << FRACBITS;
floorz = rainmo->floorz >> FRACBITS;
ceilingz = rainmo->ceilingz >> FRACBITS;
if (floorz < ceilingz)
{
// Randomly assign a height, now that floorz is set.
rainmo->z = M_RandomRange(floorz, ceilingz) << FRACBITS;
}
else
{
// ...except if the floor is above the ceiling.
rainmo->z = ceilingz << FRACBITS;
}
}
}
}
@ -12074,13 +12114,8 @@ void P_SpawnPlayer(INT32 playernum)
if ((gametyperules & GTR_BUMPERS) && !p->spectator)
{
// At leveltime == 2, K_TimerInit will get called and reset
// the bumpers to the initial value for the level.
if (leveltime > 2) // Reset those bumpers!
{
mobj->health = K_BumpersToHealth(K_StartingBumperCount());
K_SpawnPlayerBattleBumpers(p);
}
mobj->health = K_BumpersToHealth(K_StartingBumperCount());
K_SpawnPlayerBattleBumpers(p);
}
// Block visuals

View file

@ -434,6 +434,8 @@ struct mobj_t
INT32 script_args[NUM_SCRIPT_ARGS];
char *script_stringargs[NUM_SCRIPT_STRINGARGS];
boolean frozen;
// WARNING: New fields must be added separately to savegame and Lua.
};

View file

@ -2542,7 +2542,7 @@ typedef enum
MD2_WAYPOINTCAP = 1<<25,
MD2_KITEMCAP = 1<<26,
MD2_ITNEXT = 1<<27,
MD2_LASTMOMZ = 1<<28,
MD2_FROZEN = 1<<28,
MD2_TERRAIN = 1<<29,
MD2_WATERSKIP = 1<<30,
MD2_LIGHTLEVEL = (INT32)(1U<<31),
@ -2733,7 +2733,7 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
}
// not the default but the most probable
if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0)
if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0 || mobj->lastmomz != 0)
diff |= MD_MOM;
if (mobj->radius != mobj->info->radius)
diff |= MD_RADIUS;
@ -2855,8 +2855,8 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
diff2 |= MD2_KITEMCAP;
if (mobj->itnext)
diff2 |= MD2_ITNEXT;
if (mobj->lastmomz)
diff2 |= MD2_LASTMOMZ;
if (mobj->frozen)
diff2 |= MD2_FROZEN;
if (mobj->terrain != NULL || mobj->terrainOverlay != NULL)
diff2 |= MD2_TERRAIN;
@ -2919,6 +2919,7 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
WRITEFIXED(save->p, mobj->momy);
WRITEFIXED(save->p, mobj->momz);
WRITEFIXED(save->p, mobj->pmomz);
WRITEFIXED(save->p, mobj->lastmomz);
}
if (diff & MD_RADIUS)
WRITEFIXED(save->p, mobj->radius);
@ -3123,9 +3124,9 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8
{
WRITEINT32(save->p, mobj->dispoffset);
}
if (diff2 & MD2_LASTMOMZ)
if (diff2 & MD2_FROZEN)
{
WRITEINT32(save->p, mobj->lastmomz);
WRITEUINT8(save->p, mobj->frozen);
}
if (diff2 & MD2_TERRAIN)
{
@ -4102,6 +4103,7 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
mobj->momy = READFIXED(save->p);
mobj->momz = READFIXED(save->p);
mobj->pmomz = READFIXED(save->p);
mobj->lastmomz = READFIXED(save->p);
} // otherwise they're zero, and the memset took care of it
if (diff & MD_RADIUS)
@ -4357,9 +4359,9 @@ static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker)
{
mobj->dispoffset = READINT32(save->p);
}
if (diff2 & MD2_LASTMOMZ)
if (diff2 & MD2_FROZEN)
{
mobj->lastmomz = READINT32(save->p);
mobj->frozen = (boolean)READUINT8(save->p);
}
if (diff2 & MD2_TERRAIN)
{

View file

@ -7539,6 +7539,9 @@ static void P_InitLevelSettings(void)
leveltime = 0;
modulothing = 0;
P_SetFreezeLevel(false);
P_SetFreezeCheat(false);
K_TimerReset();
nummaprings = 0;

View file

@ -2867,7 +2867,6 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha
camera[i].z += z;
camera[i].subsector = R_PointInSubsector(camera[i].x, camera[i].y);
R_RelativeTeleportViewInterpolation(i, x, y, z, 0);
break;
}
}
}

View file

@ -79,7 +79,6 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
if (camera[i].chase)
P_ResetCamera(thing->player, &camera[i]);
R_ResetViewInterpolation(i + 1);
break;
}
// don't run in place after a teleport
@ -170,8 +169,6 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle
}
R_ResetViewInterpolation(1 + i);
break;
}
}

View file

@ -52,6 +52,63 @@
tic_t leveltime;
boolean thinkersCompleted;
static boolean g_freezeCheat;
static boolean g_freezeLevel;
boolean P_LevelIsFrozen(void)
{
return (g_freezeLevel || g_freezeCheat);
}
boolean P_FreezeCheat(void)
{
return (g_freezeLevel || g_freezeCheat);
}
void P_SetFreezeCheat(boolean value)
{
g_freezeCheat = value;
}
void P_SetFreezeLevel(boolean value)
{
g_freezeLevel = value;
}
boolean P_MobjIsFrozen(mobj_t *mobj)
{
if (g_freezeCheat == true)
{
// freeze cheat
switch (mobj->type)
{
case MT_PLAYER:
{
break;
}
default:
{
return true;
}
}
}
if (g_freezeLevel == true)
{
// level totally frozen
return true;
}
if ((mobj->eflags & MFE_PAUSED) == MFE_PAUSED)
{
// hitlag
return true;
}
// manual
return mobj->frozen;
}
INT32 P_AltFlip(INT32 n, tic_t tics)
{
return leveltime % (2 * tics) < tics ? n : -(n);

View file

@ -27,6 +27,12 @@ extern "C" {
extern tic_t leveltime;
extern boolean thinkersCompleted;
boolean P_LevelIsFrozen(void);
boolean P_FreezeCheat(void);
void P_SetFreezeCheat(boolean value);
void P_SetFreezeLevel(boolean value);
boolean P_MobjIsFrozen(mobj_t *mobj);
// Called by G_Ticker. Carries out all thinking of enemies and players.
void Command_Numthinkers_f(void);
void Command_CountMobjs_f(void);

View file

@ -2887,7 +2887,7 @@ fixed_t t_cam_rotate[MAXSPLITSCREENPLAYERS] = {-42,-42,-42,-42};
struct demofreecam_s democam;
void P_DemoCameraMovement(camera_t *cam)
void P_DemoCameraMovement(camera_t *cam, UINT8 num)
{
ticcmd_t *cmd;
angle_t thrustangle;
@ -2897,7 +2897,7 @@ void P_DemoCameraMovement(camera_t *cam)
boolean moving = false;
// first off we need to get button input
cmd = D_LocalTiccmd(0);
cmd = D_LocalTiccmd(num);
if (cmd->aiming != 0)
{
@ -3083,18 +3083,6 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (thiscam->subsector == NULL || thiscam->subsector->sector == NULL)
return true;
if (demo.freecam || player->spectator)
{
P_DemoCameraMovement(thiscam);
return true;
}
if (paused || P_AutoPause())
return true;
playerScale = FixedDiv(player->mo->scale, mapobjectscale);
scaleDiff = playerScale - FRACUNIT;
if (thiscam == &camera[1]) // Camera 2
{
num = 1;
@ -3112,9 +3100,21 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
num = 0;
}
if (demo.freecam || player->spectator)
{
P_DemoCameraMovement(thiscam, num);
return true;
}
if (paused || P_AutoPause())
return true;
playerScale = FixedDiv(player->mo->scale, mapobjectscale);
scaleDiff = playerScale - FRACUNIT;
mo = player->mo;
if (mo->hitlag > 0 || player->playerstate == PST_DEAD)
if (P_MobjIsFrozen(mo) || player->playerstate == PST_DEAD)
{
// Do not move the camera while in hitlag!
// The camera zooming out after you got hit makes it hard to focus on the vibration.
@ -3544,19 +3544,10 @@ boolean P_SpectatorJoinGame(player_t *player)
player->enteredGame = true;
// Reset away view (some code referenced from Got_Teamchange)
if (G_IsPartyLocal(player - players))
{
UINT8 i = 0;
const UINT8 *localplayertable = G_PartyArray(consoleplayer);
for (i = 0; i <= r_splitscreen; i++)
{
if (localplayertable[i] == (player-players))
{
LUA_HookViewpointSwitch(player, player, true);
displayplayers[i] = (player-players);
break;
}
}
LUA_HookViewpointSwitch(player, player, true);
displayplayers[G_PartyPosition(player - players)] = (player-players);
}
// a surprise tool that will help us later...
@ -3572,11 +3563,11 @@ boolean P_SpectatorJoinGame(player_t *player)
}
// the below is first person only, if you're curious. check out P_CalcChasePostImg in p_mobj.c for chasecam
static void P_CalcPostImg(player_t *player)
static void P_CalcPostImg(player_t *player, size_t viewnum)
{
sector_t *sector = player->mo->subsector->sector;
postimg_t *type = NULL;
INT32 *param;
postimg_t *type = &postimgtype[viewnum];
INT32 *param = &postimgparam[viewnum];
fixed_t pviewheight;
size_t i;
@ -3591,16 +3582,6 @@ static void P_CalcPostImg(player_t *player)
pviewheight = player->awayview.mobj->z;
}
for (i = 0; i <= (unsigned)r_splitscreen; i++)
{
if (player == &players[displayplayers[i]])
{
type = &postimgtype[i];
param = &postimgparam[i];
break;
}
}
// see if we are in heat (no, not THAT kind of heat...)
for (i = 0; i < sector->tags.count; i++)
{
@ -4208,7 +4189,7 @@ void P_PlayerThink(player_t *player)
ALL ABOVE THIS BLOCK OCCURS EVEN WITH HITLAG
/ ------------------------------------------ */
if (player->mo->hitlag > 0)
if (P_MobjIsFrozen(player->mo))
{
return;
}
@ -4400,7 +4381,6 @@ void P_PlayerThink(player_t *player)
//
void P_PlayerAfterThink(player_t *player)
{
camera_t *thiscam = NULL; // if not one of the displayed players, just don't bother
UINT8 i;
#ifdef PARANOIA
@ -4425,15 +4405,6 @@ void P_PlayerAfterThink(player_t *player)
P_PlayerInSpecialSector(player);
#endif
for (i = 0; i <= r_splitscreen; i++)
{
if (player == &players[displayplayers[i]])
{
thiscam = &camera[i];
break;
}
}
if (player->playerstate == PST_DEAD)
{
// Followers need handled while dead.
@ -4448,12 +4419,20 @@ void P_PlayerAfterThink(player_t *player)
return;
}
if (thiscam)
{
if (!thiscam->chase) // bob view only if looking through the player's eyes
boolean chase = true;
for (i = 0; i <= r_splitscreen; i++)
{
if (player == &players[displayplayers[i]] && !camera[i].chase)
{
chase = false;
}
}
if (!chase) // bob view only if looking through the player's eyes
{
P_CalcHeight(player);
P_CalcPostImg(player);
}
else
{
@ -4466,6 +4445,14 @@ void P_PlayerAfterThink(player_t *player)
else
player->viewz = player->mo->z + player->viewheight;
}
for (i = 0; i <= r_splitscreen; i++)
{
if (player == &players[displayplayers[i]] && !camera[i].chase)
{
P_CalcPostImg(player, i);
}
}
}
// spectator invisibility and nogravity.
@ -4530,10 +4517,15 @@ void P_PlayerAfterThink(player_t *player)
K_UpdateBotGameplayVars(player);
}
if (thiscam)
for (i = 0; i <= r_splitscreen; i++)
{
if (player != &players[displayplayers[i]])
{
continue;
}
// Store before it gets 0'd out
thiscam->pmomz = player->mo->pmomz;
camera[i].pmomz = player->mo->pmomz;
}
if (P_IsObjectOnGround(player->mo))
@ -4546,7 +4538,7 @@ void P_IncrementGriefValue(player_t *player, UINT32 *grief, const UINT32 griefMa
INT32 progress = player->distancetofinishprev - player->distancetofinish;
boolean exceptions = (
player->flashing != 0
|| player->mo->hitlag != 0
|| P_MobjIsFrozen(player->mo)
|| player->airtime > 3*TICRATE/2
|| (player->justbumped > 0 && player->justbumped < bumptime-1)
);
@ -4632,21 +4624,6 @@ void P_SetPlayerAngle(player_t *player, angle_t angle)
player->angleturn = angle;
}
angle_t P_GetLocalAngle(player_t *player)
{
// this function is from vanilla srb2. can you tell?
// (hint: they have separate variables for all of this shit instead of arrays)
UINT8 i;
for (i = 0; i <= r_splitscreen; i++)
{
if (player == &players[displayplayers[i]])
return localangle[i];
}
return 0;
}
void P_ForceLocalAngle(player_t *player, angle_t angle)
{
UINT8 i;
@ -4658,8 +4635,6 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
if (player == &players[displayplayers[i]])
{
localangle[i] = angle;
break;
}
}

View file

@ -20,6 +20,7 @@
#include "r_local.h"
#include "r_state.h"
#include "r_portal.h" // Add seg portals
#include "r_fps.h"
#include "r_splats.h"
#include "p_local.h" // camera
@ -276,18 +277,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
mobj_t *viewmobj = viewplayer->mo;
INT32 heightsec;
boolean underwater;
UINT8 i;
UINT8 i = R_GetViewNumber();
for (i = 0; i <= r_splitscreen; i++)
{
if (viewplayer == &players[displayplayers[i]] && camera[i].chase)
{
heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec;
break;
}
}
if (i > r_splitscreen && viewmobj)
if (camera[i].chase)
heightsec = R_PointInSubsector(camera[i].x, camera[i].y)->sector->heightsec;
else if (i > r_splitscreen && viewmobj)
heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec;
else
return sec;

View file

@ -22,6 +22,7 @@
#include "r_state.h"
#include "z_zone.h"
#include "console.h" // con_startup_loadprogress
#include "i_time.h"
UINT32 R_GetFramerateCap(void)
{
@ -58,6 +59,7 @@ static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS];
static viewvars_t skyview_new[MAXSPLITSCREENPLAYERS];
static viewvars_t *oldview = &pview_old[0];
static tic_t last_view_update;
static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0};
viewvars_t *newview = &pview_new[0];
@ -165,21 +167,27 @@ void R_UpdateViewInterpolation(void)
skyview_old[i] = skyview_new[i];
if (oldview_invalid[i] > 0) oldview_invalid[i]--;
}
last_view_update = I_GetTime();
}
void R_ResetViewInterpolation(UINT8 p)
{
// Wait an extra tic if the interpolation state hasn't
// updated yet.
int t = last_view_update == I_GetTime() ? 1 : 2;
if (p == 0)
{
UINT8 i;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
oldview_invalid[i]++;
oldview_invalid[i] = t;
}
}
else
{
oldview_invalid[p - 1]++;
oldview_invalid[p - 1] = t;
}
}

View file

@ -218,7 +218,7 @@ void ChaseCam4_OnChange(void)
//
// killough 5/2/98: reformatted
//
INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node)
INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *restrict node)
{
if (!node->dx)
return x <= node->x ? node->dy > 0 : node->dy < 0;
@ -230,9 +230,10 @@ INT32 R_PointOnSide(fixed_t x, fixed_t y, node_t *node)
y -= node->y;
// Try to quickly decide by looking at sign bits.
if ((node->dy ^ node->dx ^ x ^ y) < 0)
return (node->dy ^ x) < 0; // (left is negative)
return FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x);
// also use a mask to avoid branch prediction
INT32 mask = (node->dy ^ node->dx ^ x ^ y) >> 31;
return (mask & ((node->dy ^ x) < 0)) | // (left is negative)
(~mask & (FixedMul(y, node->dx>>FRACBITS) >= FixedMul(node->dy>>FRACBITS, x)));
}
// killough 5/2/98: reformatted

View file

@ -20,6 +20,7 @@
#include "g_game.h"
#include "p_setup.h" // levelflats
#include "p_slopes.h"
#include "r_fps.h"
#include "r_data.h"
#include "r_textures.h"
#include "r_local.h"
@ -963,8 +964,6 @@ void R_DrawSinglePlane(visplane_t *pl)
planeripple.active = true;
if (spanfunctype == SPANDRAWFUNC_TRANS)
{
UINT8 i;
spanfunctype = SPANDRAWFUNC_WATER;
// Copy the current scene, ugh
@ -977,43 +976,38 @@ void R_DrawSinglePlane(visplane_t *pl)
bottom = viewheight;
// Only copy the part of the screen we need
for (i = 0; i <= r_splitscreen; i++)
UINT8 i = R_GetViewNumber();
INT32 scrx = 0;
INT32 scry = top;
INT32 offset;
if (r_splitscreen == 1)
{
if (viewplayer == &players[displayplayers[i]])
if (i & 1)
{
INT32 scrx = 0;
INT32 scry = top;
INT32 offset;
if (r_splitscreen == 1)
{
if (i & 1)
{
scry += viewheight;
}
}
else
{
if (i & 1)
{
scrx += viewwidth;
}
if (i / 2)
{
scry += viewheight;
}
}
offset = (scry*vid.width) + scrx;
// No idea if this works
VID_BlitLinearScreen(screens[0] + offset,
screens[1] + (top*vid.width), // intentionally not +offset
viewwidth, bottom-top,
vid.width, vid.width);
scry += viewheight;
}
}
else
{
if (i & 1)
{
scrx += viewwidth;
}
if (i / 2)
{
scry += viewheight;
}
}
offset = (scry*vid.width) + scrx;
// No idea if this works
VID_BlitLinearScreen(screens[0] + offset,
screens[1] + (top*vid.width), // intentionally not +offset
viewwidth, bottom-top,
vid.width, vid.width);
}
}
#endif

View file

@ -532,12 +532,9 @@ void SCR_DisplayTicRate(void)
const UINT8 *ticcntcolor = NULL;
UINT32 cap = R_GetFramerateCap();
UINT32 benchmark = (cap == 0) ? I_GetRefreshRate() : cap;
INT32 x = 318;
INT32 x = 317;
double fps = round(averageFPS);
// draw "FPS"
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
if (fps > (benchmark * 0.9))
ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
else if (fps < (benchmark * 0.5))
@ -571,15 +568,28 @@ void SCR_DisplayTicRate(void)
void SCR_DisplayLocalPing(void)
{
boolean offline;
UINT32 ping = playerpingtable[consoleplayer]; // consoleplayer's ping is everyone's ping in a splitnetgame :P
if (! r_splitscreen && ( cv_showping.value == 1 || (cv_showping.value == 2 && ping > servermaxping) )) // only show 2 (warning) if our ping is at a bad level
// Splitscreen party has its own ping counter, but show the
// 1P version anyway in some cases:
// - On intermission, vote, etc. gamestates where the player
// HUD is not drawn.
// - If the menu is opened, since it draws over the player
// HUD.
if (r_splitscreen && gamestate == GS_LEVEL && !menuactive)
{
INT32 dispy = cv_ticrate.value ? 160 : 181;
offline = (consoleplayer == serverplayer);
HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM | V_HUDTRANS, offline, 0);
return;
}
UINT32 ping = playerpingtable[consoleplayer];
if (cv_showping.value == 2 && ping <= servermaxping) // only show 2 (warning) if our ping is at a bad level
{
return;
}
INT32 dispy = cv_ticrate.value ? 170 : 181;
boolean offline = (consoleplayer == serverplayer);
HU_drawPing(307 * FRACUNIT, dispy * FRACUNIT, ping, V_SNAPTORIGHT | V_SNAPTOBOTTOM, offline, 0);
}

View file

@ -235,6 +235,11 @@ static void SDLSetMode(INT32 width, INT32 height, SDL_bool fullscreen, SDL_bool
SDL_GetWindowSize(window, &width, &height);
vid.realwidth = static_cast<uint32_t>(width);
vid.realheight = static_cast<uint32_t>(height);
if (graphics_started)
{
I_UpdateNoVsync();
}
}
static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
@ -501,6 +506,11 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
case SDL_WINDOWEVENT_MOVED:
window_x = evt.data1;
window_y = evt.data2;
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
vid.realwidth = evt.data1;
vid.realheight = evt.data2;
break;
}
if (FOCUSUNION == oldfocus) // No state change
@ -1535,7 +1545,7 @@ INT32 VID_SetMode(INT32 modeNum)
static SDL_bool Impl_CreateWindow(SDL_bool fullscreen)
{
int flags = 0;
uint32_t flags = SDL_WINDOW_RESIZABLE;
if (rendermode == render_none) // dedicated
return SDL_TRUE; // Monster Iestyn -- not sure if it really matters what we return here tbh

View file

@ -1203,7 +1203,7 @@ static void ST_overlayDrawer(void)
{
char name[MAXPLAYERNAME+12];
INT32 y = (stplyr == &players[displayplayers[0]]) ? 4 : BASEVIDHEIGHT/2-12;
INT32 y = (viewnum == 0) ? 4 : BASEVIDHEIGHT/2-12;
sprintf(name, "VIEWPOINT: %s", player_names[stplyr-players]);
V_DrawRightAlignedThinString(BASEVIDWIDTH-40, y, V_HUDTRANSHALF|V_SNAPTOTOP|V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_SPLITSCREEN, name);
}
@ -1451,8 +1451,15 @@ static fixed_t ST_CalculateFadeIn(player_t *player)
if (player->tally.hudSlide != 0)
{
tic_t timer = length - player->tally.hudSlide;
fixed_t f = timer * FRACUNIT;
return ((timer * FRACUNIT) + (FRACUNIT - rendertimefrac)) / length;
// Not interpolated at very beginning or end
if (timer > 0 && timer < length)
{
f += FRACUNIT - rendertimefrac;
}
return f / length;
}
tic_t timer = lt_exitticker;
@ -1467,9 +1474,18 @@ static fixed_t ST_CalculateFadeIn(player_t *player)
if (timer < length)
{
return ((timer * FRACUNIT) + rendertimefrac) / length;
fixed_t f = timer * FRACUNIT;
// Not interpolated at very beginning
if (timer > 0)
{
f += rendertimefrac;
}
return f / length;
}
// Not interpolated at very end
return FRACUNIT;
}

View file

@ -27,6 +27,7 @@
#include "f_finale.h"
#include "r_draw.h"
#include "console.h"
#include "r_fps.h"
#include "i_video.h" // rendermode
#include "z_zone.h"
@ -513,8 +514,7 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
INT32 screenheight = vid.height;
INT32 basewidth = BASEVIDWIDTH * dupx;
INT32 baseheight = BASEVIDHEIGHT * dupy;
SINT8 player = -1;
UINT8 i;
SINT8 player = R_GetViewNumber();
if (options & V_SPLITSCREEN)
{
@ -531,15 +531,6 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
}
}
for (i = 0; i <= r_splitscreen; i++)
{
if (stplyr == &players[displayplayers[i]])
{
player = i;
break;
}
}
if (vid.width != (BASEVIDWIDTH * dupx))
{
if (options & V_SNAPTORIGHT)
@ -586,7 +577,7 @@ void V_AdjustXYWithSnap(INT32 *x, INT32 *y, UINT32 options, INT32 dupx, INT32 du
if (r_splitscreen > 1)
{
if (stplyr == &players[displayplayers[1]] || stplyr == &players[displayplayers[3]])
if (player & 1)
slidefromright = true;
}