REDRIVER2/src_rebuild/Game/C/cutrecorder.c

840 lines
19 KiB
C

#ifdef PSX
#error This file is not applicable for PSX build
#endif
#ifdef CUTSCENE_RECORDER
#include "driver2.h"
#include "cutrecorder.h"
#include "main.h"
#include "pad.h"
#include "cop_ai.h"
#include "spool.h"
#include "civ_ai.h"
#include "cutscene.h"
#include "cars.h"
#include "camera.h"
#include "glaunch.h"
#include "mission.h"
#include "replays.h"
#include "state.h"
#include "system.h"
#include "pause.h"
#include "pres.h"
#include "players.h"
#include "../utils/ini.h"
typedef struct AutoTestStats
{
int numHitCars;
int numHitWalls;
int stuck;
int saved;
};
PING_PACKET NewPingBuffer[MAX_REPLAY_PINGS];
AutoTestStats gAutoTestStats[16]; // 16th is dummy
int gCutsceneChaseAutoTest = 0;
int gChaseStuckTimer = 0;
int gCutsceneAsReplay_ReChaseLoaded = 0;
int gCutsceneAsReplay = 0;
int gCutsceneAsReplay_NumReplayStreams = 0;
int gCutsceneAsReplay_PlayerId = 0;
int gCutsceneAsReplay_PlayerChanged = 0;
int gCutsceneAsReplay_ReserveSlots = 2;
char gCutsceneRecorderPauseText[64] = { 0 };
char gCurrentChasePauseText[64] = { 0 };
extern int gDieWithFade;
int CutRec_LoadCutsceneAsReplayFromBuffer(char* buffer);
void InitCutsceneRecorder(char* configFilename);
int LoadCutsceneAsReplay(int subindex);
void CutRec_Reset()
{
if (gCutsceneChaseAutoTest != 0 && gCutsceneChaseAutoTest < 15)
{
gAutoTestStats[gCutsceneChaseAutoTest].numHitCars = 0;
gAutoTestStats[gCutsceneChaseAutoTest].numHitWalls = 0;
gAutoTestStats[gCutsceneChaseAutoTest].stuck = 0;
gAutoTestStats[gCutsceneChaseAutoTest].saved = 0;
gChaseStuckTimer = 0;
return;
}
gCutsceneChaseAutoTest = 0;
gCutsceneAsReplay = 0;
gCutsceneAsReplay_PlayerId = 0;
gCutsceneAsReplay_PlayerChanged = 0;
gCutsceneAsReplay_ReserveSlots = 2;
}
void CutRec_NextChase(int dir)
{
if (dir > 0)
gChaseNumber++;
else if (dir < 0)
gChaseNumber--;
if (gChaseNumber < 0)
gChaseNumber = 0;
if (gChaseNumber > 15)
gChaseNumber = 15;
sprintf(gCurrentChasePauseText, "Chase ID: %d", gChaseNumber);
}
int CutRec_GotoChase(int number)
{
if (number < 2)
return 0;
if (number > 15)
return 0;
gCutsceneChaseAutoTest = number;
// load next replay and restart
if (LoadCutsceneAsReplay(gCutsceneChaseAutoTest))
{
State_GameComplete(NULL);
gDrawPauseMenus = 0;
gLoadedReplay = 1;
CurrentGameMode = GAMEMODE_REPLAY;
SetState(STATE_GAMELAUNCH);
return 1;
}
return 0;
}
void CutRec_Step()
{
if (gCutsceneChaseAutoTest != 0 && CutRec_IsPlaying())
{
// goto previous chase
if (Pads[0].dirnew & CAR_PAD_LEFT)
{
CutRec_GotoChase(gCutsceneChaseAutoTest - 1);
return;
}
// goto next chase
if (Pads[0].dirnew & CAR_PAD_RIGHT)
{
CutRec_GotoChase(gCutsceneChaseAutoTest + 1);
return;
}
if (!pauseflag)
{
int carId = player[gCutsceneAsReplay_PlayerId].playerCarId;
if (car_data[carId].hd.speed < 5)
gChaseStuckTimer++;
else
gChaseStuckTimer = 0;
if (gChaseStuckTimer > 45)
{
gAutoTestStats[gCutsceneChaseAutoTest].stuck = 1;
gChaseStuckTimer = 0;
}
return;
}
if (gCutsceneChaseAutoTest < 15 &&
(NoPlayerControl && ReplayParameterPtr->RecordingEnd - 2 < CameraCnt || gDieWithFade))
{
gCutsceneChaseAutoTest++;
// load next replay and restart
if (!CutRec_GotoChase(gCutsceneChaseAutoTest))
{
printInfo("------- AUTOTEST RESULTS -------\n");
for (int i = 0; i < 15; i++)
printInfo(" chase %d - hit cars: %d, stuck: %d\n", i, gAutoTestStats[i].numHitCars, gAutoTestStats[i].stuck);
printInfo("------- ---------------- -------\n");
}
}
}
}
void CutRec_Draw()
{
char text[64];
if (gCutsceneAsReplay == 0)
return;
SetTextColour(128, 128, 128);
if(gCutsceneChaseAutoTest)
{
sprintf(text, "Auto-test - chase %d %s", gCutsceneChaseAutoTest, gAutoTestStats[gCutsceneChaseAutoTest].saved ? "-SAVED-" : "");
PrintString(text, 5, 10);
if(gCutsceneAsReplay_ReChaseLoaded)
{
SetTextColour(32, 128, 32);
PrintString("Re-recorded", 5, 20);
}
else
{
SetTextColour(128, 80, 32);
PrintString("Reflections", 5, 20);
}
SetTextColour(128, 128, 128);
sprintf(text, "Frame %d of %d", CameraCnt, ReplayParameterPtr->RecordingEnd);
PrintString(text, 5, 215);
}
if(PingBufferPos >= MAX_REPLAY_PINGS-1)
SetTextColour(128, 0, 0);
sprintf(text, "Pings: %d", PingBufferPos);
PrintString(text, 5, 205);
SetTextColour(128, 128, 128);
if (gAutoTestStats[gCutsceneChaseAutoTest].numHitCars > 0)
SetTextColour(128, 0, 0);
sprintf(text, "Hit cars: %d", gAutoTestStats[gCutsceneChaseAutoTest].numHitCars);
PrintString(text, 120, 205);
if(gAutoTestStats[gCutsceneChaseAutoTest].stuck)
{
SetTextColour(128, 0, 0);
sprintf(text, "Car is stuck!");
PrintString(text, 5, 60);
}
}
void CutRec_ReserveSlots()
{
if (gCutsceneAsReplay == 0)
return;
for (int i = 0; i < gCutsceneAsReplay_ReserveSlots; i++)
reservedSlots[i] = 1;
}
void CutRec_HandleCarRequest()
{
if (gCutsceneAsReplay == 0)
return;
requestCopCar = 0;
allowSpecSpooling = 0;
}
void CutRec_NextPlayer(int dir)
{
int old_player = gCutsceneAsReplay_PlayerId;
if (dir > 0)
gCutsceneAsReplay_PlayerId++;
else if (dir < 0)
gCutsceneAsReplay_PlayerId--;
if (gCutsceneAsReplay_PlayerId >= gCutsceneAsReplay_NumReplayStreams)
gCutsceneAsReplay_PlayerId -= gCutsceneAsReplay_NumReplayStreams;
else if (gCutsceneAsReplay_PlayerId < 0)
gCutsceneAsReplay_PlayerId += gCutsceneAsReplay_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;
CUTSCENE_HEADER header;
char filename[64];
// Try loading existing ReChase
sprintf(filename, "REPLAYS\\ReChases\\CUT%d_N.R", gCutsceneAsReplay);
if(!FileExists(filename))
{
gCutsceneAsReplay_ReChaseLoaded = 0;
printWarning("--- NO re-recorded chases available! ---\n");
if (gCutsceneAsReplay < 21)
sprintf(filename, "REPLAYS\\CUT%d.R", gCutsceneAsReplay);
else
sprintf(filename, "REPLAYS\\A\\CUT%d.R", gCutsceneAsReplay);
}
else
{
gCutsceneAsReplay_ReChaseLoaded = 1;
printInfo("--- Re-recorded chases loaded ---\n");
}
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, (char*)_other_buffer, offset, size);
int result = CutRec_LoadCutsceneAsReplayFromBuffer((char*)_other_buffer);
return result;
}
}
printError("Invalid cutscene subindex or mission!\n");
return 0;
}
void InitChaseAutoTest(char* configFilename)
{
gCutsceneChaseAutoTest = 2;
InitCutsceneRecorder(configFilename);
}
void InitCutsceneRecorder(char* configFilename)
{
ini_t* config;
int loadExistingCutscene;
int subindex;
config = ini_load(configFilename);
if (!config)
{
printError("Unable to open '%s'!\n", configFilename);
return;
}
//const char* stream = ini_get(config, "fs", "dataFolder");
loadExistingCutscene = 0;
ini_sget(config, "settings", "loadExistingCutscene", "%d", &loadExistingCutscene);
ini_sget(config, "settings", "mission", "%d", &gCutsceneAsReplay);
ini_sget(config, "settings", "baseMission", "%d", &gCurrentMissionNumber);
ini_sget(config, "settings", "player", "%d", &gCutsceneAsReplay_PlayerId);
ini_sget(config, "settings", "reserveSlots", "%d", &gCutsceneAsReplay_ReserveSlots);
ini_sget(config, "settings", "subindex", "%d", &subindex);
// totally limited by streams
if (gCutsceneAsReplay_ReserveSlots > 8)
gCutsceneAsReplay_ReserveSlots = 8;
if (loadExistingCutscene)
{
if(gCutsceneChaseAutoTest != 0)
{
subindex = gCutsceneChaseAutoTest;
}
if (!LoadCutsceneAsReplay(subindex))
{
ini_free(config);
gLoadedReplay = 0;
gCutsceneAsReplay = 0;
return;
}
gCutsceneAsReplay_NumReplayStreams = NumReplayStreams;
gLoadedReplay = 1;
CurrentGameMode = GAMEMODE_REPLAY;
}
else
{
int i;
char curStreamName[40];
STREAM_SOURCE* stream;
InitPadRecording();
ini_sget(config, "settings", "streams", "%d", &gCutsceneAsReplay_NumReplayStreams);
// initialize all streams
for (i = 0; i < gCutsceneAsReplay_NumReplayStreams; i++)
{
stream = &ReplayStreams[i].SourceType;
sprintf(curStreamName, "stream%d", i);
stream->position.vy = 0;
ini_sget(config, curStreamName, "type", "%hhd", &stream->type);
ini_sget(config, curStreamName, "model", "%hhd", &stream->model);
ini_sget(config, curStreamName, "palette", "%hhd", &stream->palette);
ini_sget(config, curStreamName, "controlType", "%hhd", &stream->controlType);
ini_sget(config, curStreamName, "startRot", "%d", &stream->rotation);
ini_sget(config, curStreamName, "startPosX", "%d", &stream->position.vx);
ini_sget(config, curStreamName, "startPosY", "%d", &stream->position.vy);
ini_sget(config, curStreamName, "startPosZ", "%d", &stream->position.vz);
}
}
GameType = GAME_TAKEADRIVE;
CameraCnt = 0;
ini_free(config);
CutRec_NextChase(0);
CutRec_NextPlayer(0);
SetState(STATE_GAMELAUNCH);
}
// [A] Stores ping info into replay buffer
int CutRec_StorePingInfo(int cookieCount, int carId)
{
PING_PACKET* buffer;
PING_PACKET* packet;
if (!CutRec_IsRecording())
return 0;
if (PingBufferPos < MAX_REPLAY_PINGS-1)
{
packet = &NewPingBuffer[PingBufferPos++];
packet->frame = CameraCnt - frameStart;
packet->carId = carId;
packet->cookieCount = cookieCount;
PingBuffer[PingBufferPos - 1] = *packet;
// always finalize last ping
packet = &NewPingBuffer[PingBufferPos];
packet->frame = 0xffff;
packet->carId = -1;
packet->cookieCount = -1;
return 1;
}
return 0;
}
void CutRec_CheckInvalidatePing(int carId, int howHard)
{
int pos;
if (gCutsceneAsReplay == 0)
return;
if (howHard < 60000)
return;
gAutoTestStats[gCutsceneChaseAutoTest].numHitCars++;
pos = PingBufferPos;
while (pos >= 0)
{
pos--;
if (PingBuffer[pos].carId == carId)
{
printWarning("Removing ping at %d\n", PingBuffer[pos].frame);
PingBuffer[pos].carId = -1;
NewPingBuffer[pos].carId = -1;
PingOutCar(&car_data[carId]);
break;
}
}
}
int CutRec_InitPlayers()
{
STREAM_SOURCE* temp;
if (gCutsceneAsReplay == 0)
return 0;
for (int i = 0; i < gCutsceneAsReplay_NumReplayStreams; i++)
{
PlayerStartInfo[i] = &ReplayStreams[i].SourceType;
PlayerStartInfo[i]->controlType = CONTROL_TYPE_CUTSCENE;
}
temp = PlayerStartInfo[0];
PlayerStartInfo[0] = PlayerStartInfo[gCutsceneAsReplay_PlayerId];
PlayerStartInfo[gCutsceneAsReplay_PlayerId] = temp;
NumReplayStreams = gCutsceneAsReplay_NumReplayStreams;
numPlayersToCreate = gCutsceneAsReplay_NumReplayStreams;
return 1;
}
int CutRec_InitMission(char* filename)
{
int header;
if (gCutsceneAsReplay == 0)
return 0;
LoadfileSeg(filename, (char*)&header, gCutsceneAsReplay * 4, 4);
if (header == 0)
return 0;
// load some data from target cutscene mission
MS_MISSION missionTempHeader;
LoadfileSeg(filename, (char*)&missionTempHeader, header & 0x7ffff, sizeof(MS_MISSION));
memcpy((u_char*)MissionHeader->residentModels, (u_char*)missionTempHeader.residentModels, sizeof(missionTempHeader.residentModels));
MissionHeader->time = missionTempHeader.time;
MissionHeader->weather = missionTempHeader.weather;
MissionHeader->cops = missionTempHeader.cops;
if(gCutsceneChaseAutoTest == 0)
ClearMem((char*)gAutoTestStats, sizeof(gAutoTestStats));
return 1;
}
// Loads original cutscene replay inside CUT*.R
int CutRec_LoadCutsceneAsReplayFromBuffer(char* buffer)
{
REPLAY_SAVE_HEADER* header;
REPLAY_STREAM_HEADER* sheader;
char* pt = buffer;
header = (REPLAY_SAVE_HEADER*)pt;
if (header->magic != DRIVER2_REPLAY_MAGIC &&
header->magic != REDRIVER2_CHASE_MAGIC || // [A]
header->NumReplayStreams == 0)
return 0;
ReplayStart = replayptr = (char*)_replay_buffer;
GameLevel = header->GameLevel;
GameType = (GAMETYPE)header->GameType;
NumReplayStreams = header->NumReplayStreams;
NumPlayers = header->NumPlayers;
gRandomChase = header->RandomChase;
CutsceneEventTrigger = header->CutsceneEvent;
gCopDifficultyLevel = header->gCopDifficultyLevel;
ActiveCheats = header->ActiveCheats; // TODO: restore old value
wantedCar[0] = header->wantedCar[0];
wantedCar[1] = header->wantedCar[1];
memcpy((u_char*)&MissionEndData, (u_char*)&header->SavedData, sizeof(MISSION_DATA));
pt = (char*)(header + 1);
int maxLength = 0;
for (int i = 0; i < NumReplayStreams; i++)
{
sheader = (REPLAY_STREAM_HEADER*)pt;
pt += sizeof(REPLAY_STREAM_HEADER);
REPLAY_STREAM* destStream = &ReplayStreams[i];
// copy source type
memcpy((u_char*)&destStream->SourceType, (u_char*)&sheader->SourceType, sizeof(STREAM_SOURCE));
int size = (sheader->Size + sizeof(PADRECORD)) & -4;
// init buffers
AllocateReplayStream(destStream, 4000);
// copy pad data and advance buffer
memcpy((u_char*)destStream->PadRecordBuffer, pt, size);
pt += size;
destStream->padCount = size / sizeof(PADRECORD);
destStream->length = sheader->Length;
if (sheader->Length > maxLength)
maxLength = sheader->Length;
}
#if 0
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK*)replayptr;
memset((u_char*)ReplayParameterPtr, 0, sizeof(REPLAY_PARAMETER_BLOCK));
ReplayParameterPtr->RecordingEnd = maxLength;
PlayerWayRecordPtr = (SXYPAIR*)(ReplayParameterPtr + 1);
memset(PlayerWayRecordPtr, 0, sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS);
PlaybackCamera = (PLAYBACKCAMERA*)(PlayerWayRecordPtr + MAX_REPLAY_WAYPOINTS);
memcpy((u_char*)PlaybackCamera, (u_char*)pt, sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS);
pt += sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS;
PingBufferPos = 0;
PingBuffer = (PING_PACKET*)(PlaybackCamera + MAX_REPLAY_CAMERAS);
memcpy((u_char*)PingBuffer, (u_char*)pt, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
pt += sizeof(PING_PACKET) * MAX_REPLAY_PINGS;
replayptr = (char*)(PingBuffer + MAX_REPLAY_PINGS);
if (header->HaveStoredData == 0x91827364) // -0x6e7d8c9c
{
memcpy((u_char*)&MissionStartData, (u_char*)pt, sizeof(MISSION_DATA));
gHaveStoredData = 1;
}
#else
// [A] REDRIVER2 chase replays skip cameras
if (header->magic == REDRIVER2_CHASE_MAGIC)
{
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK*)replayptr;
memset((u_char*)ReplayParameterPtr, 0, sizeof(REPLAY_PARAMETER_BLOCK));
ReplayParameterPtr->RecordingEnd = maxLength;
PlayerWayRecordPtr = (SXYPAIR*)(ReplayParameterPtr + 1);
PlaybackCamera = (PLAYBACKCAMERA*)(PlayerWayRecordPtr + MAX_REPLAY_WAYPOINTS);
}
else
{
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK*)replayptr;
memset((u_char*)ReplayParameterPtr, 0, sizeof(REPLAY_PARAMETER_BLOCK));
ReplayParameterPtr->RecordingEnd = maxLength;
PlayerWayRecordPtr = (SXYPAIR*)(ReplayParameterPtr + 1);
memset(PlayerWayRecordPtr, 0, sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS);
PlaybackCamera = (PLAYBACKCAMERA*)(PlayerWayRecordPtr + MAX_REPLAY_WAYPOINTS);
memcpy((u_char*)PlaybackCamera, (u_char*)pt, sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS);
pt += sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS;
}
PingBufferPos = 0;
PingBuffer = (PING_PACKET*)(PlaybackCamera + MAX_REPLAY_CAMERAS);
memcpy((u_char*)PingBuffer, (u_char*)pt, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
memcpy((u_char*)NewPingBuffer, (u_char*)pt, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
pt += sizeof(PING_PACKET) * MAX_REPLAY_PINGS;
replayptr = (char*)(PingBuffer + MAX_REPLAY_PINGS);
if (header->HaveStoredData == 0x91827364) // -0x6e7d8c9c
{
memcpy((u_char*)&MissionStartData, (u_char*)pt, sizeof(MISSION_DATA));
gHaveStoredData = 1;
}
#endif
return 1;
}
// [D] [T]
int CutRec_SaveReplayToBuffer(char* buffer)
{
REPLAY_STREAM_HEADER* sheader;
REPLAY_SAVE_HEADER* header;
if (buffer == NULL)
return 0x3644;
char* pt = buffer;
header = (REPLAY_SAVE_HEADER*)pt;
pt += sizeof(REPLAY_SAVE_HEADER);
header->magic = DRIVER2_REPLAY_MAGIC;
header->GameLevel = GameLevel;
header->GameType = GameType;
header->MissionNumber = gCurrentMissionNumber;
header->NumReplayStreams = NumReplayStreams - NumCutsceneStreams;
header->NumPlayers = NumPlayers;
header->CutsceneEvent = -1;
header->RandomChase = gRandomChase;
header->gCopDifficultyLevel = gCopDifficultyLevel;
header->ActiveCheats = ActiveCheats;
header->wantedCar[0] = wantedCar[0];
header->wantedCar[1] = wantedCar[1];
memcpy((u_char*)&header->SavedData, (u_char*)&MissionEndData, sizeof(MISSION_DATA));
// write each stream data
for (int i = 0; i < NumReplayStreams; i++)
{
sheader = (REPLAY_STREAM_HEADER*)pt;
pt += sizeof(REPLAY_STREAM_HEADER);
REPLAY_STREAM* srcStream = &ReplayStreams[i];
// copy source type
memcpy((u_char*)&sheader->SourceType, (u_char*)&srcStream->SourceType, sizeof(STREAM_SOURCE));
sheader->Size = srcStream->padCount * sizeof(PADRECORD);
sheader->Length = srcStream->length;
int size = (sheader->Size + sizeof(PADRECORD)) & -4;
// copy pad data to write buffer
memcpy((u_char*)pt, (u_char*)srcStream->InitialPadRecordBuffer, size);
pt += size;
}
memcpy((u_char*)pt, (u_char*)PlaybackCamera, sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS);
pt += sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS;
memcpy((u_char*)pt, (u_char*)NewPingBuffer, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
pt += sizeof(PING_PACKET) * MAX_REPLAY_PINGS;
// [A] is that ever valid?
if (gHaveStoredData)
{
header->HaveStoredData = 0x91827364; // -0x6e7d8c9c
memcpy((u_char*)pt, (u_char*)&MissionStartData, sizeof(MISSION_DATA));
}
return pt - buffer;
}
// saves chase to file
int CutRec_SaveReplayToFile(char* filename)
{
int size = CutRec_SaveReplayToBuffer((char*)_other_buffer);
FILE* fp = fopen(filename, "wb");
if (fp)
{
fwrite((char*)_other_buffer, 1, size, fp);
fclose(fp);
return 1;
}
return 0;
}
int CutRec_SaveChase()
{
char filename[64];
FILE* temp;
int cnt;
cnt = 2;
// put files to folder
sprintf(filename, "CUT%d", gCutsceneAsReplay);
_mkdir(filename);
// find suitable filename
while (cnt < 14)
{
sprintf(filename, "CUT%d/CUT%d_%d.D2RP", gCutsceneAsReplay, gCutsceneAsReplay, cnt);
if ((temp = fopen(filename, "rb")) != NULL)
{
fclose(temp);
cnt++;
}
else
break;
}
if (cnt > 14)
return 0;
if(CutRec_SaveReplayToFile(filename))
{
printInfo("Chase replay '%s' saved\n", filename);
if (gCutsceneChaseAutoTest != 0)
gAutoTestStats[gCutsceneChaseAutoTest].saved = 1;
return 1;
}
return 0;
}
int CutRec_RecordCarPad(CAR_DATA* cp, uint* t0, char* t1, char* t2)
{
if (gCutsceneAsReplay == 0 || NoPlayerControl || (-*cp->ai.padid) != gCutsceneAsReplay_PlayerId)
return 0;
*t0 = Pads[0].mapped; // [A] padid might be wrong
*t1 = Pads[0].mapanalog[2];
*t2 = Pads[0].type & 4;
if (gStopPadReads != 0)
{
*t0 = CAR_PAD_BRAKE;
if (cp->hd.wheel_speed <= 0x9000)
*t0 = CAR_PAD_HANDBRAKE;
*t1 = 0;
*t2 = 1;
}
cjpRecord(-*cp->ai.padid, t0, t1, t2);
return 1;
}
int CutRec_RecordPad(PLAYER* pl, uint* t0, char* t1, char* t2)
{
if (gCutsceneAsReplay == 0 || NoPlayerControl || (-pl->padid) != gCutsceneAsReplay_PlayerId)
return 0;
*t0 = Pads[0].mapped;
*t1 = Pads[0].mapanalog[2];
*t2 = Pads[0].type & 4;
// [A] handle REDRIVER2 dedicated car entry button
if (*t0 & TANNER_PAD_ACTION_DED)
{
*t0 &= ~TANNER_PAD_ACTION_DED;
*t0 |= TANNER_PAD_ACTION;
}
cjpRecord(-pl->padid, t0, t1, t2);
return 1;
}
int CutRec_IsRecording()
{
if (gCutsceneAsReplay == 0)
return 0;
return CurrentGameMode != GAMEMODE_REPLAY;
}
int CutRec_IsPlaying()
{
if (gCutsceneAsReplay == 0)
return 0;
return CurrentGameMode == GAMEMODE_REPLAY;
}
#endif // CUTSCENE_RECORDER