Merge branch 'replay-stupid-parties' into 'master'

Emulate parties when watching replays

Closes #1090

See merge request KartKrew/Kart!1977
This commit is contained in:
Oni 2024-03-02 21:29:43 +00:00
commit b00255e333
7 changed files with 148 additions and 48 deletions

View file

@ -1838,8 +1838,15 @@ static void Command_SetViews_f(void)
// 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 (demo.playback)
{
G_SyncDemoParty(consoleplayer, newsplits-1);
}
else
{
r_splitscreen = newsplits-1;
R_ExecuteSetViewSize();
}
// If promoting (outside of replays), make sure the
// camera is in the correct position.
@ -6226,35 +6233,85 @@ static void Got_Cheat(const UINT8 **cp, INT32 playernum)
}
}
static const char *displayplayer_compose_col(int playernum)
{
return va("\x84(%d) \x83%s\x80", playernum, player_names[playernum]);
}
static int displayplayer_col_len(const char *text)
{
int n = strlen(text);
int k = n;
int i;
for (i = 0; i < n; ++i)
{
if (!isprint(text[i]))
k--;
}
return k;
}
static void displayplayer_calc_col(int *col, const char *text)
{
if (text && text[0] != ' ')
{
int n = displayplayer_col_len(text);
if (*col < n)
*col = n;
}
}
static void displayplayer_print_col(int *col, const char *text)
{
if (text)
{
if (*col)
{
int n = *col - displayplayer_col_len(text);
CONS_Printf("%s%*s ", text, n, "");
}
}
else
CONS_Printf("\n");
}
static void displayplayer_iter_table(int table[5], void(*col_cb)(int*,const char*))
{
int i;
col_cb(&table[0], "");
for (i = 0; i < 4; ++i)
col_cb(&table[1 + i], va(" %d", i));
col_cb(NULL, NULL);
col_cb(&table[0], "g_local");
for (i = 0; i <= splitscreen; ++i)
col_cb(&table[1 + i], displayplayer_compose_col(g_localplayers[i]));
col_cb(NULL, NULL);
col_cb(&table[0], "display");
for (i = 0; i <= r_splitscreen; ++i)
col_cb(&table[1 + i], displayplayer_compose_col(displayplayers[i]));
col_cb(NULL, NULL);
col_cb(&table[0], "local party");
for (i = 0; i < G_LocalSplitscreenPartySize(consoleplayer); ++i)
col_cb(&table[1 + i], displayplayer_compose_col(G_LocalSplitscreenPartyMember(consoleplayer, i)));
col_cb(NULL, NULL);
col_cb(&table[0], "final party");
for (i = 0; i < G_PartySize(consoleplayer); ++i)
col_cb(&table[1 + i], displayplayer_compose_col(G_PartyMember(consoleplayer, i)));
col_cb(NULL, NULL);
}
/** Prints the number of displayplayers[0].
*
* \todo Possibly remove this; it was useful for debugging at one point.
*/
static void Command_Displayplayer_f(void)
{
int playernum;
int i;
for (i = 0; i <= splitscreen; ++i)
{
playernum = g_localplayers[i];
CONS_Printf(
"local player %d: \x84(%d) \x83%s\x80\n",
i,
playernum,
player_names[playernum]
);
}
CONS_Printf("\x83----------------------------------------\x80\n");
for (i = 0; i <= r_splitscreen; ++i)
{
playernum = displayplayers[i];
CONS_Printf(
"display player %d: \x84(%d) \x83%s\x80\n",
i,
playernum,
player_names[playernum]
);
}
int table[5] = {0};
displayplayer_iter_table(table, displayplayer_calc_col);
displayplayer_iter_table(table, displayplayer_print_col);
}
/** Quits a game and returns to the title screen.

View file

@ -47,6 +47,7 @@
#include "lua_hook.h"
#include "md5.h" // demo checksums
#include "p_saveg.h" // savebuffer_t
#include "g_party.h"
// SRB2Kart
#include "d_netfil.h" // nameonly
@ -3227,15 +3228,13 @@ void G_DoPlayDemo(const char *defdemoname)
// didn't start recording right away.
demo.deferstart = false;
displayplayers[0] = consoleplayer = 0;
consoleplayer = 0;
memset(playeringame,0,sizeof(playeringame));
memset(displayplayers,0,sizeof(displayplayers));
// Load players that were in-game when the map started
p = READUINT8(demobuf.p);
for (i = 1; i < MAXSPLITSCREENPLAYERS; i++)
displayplayers[i] = INT32_MAX;
while (p != 0xFF)
{
UINT8 flags = READUINT8(demobuf.p);
@ -4126,3 +4125,33 @@ boolean G_CheckDemoTitleEntry(void)
return true;
}
void G_SyncDemoParty(INT32 rem, INT32 newsplitscreen)
{
int r_splitscreen_copy = r_splitscreen;
INT32 displayplayers_copy[MAXSPLITSCREENPLAYERS];
memcpy(displayplayers_copy, displayplayers, sizeof displayplayers);
// If we switch away from someone's view, that player
// should be removed from the party.
// However, it is valid to have the player on multiple
// viewports.
// Remove this player
G_LeaveParty(rem);
// And reset the rest of the party
for (int i = 0; i <= r_splitscreen_copy; ++i)
G_LeaveParty(displayplayers_copy[i]);
// Restore the party, without the removed player, and
// with the order matching displayplayers
for (int i = 0; i <= newsplitscreen; ++i)
G_JoinParty(consoleplayer, displayplayers_copy[i]);
// memcpy displayplayers back to preserve duplicates
// (G_JoinParty will not create duplicates itself)
r_splitscreen = newsplitscreen;
memcpy(displayplayers, displayplayers_copy, sizeof displayplayers);
R_ExecuteSetViewSize();
}

View file

@ -243,6 +243,8 @@ typedef enum
DEMO_ATTRACT_CREDITS
} demoAttractMode_t;
void G_SyncDemoParty(INT32 rem, INT32 newsplitscreen);
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -1648,13 +1648,6 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
viewnum = playersviewable;
r_splitscreen = viewnum-1;
/* Prepare extra views for G_FindView to pass. */
for (viewd = splits+1; viewd < viewnum; ++viewd)
{
displayplayerp = (&displayplayers[viewd-1]);
(*displayplayerp) = INT32_MAX;
}
R_ExecuteSetViewSize();
}
@ -1679,21 +1672,30 @@ void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive)
/* Focus our target view first so that we don't take its player. */
(*displayplayerp) = playernum;
if ((*displayplayerp) != olddisplayplayer)
{
G_FixCamera(viewnum);
}
/* If a viewpoint changes, reset the camera to clear uninitialized memory. */
if (viewnum > splits)
{
for (viewd = splits+1; viewd < viewnum; ++viewd)
for (viewd = splits+1; viewd <= viewnum; ++viewd)
{
G_FixCamera(viewd);
}
}
else
{
if ((*displayplayerp) != olddisplayplayer)
{
G_FixCamera(viewnum);
}
}
if (viewnum == 1 && demo.playback)
consoleplayer = displayplayers[0];
if (demo.playback)
{
if (viewnum == 1)
consoleplayer = displayplayers[0];
G_SyncDemoParty(olddisplayplayer, r_splitscreen);
}
// change statusbar also if playing back demo
if (demo.quitafterplaying)

View file

@ -323,3 +323,10 @@ UINT8 G_LocalSplitscreenPartyPosition(UINT8 player)
return party.find(player) - party.begin();
}
UINT8 G_LocalSplitscreenPartyMember(UINT8 player, UINT8 index)
{
SRB2_ASSERT(index < local_party[player].size());
return local_party[player][index];
}

View file

@ -65,6 +65,9 @@ UINT8 G_PartyPosition(UINT8 player);
//
UINT8 G_LocalSplitscreenPartyPosition(UINT8 player);
//
UINT8 G_LocalSplitscreenPartyMember(UINT8 player, UINT8 index);
//
// Globals
//

View file

@ -9,6 +9,7 @@
#include "../../p_local.h" // P_InitCameraCmd
#include "../../d_main.h" // D_StartTitle
#include "../../k_credits.h"
#include "../../g_demo.h"
static void M_PlaybackTick(void);
@ -220,13 +221,12 @@ void M_PlaybackSetViews(INT32 choice)
{
if (choice == 0)
{
r_splitscreen--;
G_SyncDemoParty(displayplayers[r_splitscreen], r_splitscreen - 1);
}
else
{
r_splitscreen = 0;
G_SyncDemoParty(consoleplayer, 0);
}
R_ExecuteSetViewSize();
}
}