- Cutscene recorder command-line feature

- implement LoadCutsceneAsReplay
- implement cutscene recorder under CUTSCENE_RECORDER define
This commit is contained in:
Ilya Shurumov 2020-05-21 03:33:21 +06:00
parent c1e923a4e2
commit 51a7512123
9 changed files with 303 additions and 57 deletions

View File

@ -1195,6 +1195,7 @@ int LoadCutsceneToReplayBuffer(int residentCutscene)
ShowCutsceneError();
return 0;
}
CutsceneStreamIndex = NumReplayStreams;
NumCutsceneStreams = rheader->NumReplayStreams;

View File

@ -191,14 +191,15 @@ void GameStart(void)
LaunchGame();
break;
case GAME_IDLEDEMO:
iVar2 = LoadAttractReplay(gCurrentMissionNumber);
iVar1 = gVibration;
gVibration = iVar1;
if (iVar2 != 0) {
if (LoadAttractReplay(gCurrentMissionNumber))
{
gVibration = 0;
CurrentGameMode = GAMEMODE_DEMO;
gLoadedReplay = 1;
LaunchGame();
gLoadedReplay = 0;
gVibration = iVar1;
}

View File

@ -63,6 +63,7 @@
#include "PAUSE.H"
#include <stdlib.h>
#include "STRINGS.H"
#include "../FRONTEND/FEMAIN.H"
@ -860,10 +861,10 @@ void GameInit(void)
{
do {
pSVar3 = PlayerStartInfo[i];
padid = -(char)i;
padid = -i;
if (i < (int)(uint)NumPlayers)
padid = (char)i;
if (i < NumPlayers)
padid = i;
gStartOnFoot = (pSVar3->type == 2);
@ -887,6 +888,16 @@ void GameInit(void)
} while (i < numPlayersToCreate);
}
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
extern int gCutsceneAsReplay_PlayerId;
if (gCutsceneAsReplay != 0)
{
player[0].playerCarId = gCutsceneAsReplay_PlayerId;
player[0].cameraCarId = gCutsceneAsReplay_PlayerId;
}
#endif
if (pathAILoaded != 0)
InitCops();
@ -918,6 +929,10 @@ void GameInit(void)
if (NoPlayerControl == 0)
{
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
if(gCutsceneAsReplay == 0)
#endif
DeleteAllCameras();
}
else
@ -1362,6 +1377,31 @@ LAB_00059c1c:
}*/
break;
case 7:
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
extern int gCutsceneAsReplay_PlayerId;
if (gCutsceneAsReplay != 0 && NoPlayerControl == 0 && cp->id == gCutsceneAsReplay_PlayerId)
{
t0 = Pads[0].mapped; // [A] padid might be wrong
t1 = Pads[0].mapanalog[2];
t2 = Pads[0].type & 4;
if (gStopPadReads != 0)
{
t0 = 0x80;
if (cp->hd.wheel_speed < 0x9001)
t0 = 0x10;
t1 = 0;
t2 = 1;
}
cjpRecord(-*cp->ai.padid, &t0, &t1, &t2);
}
else
#endif
cjpPlay(-*cp->ai.padid, &t0, &t1, &t2);
ProcessCarPad(cp, t0, t1, t2);
}
@ -2390,7 +2430,7 @@ void SsSetSerialVol(char param_1, short param_2, short param_3)
#ifdef PSX
int main(void)
#else
int redriver2_main(void)
int redriver2_main(int argc, char** argv)
#endif // PSX
{
char *PALScreenNames[4] = { // [A] don't show publisher logo
@ -2437,13 +2477,18 @@ int redriver2_main(void)
Init_FileSystem();
InitSound();
//PlayFMV(99); // [A] don't show publisher logo
#ifndef PSX
if(argc <= 1)
#endif
{
//PlayFMV(99); // [A] don't show publisher logo
ShowHiresScreens(OPMScreenNames, 300, 0); // [A]
ShowHiresScreens(OPMScreenNames, 300, 0); // [A]
PlayFMV(0); // play intro movie
PlayFMV(0); // play intro movie
CheckForCorrectDisc(0);
CheckForCorrectDisc(0);
}
// Init frontend
#ifdef PSX
@ -2460,6 +2505,47 @@ int redriver2_main(void)
InitialiseScoreTables();
#ifdef CUTSCENE_RECORDER
for (int i = 0; i < argc; i++)
{
if (!_stricmp(argv[i], "-recordcutscene"))
{
if (argc-i < 3)
{
printWarning("Example: -recordcutscene <mission_number> <base_mission> <player_id>");
return 0;
}
SetFEDrawMode();
gInFrontend = 0;
AttractMode = 0;
int player_id = atoi(argv[i+3]);
extern int LoadCutsceneAsReplay(int subindex);
extern int gCutsceneAsReplay;
extern int gCutsceneAsReplay_PlayerId;
gCutsceneAsReplay = atoi(argv[i + 1]); // acts as cutscene mission
gCurrentMissionNumber = atoi(argv[i + 2]); // acts as base mission. Some mission requires other base
gCutsceneAsReplay_PlayerId = atoi(argv[i + 3]);
if (LoadCutsceneAsReplay(0))
{
CurrentGameMode = GAMEMODE_REPLAY;
gLoadedReplay = 1;
LaunchGame();
gLoadedReplay = 0;
}
gCutsceneAsReplay = 0;
return 1;
}
}
#endif
// now run the frontend
DoFrontEnd();
@ -2985,7 +3071,7 @@ void InitGameVariables(void)
gLoadedMotionCapture = 0;
}
gRainCount = '\0';
gRainCount = 0;
if ((NoPlayerControl == 0) || (AttractMode != 0)) {
pauseflag = 0;
@ -3010,40 +3096,63 @@ void InitGameVariables(void)
FrameCnt = 0;
CameraCnt = 0;
ClearMem((char *)&lightsOnDelay, 0x14);
ClearMem((char *)&lightsOnDelay, sizeof(lightsOnDelay));
PlayerStartInfo[0] = &ReplayStreams[0].SourceType;
ClearMem((char *)PlayerStartInfo[0], sizeof(STREAM_SOURCE));
PlayerStartInfo[0]->type = 1;
PlayerStartInfo[0]->model = defaultPlayerModel[0];
PlayerStartInfo[0]->palette = defaultPlayerPalette;
PlayerStartInfo[0]->controlType = 1;
PlayerStartInfo[0]->flags = 0;
#ifdef CUTSCENE_RECORDER
extern int gCutsceneAsReplay;
if (gCutsceneAsReplay == 0)
{
#endif
ClearMem((char *)PlayerStartInfo[0], sizeof(STREAM_SOURCE));
PlayerStartInfo[0]->rotation = levelstartpos[GameLevel][1];
PlayerStartInfo[0]->position.vx = levelstartpos[GameLevel][0];
PlayerStartInfo[0]->position.vy = 0;
PlayerStartInfo[0]->position.vz = levelstartpos[GameLevel][2];
PlayerStartInfo[0]->type = 1;
PlayerStartInfo[0]->model = defaultPlayerModel[0];
PlayerStartInfo[0]->palette = defaultPlayerPalette;
PlayerStartInfo[0]->controlType = 1;
PlayerStartInfo[0]->flags = 0;
numPlayersToCreate = 1;
PlayerStartInfo[0]->rotation = levelstartpos[GameLevel][1];
PlayerStartInfo[0]->position.vx = levelstartpos[GameLevel][0];
PlayerStartInfo[0]->position.vy = 0;
PlayerStartInfo[0]->position.vz = levelstartpos[GameLevel][2];
if (NumPlayers == 2) {
PlayerStartInfo[1] = &ReplayStreams[1].SourceType;
ClearMem((char *)PlayerStartInfo[1], sizeof(STREAM_SOURCE));
numPlayersToCreate = 1;
PlayerStartInfo[1]->type = 1;
PlayerStartInfo[1]->model = defaultPlayerModel[1];
PlayerStartInfo[1]->palette = defaultPlayerPalette;
PlayerStartInfo[1]->controlType = 1;
PlayerStartInfo[1]->flags = 0;
PlayerStartInfo[1]->rotation = levelstartpos[GameLevel][1];
PlayerStartInfo[1]->position.vx = levelstartpos[GameLevel][0] + 600;
PlayerStartInfo[1]->position.vy = 0;
PlayerStartInfo[1]->position.vz = levelstartpos[GameLevel][2];
if (NumPlayers == 2)
{
PlayerStartInfo[1] = &ReplayStreams[1].SourceType;
ClearMem((char *)PlayerStartInfo[1], sizeof(STREAM_SOURCE));
numPlayersToCreate = NumPlayers;
PlayerStartInfo[1]->type = 1;
PlayerStartInfo[1]->model = defaultPlayerModel[1];
PlayerStartInfo[1]->palette = defaultPlayerPalette;
PlayerStartInfo[1]->controlType = 1;
PlayerStartInfo[1]->flags = 0;
PlayerStartInfo[1]->rotation = levelstartpos[GameLevel][1];
PlayerStartInfo[1]->position.vx = levelstartpos[GameLevel][0] + 600;
PlayerStartInfo[1]->position.vy = 0;
PlayerStartInfo[1]->position.vz = levelstartpos[GameLevel][2];
numPlayersToCreate = NumPlayers;
}
#ifdef CUTSCENE_RECORDER
}
else
{
extern int gCutsceneAsReplay_PlayerId;
extern int gCutsceneAsReplay_PlayerChanged;
for (int i = 0; i < NumReplayStreams; i++)
{
PlayerStartInfo[i] = &ReplayStreams[i].SourceType;
}
numPlayersToCreate = NumReplayStreams;
}
#endif // CUTSCENE_RECORDER
InitCivCars();
return;

View File

@ -42,7 +42,7 @@ extern void EnablePause(enum PAUSEMODE mode); // 0x0005C590
extern void CheckForPause(); // 0x0005C5D0
extern int redriver2_main(); // 0x0005B384
extern int redriver2_main(int argc, char** argv); // 0x0005B384
extern void FadeScreen(int end_value); // 0x0005C668

View File

@ -382,7 +382,6 @@ void LoadMission(int missionnum)
if (NewLevel != 0)
MissionLoadAddress = (_MISSION *)mallocptr;
sprintf(filename, "MISSIONS\\MISSIONS.BLK");
if (FileExists(filename) == 0)
@ -427,6 +426,7 @@ void LoadMission(int missionnum)
return;
}
MissionHeader->id = 0;
if (MissionHeader->region != 0)
@ -442,11 +442,35 @@ void LoadMission(int missionnum)
Mission.active = 1;
GameLevel = MissionHeader->city;
PlayerStartInfo[0]->position.vx = MissionHeader->playerStartPosition.x;
PlayerStartInfo[0]->rotation = MissionHeader->playerStartRotation;
PlayerStartInfo[0]->position.vz = MissionHeader->playerStartPosition.y;
PlayerStartInfo[0]->model = MissionHeader->playerCarModel;
PlayerStartInfo[0]->palette = MissionHeader->playerCarColour;
#ifdef CUTSCENE_RECORDER
// load some data from target cutscene mission
extern int gCutsceneAsReplay;
if(gCutsceneAsReplay)
{
LoadfileSeg(filename, (char*)&header, gCutsceneAsReplay * 4, 4);
if (header == 0)
return;
_MISSION missionTempHeader;
loadsize = header >> 0x13;
LoadfileSeg(filename, (char *)&missionTempHeader, header & 0x7ffff, sizeof(_MISSION));
memcpy(MissionHeader->residentModels, missionTempHeader.residentModels, sizeof(missionTempHeader.residentModels));
MissionHeader->time = missionTempHeader.time;
MissionHeader->weather = missionTempHeader.weather;
}
if (gCutsceneAsReplay == 0)
#endif
{
PlayerStartInfo[0]->position.vx = MissionHeader->playerStartPosition.x;
PlayerStartInfo[0]->rotation = MissionHeader->playerStartRotation;
PlayerStartInfo[0]->position.vz = MissionHeader->playerStartPosition.y;
PlayerStartInfo[0]->model = MissionHeader->playerCarModel;
PlayerStartInfo[0]->palette = MissionHeader->playerCarColour;
}
if (MissionHeader->maxDamage != 0)
{

View File

@ -160,12 +160,20 @@ MENU_HEADER YesNoRestartHeader =
MENU_HEADER YesNoQuitHeader =
{ "Are you sure?", { 0, 0, 0, 0 }, 0u, YesNoQuitItems };
#ifdef CUTSCENE_RECORDER
extern void NextCutsceneRecorderPlayer(int dir);
extern char gCutsceneRecorderPauseText[64];
#endif
MENU_ITEM MainPauseItems[] =
{
{ "Continue", 1u, 2u, NULL, MENU_QUIT_CONTINUE, NULL },
{ "Show Map", 3u, 2u, (pauseFunc)&PauseMap, MENU_QUIT_NONE, NULL },
#if defined(_DEBUG) || defined(DEBUG_OPTIONS)
{ "Debug Options", 65u, 2u, NULL, MENU_QUIT_NONE, &DebugOptionsHeader },
#endif
#ifdef CUTSCENE_RECORDER
{ gCutsceneRecorderPauseText, 5u, 2u, (pauseFunc)&NextCutsceneRecorderPlayer, MENU_QUIT_NONE, NULL },
#endif
{ "Restart", 65u, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
{ "Effects Volume", 13u, 2u, (pauseFunc)&SfxVolume, MENU_QUIT_NONE, NULL },
@ -223,8 +231,11 @@ MENU_ITEM MissionFailedItems[6] =
{ NULL, 128u, 0u, NULL, MENU_QUIT_NONE, NULL }
};
MENU_ITEM TakeARideFinishedItems[6] =
MENU_ITEM TakeARideFinishedItems[] =
{
#ifdef CUTSCENE_RECORDER
{ gCutsceneRecorderPauseText, 5u, 2u, (pauseFunc)&NextCutsceneRecorderPlayer, MENU_QUIT_NONE, NULL },
#endif
{ "Restart", 65u, 2u, NULL, MENU_QUIT_NONE, &YesNoRestartHeader },
{ "Film Director",1u,2u,NULL,MENU_QUIT_DIRECTOR,NULL},
{ "Quick Replay",1u,2u,NULL,MENU_QUIT_QUICKREPLAY,NULL},
@ -1504,7 +1515,8 @@ void ControlMenu(void)
{
controlmenu_debounce = controlmenu_debounce + -1;
iVar3 = 2;
if (controlmenu_debounce != 0) goto LAB_0006cd08;
if (controlmenu_debounce != 0)
goto LAB_0006cd08;
}
bVar2 = true;

View File

@ -115,7 +115,7 @@ void InitPadRecording(void)
for (i = 0; i < NumReplayStreams; i++)
{
ReplayStreams[i].playbackrun = 0;
ReplayStreams[i].PadRecordBuffer = ReplayStreams[0].InitialPadRecordBuffer;
ReplayStreams[i].PadRecordBuffer = ReplayStreams[i].InitialPadRecordBuffer;
}
}
@ -435,6 +435,71 @@ int SaveReplayToBuffer(char *buffer)
/* end block 5 */
// End Line: 1588
#ifdef CUTSCENE_RECORDER
int gCutsceneAsReplay = 0;
int gCutsceneAsReplay_PlayerId = 0;
int gCutsceneAsReplay_PlayerChanged = 0;
char gCutsceneRecorderPauseText[64] = { 0 };
void NextCutsceneRecorderPlayer(int dir)
{
int old_player = gCutsceneAsReplay_PlayerId;
if(dir > 0)
gCutsceneAsReplay_PlayerId++;
else if(dir < 0)
gCutsceneAsReplay_PlayerId--;
if (gCutsceneAsReplay_PlayerId >= NumReplayStreams)
gCutsceneAsReplay_PlayerId -= NumReplayStreams;
else if (gCutsceneAsReplay_PlayerId < 0)
gCutsceneAsReplay_PlayerId += NumReplayStreams;
if (old_player != gCutsceneAsReplay_PlayerId)
gCutsceneAsReplay_PlayerChanged = 1;
sprintf(gCutsceneRecorderPauseText, "CUTSCENE PLAYER ID: %d", gCutsceneAsReplay_PlayerId);
}
int LoadCutsceneAsReplay(int subindex)
{
int offset;
int size;
if (gCutsceneAsReplay_PlayerId > 0)
gCutsceneAsReplay_PlayerChanged = 1;
NextCutsceneRecorderPlayer(0);
CUTSCENE_HEADER header;
char filename[64];
if (gCutsceneAsReplay < 21)
sprintf(filename, "REPLAYS\\CUT%d.R", gCutsceneAsReplay);
else
sprintf(filename, "REPLAYS\\A\\CUT%d.R", gCutsceneAsReplay);
if (FileExists(filename))
{
LoadfileSeg(filename, (char *)&header, 0, sizeof(CUTSCENE_HEADER));
if (header.data[subindex].offset != 0xffff)
{
offset = header.data[subindex].offset * 4;
size = header.data[subindex].size;
LoadfileSeg(filename, _other_buffer, offset, size);
return LoadReplayFromBuffer(_other_buffer);
}
}
printError("Invalid cutscene subindex or mission!\n");
return 0;
}
#endif // CUTSCENE_RECORDER
// [D]
int LoadReplayFromBuffer(char *buffer)
{
@ -454,7 +519,12 @@ int LoadReplayFromBuffer(char *buffer)
GameLevel = header->GameLevel;
GameType = (GAMETYPE)header->GameType;
gCurrentMissionNumber = header->MissionNumber;
#ifdef CUTSCENE_RECORDER
if(gCutsceneAsReplay == 0)
#endif
gCurrentMissionNumber = header->MissionNumber;
NumReplayStreams = header->NumReplayStreams;
NumPlayers = header->NumPlayers;
gRandomChase = header->RandomChase;
@ -469,6 +539,7 @@ int LoadReplayFromBuffer(char *buffer)
pt = (char*)(header+1);
int maxLength = 0;
for (int i = 0; i < NumReplayStreams; i++)
{
sheader = (REPLAY_STREAM_HEADER *)pt;
@ -485,6 +556,9 @@ int LoadReplayFromBuffer(char *buffer)
destStream->PadRecordBufferEnd = (PADRECORD *)(replayptr + sheader->Size);
destStream->length = sheader->Length;
if (sheader->Length > maxLength)
maxLength = sheader->Length;
int size = (sheader->Size + sizeof(PADRECORD)) & -4;
// copy pad data and advance buffer
@ -495,12 +569,33 @@ int LoadReplayFromBuffer(char *buffer)
}
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK *)replayptr;
memcpy(ReplayParameterPtr, pt, sizeof(REPLAY_PARAMETER_BLOCK));
pt += sizeof(REPLAY_PARAMETER_BLOCK);
#ifdef CUTSCENE_RECORDER
if (gCutsceneAsReplay != 0)
{
memset(ReplayParameterPtr, 0, sizeof(REPLAY_PARAMETER_BLOCK));
ReplayParameterPtr->RecordingEnd = maxLength;
}
else
#endif
{
memcpy(ReplayParameterPtr, pt, sizeof(REPLAY_PARAMETER_BLOCK));
pt += sizeof(REPLAY_PARAMETER_BLOCK);
}
PlayerWayRecordPtr = (SXYPAIR *)(ReplayParameterPtr + 1);
memcpy(PlayerWayRecordPtr, pt, sizeof(SXYPAIR) * 150);
pt += sizeof(SXYPAIR) * 150;
#ifdef CUTSCENE_RECORDER
if (gCutsceneAsReplay != 0)
{
memset(PlayerWayRecordPtr, 0, sizeof(SXYPAIR) * 150);
}
else
#endif
{
memcpy(PlayerWayRecordPtr, pt, sizeof(SXYPAIR) * 150);
pt += sizeof(SXYPAIR) * 150;
}
PlaybackCamera = (PLAYBACKCAMERA *)(PlayerWayRecordPtr + 150);
memcpy(PlaybackCamera, pt, sizeof(PLAYBACKCAMERA) * 60);
@ -723,6 +818,11 @@ int cjpPlay(int stream, ulong *ppad, char *psteer, char *ptype)
int t1;
ulong t0;
#ifdef CUTSCENE_RECORDER
if (stream < 0)
stream = -stream;
#endif
ret = Get(stream, &t0);
t1 = (t0 >> 8) & 0xF;

View File

@ -4,7 +4,7 @@
#include "THISDUST.H"
#include "GAME/C/MAIN.H"
#include "GAME/C/SYSTEM.H"
#include "GAME/C/GLAUNCH.H"
#include "EMULATOR.H"
@ -248,7 +248,7 @@ char g_PrimTab2[0x1a180]; // 0x119400
char g_Replay_buffer[0x50000]; // 0x1fabbc
#endif
int main()
int main(int argc, char** argv)
{
#ifdef USE_CRT_MALLOC
_overlay_buffer = (char*)malloc(0x50000); // 0x1C0000
@ -280,8 +280,7 @@ int main()
GPU_printf = printf;
Emulator_Initialise("REDRIVER2", 800, 600);
redriver2_main();
redriver2_main(argc, argv);
Emulator_ShutDown();
}

View File

@ -129,7 +129,7 @@
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<Optimization>Full</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>false</SDLCheck>