#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