mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into hwr2-twodee
This commit is contained in:
commit
40271cd128
29 changed files with 500 additions and 326 deletions
|
|
@ -2610,15 +2610,6 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
|
|||
|
||||
LUA_HookPlayerQuit(&players[playernum], reason); // Lua hook for player quitting
|
||||
|
||||
// don't look through someone's view who isn't there
|
||||
if (playernum == displayplayers[0] && !demo.playback)
|
||||
{
|
||||
// Call ViewpointSwitch hooks here.
|
||||
// The viewpoint was forcibly changed.
|
||||
LUA_HookViewpointSwitch(&players[consoleplayer], &players[consoleplayer], true);
|
||||
displayplayers[0] = consoleplayer;
|
||||
}
|
||||
|
||||
G_RemovePartyMember(playernum);
|
||||
|
||||
// Reset player data
|
||||
|
|
@ -2638,6 +2629,9 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason)
|
|||
|
||||
LUA_InvalidatePlayer(&players[playernum]);
|
||||
|
||||
// don't look through someone's view who isn't there
|
||||
G_ResetViews();
|
||||
|
||||
K_CheckBumpers();
|
||||
P_CheckRacers();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,10 +359,10 @@ struct doomdata_t
|
|||
UINT8 reserved; // Padding
|
||||
union
|
||||
{
|
||||
clientcmd_pak clientpak; // 145 bytes
|
||||
client2cmd_pak client2pak; // 202 bytes
|
||||
client3cmd_pak client3pak; // 258 bytes(?)
|
||||
client4cmd_pak client4pak; // 316 bytes(?)
|
||||
clientcmd_pak clientpak; // 147 bytes
|
||||
client2cmd_pak client2pak; // 206 bytes
|
||||
client3cmd_pak client3pak; // 264 bytes(?)
|
||||
client4cmd_pak client4pak; // 324 bytes(?)
|
||||
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
|
||||
serverconfig_pak servercfg; // 773 bytes
|
||||
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)
|
||||
|
|
|
|||
|
|
@ -548,8 +548,6 @@ static CV_PossibleValue_t perfstats_cons_t[] = {
|
|||
};
|
||||
consvar_t cv_perfstats = CVAR_INIT ("perfstats", "Off", 0, perfstats_cons_t, NULL);
|
||||
|
||||
consvar_t cv_director = CVAR_INIT ("director", "Off", 0, CV_OnOff, NULL);
|
||||
|
||||
consvar_t cv_schedule = CVAR_INIT ("schedule", "On", CV_NETVAR|CV_CALL, CV_OnOff, Schedule_OnChange);
|
||||
|
||||
consvar_t cv_automate = CVAR_INIT ("automate", "On", CV_NETVAR, CV_OnOff, NULL);
|
||||
|
|
@ -1060,8 +1058,6 @@ void D_RegisterClientCommands(void)
|
|||
CV_RegisterVar(&cv_scr_width);
|
||||
CV_RegisterVar(&cv_scr_height);
|
||||
|
||||
CV_RegisterVar(&cv_director);
|
||||
|
||||
CV_RegisterVar(&cv_soundtest);
|
||||
|
||||
CV_RegisterVar(&cv_invincmusicfade);
|
||||
|
|
@ -1596,21 +1592,8 @@ static void FinalisePlaystateChange(INT32 playernum)
|
|||
K_StripItems(&players[playernum]);
|
||||
}
|
||||
|
||||
// Reset away view (some code referenced from P_SpectatorJoinGame)
|
||||
{
|
||||
UINT8 i = 0;
|
||||
INT32 *localplayertable = (splitscreen_partied[consoleplayer] ? splitscreen_party[consoleplayer] : g_localplayers);
|
||||
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
{
|
||||
if (localplayertable[i] == playernum)
|
||||
{
|
||||
LUA_HookViewpointSwitch(players+playernum, players+playernum, true);
|
||||
displayplayers[i] = playernum;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reset away view
|
||||
G_ResetViews();
|
||||
|
||||
K_CheckBumpers(); // SRB2Kart
|
||||
P_CheckRacers(); // also SRB2Kart
|
||||
|
|
|
|||
|
|
@ -128,8 +128,6 @@ extern consvar_t cv_sleep;
|
|||
|
||||
extern consvar_t cv_perfstats;
|
||||
|
||||
extern consvar_t cv_director;
|
||||
|
||||
extern consvar_t cv_schedule;
|
||||
|
||||
extern consvar_t cv_livestudioaudience;
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@ struct ticcmd_t
|
|||
{
|
||||
SINT8 forwardmove; // -MAXPLMOVE to MAXPLMOVE (50)
|
||||
INT16 turning; // Turn speed
|
||||
INT16 angle; // Predicted angle, use me if you can!
|
||||
INT16 throwdir; // Aiming direction
|
||||
INT16 aiming; // vertical aiming, see G_BuildTicCmd
|
||||
UINT16 buttons;
|
||||
|
|
|
|||
|
|
@ -131,6 +131,7 @@ extern char logfilename[1024];
|
|||
|
||||
//#define DEVELOP // Disable this for release builds to remove excessive cheat commands and enable MD5 checking and stuff, all in one go. :3
|
||||
#ifdef DEVELOP
|
||||
#define PARANOIA // On by default for DEVELOP builds
|
||||
#define VERSIONSTRING "Development EXE"
|
||||
#define VERSIONSTRING_RC "Development EXE" "\0"
|
||||
// most interface strings are ignored in development mode.
|
||||
|
|
|
|||
45
src/g_demo.c
45
src/g_demo.c
|
|
@ -136,15 +136,16 @@ demoghost *ghosts = NULL;
|
|||
#define DEMO_BOT 0x08
|
||||
|
||||
// For demos
|
||||
#define ZT_FWD 0x01
|
||||
#define ZT_SIDE 0x02
|
||||
#define ZT_TURNING 0x04
|
||||
#define ZT_THROWDIR 0x08
|
||||
#define ZT_BUTTONS 0x10
|
||||
#define ZT_AIMING 0x20
|
||||
#define ZT_LATENCY 0x40
|
||||
#define ZT_FLAGS 0x80
|
||||
// OUT OF ZIPTICS...
|
||||
#define ZT_FWD 0x0001
|
||||
#define ZT_SIDE 0x0002
|
||||
#define ZT_TURNING 0x0004
|
||||
#define ZT_ANGLE 0x0008
|
||||
#define ZT_THROWDIR 0x0010
|
||||
#define ZT_BUTTONS 0x0020
|
||||
#define ZT_AIMING 0x0040
|
||||
#define ZT_LATENCY 0x0080
|
||||
#define ZT_FLAGS 0x0100
|
||||
// Ziptics are UINT16 now, go nuts
|
||||
|
||||
#define DEMOMARKER 0x80 // demobuf.end
|
||||
|
||||
|
|
@ -530,17 +531,19 @@ void G_WriteDemoExtraData(void)
|
|||
|
||||
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
||||
{
|
||||
UINT8 ziptic;
|
||||
UINT16 ziptic;
|
||||
|
||||
if (!demobuf.p || !demo.deferstart)
|
||||
return;
|
||||
|
||||
ziptic = READUINT8(demobuf.p);
|
||||
ziptic = READUINT16(demobuf.p);
|
||||
|
||||
if (ziptic & ZT_FWD)
|
||||
oldcmd[playernum].forwardmove = READSINT8(demobuf.p);
|
||||
if (ziptic & ZT_TURNING)
|
||||
oldcmd[playernum].turning = READINT16(demobuf.p);
|
||||
if (ziptic & ZT_ANGLE)
|
||||
oldcmd[playernum].angle = READINT16(demobuf.p);
|
||||
if (ziptic & ZT_THROWDIR)
|
||||
oldcmd[playernum].throwdir = READINT16(demobuf.p);
|
||||
if (ziptic & ZT_BUTTONS)
|
||||
|
|
@ -564,13 +567,14 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
|||
|
||||
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
||||
{
|
||||
char ziptic = 0;
|
||||
UINT16 ziptic = 0;
|
||||
UINT8 *ziptic_p;
|
||||
(void)playernum;
|
||||
|
||||
if (!demobuf.p)
|
||||
return;
|
||||
ziptic_p = demobuf.p++; // the ziptic, written at the end of this function
|
||||
ziptic_p = demobuf.p; // the ziptic, written at the end of this function
|
||||
demobuf.p += 2;
|
||||
|
||||
if (cmd->forwardmove != oldcmd[playernum].forwardmove)
|
||||
{
|
||||
|
|
@ -586,6 +590,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
|||
ziptic |= ZT_TURNING;
|
||||
}
|
||||
|
||||
if (cmd->angle != oldcmd[playernum].angle)
|
||||
{
|
||||
WRITEINT16(demobuf.p,cmd->angle);
|
||||
oldcmd[playernum].angle = cmd->angle;
|
||||
ziptic |= ZT_ANGLE;
|
||||
}
|
||||
|
||||
if (cmd->throwdir != oldcmd[playernum].throwdir)
|
||||
{
|
||||
WRITEINT16(demobuf.p,cmd->throwdir);
|
||||
|
|
@ -621,7 +632,7 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
|
|||
ziptic |= ZT_FLAGS;
|
||||
}
|
||||
|
||||
*ziptic_p = ziptic;
|
||||
WRITEUINT16(ziptic_p, ziptic);
|
||||
|
||||
// attention here for the ticcmd size!
|
||||
// latest demos with mouse aiming byte in ticcmd
|
||||
|
|
@ -1173,7 +1184,7 @@ void G_GhostTicker(void)
|
|||
for(g = ghosts, p = NULL; g; g = g->next)
|
||||
{
|
||||
// Skip normal demo data.
|
||||
UINT8 ziptic = READUINT8(g->p);
|
||||
UINT16 ziptic = READUINT8(g->p);
|
||||
UINT8 xziptic = 0;
|
||||
|
||||
while (ziptic != DW_END) // Get rid of extradata stuff
|
||||
|
|
@ -1214,12 +1225,14 @@ void G_GhostTicker(void)
|
|||
ziptic = READUINT8(g->p);
|
||||
}
|
||||
|
||||
ziptic = READUINT8(g->p);
|
||||
ziptic = READUINT16(g->p);
|
||||
|
||||
if (ziptic & ZT_FWD)
|
||||
g->p++;
|
||||
if (ziptic & ZT_TURNING)
|
||||
g->p += 2;
|
||||
if (ziptic & ZT_ANGLE)
|
||||
g->p += 2;
|
||||
if (ziptic & ZT_THROWDIR)
|
||||
g->p += 2;
|
||||
if (ziptic & ZT_BUTTONS)
|
||||
|
|
|
|||
171
src/g_game.c
171
src/g_game.c
|
|
@ -61,6 +61,7 @@
|
|||
#include "k_specialstage.h"
|
||||
#include "k_bot.h"
|
||||
#include "doomstat.h"
|
||||
#include "k_director.h"
|
||||
|
||||
#ifdef HAVE_DISCORDRPC
|
||||
#include "discord.h"
|
||||
|
|
@ -1080,80 +1081,32 @@ INT32 localaiming[MAXSPLITSCREENPLAYERS];
|
|||
angle_t localangle[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
INT32 localsteering[MAXSPLITSCREENPLAYERS];
|
||||
INT32 localdelta[MAXSPLITSCREENPLAYERS];
|
||||
INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
|
||||
UINT8 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
|
||||
UINT8 localtic;
|
||||
|
||||
void G_ResetAnglePrediction(player_t *player)
|
||||
{
|
||||
UINT16 i, j;
|
||||
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
{
|
||||
if (&players[displayplayers[i]] == player)
|
||||
{
|
||||
localdelta[i] = 0;
|
||||
for (j = 0; j < TICCMD_LATENCYMASK; j++)
|
||||
{
|
||||
localstoredeltas[i][j] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turning was removed from G_BuildTiccmd to prevent easy client hacking.
|
||||
// This brings back the camera prediction that was lost.
|
||||
static void G_DoAnglePrediction(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer, player_t *player)
|
||||
{
|
||||
angle_t angleChange = 0;
|
||||
angle_t destAngle = player->angleturn;
|
||||
angle_t diff = 0;
|
||||
|
||||
localtic = cmd->latency;
|
||||
|
||||
if (player->pflags & PF_DRIFTEND)
|
||||
while (realtics > 0)
|
||||
{
|
||||
// Otherwise, your angle slingshots off to the side violently...
|
||||
G_ResetAnglePrediction(player);
|
||||
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
|
||||
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
|
||||
|
||||
realtics--;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Left here in case it needs unsealing later. This tried to replicate an old localcam function, but this behavior was unpopular in tests.
|
||||
//if (player->pflags & PF_DRIFTEND)
|
||||
{
|
||||
localangle[ssplayer - 1] = player->mo->angle;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
while (realtics > 0)
|
||||
{
|
||||
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
|
||||
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
|
||||
|
||||
// Store the angle we applied to this tic, so we can revert it later.
|
||||
// If we trust the camera to do all of the work, then it can get out of sync fast.
|
||||
localstoredeltas[ssplayer - 1][cmd->latency] += angleChange;
|
||||
localdelta[ssplayer - 1] += angleChange;
|
||||
|
||||
realtics--;
|
||||
}
|
||||
localangle[ssplayer - 1] += angleChange;
|
||||
}
|
||||
|
||||
// We COULD set it to destAngle directly...
|
||||
// but this causes incredible jittering when the prediction turns out to be wrong. So we ease into it.
|
||||
// Slight increased camera lag in all scenarios > Mostly lagless camera but with jittering
|
||||
destAngle = player->angleturn + localdelta[ssplayer - 1];
|
||||
|
||||
diff = destAngle - localangle[ssplayer - 1];
|
||||
|
||||
if (diff > ANGLE_180)
|
||||
{
|
||||
diff = InvAngle(InvAngle(diff) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff /= 2;
|
||||
}
|
||||
|
||||
localangle[ssplayer - 1] += diff;
|
||||
|
||||
// In case of angle debugging, break glass
|
||||
// localangle[ssplayer - 1] = destAngle;
|
||||
}
|
||||
|
||||
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
||||
|
|
@ -1189,6 +1142,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
break;
|
||||
}
|
||||
|
||||
cmd->angle = localangle[forplayer] >> TICCMD_REDUCE;
|
||||
|
||||
// why build a ticcmd if we're paused?
|
||||
// Or, for that matter, if we're being reborn.
|
||||
if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN))
|
||||
|
|
@ -1210,6 +1165,28 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
goto aftercmdinput;
|
||||
}
|
||||
|
||||
if (displayplayers[forplayer] != g_localplayers[forplayer])
|
||||
{
|
||||
if (M_MenuButtonPressed(forplayer, MBT_A))
|
||||
{
|
||||
G_AdjustView(ssplayer, 1, true);
|
||||
K_ToggleDirector(false);
|
||||
}
|
||||
|
||||
if (M_MenuButtonPressed(forplayer, MBT_X))
|
||||
{
|
||||
G_AdjustView(ssplayer, -1, true);
|
||||
K_ToggleDirector(false);
|
||||
}
|
||||
|
||||
if (M_MenuButtonPressed(forplayer, MBT_R))
|
||||
{
|
||||
K_ToggleDirector(true);
|
||||
}
|
||||
|
||||
goto aftercmdinput;
|
||||
}
|
||||
|
||||
if (K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
// Bot ticcmd is generated by K_BuildBotTiccmd
|
||||
|
|
@ -1398,16 +1375,6 @@ aftercmdinput:
|
|||
cmd->throwdir = -KART_FULLTURN;
|
||||
|
||||
G_DoAnglePrediction(cmd, realtics, ssplayer, player);
|
||||
|
||||
// Reset away view if a command is given.
|
||||
if ((cmd->forwardmove || cmd->buttons)
|
||||
&& !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1)
|
||||
{
|
||||
// Call ViewpointSwitch hooks here.
|
||||
// The viewpoint was forcibly changed.
|
||||
LUA_HookViewpointSwitch(player, &players[consoleplayer], true);
|
||||
displayplayers[0] = consoleplayer;
|
||||
}
|
||||
}
|
||||
|
||||
ticcmd_t *G_CopyTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
|
||||
|
|
@ -1422,6 +1389,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
|
|||
{
|
||||
dest[i].forwardmove = src[i].forwardmove;
|
||||
dest[i].turning = (INT16)SHORT(src[i].turning);
|
||||
dest[i].angle = (INT16)SHORT(src[i].angle);
|
||||
dest[i].throwdir = (INT16)SHORT(src[i].throwdir);
|
||||
dest[i].aiming = (INT16)SHORT(src[i].aiming);
|
||||
dest[i].buttons = (UINT16)SHORT(src[i].buttons);
|
||||
|
|
@ -1740,44 +1708,8 @@ boolean G_Responder(event_t *ev)
|
|||
return true; // chat ate the event
|
||||
}
|
||||
|
||||
// allow spy mode changes even during the demo
|
||||
if (gamestate == GS_LEVEL && ev->type == ev_keydown
|
||||
&& (ev->data1 == KEY_F12 /*|| ev->data1 == gamecontrol[0][gc_viewpoint][0] || ev->data1 == gamecontrol[0][gc_viewpoint][1]*/))
|
||||
{
|
||||
if (!demo.playback && (r_splitscreen || !netgame))
|
||||
g_localplayers[0] = consoleplayer;
|
||||
else
|
||||
{
|
||||
G_AdjustView(1, 1, true);
|
||||
|
||||
// change statusbar also if playing back demo
|
||||
if (demo.quitafterplaying)
|
||||
ST_changeDemoView();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (gamestate == GS_LEVEL && ev->type == ev_keydown && multiplayer && demo.playback && !demo.freecam)
|
||||
{
|
||||
/*
|
||||
if (ev->data1 == gamecontrol[1][gc_viewpoint][0] || ev->data1 == gamecontrol[1][gc_viewpoint][1])
|
||||
{
|
||||
G_AdjustView(2, 1, true);
|
||||
return true;
|
||||
}
|
||||
else if (ev->data1 == gamecontrol[2][gc_viewpoint][0] || ev->data1 == gamecontrol[2][gc_viewpoint][1])
|
||||
{
|
||||
G_AdjustView(3, 1, true);
|
||||
return true;
|
||||
}
|
||||
else if (ev->data1 == gamecontrol[3][gc_viewpoint][0] || ev->data1 == gamecontrol[3][gc_viewpoint][1])
|
||||
{
|
||||
G_AdjustView(4, 1, true);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
// Allow pausing
|
||||
if (
|
||||
//ev->data1 == gamecontrol[0][gc_pause][0]
|
||||
|
|
@ -1964,7 +1896,7 @@ boolean G_CanView(INT32 playernum, UINT8 viewnum, boolean onlyactive)
|
|||
INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive, boolean reverse)
|
||||
{
|
||||
INT32 i, dir = reverse ? -1 : 1;
|
||||
startview = min(max(startview, 0), MAXPLAYERS);
|
||||
startview = min(max(startview, -1), MAXPLAYERS);
|
||||
for (i = startview; i < MAXPLAYERS && i >= 0; i += dir)
|
||||
{
|
||||
if (G_CanView(i, viewnum, onlyactive))
|
||||
|
|
@ -2035,7 +1967,14 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
|
|||
|
||||
/* Check if anyone is available to view. */
|
||||
if (( playernum = G_FindView(playernum, viewnum, onlyactive, playernum < olddisplayplayer) ) == -1)
|
||||
return;
|
||||
{
|
||||
/* Fall back on true self */
|
||||
playernum = g_localplayers[viewnum-1];
|
||||
}
|
||||
|
||||
// Call ViewpointSwitch hooks here.
|
||||
// The viewpoint was forcibly changed.
|
||||
LUA_HookViewpointSwitch(&players[g_localplayers[viewnum - 1]], &players[playernum], true);
|
||||
|
||||
/* Focus our target view first so that we don't take its player. */
|
||||
(*displayplayerp) = playernum;
|
||||
|
|
@ -2043,6 +1982,10 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
|
|||
{
|
||||
camerap = &camera[viewnum-1];
|
||||
P_ResetCamera(&players[(*displayplayerp)], camerap);
|
||||
|
||||
// Why does it need to be done twice?
|
||||
R_ResetViewInterpolation(viewnum);
|
||||
R_ResetViewInterpolation(viewnum);
|
||||
}
|
||||
|
||||
if (viewnum > splits)
|
||||
|
|
@ -2060,6 +2003,10 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
|
|||
|
||||
if (viewnum == 1 && demo.playback)
|
||||
consoleplayer = displayplayers[0];
|
||||
|
||||
// change statusbar also if playing back demo
|
||||
if (demo.quitafterplaying)
|
||||
ST_changeDemoView();
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -2097,8 +2044,8 @@ void G_ResetViews(void)
|
|||
/* Demote splits */
|
||||
if (playersviewable < splits)
|
||||
{
|
||||
splits = playersviewable;
|
||||
r_splitscreen = max(splits-1, 0);
|
||||
splits = max(playersviewable, splitscreen + 1); // don't delete local players
|
||||
r_splitscreen = splits - 1;
|
||||
R_ExecuteSetViewSize();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ extern consvar_t cv_resume;
|
|||
const char *G_BuildMapName(INT32 map);
|
||||
INT32 G_MapNumber(const char *mapname);
|
||||
|
||||
void G_ResetAnglePrediction(player_t *player);
|
||||
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
|
||||
|
||||
// copy ticcmd_t to and fro the normal way
|
||||
|
|
@ -116,10 +115,6 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming);
|
|||
extern angle_t localangle[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed
|
||||
extern INT32 localsteering[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localdelta[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
|
||||
extern UINT8 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
|
||||
extern UINT8 localtic;
|
||||
|
||||
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers);
|
||||
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ void K_InitDirector(void)
|
|||
{
|
||||
INT32 playernum;
|
||||
|
||||
directorinfo.active = false;
|
||||
directorinfo.cooldown = SWITCHTIME;
|
||||
directorinfo.freeze = 0;
|
||||
directorinfo.attacker = 0;
|
||||
|
|
@ -109,6 +110,11 @@ static boolean K_CanSwitchDirector(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!directorinfo.active)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -218,11 +224,6 @@ void K_UpdateDirector(void)
|
|||
INT32 *displayplayerp = &displayplayers[0];
|
||||
INT32 targetposition;
|
||||
|
||||
if (!cv_director.value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
K_UpdateDirectorPositions();
|
||||
|
||||
if (directorinfo.cooldown > 0) {
|
||||
|
|
@ -238,6 +239,13 @@ void K_UpdateDirector(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// if there's only one player left in the list, just switch to that player
|
||||
if (directorinfo.sortedplayers[0] != -1 && directorinfo.sortedplayers[1] == -1)
|
||||
{
|
||||
K_DirectorSwitch(directorinfo.sortedplayers[0], false);
|
||||
return;
|
||||
}
|
||||
|
||||
// aaight, time to walk through the standings to find the first interesting pair
|
||||
// NB: targetposition/sortedplayers is 0-indexed, aiming at the "back half" of a given pair by default.
|
||||
// we adjust for this when comparing to player->position or when looking at the leading player, Don't Freak Out
|
||||
|
|
@ -277,18 +285,40 @@ void K_UpdateDirector(void)
|
|||
|
||||
target = directorinfo.sortedplayers[targetposition];
|
||||
|
||||
// stop here since we're already viewing this player
|
||||
if (*displayplayerp == target)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// if this is a splitscreen player, try next pair
|
||||
if (P_IsDisplayPlayer(&players[target]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if we're certain the back half of the pair is actually in this position, try to switch
|
||||
if (*displayplayerp != target && !players[target].positiondelay)
|
||||
if (!players[target].positiondelay)
|
||||
{
|
||||
K_DirectorSwitch(target, false);
|
||||
}
|
||||
|
||||
// even if we're not certain, if we're certain we're watching the WRONG player, try to switch
|
||||
if (players[*displayplayerp].position != targetposition+1 && !players[target].positiondelay)
|
||||
if (players[*displayplayerp].position != targetposition+1 && !players[*displayplayerp].positiondelay)
|
||||
{
|
||||
K_DirectorSwitch(target, false);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void K_ToggleDirector(boolean active)
|
||||
{
|
||||
if (directorinfo.active != active)
|
||||
{
|
||||
directorinfo.cooldown = 0; // switch immediately
|
||||
}
|
||||
|
||||
directorinfo.active = active;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ extern "C" {
|
|||
|
||||
extern struct directorinfo
|
||||
{
|
||||
boolean active; // is view point switching enabled?
|
||||
tic_t cooldown; // how long has it been since we last switched?
|
||||
tic_t freeze; // when nonzero, fixed switch pending, freeze logic!
|
||||
INT32 attacker; // who to switch to when freeze delay elapses
|
||||
|
|
@ -26,6 +27,7 @@ void K_InitDirector(void);
|
|||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
32
src/k_hud.c
32
src/k_hud.c
|
|
@ -4639,6 +4639,33 @@ K_drawMiniPing (void)
|
|||
}
|
||||
}
|
||||
|
||||
static void K_DrawDirectorButton(INT32 idx, const char *label, patch_t *kp[2])
|
||||
{
|
||||
const INT32 flags = V_SNAPTORIGHT | V_SLIDEIN;
|
||||
const INT32 textflags = flags | V_6WIDTHSPACE | V_ALLOWLOWERCASE;
|
||||
|
||||
const UINT8 anim_duration = 16;
|
||||
const UINT8 anim = (leveltime % (anim_duration * 2)) < anim_duration;
|
||||
|
||||
const INT32 x = BASEVIDWIDTH - 60;
|
||||
const INT32 y = BASEVIDHEIGHT - 70 + (idx * 16);
|
||||
|
||||
V_DrawScaledPatch(x, y - 4, flags, kp[anim]);
|
||||
V_DrawRightAlignedThinString(x - 2, y, textflags, label);
|
||||
}
|
||||
|
||||
static void K_drawDirectorHUD(void)
|
||||
{
|
||||
if (!LUA_HudEnabled(hud_textspectator))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
K_DrawDirectorButton(0, "Next Player", kp_button_a[0]);
|
||||
K_DrawDirectorButton(1, "Prev Player", kp_button_x[0]);
|
||||
K_DrawDirectorButton(2, "Director", kp_button_r);
|
||||
}
|
||||
|
||||
static void K_drawDistributionDebugger(void)
|
||||
{
|
||||
itemroulette_t rouletteData = {0};
|
||||
|
|
@ -4957,6 +4984,11 @@ void K_drawKartHUD(void)
|
|||
K_drawMiniPing();
|
||||
}
|
||||
|
||||
if (displayplayers[viewnum] != g_localplayers[viewnum])
|
||||
{
|
||||
K_drawDirectorHUD();
|
||||
}
|
||||
|
||||
if (cv_kartdebugdistribution.value)
|
||||
K_drawDistributionDebugger();
|
||||
|
||||
|
|
|
|||
79
src/k_kart.c
79
src/k_kart.c
|
|
@ -7748,12 +7748,12 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
}
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer)
|
||||
if (player->invincibilitytimer && onground == true)
|
||||
player->invincibilitytimer--;
|
||||
|
||||
if ((player->respawn.state == RESPAWNST_NONE) && player->growshrinktimer != 0)
|
||||
{
|
||||
if (player->growshrinktimer > 0)
|
||||
if (player->growshrinktimer > 0 && onground == true)
|
||||
player->growshrinktimer--;
|
||||
if (player->growshrinktimer < 0)
|
||||
player->growshrinktimer++;
|
||||
|
|
@ -7810,7 +7810,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
|
|||
|
||||
|
||||
if (player->stealingtimer == 0
|
||||
&& player->rocketsneakertimer)
|
||||
&& player->rocketsneakertimer
|
||||
&& onground == true)
|
||||
player->rocketsneakertimer--;
|
||||
|
||||
if (player->hyudorotimer)
|
||||
|
|
@ -9728,6 +9729,7 @@ static void K_KartSpindash(player_t *player)
|
|||
|
||||
player->spindash = 0;
|
||||
S_ReducedVFXSound(player->mo, sfx_s23c, player);
|
||||
S_StopSoundByID(player->mo, sfx_kc38);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -9779,11 +9781,15 @@ static void K_KartSpindash(player_t *player)
|
|||
UINT8 ringdropframes = 2 + (player->kartspeed + player->kartweight);
|
||||
boolean spawnOldEffect = true;
|
||||
|
||||
if (player->rings <= 0) // Use the damn spindash
|
||||
player->spindash++; // I am no longer asking
|
||||
|
||||
INT16 chargetime = MAXCHARGETIME - ++player->spindash;
|
||||
|
||||
if (player->rings <= 0 && chargetime >= 0) // Desperation spindash
|
||||
{
|
||||
player->spindash++;
|
||||
if (!S_SoundPlaying(player->mo, sfx_kc38))
|
||||
S_StartSound(player->mo, sfx_kc38);
|
||||
}
|
||||
|
||||
if (player->spindash >= SPINDASHTHRUSTTIME)
|
||||
{
|
||||
K_KartSpindashDust(player->mo);
|
||||
|
|
@ -10504,40 +10510,43 @@ void K_MoveKartPlayer(player_t *player, boolean onground)
|
|||
{
|
||||
if (player->growshrinktimer < 0)
|
||||
{
|
||||
// If you're shrunk, then "grow" will just make you normal again.
|
||||
// Old v1 behavior was to have Grow counter Shrink,
|
||||
// but Shrink is now so ephemeral that it should just work.
|
||||
K_RemoveGrowShrink(player);
|
||||
// So we fall through here.
|
||||
}
|
||||
else
|
||||
|
||||
K_PlayPowerGloatSound(player->mo);
|
||||
|
||||
player->mo->scalespeed = mapobjectscale/TICRATE;
|
||||
player->mo->destscale = FixedMul(mapobjectscale, GROW_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(player) == true)
|
||||
{
|
||||
K_PlayPowerGloatSound(player->mo);
|
||||
|
||||
player->mo->scalespeed = mapobjectscale/TICRATE;
|
||||
player->mo->destscale = FixedMul(mapobjectscale, GROW_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(player) == true)
|
||||
{
|
||||
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
player->growshrinktimer = max(player->growshrinktimer, ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE);
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
; // invincibility has priority in P_RestoreMusic, no point in starting here
|
||||
}
|
||||
else if (P_IsLocalPlayer(player) == true)
|
||||
{
|
||||
S_ChangeMusicSpecial("kgrow");
|
||||
}
|
||||
else //used to be "if (P_IsDisplayPlayer(player) == false)"
|
||||
{
|
||||
S_StartSound(player->mo, sfx_alarmg);
|
||||
}
|
||||
|
||||
P_RestoreMusic(player);
|
||||
S_StartSound(player->mo, sfx_kc5a);
|
||||
player->mo->destscale = FixedMul(player->mo->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
if (player->invincibilitytimer > 0)
|
||||
{
|
||||
; // invincibility has priority in P_RestoreMusic, no point in starting here
|
||||
}
|
||||
else if (P_IsLocalPlayer(player) == true)
|
||||
{
|
||||
if (player->growshrinktimer < 1)
|
||||
S_ChangeMusicSpecial("kgrow");
|
||||
}
|
||||
else //used to be "if (P_IsDisplayPlayer(player) == false)"
|
||||
{
|
||||
S_StartSound(player->mo, sfx_alarmg);
|
||||
}
|
||||
|
||||
P_RestoreMusic(player);
|
||||
|
||||
player->growshrinktimer = max(0, player->growshrinktimer);
|
||||
player->growshrinktimer += ((gametyperules & GTR_CLOSERPLAYERS) ? 8 : 12) * TICRATE;
|
||||
|
||||
S_StartSound(player->mo, sfx_kc5a);
|
||||
|
||||
player->itemamount--;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -650,6 +650,7 @@ struct setup_player_t
|
|||
UINT16 color;
|
||||
UINT8 mdepth;
|
||||
boolean hitlag;
|
||||
boolean showextra;
|
||||
|
||||
// Hack, save player 1's original device even if they init charsel with keyboard.
|
||||
// If they play ALONE, allow them to retain that original device, otherwise, ignore this.
|
||||
|
|
@ -1158,6 +1159,8 @@ extern struct challengesmenu_s {
|
|||
boolean pending;
|
||||
boolean requestnew;
|
||||
|
||||
boolean requestflip;
|
||||
|
||||
UINT8 unlockcount[CC_MAX];
|
||||
|
||||
UINT8 fade;
|
||||
|
|
|
|||
|
|
@ -1363,16 +1363,19 @@ static void M_DrawCharSelectPreview(UINT8 num)
|
|||
M_DrawCharSelectCircle(p, x+32, y+64);
|
||||
}
|
||||
|
||||
V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE));
|
||||
V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE));
|
||||
if (p->mdepth > CSSTEP_PROFILE)
|
||||
if (p->showextra == false)
|
||||
{
|
||||
profile_t *pr = PR_GetProfile(p->profilen);
|
||||
V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawFileString(x+16, y+2, 0, "PLAYER");
|
||||
V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE));
|
||||
V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE));
|
||||
if (p->mdepth > CSSTEP_PROFILE)
|
||||
{
|
||||
profile_t *pr = PR_GetProfile(p->profilen);
|
||||
V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawFileString(x+16, y+2, 0, "PLAYER");
|
||||
}
|
||||
}
|
||||
|
||||
if (p->mdepth >= CSSTEP_FOLLOWER)
|
||||
|
|
@ -1471,6 +1474,82 @@ static void M_DrawCharSelectPreview(UINT8 num)
|
|||
V_DrawThinString(xpos+16, cy, (p->changeselect == i ? highlightflags : 0)|V_6WIDTHSPACE, choices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (p->showextra == true)
|
||||
{
|
||||
switch (p->mdepth)
|
||||
{
|
||||
case CSSTEP_CHARS: // Character Select grid
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("Speed %u - Weight %u", p->gridx+1, p->gridy+1));
|
||||
break;
|
||||
case CSSTEP_ALTS: // Select clone
|
||||
case CSSTEP_READY:
|
||||
if (p->clonenum < setup_chargrid[p->gridx][p->gridy].numskins
|
||||
&& setup_chargrid[p->gridx][p->gridy].skinlist[p->clonenum] < numskins)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
|
||||
skins[setup_chargrid[p->gridx][p->gridy].skinlist[p->clonenum]].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD CLONENUM %u", p->clonenum));
|
||||
}
|
||||
break;
|
||||
case CSSTEP_COLORS: // Select color
|
||||
if (p->color < numskincolors)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, skincolors[p->color].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD COLOR %u", p->color));
|
||||
}
|
||||
break;
|
||||
case CSSTEP_FOLLOWERCATEGORY:
|
||||
if (p->followercategory == -1)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "None");
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
|
||||
followercategories[setup_followercategories[p->followercategory][1]].name);
|
||||
}
|
||||
break;
|
||||
case CSSTEP_FOLLOWER:
|
||||
if (p->followern == -1)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "None");
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE,
|
||||
followers[p->followern].name);
|
||||
}
|
||||
break;
|
||||
case CSSTEP_FOLLOWERCOLORS:
|
||||
if (p->followercolor == FOLLOWERCOLOR_MATCH)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "Match");
|
||||
}
|
||||
else if (p->followercolor == FOLLOWERCOLOR_OPPOSITE)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "Opposite");
|
||||
}
|
||||
else if (p->followercolor < numskincolors)
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, skincolors[p->followercolor].name);
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, va("BAD FOLLOWERCOLOR %u", p->followercolor));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
V_DrawThinString(x-3, y+2, V_6WIDTHSPACE, "[extrainfo mode]");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void M_DrawCharSelectExplosions(boolean charsel, INT16 basex, INT16 basey)
|
||||
|
|
|
|||
|
|
@ -175,6 +175,7 @@ menu_t *M_InterruptMenuWithChallenges(menu_t *desiredmenu)
|
|||
if (challengesmenu.pending || desiredmenu == NULL)
|
||||
{
|
||||
challengesmenu.ticker = 0;
|
||||
challengesmenu.requestflip = false;
|
||||
challengesmenu.requestnew = false;
|
||||
challengesmenu.currentunlock = MAXUNLOCKABLES;
|
||||
challengesmenu.unlockcondition = NULL;
|
||||
|
|
@ -287,7 +288,7 @@ void M_ChallengesTick(void)
|
|||
if (challengesmenu.extradata != NULL)
|
||||
{
|
||||
UINT16 id = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
||||
boolean seeeveryone = M_MenuButtonHeld(pid, MBT_R);
|
||||
boolean seeeveryone = challengesmenu.requestflip;
|
||||
boolean allthewaythrough;
|
||||
UINT8 maxflip;
|
||||
for (i = 0; i < (CHALLENGEGRIDHEIGHT * gamedata->challengegridwidth); i++)
|
||||
|
|
@ -479,8 +480,17 @@ boolean M_ChallengesInputs(INT32 ch)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (M_MenuButtonPressed(pid, MBT_R))
|
||||
{
|
||||
challengesmenu.requestflip ^= true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (challengesmenu.extradata != NULL && move)
|
||||
{
|
||||
challengesmenu.requestflip = false;
|
||||
|
||||
// Determine movement around the grid
|
||||
// For right/down movement, we can pre-determine the number of steps based on extradata.
|
||||
// For left/up movement, we can't - we have to be ready to iterate twice, and break early if we don't run into a large tile.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
menuitem_t OPTIONS_Data[] =
|
||||
{
|
||||
|
||||
{IT_STRING | IT_SUBMENU, "Screenshot Options...", "Set options relative to screenshot and GIF capture.",
|
||||
{IT_STRING | IT_SUBMENU, "Media Options...", "Set options relative to screenshot and movie capture.",
|
||||
NULL, {.submenu = &OPTIONS_DataScreenshotDef}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_SUBMENU, "Addon Options...", "Set options relative to the addons menu.",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ menuitem_t OPTIONS_DataReplay[] =
|
|||
{IT_STRING | IT_CVAR, "Record Replays", "Select when to save replays.",
|
||||
NULL, {.cvar = &cv_recordmultiplayerdemos}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Synch. Check Interval", "How often to check for synchronization while playing back a replay.",
|
||||
{IT_STRING | IT_CVAR, "Net Consistency Quality", "For filesize, how often do we write position data in online replays?",
|
||||
NULL, {.cvar = &cv_netdemosyncquality}, 0, 0},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "../k_menu.h"
|
||||
#include "../m_misc.h" // screenshot cvars
|
||||
#include "../m_avrecorder.h"
|
||||
|
||||
menuitem_t OPTIONS_DataScreenshot[] =
|
||||
{
|
||||
|
|
@ -19,13 +20,19 @@ menuitem_t OPTIONS_DataScreenshot[] =
|
|||
{IT_SPACE | IT_NOTHING, NULL, NULL,
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
||||
{IT_HEADER, "GIF RECORDING (F9)", NULL,
|
||||
{IT_HEADER, "MOVIE RECORDING (F9)", NULL,
|
||||
NULL, {NULL}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Storage Location", "Sets where to store GIFs",
|
||||
{IT_STRING | IT_CVAR, "Recording Format", "What file format will movies will be recorded in?",
|
||||
NULL, {.cvar = &cv_moviemode}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Real-Time Data", "If enabled, shows fps, duration and filesize of recording in real-time.",
|
||||
NULL, {.cvar = &cv_movie_showfps}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR, "Storage Location", "Sets where to store movies.",
|
||||
NULL, {.cvar = &cv_movie_option}, 0, 0},
|
||||
|
||||
{IT_STRING | IT_CVAR | IT_CV_STRING, "Custom Folder", "Specify which folder to save GIFs in.",
|
||||
{IT_STRING | IT_CVAR | IT_CV_STRING, "Custom Folder", "Specify which folder to save videos in.",
|
||||
NULL, {.cvar = &cv_movie_folder}, 24, 0},
|
||||
|
||||
};
|
||||
|
|
@ -56,6 +63,10 @@ void Screenshot_option_Onchange(void)
|
|||
|
||||
void Moviemode_mode_Onchange(void)
|
||||
{
|
||||
// opt 7 in a 0 based array, you get the idea...
|
||||
OPTIONS_DataScreenshot[6].status =
|
||||
(cv_moviemode.value == MM_AVRECORDER ? IT_CVAR|IT_STRING : IT_DISABLED);
|
||||
|
||||
#if 0
|
||||
INT32 i, cstart, cend;
|
||||
for (i = op_screenshot_gif_start; i <= op_screenshot_apng_end; ++i)
|
||||
|
|
@ -81,7 +92,7 @@ void Moviemode_mode_Onchange(void)
|
|||
|
||||
void Moviemode_option_Onchange(void)
|
||||
{
|
||||
// opt 7 in a 0 based array, you get the idea...
|
||||
OPTIONS_DataScreenshot[6].status =
|
||||
// opt 9 in a 0 based array, you get the idea...
|
||||
OPTIONS_DataScreenshot[8].status =
|
||||
(cv_movie_option.value == 3 ? IT_CVAR|IT_STRING|IT_CV_STRING : IT_DISABLED);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,44 +7,45 @@
|
|||
menuitem_t OPTIONS_GameplayItems[] =
|
||||
{
|
||||
// Mostly handled by the drawing function.
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Super Rings", NULL, {.routine = M_HandleItemToggles}, KITEM_SUPERRING, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Self-Propelled Bombs", NULL, {.routine = M_HandleItemToggles}, KITEM_SPB, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Eggman Marks", NULL, {.routine = M_HandleItemToggles}, KITEM_EGGMAN, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Super Ring", NULL, {.routine = M_HandleItemToggles}, KITEM_SUPERRING, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Self-Propelled Bomb", NULL, {.routine = M_HandleItemToggles}, KITEM_SPB, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0}, // maybe KITEM_PUYO eventually?
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Toggle All", NULL, {.routine = M_HandleItemToggles}, 0, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers", NULL, {.routine = M_HandleItemToggles}, KITEM_SNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALSNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneakers x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLESNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Rocket Sneakers", NULL, {.routine = M_HandleItemToggles}, KITEM_ROCKETSNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker", NULL, {.routine = M_HandleItemToggles}, KITEM_SNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALSNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Sneaker x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLESNEAKER, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Rocket Sneaker", NULL, {.routine = M_HandleItemToggles}, KITEM_ROCKETSNEAKER, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas", NULL, {.routine = M_HandleItemToggles}, KITEM_BANANA, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bananas x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEBANANA, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Proximity Mines", NULL, {.routine = M_HandleItemToggles}, KITEM_MINE, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Banana", NULL, {.routine = M_HandleItemToggles}, KITEM_BANANA, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Banana x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEBANANA, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Eggman Mark", NULL, {.routine = M_HandleItemToggles}, KITEM_EGGMAN, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gachabom", NULL, {.routine = M_HandleItemToggles}, KITEM_GACHABOM, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts", NULL, {.routine = M_HandleItemToggles}, KITEM_ORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinauts x4", NULL, {.routine = M_HandleItemToggles}, KRITEM_QUADORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Land Mines", NULL, {.routine = M_HandleItemToggles}, KITEM_LANDMINE, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut", NULL, {.routine = M_HandleItemToggles}, KITEM_ORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Orbinaut x4", NULL, {.routine = M_HandleItemToggles}, KRITEM_QUADORBINAUT, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gachabom x3", NULL, {.routine = M_HandleItemToggles}, KRITEM_TRIPLEGACHABOM, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz", NULL, {.routine = M_HandleItemToggles}, KITEM_JAWZ, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Jawz x2", NULL, {.routine = M_HandleItemToggles}, KRITEM_DUALJAWZ, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Ballhogs", NULL, {.routine = M_HandleItemToggles}, KITEM_BALLHOG, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Drop Targets", NULL, {.routine = M_HandleItemToggles}, KITEM_DROPTARGET, sfx_s258},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Proximity Mine", NULL, {.routine = M_HandleItemToggles}, KITEM_MINE, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Ballhog", NULL, {.routine = M_HandleItemToggles}, KITEM_BALLHOG, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Lightning Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_LIGHTNINGSHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bubble Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_BUBBLESHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Flame Shields", NULL, {.routine = M_HandleItemToggles}, KITEM_FLAMESHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoros", NULL, {.routine = M_HandleItemToggles}, KITEM_HYUDORO, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Hyudoro", NULL, {.routine = M_HandleItemToggles}, KITEM_HYUDORO, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Drop Target", NULL, {.routine = M_HandleItemToggles}, KITEM_DROPTARGET, sfx_s258},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Land Mine", NULL, {.routine = M_HandleItemToggles}, KITEM_LANDMINE, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Spring", NULL, {.routine = M_HandleItemToggles}, KITEM_POGOSPRING, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Invinciblity", NULL, {.routine = M_HandleItemToggles}, KITEM_INVINCIBILITY, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Grow", NULL, {.routine = M_HandleItemToggles}, KITEM_GROW, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Shrink", NULL, {.routine = M_HandleItemToggles}, KITEM_SHRINK, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Gardentop", NULL, {.routine = M_HandleItemToggles}, KITEM_GARDENTOP, 0},
|
||||
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Pogo Springs", NULL, {.routine = M_HandleItemToggles}, KITEM_POGOSPRING, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sinks", NULL, {.routine = M_HandleItemToggles}, KITEM_KITCHENSINK, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, NULL, NULL, {.routine = M_HandleItemToggles}, 255, 0}
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Lightning Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_LIGHTNINGSHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Bubble Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_BUBBLESHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Flame Shield", NULL, {.routine = M_HandleItemToggles}, KITEM_FLAMESHIELD, 0},
|
||||
{IT_KEYHANDLER | IT_NOTHING, NULL, "Kitchen Sink", NULL, {.routine = M_HandleItemToggles}, KITEM_KITCHENSINK, 0}
|
||||
};
|
||||
|
||||
menu_t OPTIONS_GameplayItemsDef = {
|
||||
|
|
|
|||
|
|
@ -905,16 +905,6 @@ static boolean M_HandleCharacterGrid(setup_player_t *p, UINT8 num)
|
|||
if (num == 0 && setup_numplayers == 1 && setup_maxpage && !forceskin) // ONLY one player.
|
||||
{
|
||||
if (M_MenuButtonPressed(num, MBT_L))
|
||||
{
|
||||
if (setup_page == 0)
|
||||
setup_page = setup_maxpage;
|
||||
else
|
||||
setup_page--;
|
||||
|
||||
S_StartSound(NULL, sfx_s3k63);
|
||||
M_SetMenuDelay(num);
|
||||
}
|
||||
else if (M_MenuButtonPressed(num, MBT_R))
|
||||
{
|
||||
if (setup_page == setup_maxpage)
|
||||
setup_page = 0;
|
||||
|
|
@ -1295,6 +1285,11 @@ boolean M_CharacterSelectHandler(INT32 choice)
|
|||
if (i > 0 && setup_player[i-1].mdepth < CSSTEP_READY)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (M_MenuButtonPressed(i, MBT_R))
|
||||
{
|
||||
p->showextra ^= true;
|
||||
}
|
||||
}
|
||||
|
||||
switch (p->mdepth)
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ void M_SetupGametypeMenu(INT32 choice)
|
|||
if (!anyunlocked)
|
||||
{
|
||||
// Only one non-Back entry, let's skip straight to Race.
|
||||
M_SetupRaceMenu(-1);
|
||||
M_SetupRaceMenu(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -602,6 +602,12 @@ Obj_MonitorGetDamage
|
|||
damage = HEALTHFACTOR +
|
||||
(FixedMul(weight, HEALTHFACTOR) / 9);
|
||||
|
||||
|
||||
if (inflictor->player->tiregrease > 0)
|
||||
{
|
||||
damage *= 3; // Do 3x the damage if the player is in spring grease state
|
||||
}
|
||||
|
||||
if (inflictor->scale > mapobjectscale)
|
||||
{
|
||||
damage = P_ScaleFromMap(damage, inflictor->scale);
|
||||
|
|
|
|||
|
|
@ -542,50 +542,51 @@ boolean Obj_ShrinkLaserCollide(mobj_t *gun, mobj_t *victim)
|
|||
// Take away Shrink.
|
||||
K_RemoveGrowShrink(victim->player);
|
||||
}
|
||||
else
|
||||
|
||||
victim->player->growshrinktimer += 3*TICRATE;
|
||||
S_StartSound(victim, sfx_kc5a);
|
||||
|
||||
if (prevTimer <= 0)
|
||||
{
|
||||
victim->player->growshrinktimer += 3*TICRATE;
|
||||
S_StartSound(victim, sfx_kc5a);
|
||||
victim->scalespeed = mapobjectscale/TICRATE;
|
||||
victim->destscale = FixedMul(mapobjectscale, GROW_SCALE);
|
||||
|
||||
if (prevTimer <= 0)
|
||||
if (K_PlayerShrinkCheat(victim->player) == true)
|
||||
{
|
||||
victim->scalespeed = mapobjectscale/TICRATE;
|
||||
victim->destscale = FixedMul(mapobjectscale, GROW_SCALE);
|
||||
|
||||
if (K_PlayerShrinkCheat(victim->player) == true)
|
||||
{
|
||||
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
if (victim->player->invincibilitytimer > 0)
|
||||
{
|
||||
; // invincibility has priority in P_RestoreMusic, no point in starting here
|
||||
}
|
||||
else if (P_IsLocalPlayer(victim->player) == true)
|
||||
{
|
||||
S_ChangeMusicSpecial("kgrow");
|
||||
}
|
||||
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
|
||||
{
|
||||
S_StartSound(victim, sfx_alarmg);
|
||||
}
|
||||
|
||||
P_RestoreMusic(victim->player);
|
||||
victim->destscale = FixedMul(victim->destscale, SHRINK_SCALE);
|
||||
}
|
||||
|
||||
if (victim->player->invincibilitytimer > 0)
|
||||
{
|
||||
; // invincibility has priority in P_RestoreMusic, no point in starting here
|
||||
}
|
||||
else if (P_IsLocalPlayer(victim->player) == true)
|
||||
{
|
||||
S_ChangeMusicSpecial("kgrow");
|
||||
}
|
||||
else //used to be "if (P_IsDisplayPlayer(victim->player) == false)"
|
||||
{
|
||||
S_StartSound(victim, sfx_alarmg);
|
||||
}
|
||||
|
||||
P_RestoreMusic(victim->player);
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (prevTimer > 0)
|
||||
{
|
||||
// Take away Grow.
|
||||
K_RemoveGrowShrink(victim->player);
|
||||
// Dock some Grow time.
|
||||
// (Hack-adjacent: Always make sure there's a tic left so standard timer handling can remove the effect properly.)
|
||||
victim->player->growshrinktimer -= min(3*TICRATE/2, victim->player->growshrinktimer - 1);
|
||||
S_StartSound(victim, sfx_s3k40);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start shrinking!
|
||||
victim->player->growshrinktimer -= 5*TICRATE;
|
||||
S_StartSound(victim, sfx_kc59);
|
||||
S_StartSound(victim, sfx_kc59); // I don't think you ever get to hear this while the pohbee laser is in your teeth, but best effort.
|
||||
|
||||
if (prevTimer >= 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "../z_zone.h"
|
||||
#include "../k_waypoint.h"
|
||||
#include "../k_specialstage.h"
|
||||
#include "../r_skins.h"
|
||||
|
||||
#define UFO_BASE_SPEED (42 * FRACUNIT) // UFO's slowest speed.
|
||||
#define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration
|
||||
|
|
@ -671,6 +672,16 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
|
|||
return false;
|
||||
}
|
||||
|
||||
if (source->player)
|
||||
{
|
||||
UINT32 skinflags = (demo.playback)
|
||||
? demo.skinlist[demo.currentskinid[(source->player-players)]].flags
|
||||
: skins[source->player->skin].flags;
|
||||
if (skinflags & SF_IRONMAN)
|
||||
SetRandomFakePlayerSkin(source->player, true);
|
||||
}
|
||||
|
||||
|
||||
// Speed up on damage!
|
||||
ufo_speed(ufo) += addSpeed;
|
||||
|
||||
|
|
@ -700,6 +711,7 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN
|
|||
S_StopSoundByID(ufo, sfx_clawzm);
|
||||
P_StartQuake(64<<FRACBITS, 10);
|
||||
ufo->health -= damage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
17
src/p_mobj.c
17
src/p_mobj.c
|
|
@ -46,6 +46,7 @@
|
|||
#include "k_collide.h"
|
||||
#include "k_objects.h"
|
||||
#include "k_grandprix.h"
|
||||
#include "k_director.h"
|
||||
|
||||
static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}};
|
||||
consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL);
|
||||
|
|
@ -11827,6 +11828,22 @@ void P_SpawnPlayer(INT32 playernum)
|
|||
K_SpawnPlayerBattleBumpers(p);
|
||||
}
|
||||
}
|
||||
|
||||
// I'm not refactoring the loop at the top of this file.
|
||||
pcount = 0;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; ++i)
|
||||
{
|
||||
if (G_CouldView(i))
|
||||
{
|
||||
pcount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Spectating when there is literally any other player in
|
||||
// the level enables director cam.
|
||||
// TODO: how do we support splitscreen?
|
||||
K_ToggleDirector(players[consoleplayer].spectator && pcount > 0);
|
||||
}
|
||||
|
||||
void P_AfterPlayerSpawn(INT32 playernum)
|
||||
|
|
|
|||
|
|
@ -9100,15 +9100,17 @@ void T_Pusher(pusher_t *p)
|
|||
thing->player->carry = CR_SLIDING;
|
||||
thing->angle = R_PointToAngle2(0, 0, xspeed, yspeed);
|
||||
|
||||
|
||||
if (!demo.playback)
|
||||
{
|
||||
angle_t angle = thing->player->angleturn;
|
||||
angle_t angle = thing->player->boostangle;
|
||||
if (thing->angle - angle > ANGLE_180)
|
||||
P_SetPlayerAngle(thing->player, angle - (angle - thing->angle) / 8);
|
||||
thing->player->boostangle = angle - (angle - thing->angle) / 8;
|
||||
else
|
||||
P_SetPlayerAngle(thing->player, angle + (thing->angle - angle) / 8);
|
||||
thing->player->boostangle = angle + (thing->angle - angle) / 8;
|
||||
//P_SetPlayerAngle(thing->player, thing->angle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (p->exclusive)
|
||||
|
|
|
|||
90
src/p_user.c
90
src/p_user.c
|
|
@ -2120,7 +2120,6 @@ static void P_3dMovement(player_t *player)
|
|||
static void P_UpdatePlayerAngle(player_t *player)
|
||||
{
|
||||
angle_t angleChange = ANGLE_MAX;
|
||||
UINT8 maxlatency;
|
||||
UINT8 p = UINT8_MAX;
|
||||
UINT8 i;
|
||||
|
||||
|
|
@ -2133,8 +2132,58 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
player->steering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
|
||||
angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE;
|
||||
// Don't apply steering just yet. If we make a correction, we'll need to adjust it.
|
||||
INT16 targetsteering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
|
||||
angleChange = K_GetKartTurnValue(player, targetsteering) << TICCMD_REDUCE;
|
||||
|
||||
if (!K_PlayerUsesBotMovement(player))
|
||||
{
|
||||
// With a full slam on the analog stick, how far could we steer in either direction?
|
||||
INT16 steeringRight = K_UpdateSteeringValue(player->steering, KART_FULLTURN);
|
||||
angle_t maxTurnRight = K_GetKartTurnValue(player, steeringRight) << TICCMD_REDUCE;
|
||||
INT16 steeringLeft = K_UpdateSteeringValue(player->steering, -KART_FULLTURN);
|
||||
angle_t maxTurnLeft = K_GetKartTurnValue(player, steeringLeft) << TICCMD_REDUCE;
|
||||
|
||||
// Grab local camera angle from ticcmd. Where do we actually want to go?
|
||||
angle_t targetAngle = (player->cmd.angle) << TICCMD_REDUCE;
|
||||
angle_t targetDelta = targetAngle - (player->mo->angle);
|
||||
|
||||
if (targetDelta == angleChange || player->pflags & PF_DRIFTEND || (maxTurnRight == 0 && maxTurnLeft == 0))
|
||||
{
|
||||
// We are where we need to be.
|
||||
// ...Or we aren't, but shouldn't be able to steer.
|
||||
player->steering = targetsteering;
|
||||
// Alternatively, while in DRIFTEND we want to trust inputs for a bit, not camera.
|
||||
// The game client doesn't know we're DRIFTEND until after a response gets back,
|
||||
// so we momentarily ignore the camera angle and let the server trust our inputs instead.
|
||||
// That way, even if you're steering blind, you get the intended "kick-out" effect.
|
||||
}
|
||||
else if (targetDelta >= ANGLE_180 && maxTurnLeft >= targetDelta) // Overshot, so just fudge it.
|
||||
{
|
||||
angleChange = targetDelta;
|
||||
player->steering = targetsteering;
|
||||
}
|
||||
else if (targetDelta <= ANGLE_180 && maxTurnRight <= targetDelta) // Overshot, so just fudge it.
|
||||
{
|
||||
angleChange = targetDelta;
|
||||
player->steering = targetsteering;
|
||||
}
|
||||
else if (targetDelta >= ANGLE_180 && maxTurnLeft < targetDelta) // Undershot, slam the stick.
|
||||
{
|
||||
angleChange = maxTurnLeft;
|
||||
player->steering = steeringLeft;
|
||||
}
|
||||
else if (targetDelta <= ANGLE_180 && maxTurnRight > targetDelta) // Undershot, slam the stick.
|
||||
{
|
||||
angleChange = maxTurnRight;
|
||||
player->steering = steeringRight;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// You're a bot. Go where you're supposed to go
|
||||
player->steering = targetsteering;
|
||||
}
|
||||
|
||||
if (p == UINT8_MAX)
|
||||
{
|
||||
|
|
@ -2144,33 +2193,8 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
}
|
||||
else
|
||||
{
|
||||
// During standard play, our latency can vary by up to 1 tic in either direction, even on a stable connection.
|
||||
// This probably comes from differences in ticcmd dispatch vs consumption rate. Probably.
|
||||
// Uncorrected, this 2-tic "wobble" causes camera corrections to sometimes be skipped or batched.
|
||||
// So just use the highest recent value for the furthest possible search.
|
||||
// We unset the correction after applying, anyway.
|
||||
locallatency[p][leveltime%TICRATE] = maxlatency = player->cmd.latency;
|
||||
for (i = 0; i < TICRATE; i++)
|
||||
{
|
||||
maxlatency = max(locallatency[p][i], maxlatency);
|
||||
}
|
||||
|
||||
UINT8 lateTic = ((leveltime - maxlatency) & TICCMD_LATENCYMASK);
|
||||
UINT8 clearTic = ((localtic + 1) & TICCMD_LATENCYMASK);
|
||||
|
||||
player->angleturn += angleChange;
|
||||
player->mo->angle = player->angleturn;
|
||||
|
||||
// Undo the ticcmd's old emulated angle,
|
||||
// now that we added the actual game logic angle.
|
||||
|
||||
while (lateTic != clearTic)
|
||||
{
|
||||
localdelta[p] -= localstoredeltas[p][lateTic];
|
||||
localstoredeltas[p][lateTic] = 0;
|
||||
|
||||
lateTic = (lateTic - 1) & TICCMD_LATENCYMASK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cv_allowmlook.value || player->spectator == false)
|
||||
|
|
@ -3162,7 +3186,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
|
|||
|
||||
if (demo.playback)
|
||||
{
|
||||
focusangle = mo->angle;
|
||||
// Hack-adjacent.
|
||||
// Sometimes stale ticcmds send a weird angle at the start of the race.
|
||||
// P_UpdatePlayerAngle knows to ignore cmd angle when you literally can't turn, so we do the same here.
|
||||
if (leveltime > introtime)
|
||||
focusangle = player->cmd.angle << TICCMD_REDUCE;
|
||||
else
|
||||
focusangle = mo->angle; // Just use something known sane.
|
||||
focusaiming = 0;
|
||||
}
|
||||
else
|
||||
|
|
@ -4478,7 +4508,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
|
|||
if (player == &players[displayplayers[i]])
|
||||
{
|
||||
localangle[i] = angle;
|
||||
G_ResetAnglePrediction(player);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1095,6 +1095,8 @@ void ST_preLevelTitleCardDrawer(void)
|
|||
//
|
||||
static void ST_overlayDrawer(void)
|
||||
{
|
||||
const UINT8 viewnum = R_GetViewNumber();
|
||||
|
||||
// hu_showscores = auto hide score/time/rings when tab rankings are shown
|
||||
if (!(hu_showscores && (netgame || multiplayer)))
|
||||
{
|
||||
|
|
@ -1135,7 +1137,7 @@ static void ST_overlayDrawer(void)
|
|||
|
||||
if (!hu_showscores && netgame && !mapreset)
|
||||
{
|
||||
if (stplyr->spectator && LUA_HudEnabled(hud_textspectator))
|
||||
if (stplyr->spectator && displayplayers[viewnum] == g_localplayers[viewnum] && LUA_HudEnabled(hud_textspectator))
|
||||
{
|
||||
const char *itemtxt = M_GetText("Item - Join Game");
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue