2020-12-28 09:51:40 +01:00
|
|
|
#include "driver2.h"
|
|
|
|
#include "replays.h"
|
|
|
|
#include "map.h"
|
|
|
|
#include "spool.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "cutscene.h"
|
|
|
|
#include "players.h"
|
|
|
|
#include "glaunch.h"
|
|
|
|
#include "mission.h"
|
|
|
|
#include "director.h"
|
|
|
|
#include "camera.h"
|
|
|
|
#include "civ_ai.h"
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
#include "STRINGS.H"
|
2020-11-13 18:48:25 +01:00
|
|
|
#include "RAND.H"
|
2020-05-20 20:30:02 +02:00
|
|
|
|
2020-05-19 21:00:39 +02:00
|
|
|
char AnalogueUnpack[16] = {
|
|
|
|
0, -51, -63, -75, -87, -99, -111, -123,
|
|
|
|
0, 51, 63, 75, 87, 99, 111, 123
|
|
|
|
};
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-04-17 20:27:24 +02:00
|
|
|
int gOutOfTape = 0;
|
|
|
|
|
2020-04-17 21:55:31 +02:00
|
|
|
REPLAY_PARAMETER_BLOCK *ReplayParameterPtr = NULL;
|
|
|
|
|
- implement MRCommitThreadGenocide, MRStartThread, MRFunction, MRHandleCarRequests, MRCreateCar, MRCancelCarRequest, SetPlayerMessage, SetMissionMessage, PauseMissionTimer, PreProcessTargets, HandleGameOver, CompleteAllActiveTargets, SetMissionComplete, SetMissionOver, ActivateNextFlag, CalcLapTime, SetCarToBeStolen, MakePhantomCarEqualPlayerCar
- bunch of pretty mission code
2020-05-16 17:42:55 +02:00
|
|
|
REPLAY_STREAM ReplayStreams[8];
|
|
|
|
int NumReplayStreams = 1;
|
|
|
|
|
2020-05-18 20:32:30 +02:00
|
|
|
char *ReplayStart;
|
|
|
|
char *replayptr = NULL;
|
|
|
|
int ReplaySize = 0;
|
|
|
|
|
2020-12-08 18:12:17 +01:00
|
|
|
int PingBufferPos = 0;
|
2020-10-31 01:11:58 +01:00
|
|
|
PING_PACKET *PingBuffer = NULL;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
|
|
|
SXYPAIR *PlayerWayRecordPtr = NULL;
|
|
|
|
PLAYBACKCAMERA *PlaybackCamera = NULL;
|
|
|
|
|
|
|
|
int TimeToWay = 0;
|
|
|
|
short PlayerWaypoints = 0;
|
|
|
|
int way_distance = 0;
|
2020-10-20 19:35:54 +02:00
|
|
|
int gUseStoredPings = 1;
|
2020-12-09 09:33:57 +01:00
|
|
|
char ReplayMode = 0;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-12-09 09:33:57 +01:00
|
|
|
#define REPLAY_IDENT (('D' << 24) | ('2' << 16) | ('R' << 8) | 'P' )
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
void InitPadRecording(void)
|
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
char *bufferEnd;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
int remain;
|
2020-05-18 20:32:30 +02:00
|
|
|
int i;
|
2020-03-29 22:33:32 +02:00
|
|
|
|
|
|
|
gOutOfTape = 0;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-21 09:30:50 +02:00
|
|
|
if (gLoadedReplay == 0 &&
|
|
|
|
CurrentGameMode != GAMEMODE_REPLAY &&
|
|
|
|
CurrentGameMode != GAMEMODE_DIRECTOR)
|
2020-05-18 20:32:30 +02:00
|
|
|
{
|
2020-03-29 22:33:32 +02:00
|
|
|
NumReplayStreams = 0;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
ReplayStart = (char*)_replay_buffer;
|
2020-05-18 20:32:30 +02:00
|
|
|
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK *)ReplayStart;
|
|
|
|
|
2020-05-20 17:34:30 +02:00
|
|
|
PlayerWayRecordPtr = (SXYPAIR *)(ReplayParameterPtr + 1);
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
PlaybackCamera = (PLAYBACKCAMERA *)(PlayerWayRecordPtr + MAX_REPLAY_WAYPOINTS);
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-31 01:11:58 +01:00
|
|
|
PingBuffer = (PING_PACKET *)(PlaybackCamera + MAX_REPLAY_CAMERAS);
|
|
|
|
setMem8((u_char*)PingBuffer, -1, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
replayptr = (char*)(PingBuffer + MAX_REPLAY_PINGS);
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// FIXME: is that correct?
|
|
|
|
bufferEnd = replayptr-13380;
|
|
|
|
remain = (uint)ReplayStart - (uint)bufferEnd - CalcInGameCutsceneSize();
|
2020-05-18 20:32:30 +02:00
|
|
|
|
|
|
|
for (i = 0; i < NumPlayers; i++)
|
2020-05-19 17:45:40 +02:00
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
AllocateReplayStream(&ReplayStreams[i], remain / sizeof(PADRECORD) / NumPlayers);
|
2020-05-19 17:45:40 +02:00
|
|
|
NumReplayStreams++;
|
|
|
|
}
|
2020-05-18 20:32:30 +02:00
|
|
|
|
|
|
|
ReplaySize = (replayptr - ReplayStart);
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-18 20:32:30 +02:00
|
|
|
else
|
|
|
|
{
|
2020-11-17 17:01:20 +01:00
|
|
|
// reset stream count as cutscene/chase can increase it
|
|
|
|
NumReplayStreams = NumPlayers;
|
|
|
|
|
2020-05-18 20:32:30 +02:00
|
|
|
for (i = 0; i < NumReplayStreams; i++)
|
|
|
|
{
|
|
|
|
ReplayStreams[i].playbackrun = 0;
|
2020-05-20 23:33:21 +02:00
|
|
|
ReplayStreams[i].PadRecordBuffer = ReplayStreams[i].InitialPadRecordBuffer;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-18 20:32:30 +02:00
|
|
|
|
|
|
|
TimeToWay = 150;
|
2020-03-29 22:33:32 +02:00
|
|
|
PlayerWaypoints = 0;
|
|
|
|
way_distance = 100;
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-03-29 22:33:32 +02:00
|
|
|
InitDirectorVariables();
|
|
|
|
InitInGameCutsceneVariables();
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
int SaveReplayToBuffer(char *buffer)
|
|
|
|
{
|
2020-05-27 18:02:16 +02:00
|
|
|
REPLAY_STREAM_HEADER *sheader;
|
|
|
|
REPLAY_SAVE_HEADER *header;
|
|
|
|
|
|
|
|
if (buffer == NULL)
|
2020-08-26 16:56:22 +02:00
|
|
|
return 0x3644;
|
2020-05-27 18:02:16 +02:00
|
|
|
|
|
|
|
char* pt = buffer;
|
|
|
|
header = (REPLAY_SAVE_HEADER*)pt;
|
|
|
|
pt += sizeof(REPLAY_SAVE_HEADER);
|
|
|
|
|
2021-02-15 17:27:55 +01:00
|
|
|
header->magic = DRIVER2_REPLAY_MAGIC;
|
2020-05-27 18:02:16 +02:00
|
|
|
header->GameLevel = GameLevel;
|
|
|
|
header->GameType = GameType;
|
|
|
|
header->MissionNumber = gCurrentMissionNumber;
|
2020-11-17 17:01:20 +01:00
|
|
|
|
|
|
|
header->NumReplayStreams = NumReplayStreams - NumCutsceneStreams;
|
2020-05-27 18:02:16 +02:00
|
|
|
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];
|
|
|
|
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)&header->SavedData, (u_char*)&MissionEndData, sizeof(MISSION_DATA));
|
2020-05-27 18:02:16 +02:00
|
|
|
|
|
|
|
// write each stream data
|
2020-05-27 20:07:54 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
2020-08-31 11:14:48 +02:00
|
|
|
extern int gCutsceneAsReplay;
|
2020-05-27 20:07:54 +02:00
|
|
|
int numStreams = gCutsceneAsReplay ? NumReplayStreams : NumPlayers;
|
|
|
|
|
|
|
|
for (int i = 0; i < numStreams; i++)
|
|
|
|
#else
|
|
|
|
for (int i = 0; i < NumPlayers; i++)
|
|
|
|
#endif
|
2020-05-27 18:02:16 +02:00
|
|
|
{
|
|
|
|
sheader = (REPLAY_STREAM_HEADER *)pt;
|
|
|
|
pt += sizeof(REPLAY_STREAM_HEADER);
|
|
|
|
|
|
|
|
REPLAY_STREAM* srcStream = &ReplayStreams[i];
|
|
|
|
|
|
|
|
// copy source type
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)&sheader->SourceType, (u_char*)&srcStream->SourceType, sizeof(STREAM_SOURCE));
|
2020-10-16 20:30:22 +02:00
|
|
|
sheader->Size = srcStream->padCount * sizeof(PADRECORD); // srcStream->PadRecordBufferEnd - srcStream->InitialPadRecordBuffer;
|
2020-05-27 18:02:16 +02:00
|
|
|
sheader->Length = srcStream->length;
|
|
|
|
|
|
|
|
int size = (sheader->Size + sizeof(PADRECORD)) & -4;
|
|
|
|
|
|
|
|
// copy pad data to write buffer
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)srcStream->InitialPadRecordBuffer, size);
|
2020-05-27 18:02:16 +02:00
|
|
|
|
|
|
|
pt += size;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-27 18:02:16 +02:00
|
|
|
|
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (gCutsceneAsReplay == 0)
|
|
|
|
#endif
|
|
|
|
{
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)ReplayParameterPtr, sizeof(REPLAY_PARAMETER_BLOCK));
|
2020-05-27 18:02:16 +02:00
|
|
|
pt += sizeof(REPLAY_PARAMETER_BLOCK);
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-27 18:02:16 +02:00
|
|
|
|
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (gCutsceneAsReplay == 0)
|
|
|
|
#endif
|
|
|
|
{
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)PlayerWayRecordPtr, sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS);
|
2020-10-17 08:45:09 +02:00
|
|
|
pt += sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS;
|
2020-05-27 18:02:16 +02:00
|
|
|
}
|
|
|
|
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)PlaybackCamera, sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS);
|
2020-10-17 08:45:09 +02:00
|
|
|
pt += sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS;
|
2020-05-27 18:02:16 +02:00
|
|
|
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)PingBuffer, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
|
2020-10-31 01:11:58 +01:00
|
|
|
pt += sizeof(PING_PACKET) * MAX_REPLAY_PINGS;
|
2020-05-27 18:02:16 +02:00
|
|
|
|
2020-05-27 20:07:54 +02:00
|
|
|
// [A] is that ever valid?
|
|
|
|
if (gHaveStoredData)
|
2020-05-27 18:02:16 +02:00
|
|
|
{
|
|
|
|
header->HaveStoredData = 0x91827364; // -0x6e7d8c9c
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy(pt, (u_char*)&MissionStartData, sizeof(MISSION_DATA));
|
2020-05-27 18:02:16 +02:00
|
|
|
}
|
|
|
|
|
2020-10-05 17:26:22 +02:00
|
|
|
#ifdef PSX
|
2020-05-27 18:02:16 +02:00
|
|
|
return 0x3644; // size?
|
2020-10-05 17:26:22 +02:00
|
|
|
#else
|
|
|
|
return pt - buffer;
|
|
|
|
#endif
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
2020-11-04 17:18:39 +01:00
|
|
|
#include "../utils/ini.h"
|
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
int gCutsceneAsReplay = 0;
|
|
|
|
int gCutsceneAsReplay_PlayerId = 0;
|
|
|
|
int gCutsceneAsReplay_PlayerChanged = 0;
|
2020-11-17 11:10:59 +01:00
|
|
|
int gCutsceneAsReplay_ReserveSlots = 2;
|
2020-05-20 23:33:21 +02:00
|
|
|
char gCutsceneRecorderPauseText[64] = { 0 };
|
2020-10-09 22:13:49 +02:00
|
|
|
char gCurrentChasePauseText[64] = { 0 };
|
|
|
|
|
|
|
|
void 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);
|
|
|
|
}
|
2020-05-20 23:33:21 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2020-10-04 20:19:53 +02:00
|
|
|
printWarning("cutscene size: %d\n", size);
|
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
LoadfileSeg(filename, (char*)_other_buffer, offset, size);
|
2020-05-20 23:33:21 +02:00
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
int result = LoadReplayFromBuffer((char*)_other_buffer);
|
2020-08-31 11:14:48 +02:00
|
|
|
|
|
|
|
return result;
|
2020-05-20 23:33:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
printError("Invalid cutscene subindex or mission!\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2020-11-04 17:18:39 +01:00
|
|
|
|
2020-11-11 19:30:16 +01:00
|
|
|
void LoadCutsceneRecorder(char* configFilename)
|
2020-11-04 17:18:39 +01:00
|
|
|
{
|
|
|
|
ini_t* config;
|
|
|
|
int loadExistingCutscene;
|
|
|
|
int subindex;
|
|
|
|
|
2020-11-11 19:30:16 +01:00
|
|
|
config = ini_load(configFilename);
|
2020-11-04 17:18:39 +01:00
|
|
|
|
|
|
|
if(!config)
|
|
|
|
{
|
2020-11-11 19:30:16 +01:00
|
|
|
printError("Unable to open '%s'!\n", configFilename);
|
2020-11-04 17:18:39 +01:00
|
|
|
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);
|
2020-11-17 11:10:59 +01:00
|
|
|
ini_sget(config, "settings", "reserveSlots", "%d", &gCutsceneAsReplay_ReserveSlots);
|
2020-11-04 17:18:39 +01:00
|
|
|
ini_sget(config, "settings", "subindex", "%d", &subindex);
|
2020-11-17 11:10:59 +01:00
|
|
|
|
|
|
|
// totally limited by streams
|
|
|
|
if(gCutsceneAsReplay_ReserveSlots > 8)
|
|
|
|
gCutsceneAsReplay_ReserveSlots = 8;
|
2020-11-04 17:18:39 +01:00
|
|
|
|
|
|
|
if(loadExistingCutscene)
|
|
|
|
{
|
|
|
|
if(!LoadCutsceneAsReplay(subindex))
|
|
|
|
{
|
|
|
|
ini_free(config);
|
|
|
|
|
|
|
|
gLoadedReplay = 0;
|
|
|
|
gCutsceneAsReplay = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gLoadedReplay = 1;
|
|
|
|
CurrentGameMode = GAMEMODE_REPLAY;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
char curStreamName[40];
|
|
|
|
STREAM_SOURCE* stream;
|
|
|
|
|
|
|
|
InitPadRecording();
|
|
|
|
|
|
|
|
ini_sget(config, "settings", "streams", "%d", &NumReplayStreams);
|
|
|
|
|
|
|
|
// initialize all streams
|
|
|
|
for(i = 0; i < 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);
|
|
|
|
|
|
|
|
LaunchGame();
|
|
|
|
|
|
|
|
gLoadedReplay = 0;
|
|
|
|
gCutsceneAsReplay = 0;
|
|
|
|
}
|
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
#endif // CUTSCENE_RECORDER
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
int LoadReplayFromBuffer(char *buffer)
|
|
|
|
{
|
2020-05-20 20:30:02 +02:00
|
|
|
REPLAY_SAVE_HEADER *header;
|
|
|
|
REPLAY_STREAM_HEADER *sheader;
|
|
|
|
|
|
|
|
char* pt = buffer;
|
|
|
|
|
|
|
|
header = (REPLAY_SAVE_HEADER*)pt;
|
|
|
|
|
2021-02-15 17:27:55 +01:00
|
|
|
if (header->magic != DRIVER2_REPLAY_MAGIC)
|
2020-05-20 20:30:02 +02:00
|
|
|
return 0;
|
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
ReplayStart = replayptr = (char*)_replay_buffer;
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
GameLevel = header->GameLevel;
|
|
|
|
GameType = (GAMETYPE)header->GameType;
|
2020-05-20 23:33:21 +02:00
|
|
|
|
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if(gCutsceneAsReplay == 0)
|
|
|
|
#endif
|
|
|
|
gCurrentMissionNumber = header->MissionNumber;
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
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];
|
|
|
|
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)&MissionEndData, (u_char*)&header->SavedData, sizeof(MISSION_DATA));
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
pt = (char*)(header+1);
|
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
int maxLength = 0;
|
2020-05-20 20:30:02 +02:00
|
|
|
for (int i = 0; i < NumReplayStreams; i++)
|
|
|
|
{
|
|
|
|
sheader = (REPLAY_STREAM_HEADER *)pt;
|
|
|
|
pt += sizeof(REPLAY_STREAM_HEADER);
|
|
|
|
|
|
|
|
REPLAY_STREAM* destStream = &ReplayStreams[i];
|
2020-10-04 20:19:53 +02:00
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
// copy source type
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)&destStream->SourceType, (u_char*)&sheader->SourceType, sizeof(STREAM_SOURCE));
|
2020-05-20 20:30:02 +02:00
|
|
|
|
2020-10-04 20:19:53 +02:00
|
|
|
int size = (sheader->Size + sizeof(PADRECORD)) & -4;
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
// init buffers
|
2020-10-04 20:19:53 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (gCutsceneAsReplay)
|
|
|
|
{
|
|
|
|
AllocateReplayStream(destStream, 4000);
|
|
|
|
|
|
|
|
// copy pad data and advance buffer
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)destStream->PadRecordBuffer, pt, size);
|
2020-10-04 20:19:53 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
destStream->InitialPadRecordBuffer = (PADRECORD*)replayptr;
|
|
|
|
destStream->PadRecordBuffer = (PADRECORD*)replayptr;
|
2020-10-16 20:30:22 +02:00
|
|
|
destStream->PadRecordBufferEnd = (PADRECORD*)(replayptr + size);
|
2020-10-04 20:19:53 +02:00
|
|
|
destStream->playbackrun = 0;
|
2020-10-16 20:30:22 +02:00
|
|
|
destStream->padCount = sheader->Size / sizeof(PADRECORD);
|
2020-10-04 20:19:53 +02:00
|
|
|
|
|
|
|
// copy pad data and advance buffer
|
|
|
|
memcpy(replayptr, pt, size);
|
|
|
|
replayptr += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
pt += size;
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
destStream->length = sheader->Length;
|
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
if (sheader->Length > maxLength)
|
|
|
|
maxLength = sheader->Length;
|
2020-05-20 20:30:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ReplayParameterPtr = (REPLAY_PARAMETER_BLOCK *)replayptr;
|
2020-05-20 23:33:21 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (gCutsceneAsReplay != 0)
|
|
|
|
{
|
|
|
|
memset(ReplayParameterPtr, 0, sizeof(REPLAY_PARAMETER_BLOCK));
|
|
|
|
ReplayParameterPtr->RecordingEnd = maxLength;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)ReplayParameterPtr, pt, sizeof(REPLAY_PARAMETER_BLOCK));
|
2020-05-20 23:33:21 +02:00
|
|
|
pt += sizeof(REPLAY_PARAMETER_BLOCK);
|
|
|
|
}
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
PlayerWayRecordPtr = (SXYPAIR *)(ReplayParameterPtr + 1);
|
2020-05-20 23:33:21 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (gCutsceneAsReplay != 0)
|
|
|
|
{
|
2020-10-17 08:45:09 +02:00
|
|
|
memset(PlayerWayRecordPtr, 0, sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS);
|
2020-05-20 23:33:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)PlayerWayRecordPtr, pt, sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS);
|
2020-10-17 08:45:09 +02:00
|
|
|
pt += sizeof(SXYPAIR) * MAX_REPLAY_WAYPOINTS;
|
2020-05-20 23:33:21 +02:00
|
|
|
}
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
PlaybackCamera = (PLAYBACKCAMERA *)(PlayerWayRecordPtr + MAX_REPLAY_WAYPOINTS);
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)PlaybackCamera, pt, sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS);
|
2020-10-17 08:45:09 +02:00
|
|
|
pt += sizeof(PLAYBACKCAMERA) * MAX_REPLAY_CAMERAS;
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
PingBufferPos = 0;
|
2020-10-31 01:11:58 +01:00
|
|
|
PingBuffer = (PING_PACKET *)(PlaybackCamera + MAX_REPLAY_CAMERAS);
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)PingBuffer, pt, sizeof(PING_PACKET) * MAX_REPLAY_PINGS);
|
2020-10-31 01:11:58 +01:00
|
|
|
pt += sizeof(PING_PACKET) * MAX_REPLAY_PINGS;
|
2020-05-20 20:30:02 +02:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
replayptr = (char*)(PingBuffer + MAX_REPLAY_PINGS);
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
if (header->HaveStoredData == 0x91827364) // -0x6e7d8c9c
|
|
|
|
{
|
2020-12-28 11:07:24 +01:00
|
|
|
memcpy((u_char*)&MissionStartData, pt, sizeof(MISSION_DATA));
|
2020-05-20 20:30:02 +02:00
|
|
|
gHaveStoredData = 1;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-20 20:30:02 +02:00
|
|
|
|
|
|
|
return 1;
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-11-14 05:23:03 +01:00
|
|
|
#ifndef PSX
|
|
|
|
int LoadUserAttractReplay(int mission, int userId)
|
|
|
|
{
|
|
|
|
char customFilename[64];
|
|
|
|
|
|
|
|
if (userId >= 0 && userId < gNumUserChases)
|
|
|
|
{
|
|
|
|
sprintf(customFilename, "REPLAYS\\User\\%s\\ATTRACT.%d", gUserReplayFolderList[userId], mission);
|
|
|
|
|
|
|
|
if (FileExists(customFilename))
|
|
|
|
{
|
2021-04-04 11:24:16 +02:00
|
|
|
if (Loadfile(customFilename, (char*)_other_buffer))
|
|
|
|
return LoadReplayFromBuffer((char*)_other_buffer);
|
2020-11-14 05:23:03 +01:00
|
|
|
}
|
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-11-14 05:23:03 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
int LoadAttractReplay(int mission)
|
|
|
|
{
|
2020-05-20 20:30:02 +02:00
|
|
|
char filename[32];
|
2020-03-29 22:33:32 +02:00
|
|
|
|
2020-11-13 18:48:25 +01:00
|
|
|
#ifndef PSX
|
2020-11-14 05:23:03 +01:00
|
|
|
int userId = -1;
|
2020-11-13 18:48:25 +01:00
|
|
|
|
|
|
|
// [A] REDRIVER2 PC - custom attract replays
|
|
|
|
if (gNumUserChases)
|
|
|
|
{
|
2020-11-14 05:23:03 +01:00
|
|
|
userId = rand() % (gNumUserChases + 1);
|
2020-11-13 18:48:25 +01:00
|
|
|
|
2020-11-14 05:23:03 +01:00
|
|
|
if (userId == gNumUserChases)
|
|
|
|
userId = -1;
|
2020-11-13 18:48:25 +01:00
|
|
|
}
|
|
|
|
|
2020-11-14 05:23:03 +01:00
|
|
|
if (LoadUserAttractReplay(mission, userId))
|
|
|
|
{
|
|
|
|
printInfo("Loaded custom attract replay (%d) by %s\n", mission, gUserReplayFolderList[userId]);
|
|
|
|
return 1;
|
|
|
|
}
|
2020-11-13 18:48:25 +01:00
|
|
|
#endif
|
2020-05-20 20:30:02 +02:00
|
|
|
|
2020-11-14 05:23:03 +01:00
|
|
|
sprintf(filename, "REPLAYS\\ATTRACT.%d", mission);
|
|
|
|
|
2020-05-20 20:30:02 +02:00
|
|
|
if (!FileExists(filename))
|
|
|
|
return 0;
|
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
if (!Loadfile(filename, (char*)_other_buffer))
|
2020-05-20 20:30:02 +02:00
|
|
|
return 0;
|
|
|
|
|
2021-04-04 11:24:16 +02:00
|
|
|
return LoadReplayFromBuffer((char*)_other_buffer);
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
char GetPingInfo(char *cookieCount)
|
|
|
|
{
|
2020-05-29 18:44:33 +02:00
|
|
|
char retCarId;
|
2020-10-31 01:11:58 +01:00
|
|
|
PING_PACKET *pp;
|
2020-03-29 22:33:32 +02:00
|
|
|
|
2020-05-29 18:44:33 +02:00
|
|
|
retCarId = -1;
|
|
|
|
|
|
|
|
pp = PingBuffer + PingBufferPos;
|
2020-05-18 21:10:55 +02:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
if (PingBuffer != NULL && PingBufferPos < MAX_REPLAY_PINGS)
|
2020-05-18 21:10:55 +02:00
|
|
|
{
|
2020-05-29 18:44:33 +02:00
|
|
|
if (pp->frame != 0xffff)
|
2020-05-18 21:10:55 +02:00
|
|
|
{
|
2020-05-29 18:44:33 +02:00
|
|
|
if ((CameraCnt - frameStart & 0xffffU) < pp->frame)
|
2020-03-29 22:33:32 +02:00
|
|
|
return -1;
|
2020-05-18 21:10:55 +02:00
|
|
|
|
2020-05-29 18:44:33 +02:00
|
|
|
retCarId = pp->carId;
|
|
|
|
*cookieCount = pp->cookieCount;
|
|
|
|
|
|
|
|
PingBufferPos++;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-11-12 19:44:04 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
printInfo("-1 frame!\n");
|
|
|
|
}
|
2020-05-29 18:44:33 +02:00
|
|
|
|
|
|
|
return retCarId;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-18 21:10:55 +02:00
|
|
|
|
2020-03-29 22:33:32 +02:00
|
|
|
return -1;
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
// [A] Stores ping info into replay buffer
|
|
|
|
int StorePingInfo(int cookieCount, int carId)
|
|
|
|
{
|
2020-11-17 13:13:45 +01:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
2020-11-17 17:01:20 +01:00
|
|
|
PING_PACKET* packet;
|
2020-11-17 13:13:45 +01:00
|
|
|
|
2020-11-17 17:01:20 +01:00
|
|
|
//extern int gCutsceneAsReplay;
|
2020-11-17 13:13:45 +01:00
|
|
|
if (gCutsceneAsReplay == 0)
|
|
|
|
return 0;
|
|
|
|
|
2020-10-20 19:35:54 +02:00
|
|
|
if (CurrentGameMode == GAMEMODE_REPLAY || gInGameChaseActive != 0)
|
|
|
|
return 0;
|
2020-11-17 13:13:45 +01:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
if(PingBuffer != NULL && PingBufferPos < MAX_REPLAY_PINGS)
|
|
|
|
{
|
2020-10-21 09:30:50 +02:00
|
|
|
packet = &PingBuffer[PingBufferPos++];
|
|
|
|
packet->frame = (CameraCnt - frameStart & 0xffffU);
|
2020-11-17 11:10:59 +01:00
|
|
|
packet->carId = carId;
|
2020-11-12 19:44:04 +01:00
|
|
|
|
2020-10-21 09:30:50 +02:00
|
|
|
packet->cookieCount = cookieCount;
|
2020-10-17 08:45:09 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2020-11-17 13:13:45 +01:00
|
|
|
#endif
|
2020-10-17 08:45:09 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-20 19:35:54 +02:00
|
|
|
// [A] returns 1 if can use ping buffer
|
|
|
|
int IsPingInfoAvailable()
|
|
|
|
{
|
2020-10-24 16:44:45 +02:00
|
|
|
// [A] loaded replays pings temporarily disabled...
|
|
|
|
|
|
|
|
if (gUseStoredPings == 0 || gInGameChaseActive == 0)// && gLoadedReplay == 0)
|
2020-10-20 19:35:54 +02:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return PingBuffer != NULL && PingBufferPos < MAX_REPLAY_PINGS;
|
|
|
|
}
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-29 22:33:32 +02:00
|
|
|
int valid_region(int x, int z)
|
2020-03-27 21:47:29 +01:00
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
XYPAIR region_coords;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
int region;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
region_coords.x = (x >> 16) + regions_across / 2;
|
|
|
|
region_coords.y = (z >> 16) + regions_down / 2;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
if (region_coords.x >= 0 && region_coords.x <= regions_across &&
|
|
|
|
region_coords.y >= 0 && region_coords.y <= regions_down)
|
|
|
|
{
|
|
|
|
region = region_coords.x + region_coords.y * regions_across;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
if (region != regions_unpacked[0])
|
|
|
|
{
|
|
|
|
if (region == regions_unpacked[1])
|
|
|
|
return region + 1;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
if (region == regions_unpacked[2])
|
|
|
|
return region + 1;
|
2020-05-09 10:00:06 +02:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
if (region != regions_unpacked[3])
|
|
|
|
return 0;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-10-13 20:43:20 +02:00
|
|
|
|
|
|
|
return region + 1;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-10-13 20:43:20 +02:00
|
|
|
|
2020-03-29 22:33:32 +02:00
|
|
|
return 0;
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-12-09 09:33:57 +01:00
|
|
|
// [D] [T]
|
|
|
|
int Get(int stream, u_int *pt0)
|
|
|
|
{
|
|
|
|
REPLAY_STREAM* rstream;
|
|
|
|
|
|
|
|
if (stream < NumReplayStreams)
|
|
|
|
{
|
|
|
|
rstream = &ReplayStreams[stream];
|
|
|
|
|
|
|
|
if (rstream->PadRecordBuffer + 1 <= rstream->PadRecordBufferEnd)
|
|
|
|
{
|
|
|
|
uint t0 = (rstream->PadRecordBuffer->pad << 8) | rstream->PadRecordBuffer->analogue;
|
|
|
|
*pt0 = t0;
|
|
|
|
|
|
|
|
if (rstream->playbackrun < rstream->PadRecordBuffer->run)
|
|
|
|
{
|
|
|
|
rstream->playbackrun++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rstream->PadRecordBuffer++;
|
|
|
|
rstream->playbackrun = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*pt0 = 0x10;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// [D] [T]
|
|
|
|
int Put(int stream, u_int*pt0)
|
|
|
|
{
|
|
|
|
REPLAY_STREAM *rstream;
|
|
|
|
u_int t0;
|
|
|
|
PADRECORD *padbuf;
|
|
|
|
|
|
|
|
rstream = &ReplayStreams[stream];
|
|
|
|
|
|
|
|
if (rstream->PadRecordBuffer + 1 >= rstream->PadRecordBufferEnd)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
padbuf = rstream->PadRecordBuffer;
|
|
|
|
t0 = *pt0;
|
|
|
|
|
|
|
|
if (CameraCnt != 0 && padbuf->run != 0xEE)
|
|
|
|
{
|
|
|
|
if (padbuf->pad == ((t0 >> 8) & 0xff) &&
|
|
|
|
padbuf->analogue == (t0 & 0xff) &&
|
2021-03-25 19:44:08 +01:00
|
|
|
padbuf->run != 143)
|
2020-12-09 09:33:57 +01:00
|
|
|
{
|
|
|
|
padbuf->run++;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
padbuf++;
|
|
|
|
|
|
|
|
padbuf->pad = (t0 >> 8) & 0xFF;
|
|
|
|
padbuf->analogue = t0 & 0xFF;
|
|
|
|
padbuf->run = 0;
|
|
|
|
|
|
|
|
rstream->PadRecordBuffer = padbuf;
|
|
|
|
rstream->padCount++;
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-12-09 09:33:57 +01:00
|
|
|
return 1;
|
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-12-09 09:33:57 +01:00
|
|
|
padbuf->pad = (t0 >> 8) & 0xFF;
|
|
|
|
padbuf->analogue = t0 & 0xFF;
|
|
|
|
padbuf->run = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-12-08 17:45:14 +01:00
|
|
|
int cjpPlay(int stream, u_int *ppad, char *psteer, char *ptype)
|
2020-03-27 21:47:29 +01:00
|
|
|
{
|
2020-05-19 21:00:39 +02:00
|
|
|
int ret;
|
|
|
|
int t1;
|
2020-12-08 17:45:14 +01:00
|
|
|
u_int t0;
|
2020-05-19 21:00:39 +02:00
|
|
|
|
2020-05-20 23:33:21 +02:00
|
|
|
#ifdef CUTSCENE_RECORDER
|
|
|
|
if (stream < 0)
|
|
|
|
stream = -stream;
|
|
|
|
#endif
|
|
|
|
|
2020-05-19 21:00:39 +02:00
|
|
|
ret = Get(stream, &t0);
|
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
t1 = (t0 >> 8) & 0xF;
|
2020-05-19 21:00:39 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
*ppad = t0 & 0xF0FC;
|
2020-05-19 21:00:39 +02:00
|
|
|
|
|
|
|
if (t1 == 0)
|
|
|
|
{
|
|
|
|
*psteer = 0;
|
|
|
|
*ptype = 0;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-19 21:00:39 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
*psteer = AnalogueUnpack[t1];
|
|
|
|
*ptype = 4;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-19 21:00:39 +02:00
|
|
|
|
|
|
|
return ret;
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-12-08 17:45:14 +01:00
|
|
|
void cjpRecord(int stream, u_int *ppad, char *psteer, char *ptype)
|
2020-03-27 21:47:29 +01:00
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
int tmp;
|
2020-05-20 13:06:29 +02:00
|
|
|
int t1;
|
2020-12-08 17:45:14 +01:00
|
|
|
u_int t0;
|
2020-03-29 22:33:32 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
if (stream > -1 && stream < NumReplayStreams)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
2020-03-29 22:33:32 +02:00
|
|
|
RecordWaypoint();
|
2020-05-20 10:28:23 +02:00
|
|
|
|
|
|
|
if ((*ptype & 4U) == 0)
|
|
|
|
{
|
2020-05-20 13:06:29 +02:00
|
|
|
t1 = 0;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-20 10:28:23 +02:00
|
|
|
else
|
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
if (*psteer < -45)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
tmp = -45 - *psteer >> 0x1f; // [A] still need to figure out this
|
|
|
|
t1 = (((-45 - *psteer) / 6 + tmp >> 1) - tmp) + 1;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-10-13 20:43:20 +02:00
|
|
|
else if (*psteer < 46)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
2020-05-20 13:06:29 +02:00
|
|
|
t1 = 8;
|
2020-05-20 10:28:23 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
tmp = *psteer - 45 >> 0x1f; // [A] still need to figure out this
|
|
|
|
t1 = (((*psteer - 45) / 6 + tmp >> 1) - tmp) + 9;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-20 10:28:23 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
t0 = (t1 & 0xF) << 8 | *ppad & 0xF0FC;
|
2020-05-20 10:28:23 +02:00
|
|
|
|
|
|
|
if (Put(stream, &t0) == 0)
|
|
|
|
{
|
2020-03-29 22:33:32 +02:00
|
|
|
gOutOfTape = 1;
|
|
|
|
}
|
2020-05-20 13:06:29 +02:00
|
|
|
else if(NoPlayerControl == 0)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
2020-05-20 13:06:29 +02:00
|
|
|
ClearCameras = 1;
|
|
|
|
|
|
|
|
if (ReplayMode != 3 && ReplayMode != 8)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
2020-03-29 22:33:32 +02:00
|
|
|
ReplayStreams[stream].length = CameraCnt;
|
2020-05-20 10:28:23 +02:00
|
|
|
ReplayParameterPtr->RecordingEnd = CameraCnt;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
|
|
|
}
|
2020-05-20 10:28:23 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
t1 = (t0 >> 8) & 0xF;
|
2020-05-20 10:28:23 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
if (t1 == 0)
|
2020-05-20 10:28:23 +02:00
|
|
|
{
|
|
|
|
*psteer = 0;
|
|
|
|
*ptype = 0;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-20 10:28:23 +02:00
|
|
|
else
|
|
|
|
{
|
2020-05-20 13:06:29 +02:00
|
|
|
*psteer = AnalogueUnpack[t1];
|
2020-05-20 10:28:23 +02:00
|
|
|
*ptype = 4;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-20 10:28:23 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
*ppad = t0 & 0xF0FC;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-29 22:33:32 +02:00
|
|
|
void AllocateReplayStream(REPLAY_STREAM *stream, int maxpad)
|
2020-03-27 21:47:29 +01:00
|
|
|
{
|
2020-05-18 20:32:30 +02:00
|
|
|
stream->playbackrun = 0;
|
2020-03-29 22:33:32 +02:00
|
|
|
stream->length = 0;
|
2020-10-24 18:35:19 +02:00
|
|
|
stream->padCount = 0;
|
2020-10-05 17:26:22 +02:00
|
|
|
|
2020-05-18 20:32:30 +02:00
|
|
|
stream->InitialPadRecordBuffer = (PADRECORD*)replayptr;
|
|
|
|
stream->PadRecordBuffer = (PADRECORD*)replayptr;
|
|
|
|
|
|
|
|
stream->PadRecordBufferEnd = (PADRECORD *)(replayptr + maxpad * sizeof(PADRECORD));
|
|
|
|
|
|
|
|
if (NoPlayerControl == 0)
|
|
|
|
{
|
|
|
|
*replayptr = 0;
|
|
|
|
|
|
|
|
stream->InitialPadRecordBuffer->analogue = 0;
|
2021-03-25 19:44:08 +01:00
|
|
|
stream->InitialPadRecordBuffer->run = 238;
|
2020-03-29 22:33:32 +02:00
|
|
|
}
|
2020-05-18 20:32:30 +02:00
|
|
|
|
2020-05-20 13:06:29 +02:00
|
|
|
replayptr = (char *)(((uint)replayptr + (maxpad+1) * sizeof(PADRECORD)) & -4);
|
2020-03-27 21:47:29 +01:00
|
|
|
}
|
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
// [D] [T]
|
2020-03-27 21:47:29 +01:00
|
|
|
void RecordWaypoint(void)
|
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
if (TimeToWay > 0)
|
2020-06-13 18:25:19 +02:00
|
|
|
{
|
2020-10-13 20:43:20 +02:00
|
|
|
TimeToWay--;
|
|
|
|
return;
|
|
|
|
}
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-17 08:45:09 +02:00
|
|
|
if (PlayerWaypoints < MAX_REPLAY_WAYPOINTS)
|
2020-10-13 20:43:20 +02:00
|
|
|
{
|
|
|
|
TimeToWay = way_distance;
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
PlayerWayRecordPtr->x = (player[0].pos[0] >> 10);
|
|
|
|
PlayerWayRecordPtr->y = (player[0].pos[2] >> 10);
|
2020-03-27 21:47:29 +01:00
|
|
|
|
2020-10-13 20:43:20 +02:00
|
|
|
PlayerWayRecordPtr++;
|
|
|
|
PlayerWaypoints++;
|
2020-06-13 18:25:19 +02:00
|
|
|
}
|
|
|
|
}
|