mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
It was all messy and none of it is called in release builds because it was so crashy in testing
295 lines
8.2 KiB
C
295 lines
8.2 KiB
C
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2025 by Kart Krew.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
/// \file menus/transient/pause-replay.c
|
|
/// \brief Replay popup menu
|
|
|
|
#include "../../k_menu.h"
|
|
#include "../../s_sound.h"
|
|
#include "../../p_tick.h" // leveltime
|
|
#include "../../i_time.h"
|
|
#include "../../r_main.h" // R_ExecuteSetViewSize
|
|
#include "../../p_local.h" // P_InitCameraCmd
|
|
#include "../../d_main.h" // D_StartTitle
|
|
#include "../../k_credits.h"
|
|
#include "../../g_demo.h"
|
|
#include "../../k_director.h"
|
|
|
|
static void M_PlaybackTick(void);
|
|
|
|
// This is barebones, just toggle director on all screens.
|
|
static void M_PlaybackToggleDirector(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
UINT8 i;
|
|
for (i = 0; i <= r_splitscreen; ++i)
|
|
{
|
|
K_ToggleDirector(i, !K_DirectorIsEnabled(i));
|
|
}
|
|
}
|
|
|
|
menuitem_t PAUSE_PlaybackMenu[] =
|
|
{
|
|
{IT_CALL | IT_STRING, "Hide Menu", NULL, "M_PHIDE", {.routine = M_SelectableClearMenus}, 0, 0},
|
|
|
|
{IT_CALL | IT_STRING, "Restart", NULL, "M_PRSTRT", {.routine = M_PlaybackRewind}, 20, 0},
|
|
{IT_CALL | IT_STRING, "Pause", NULL, "M_PPAUSE", {.routine = M_PlaybackPause}, 36, 0},
|
|
{IT_CALL | IT_STRING, "Fast-Forward", NULL, "M_PFFWD", {.routine = M_PlaybackFastForward}, 52, 0},
|
|
{IT_CALL | IT_STRING, "Restart", NULL, "M_PRSTRT", {.routine = M_PlaybackRewind}, 20, 0},
|
|
{IT_CALL | IT_STRING, "Resume", NULL, "M_PRESUM", {.routine = M_PlaybackPause}, 36, 0},
|
|
{IT_CALL | IT_STRING, "Advance Frame", NULL, "M_PFADV", {.routine = M_PlaybackAdvance}, 52, 0},
|
|
|
|
{IT_ARROWS | IT_STRING, "View Count", NULL, "M_PVIEWS", {.routine = M_PlaybackSetViews}, 72, 0},
|
|
{IT_ARROWS | IT_STRING, "Viewpoint", NULL, "M_PNVIEW", {.routine = M_PlaybackAdjustView}, 88, 0},
|
|
{IT_ARROWS | IT_STRING, "Viewpoint 2", NULL, "M_PNVIEW", {.routine = M_PlaybackAdjustView}, 104, 0},
|
|
{IT_ARROWS | IT_STRING, "Viewpoint 3", NULL, "M_PNVIEW", {.routine = M_PlaybackAdjustView}, 120, 0},
|
|
{IT_ARROWS | IT_STRING, "Viewpoint 4", NULL, "M_PNVIEW", {.routine = M_PlaybackAdjustView}, 136, 0},
|
|
|
|
{IT_CALL | IT_STRING, "Toggle Director", NULL, "UN_IC11A", {.routine = M_PlaybackToggleDirector}, 156, 0},
|
|
{IT_CALL | IT_STRING, "Toggle Free Camera", NULL, "M_PVIEWS", {.routine = M_PlaybackToggleFreecam}, 172, 0},
|
|
{IT_CALL | IT_STRING, "Stop Playback", NULL, "M_PEXIT", {.routine = M_PlaybackQuit}, 188, 0},
|
|
};
|
|
|
|
menu_t PAUSE_PlaybackMenuDef = {
|
|
sizeof (PAUSE_PlaybackMenu) / sizeof (menuitem_t),
|
|
NULL,
|
|
0,
|
|
PAUSE_PlaybackMenu,
|
|
BASEVIDWIDTH/2 - 96, 2,
|
|
0, 0,
|
|
MBF_UD_LR_FLIPPED,
|
|
NULL,
|
|
0, 0,
|
|
M_DrawPlaybackMenu,
|
|
NULL,
|
|
M_PlaybackTick,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
void M_EndModeAttackRun(void)
|
|
{
|
|
// End recording / playback.
|
|
// Why not check demo.recording?
|
|
// Because for recording, this may be called from G_AfterIntermission.
|
|
// And before this function is called, G_SaveDemo is called, which sets demo.recording to false.
|
|
// Don't need to check demo.playback; G_CheckDemoStatus is safe to call even outside of demos.
|
|
// Check modeattacking because this function is recursively called (read on for an explanation).
|
|
if (modeattacking)
|
|
{
|
|
// This must be called for both playback and
|
|
// recording, because it both finishes playback and
|
|
// frees ghost data.
|
|
G_CheckDemoStatus();
|
|
|
|
// What does G_CheckDemoStatus do? Here's the answer!
|
|
|
|
// Playback:
|
|
// - Clears everything, including demo state and modeattacking.
|
|
// - It then calls the current function (M_EndModeAttackRun) AGAIN (after everything was cleared), so return.
|
|
if (!modeattacking)
|
|
return;
|
|
|
|
// Recording:
|
|
// - Only saves the demo and clears the demo state.
|
|
// - Now we need to clear the rest of the gamestate ourself!
|
|
}
|
|
|
|
// Playback:
|
|
// - modeattacking is always false, so calling this returns to the menu.
|
|
// - Because modeattacking is false, also clears demo.attract.
|
|
//
|
|
// Recording:
|
|
// - modeattacking is still true and this function call preserves that.
|
|
Command_ExitGame_f();
|
|
|
|
if (!modeattacking)
|
|
return;
|
|
|
|
// The rest of this is relevant for recording ONLY.
|
|
|
|
if (nextmapoverride != 0)
|
|
{
|
|
M_StartMessage(
|
|
"Secret Exit",
|
|
va(
|
|
"No finish time was recorded.\n"
|
|
"Secrets don't work in Attack modes!\n"
|
|
"Try again in %s.\n",
|
|
(gametype == GT_RACE)
|
|
? "Grand Prix or Match Race"
|
|
: "Grand Prix"
|
|
),
|
|
NULL, MM_NOTHING, NULL, NULL
|
|
);
|
|
}
|
|
|
|
// Command_ExitGame_f didn't clear this, so now we do.
|
|
modeattacking = ATTACKING_NONE;
|
|
|
|
// Return to the menu.
|
|
D_ClearState();
|
|
M_StartControlPanel();
|
|
}
|
|
|
|
// Replay Playback Menu
|
|
|
|
tic_t playback_last_menu_interaction_leveltime = 0;
|
|
|
|
static void M_PlaybackTick(void)
|
|
{
|
|
INT16 i;
|
|
|
|
if (leveltime - playback_last_menu_interaction_leveltime >= 6*TICRATE)
|
|
playback_last_menu_interaction_leveltime = leveltime - 6*TICRATE;
|
|
|
|
// Toggle items
|
|
if (paused)
|
|
{
|
|
PAUSE_PlaybackMenu[playback_pause].status = PAUSE_PlaybackMenu[playback_fastforward].status = PAUSE_PlaybackMenu[playback_rewind].status = IT_DISABLED;
|
|
PAUSE_PlaybackMenu[playback_resume].status = PAUSE_PlaybackMenu[playback_advanceframe].status = PAUSE_PlaybackMenu[playback_backframe].status = IT_CALL|IT_STRING;
|
|
|
|
if (itemOn >= playback_rewind && itemOn <= playback_fastforward)
|
|
itemOn += playback_backframe - playback_rewind;
|
|
}
|
|
else
|
|
{
|
|
PAUSE_PlaybackMenu[playback_pause].status = PAUSE_PlaybackMenu[playback_fastforward].status = PAUSE_PlaybackMenu[playback_rewind].status = IT_CALL|IT_STRING;
|
|
PAUSE_PlaybackMenu[playback_resume].status = PAUSE_PlaybackMenu[playback_advanceframe].status = PAUSE_PlaybackMenu[playback_backframe].status = IT_DISABLED;
|
|
|
|
if (itemOn >= playback_backframe && itemOn <= playback_advanceframe)
|
|
itemOn -= playback_backframe - playback_rewind;
|
|
}
|
|
|
|
if (modeattacking)
|
|
{
|
|
for (i = playback_viewcount; i <= playback_director; i++)
|
|
PAUSE_PlaybackMenu[i].status = IT_DISABLED;
|
|
|
|
PAUSE_PlaybackMenu[playback_freecam].mvar1 = 72;
|
|
PAUSE_PlaybackMenu[playback_quit].mvar1 = 88;
|
|
|
|
currentMenu->x = BASEVIDWIDTH/2 - 52;
|
|
}
|
|
else
|
|
{
|
|
PAUSE_PlaybackMenu[playback_viewcount].status = IT_ARROWS|IT_STRING;
|
|
PAUSE_PlaybackMenu[playback_director].status = IT_ARROWS|IT_STRING;
|
|
PAUSE_PlaybackMenu[playback_freecam].status = IT_CALL|IT_STRING;
|
|
|
|
for (i = 0; i <= r_splitscreen; i++)
|
|
PAUSE_PlaybackMenu[playback_view1+i].status = IT_ARROWS|IT_STRING;
|
|
for (i = r_splitscreen+1; i < 4; i++)
|
|
PAUSE_PlaybackMenu[playback_view1+i].status = IT_DISABLED;
|
|
|
|
PAUSE_PlaybackMenu[playback_freecam].mvar1 = 172;
|
|
PAUSE_PlaybackMenu[playback_quit].mvar1 = 188;
|
|
|
|
//currentMenu->x = BASEVIDWIDTH/2 - 94;
|
|
currentMenu->x = BASEVIDWIDTH/2 - 96;
|
|
}
|
|
}
|
|
|
|
void M_SetPlaybackMenuPointer(void)
|
|
{
|
|
itemOn = playback_pause;
|
|
}
|
|
|
|
void M_PlaybackRewind(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
G_DoPlayDemo(NULL); // Restart the current demo
|
|
M_ClearMenus(true);
|
|
}
|
|
|
|
void M_PlaybackPause(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
paused = !paused;
|
|
|
|
if (paused)
|
|
S_PauseAudio();
|
|
else
|
|
S_ResumeAudio();
|
|
|
|
CV_SetValue(&cv_playbackspeed, 1);
|
|
}
|
|
|
|
void M_PlaybackFastForward(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
CV_SetValue(&cv_playbackspeed, cv_playbackspeed.value == 1 ? 4 : 1);
|
|
}
|
|
|
|
void M_PlaybackAdvance(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
|
|
paused = false;
|
|
TryRunTics(1);
|
|
paused = true;
|
|
}
|
|
|
|
void M_PlaybackSetViews(INT32 choice)
|
|
{
|
|
if (choice > 0)
|
|
{
|
|
if (r_splitscreen < 3)
|
|
G_AdjustView(r_splitscreen + 2, 0, true);
|
|
}
|
|
else if (r_splitscreen)
|
|
{
|
|
if (choice == 0)
|
|
{
|
|
G_SyncDemoParty(displayplayers[r_splitscreen], r_splitscreen - 1);
|
|
}
|
|
else
|
|
{
|
|
G_SyncDemoParty(consoleplayer, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void M_PlaybackAdjustView(INT32 choice)
|
|
{
|
|
G_AdjustView(itemOn - playback_viewcount, (choice > 0) ? 1 : -1, true);
|
|
}
|
|
|
|
// this one's rather tricky
|
|
void M_PlaybackToggleFreecam(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
M_ClearMenus(true);
|
|
|
|
// remove splitscreen:
|
|
splitscreen = 0;
|
|
R_ExecuteSetViewSize();
|
|
|
|
UINT8 i;
|
|
for (i = 0; i <= r_splitscreen; ++i)
|
|
{
|
|
P_ToggleDemoCamera(i);
|
|
}
|
|
}
|
|
|
|
void M_PlaybackQuit(INT32 choice)
|
|
{
|
|
(void)choice;
|
|
G_StopDemo();
|
|
|
|
if (modeattacking)
|
|
M_EndModeAttackRun();
|
|
else if (restoreMenu)
|
|
M_StartControlPanel();
|
|
else
|
|
D_StartTitle();
|
|
}
|