summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/BulletTrace.h12
-rw-r--r--src/BulletTraces.cpp3
-rw-r--r--src/BulletTraces.h9
-rw-r--r--src/Pad.cpp2
-rw-r--r--src/Pickup.h33
-rw-r--r--src/Radar.cpp140
-rw-r--r--src/Radar.h7
-rw-r--r--src/User.cpp2
-rw-r--r--src/audio/MusicManager.cpp2
-rw-r--r--src/control/Replay.cpp239
-rw-r--r--src/control/Replay.h207
-rw-r--r--src/entities/CutsceneObject.cpp2
-rw-r--r--src/entities/Entity.cpp2
-rw-r--r--src/entities/Entity.h15
-rw-r--r--src/entities/Ped.h2
-rw-r--r--src/math/Matrix.h3
-rw-r--r--src/render/Hud.cpp4
-rw-r--r--src/templates.h21
18 files changed, 673 insertions, 32 deletions
diff --git a/src/BulletTrace.h b/src/BulletTrace.h
new file mode 100644
index 00000000..d6831ef1
--- /dev/null
+++ b/src/BulletTrace.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "common.h"
+
+struct CBulletTrace
+{
+ CVector m_vecInf;
+ CVector m_vecSup;
+ bool m_bInUse;
+ uint8 m_bFramesInUse;
+ uint8 m_bLifeTime;
+};
diff --git a/src/BulletTraces.cpp b/src/BulletTraces.cpp
new file mode 100644
index 00000000..a873875c
--- /dev/null
+++ b/src/BulletTraces.cpp
@@ -0,0 +1,3 @@
+#include "BulletTraces.h"
+
+CBulletTrace (&CBulletTraces::aTraces)[16] = *(CBulletTrace(*)[16])*(uintptr*)0x72B1B8;
diff --git a/src/BulletTraces.h b/src/BulletTraces.h
new file mode 100644
index 00000000..34d2bcc6
--- /dev/null
+++ b/src/BulletTraces.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "BulletTrace.h"
+
+class CBulletTraces
+{
+public:
+ static CBulletTrace(&aTraces)[16];
+};
diff --git a/src/Pad.cpp b/src/Pad.cpp
index a563e26c..5c151bf4 100644
--- a/src/Pad.cpp
+++ b/src/Pad.cpp
@@ -525,7 +525,7 @@ void CPad::UpdatePads(void)
ControlsManager.AffectPadFromKeyBoard();
ControlsManager.AffectPadFromMouse();
- if ( CReplay::bPlayingBackFromFile )
+ if ( CReplay::IsPlayingBackFromFile() )
bUpdate = false;
if ( bUpdate )
diff --git a/src/Pickup.h b/src/Pickup.h
new file mode 100644
index 00000000..efef15fe
--- /dev/null
+++ b/src/Pickup.h
@@ -0,0 +1,33 @@
+#pragma once
+#include "common.h"
+#include "Object.h"
+
+enum ePickupType
+{
+ PICKUP_NONE = 0,
+ PICKUP_IN_SHOP = 1,
+ PICKUP_ON_STREET = 2,
+ PICKUP_ONCE = 3,
+ PICKUP_ONCE_TIMEOUT = 4,
+ PICKUP_COLLECTABLE1 = 5,
+ PICKUP_IN_SHOP_OUT_OF_STOCK = 6,
+ PICKUP_MONEY = 7,
+ PICKUP_MINE_INACTIVE = 8,
+ PICKUP_MINE_ARMED = 9,
+ PICKUP_NAUTICAL_MINE_INACTIVE = 10,
+ PICKUP_NAUTICAL_MINE_ARMED = 11,
+ PICKUP_FLOATINGPACKAGE = 12,
+ PICKUP_FLOATINGPACKAGE_FLOATING = 13,
+ PICKUP_ON_STREET_SLOW = 14,
+};
+
+class CPickup
+{
+ ePickupType m_eType;
+ uint16 m_wQuantity;
+ CObject *m_pObject;
+ uint32 m_nTimer;
+ int16 m_eModelIndex;
+ int16 m_wIndex;
+ CVector m_vecPos;
+};
diff --git a/src/Radar.cpp b/src/Radar.cpp
index 41ca0780..e9fce51e 100644
--- a/src/Radar.cpp
+++ b/src/Radar.cpp
@@ -10,14 +10,11 @@
#include "Pools.h"
#include "Script.h"
#include "TxdStore.h"
+#include "World.h"
+#include "Streaming.h"
-WRAPPER void CRadar::ClearBlipForEntity(eBlipType type, int32 id) { EAXJMP(0x4A56C0); }
WRAPPER void CRadar::Draw3dMarkers() { EAXJMP(0x4A4C70); }
-WRAPPER float CRadar::LimitRadarPoint(CVector2D *point) { EAXJMP(0x4A4F30); }
-WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); }
-WRAPPER void CRadar::StreamRadarSections(int x, int y) { EAXJMP(0x4A6100); }
WRAPPER int CRadar::ClipRadarPoly(CVector2D *out, CVector2D *in) { EAXJMP(0x4A64A0); }
-WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { EAXJMP(0x4A5530); }
WRAPPER void CRadar::TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in) { EAXJMP(0x4A5300); }
float &CRadar::m_RadarRange = *(float*)0x8E281C;
@@ -148,6 +145,49 @@ void CRadar::DrawRadarMask()
}
#endif
+#if 0
+WRAPPER void CRadar::SetRadarMarkerState(int counter, int flag) { EAXJMP(0x4A5C60); }
+#else
+void CRadar::SetRadarMarkerState(int counter, int flag)
+{
+ CEntity *e;
+ switch (ms_RadarTrace[counter].m_eBlipType) {
+ case BLIP_CAR:
+ e = CPools::GetVehiclePool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ case BLIP_CHAR:
+ e = CPools::GetPedPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ case BLIP_OBJECT:
+ e = CPools::GetObjectPool()->GetAt(ms_RadarTrace[counter].m_nEntityHandle);
+ break;
+ default:
+ return;
+ };
+
+ if (e)
+ e->bHasBlip = flag;
+
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::ClearBlipForEntity(eBlipType type, int32 id) { EAXJMP(0x4A56C0); }
+#else
+void CRadar::ClearBlipForEntity(eBlipType type, int32 id)
+{
+ for (int i = 0; i < 32; i++) {
+ if (type == ms_RadarTrace[i].m_eBlipType && id == ms_RadarTrace[i].m_nEntityHandle) {
+ CRadar::SetRadarMarkerState(i, 0);
+ ms_RadarTrace[i].m_bInUse = 0;
+ ms_RadarTrace[i].m_eBlipType = 0;
+ ms_RadarTrace[i].m_eBlipDisplay = 0;
+ ms_RadarTrace[i].m_IconID = 0;
+ }
+ };
+}
+#endif
+
#if 1
WRAPPER void CRadar::DrawRadarSection(int x, int y) { EAXJMP(0x4A67E0); }
#else
@@ -157,6 +197,61 @@ void CRadar::DrawRadarSection(int x, int y)
}
#endif
+void CRadar::RequestMapSection(int x, int y)
+{
+ ClipRadarTileCoords(&x, &y);
+ CStreaming::RequestModel(gRadarTxdIds[x + 8 * y] + 5500, 5);
+}
+
+void CRadar::RemoveMapSection(int x, int y)
+{
+ if (x >= 0 && x <= 7 && y >= 0 && y <= 7)
+ CStreaming::RemoveModel(gRadarTxdIds[x + 8 * y] + 5500);
+}
+
+#if 0
+WRAPPER void CRadar::StreamRadarSections(int x, int y) { EAXJMP(0x4A6100); }
+#else
+void CRadar::StreamRadarSections(int x, int y)
+{
+ for (int i = 0; i < 8; ++i) {
+ for (int j = 0; j < 8; ++j) {
+ if (i >= x - 1 && i <= x + 1 && j >= y - 1 && j <= y + 1)
+ RequestMapSection(x, y);
+ else
+ RemoveMapSection(x, y);
+ };
+ };
+}
+#endif
+
+#if 0
+WRAPPER float CRadar::LimitRadarPoint(CVector2D *point) { EAXJMP(0x4A4F30); }
+#else
+float CRadar::LimitRadarPoint(CVector2D *point)
+{
+ float div;
+
+ if (point->Magnitude() > 1.0f) {
+ div = 1.0f / point->Magnitude();
+ point->x *= div;
+ point->y *= div;
+ }
+ return point->Magnitude();
+}
+#endif
+
+#if 0
+WRAPPER void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) { EAXJMP(0x4A5530); }
+#else
+void CRadar::TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y) {
+ out->x = in->x - (x * 500.0f - WORLD_MAX_X);
+ out->y = -(in->y - ((8 - y) * 500.0f - WORLD_MAX_Y));
+ out->x *= 0.002f;
+ out->y *= 0.002f;
+}
+#endif
+
#if 0
WRAPPER void CRadar::DrawRadarMap() { EAXJMP(0x4A6C20); }
#else
@@ -164,8 +259,8 @@ void CRadar::DrawRadarMap()
{
CRadar::DrawRadarMask();
- int x = floorf((2000.0f + vec2DRadarOrigin.x) * 0.002f);
- int y = round(7.0f - (2000.0f + vec2DRadarOrigin.y) * 0.002f);
+ int x = floorf((WORLD_MAX_X + vec2DRadarOrigin.x) * 0.002f);
+ int y = round(7.0f - (WORLD_MAX_Y + vec2DRadarOrigin.y) * 0.002f);
CRadar::StreamRadarSections(x, y);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
@@ -407,10 +502,17 @@ WRAPPER void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha) {
#else
void CRadar::DrawRadarSprite(int sprite, float x, float y, int alpha)
{
- float w = SCREEN_SCALE_X(8.0f);
- float h = SCREEN_SCALE_Y(8.0f);
+ RadarSprites[sprite]->Draw(CRect(x - SCREEN_SCALE_X(8.0f), y - SCREEN_SCALE_Y(8.0f), x + SCREEN_SCALE_X(8.0f), y + SCREEN_SCALE_Y(8.0f)), CRGBA(255, 255, 255, alpha));
+}
+#endif
- RadarSprites[sprite]->Draw(CRect(x - w, y - h, x + w, y + h), CRGBA(255, 255, 255, alpha));
+#if 0
+WRAPPER void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha) { EAXJMP(0x4A5870); }
+#else
+void CRadar::ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha)
+{
+ CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size + 1.0f), y - SCREEN_SCALE_Y(size + 1.0f), SCREEN_SCALE_X(size + 1.0f) + x, SCREEN_SCALE_Y(size + 1.0f) + y), CRGBA(0, 0, 0, alpha));
+ CSprite2d::DrawRect(CRect(x - SCREEN_SCALE_X(size), y - SCREEN_SCALE_Y(size), SCREEN_SCALE_X(size) + x, SCREEN_SCALE_Y(size) + y), CRGBA(red, green, blue, alpha));
}
#endif
@@ -511,16 +613,16 @@ void CRadar::GetTextureCorners(int x, int y, CVector2D *out)
}
#endif
-void CRadar::ClipRadarTileCoords(int x, int y)
+void CRadar::ClipRadarTileCoords(int *x, int *y)
{
- if (x < 0)
- x = 0;
- if (x > 7)
- x = 7;
- if (y < 0)
- y = 0;
- if (y > 7)
- y = 7;
+ if (*x < 0)
+ *x = 0;
+ if (*x > 7)
+ *x = 7;
+ if (*y < 0)
+ *y = 0;
+ if (*y > 7)
+ *y = 7;
}
STARTPATCHES
diff --git a/src/Radar.h b/src/Radar.h
index 5a63a83b..19fc9038 100644
--- a/src/Radar.h
+++ b/src/Radar.h
@@ -102,8 +102,10 @@ public:
static void StreamRadarSections(int x, int y);
static int ClipRadarPoly(CVector2D *out, CVector2D *in);
static void TransformRealWorldToTexCoordSpace(CVector2D *out, CVector2D *in, int x, int y);
- static void CRadar::TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in);
+ static void TransformRadarPointToRealWorldSpace(CVector2D *out, CVector2D *in);
static void DrawRadarSection(int x, int y);
+ static void RequestMapSection(int x, int y);
+ static void RemoveMapSection(int x, int y);
static void TransformRadarPointToScreenSpace(CVector2D * out, CVector2D * in);
static void DrawBlips();
static int CalculateBlipAlpha(float dist);
@@ -116,7 +118,8 @@ public:
static void ShowRadarMarker(CVector pos, CRGBA color, float radius);
static void ShowRadarTrace(float x, float y, uint32 size, uint32 red, uint32 green, uint32 blue, uint32 alpha);
static void DrawRadarMask();
+ static void SetRadarMarkerState(int counter, int flag);
static bool DisplayThisBlip(int counter);
static void GetTextureCorners(int x, int y, CVector2D * out);
- static void ClipRadarTileCoords(int x, int y);
+ static void ClipRadarTileCoords(int *x, int *y);
};
diff --git a/src/User.cpp b/src/User.cpp
index c9ab761d..c9cb97cc 100644
--- a/src/User.cpp
+++ b/src/User.cpp
@@ -31,7 +31,7 @@ void COnscreenTimer::Init() {
}
void COnscreenTimer::Process() {
- if(CReplay::Mode != CReplay::MODE_1 && !m_bDisabled) {
+ if(!CReplay::IsPlayingBack() && !m_bDisabled) {
for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) {
m_sEntries[i].Process();
}
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp
index cc86b584..f9c02739 100644
--- a/src/audio/MusicManager.cpp
+++ b/src/audio/MusicManager.cpp
@@ -51,7 +51,7 @@ void cMusicManager::DisplayRadioStationName()
int8 gStreamedSound;
int8 gRetuneCounter;
- if (!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && cMusicManager::PlayerInCar() && CReplay::Mode != 1) {
+ if (!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && cMusicManager::PlayerInCar() && !CReplay::IsPlayingBack()) {
if (MusicManager.m_bPlayerInCar && !MusicManager.m_bPreviousPlayerInCar)
pCurrentStation = nullptr;
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 80edf097..a8d87302 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -1,8 +1,247 @@
#include "common.h"
#include "patcher.h"
+#include "BulletTraces.h"
+#include "Clock.h"
+#include "Draw.h"
+#include "math/Matrix.h"
+#include "ModelIndices.h"
#include "Replay.h"
+#include "Pad.h"
+#include "Pools.h"
+#include "CutsceneMgr.h"
+#include "Timer.h"
+#include "Weather.h"
uint8 &CReplay::Mode = *(uint8*)0x95CD5B;
+CAddressInReplayBuffer &CReplay::Record = *(CAddressInReplayBuffer*)0x942F7C;
+CAddressInReplayBuffer &CReplay::Playback = *(CAddressInReplayBuffer*)0x8F5F48;
+uint8 *&CReplay::pBuf0 = *(uint8**)0x8E2C64;
+CAutomobile *&CReplay::pBuf1 = *(CAutomobile**)0x8E2C68;
+uint8 *&CReplay::pBuf2 = *(uint8**)0x8E2C6C;
+CPlayerPed *&CReplay::pBuf3 = *(CPlayerPed**)0x8E2C70;
+uint8 *&CReplay::pBuf4 = *(uint8**)0x8E2C74;
+CCutsceneHead *&CReplay::pBuf5 = *(CCutsceneHead**)0x8E2C78;
+uint8 *&CReplay::pBuf6 = *(uint8**)0x8E2C80;
+CPtrNode *&CReplay::pBuf7 = *(CPtrNode**)0x8E2C84;
+uint8 *&CReplay::pBuf8 = *(uint8**)0x8E2C54;
+CEntryInfoNode *&CReplay::pBuf9 = *(CEntryInfoNode**)0x8E2C58;
+uint8 *&CReplay::pBuf10 = *(uint8**)0x8F2C28;
+CDummyPed *&CReplay::pBuf11 = *(CDummyPed**)0x8F2C2C;
+CBlip *&CReplay::pRadarBlips = *(CBlip**)0x8F29F8;
+CCamera *&CReplay::pStoredCam = *(CCamera**)0x8F2C34;
+CSector *&CReplay::pWorld1 = *(CSector**)0x8E29C4;
+CReference *&CReplay::pEmptyReferences = *(CReference**)0x8F256C;
+CStoredDetailedAnimationState *&CReplay::pPedAnims = *(CStoredDetailedAnimationState**)0x8F6260;
+CPickup *&CReplay::pPickups = *(CPickup**)0x8F1A48;
+CReference *&CReplay::pReferences = *(CReference**)0x880FAC;
+uint8(&CReplay::BufferStatus)[8] = *(uint8(*)[8])*(uintptr*)0x8804D8;
+uint8(&CReplay::Buffers)[8][100000] = *(uint8(*)[8][100000])*(uintptr*)0x779958;
bool &CReplay::bPlayingBackFromFile = *(bool*)0x95CD58;
+bool &CReplay::bReplayEnabled = *(bool*)0x617CAC;
+uint32 &CReplay::SlowMotion = *(uint32*)0x9414D4;
+uint32 &CReplay::FramesActiveLookAroundCam = *(uint32*)0x880F84;
+bool &CReplay::bDoLoadSceneWhenDone = *(bool*)0x95CD76;
+void PrintElementsInPtrList(void)
+{
+ for (CPtrNode* node = CWorld::GetBigBuildingList(LEVEL_NONE).first; node; node = node->next) {
+ // Most likely debug print was present here
+ }
+}
+
+void CReplay::Init(void)
+{
+ pBuf0 = nil;
+ pBuf1 = nil;
+ pBuf2 = nil;
+ pBuf3 = nil;
+ pBuf4 = nil;
+ pBuf5 = nil;
+ pBuf6 = nil;
+ pBuf7 = nil;
+ pBuf8 = nil;
+ pBuf9 = nil;
+ pBuf10 = nil;
+ pBuf11 = nil;
+ pRadarBlips = nil;
+ pStoredCam = nil;
+ pWorld1 = nil;
+ pEmptyReferences = nil;
+ pPedAnims = nil;
+ pPickups = nil;
+ pReferences = nil;
+ Mode = MODE_RECORD;
+ Playback.m_nOffset = 0;
+ Playback.m_pBase = nil;
+ Playback.m_bSlot = 0;
+ Record.m_nOffset = 0;
+ Record.m_pBase = nil;
+ Record.m_bSlot = 0;
+ for (int i = 0; i < 8; i++)
+ BufferStatus[i] = REPLAYBUFFER_UNUSED;
+ Record.m_bSlot = 0;
+ Record.m_pBase = Buffers[0];
+ BufferStatus[0] = REPLAYBUFFER_RECORD;
+ Buffers[0][Record.m_nOffset] = REPLAYPACKET_END;
+ bPlayingBackFromFile = false;
+ bReplayEnabled = true;
+ SlowMotion = 1;
+ FramesActiveLookAroundCam = 0;
+ bDoLoadSceneWhenDone = false;
+}
+
+void CReplay::DisableReplays(void)
+{
+ bReplayEnabled = false;
+}
+
+void CReplay::EnableReplays(void)
+{
+ bReplayEnabled = true;
+}
+
+void PlayReplayFromHD(void);
+void CReplay::Update(void)
+{
+ if (CCutsceneMgr::IsCutsceneProcessing() || CTimer::GetIsPaused())
+ return;
+ switch (Mode){
+ case MODE_RECORD:
+ RecordThisFrame();
+ break;
+ case MODE_PLAYBACK:
+ PlaybackThisFrame();
+ break;
+ }
+ if (CDraw::FadeValue || !bReplayEnabled)
+ return;
+ if (Mode == MODE_PLAYBACK){
+ if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0])
+ FinishPlayback();
+ }
+ else if (Mode == MODE_RECORD){
+ if (CPad::NewKeyState.F[0] && !CPad::OldKeyState.F[0])
+ TriggerPlayback(REPLAYCAMMODE_ASSTORED, 0.0f, 0.0f, 0.0f, false);
+ if (CPad::NewKeyState.F[1] && !CPad::OldKeyState.F[1])
+ SaveReplayToHD();
+ if (CPad::NewKeyState.F[2] && !CPad::OldKeyState.F[2])
+ PlayReplayFromHD();
+ }
+}
+
+#if 0
+WRAPPER void CReplay::RecordThisFrame(void) { EAXJMP(0x5932B0); }
+#else
+
+void CReplay::RecordThisFrame(void)
+{
+ tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset];
+ general->type = REPLAYPACKET_GENERAL;
+ general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix());
+ FindPlayerCoors(general->player_pos);
+ general->in_rcvehicle = CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ? true : false;
+ Record.m_nOffset += sizeof(*general);
+ tClockPacket* clock = (tClockPacket*)&Record.m_pBase[Record.m_nOffset];
+ clock->type = REPLAYPACKET_CLOCK;
+ clock->hours = CClock::GetHours();
+ clock->minutes = CClock::GetMinutes();
+ Record.m_nOffset += sizeof(*clock);
+ tWeatherPacket* weather = (tWeatherPacket*)&Record.m_pBase[Record.m_nOffset];
+ weather->type = REPLAYPACKET_WEATHER;
+ weather->old_weather = CWeather::OldWeatherType;
+ weather->new_weather = CWeather::NewWeatherType;
+ weather->interpolation = CWeather::InterpolationValue;
+ Record.m_nOffset += sizeof(*weather);
+ tTimerPacket* timer = (tTimerPacket*)&Record.m_pBase[Record.m_nOffset];
+ timer->type = REPLAYPACKET_TIMER;
+ timer->timer = CTimer::GetTimeInMilliseconds();
+ Record.m_nOffset += sizeof(*timer);
+ CVehiclePool* vehicles = CPools::GetVehiclePool();
+ for (int i = 0; i < vehicles->GetSize(); i++){
+ CVehicle* v = vehicles->GetSlot(i);
+ if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN)
+ StoreCarUpdate(v, i);
+ }
+ CPedPool* peds = CPools::GetPedPool();
+ for (int i = 0; i < peds->GetSize(); i++) {
+ CPed* p = peds->GetSlot(i);
+ if (!p || !p->m_rwObject)
+ continue;
+ if (!p->bRecordedForReplay){
+ tPedHeaderPacket* ph = (tPedHeaderPacket*)&Record.m_pBase[Record.m_nOffset];
+ ph->type = REPLAYPACKET_PED_HEADER;
+ ph->index = i;
+ ph->mi = p->GetModelIndex();
+ ph->pedtype = p->m_nPedType;
+ Record.m_nOffset += sizeof(*ph);
+ p->bRecordedForReplay = true;
+ }
+ StorePedUpdate(p, i);
+ }
+ for (uint8 i = 0; i < 16; i++){
+ if (!CBulletTraces::aTraces[i].m_bInUse)
+ continue;
+ tBulletTracePacket* bt = (tBulletTracePacket*)&Record.m_pBase[Record.m_nOffset];
+ bt->type = REPLAYPACKET_BULLETTRACES;
+ bt->index = i;
+ bt->frames = CBulletTraces::aTraces[i].m_bFramesInUse;
+ bt->lifetime = CBulletTraces::aTraces[i].m_bLifeTime;
+ bt->inf = CBulletTraces::aTraces[i].m_vecInf;
+ bt->sup = CBulletTraces::aTraces[i].m_vecSup;
+ Record.m_nOffset += sizeof(*bt);
+ }
+ tEndOfFramePacket* eof = (tEndOfFramePacket*)&Record.m_pBase[Record.m_nOffset];
+ eof->type = REPLAYPACKET_ENDOFFRAME;
+ Record.m_nOffset += sizeof(*eof);
+ if (Record.m_nOffset <= 97000){
+ /* Unsafe assumption which can cause buffer overflow
+ * if size of next frame exceeds 3000 bytes.
+ * Most notably it causes various timecyc errors. */
+ Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
+ return;
+ }
+ Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
+ BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK;
+ Record.m_bSlot = (Record.m_bSlot + 1) % 8;
+ BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD;
+ Record.m_pBase = Buffers[Record.m_bSlot];
+ Record.m_nOffset = 0;
+ *Record.m_pBase = REPLAYPACKET_END;
+ MarkEverythingAsNew();
+}
+#endif
+WRAPPER void CReplay::StorePedUpdate(CPed *ped, int id) { EAXJMP(0x5935B0); }
+WRAPPER void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x593670); }
+WRAPPER void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x593BB0); }
+WRAPPER void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594050); }
+WRAPPER void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state) { EAXJMP(0x5942A0); }
+WRAPPER void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state) { EAXJMP(0x5944B0); }
+WRAPPER void CReplay::PlaybackThisFrame(void) { EAXJMP(0x5946B0); }
+WRAPPER void CReplay::StoreCarUpdate(CVehicle *vehicle, int id) { EAXJMP(0x5947F0); }
+WRAPPER void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer) { EAXJMP(0x594D10); }
+WRAPPER bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer) { EAXJMP(0x595240); }
+WRAPPER void CReplay::FinishPlayback(void) { EAXJMP(0x595B20); }
+WRAPPER void CReplay::Shutdown(void) { EAXJMP(0x595BD0); }
+WRAPPER void CReplay::ProcessReplayCamera(void) { EAXJMP(0x595C40); }
WRAPPER void CReplay::Display(void) { EAXJMP(0x595EE0); }
+WRAPPER void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene) { EAXJMP(0x596030); }
+WRAPPER void CReplay::StoreStuffInMem(void) { EAXJMP(0x5961F0); }
+WRAPPER void CReplay::RestoreStuffFromMem(void) { EAXJMP(0x5966E0); }
+WRAPPER void CReplay::EmptyPedsAndVehiclePools(void) { EAXJMP(0x5970E0); }
+WRAPPER void CReplay::EmptyAllPools(void) { EAXJMP(0x5971B0); }
+WRAPPER void CReplay::MarkEverythingAsNew(void) { EAXJMP(0x597280); }
+WRAPPER void CReplay::SaveReplayToHD(void) { EAXJMP(0x597330); }
+WRAPPER void PlayReplayFromHD(void) { EAXJMP(0x597420); }
+WRAPPER void CReplay::StreamAllNecessaryCarsAndPeds(void) { EAXJMP(0x597560); }
+WRAPPER void CReplay::FindFirstFocusCoordinate(CVector *coord) { EAXJMP(0x5975E00); }
+WRAPPER bool CReplay::ShouldStandardCameraBeProcessed(void) { EAXJMP(0x597680); }
+WRAPPER void CReplay::ProcessLookAroundCam(void) { EAXJMP(0x5976C0); }
+WRAPPER size_t CReplay::FindSizeOfPacket(uint8 type) { EAXJMP(0x597CC0); }
+
+STARTPATCHES
+InjectHook(0x592FC0, PrintElementsInPtrList, PATCH_JUMP);
+InjectHook(0x592FE0, CReplay::Init, PATCH_JUMP);
+InjectHook(0x593150, CReplay::DisableReplays, PATCH_JUMP);
+InjectHook(0x593150, CReplay::EnableReplays, PATCH_JUMP);
+InjectHook(0x593170, CReplay::Update, PATCH_JUMP);
+ENDPATCHES
diff --git a/src/control/Replay.h b/src/control/Replay.h
index 70835596..b37bd29f 100644
--- a/src/control/Replay.h
+++ b/src/control/Replay.h
@@ -1,14 +1,217 @@
#pragma once
+#include "Camera.h"
+#include "Ped.h"
+#include "Pools.h"
+#include "Pickup.h"
+#include "Radar.h"
+#include "References.h"
+#include "Vehicle.h"
+#include "World.h"
+#include "common.h"
+
+struct CAddressInReplayBuffer
+{
+ uint32 m_nOffset;
+ uint8 *m_pBase;
+ uint8 m_bSlot;
+};
+
+struct CStoredAnimationState
+{
+ int8 animId;
+ int8 time;
+ int8 speed;
+ int8 secAnimId;
+ int8 secTime;
+ int8 secSpeed;
+ int8 blendAmount;
+ int8 partAnimId;
+ int8 partAnimTime;
+ int8 partAnimSpeed;
+ int8 partBlendAmount;
+};
+
+struct CStoredDetailedAnimationState
+{
+ int8 m_abAnimId[3];
+ int8 m_abCurTime[3];
+ int8 m_abSpeed[3];
+ int8 m_abBlendAmount[3];
+ int8 m_abFunctionCallbackID[3];
+ int16 m_awFlags[3];
+ int8 m_abAnimId2[6];
+ int8 m_abCurTime2[6];
+ int8 m_abSpeed2[6];
+ int8 m_abBlendAmount2[6];
+ int8 m_abFunctionCallbackID2[6];
+ int16 m_awFlags2[6];
+};
+
class CReplay
{
-public:
enum {
- MODE_1 = 1
+ MODE_RECORD = 0,
+ MODE_PLAYBACK = 1
+ };
+
+ enum {
+ REPLAYCAMMODE_ASSTORED = 0,
+ REPLAYCAMMODE_TOPDOWN = 1,
+ REPLAYCAMMODE_FIXED = 2
+ };
+
+ enum {
+ REPLAYPACKET_END = 0,
+ REPLAYPACKET_VEHICLE = 1,
+ REPLAYPACKET_PED_HEADER = 2,
+ REPLAYPACKET_PED = 3,
+ REPLAYPACKET_GENERAL = 4,
+ REPLAYPACKET_CLOCK = 5,
+ REPLAYPACKET_WEATHER = 6,
+ REPLAYPACKET_ENDOFFRAME = 7,
+ REPLAYPACKET_TIMER = 8,
+ REPLAYPACKET_BULLETTRACES = 9
+ };
+
+ enum {
+ REPLAYBUFFER_UNUSED = 0,
+ REPLAYBUFFER_PLAYBACK = 1,
+ REPLAYBUFFER_RECORD = 2
+ };
+
+
+ struct tGeneralPacket
+ {
+ uint8 type;
+ bool in_rcvehicle;
+ CMatrix camera_pos;
+ CVector player_pos;
+ };
+ static_assert(sizeof(tGeneralPacket) == 88, "tGeneralPacket: error");
+
+ struct tClockPacket
+ {
+ uint8 type;
+ uint8 hours;
+ uint8 minutes;
+ private:
+ uint8 __align;
+ };
+ static_assert(sizeof(tClockPacket) == 4, "tClockPacket: error");
+
+ struct tWeatherPacket
+ {
+ uint8 type;
+ uint8 old_weather;
+ uint8 new_weather;
+ float interpolation;
+ };
+ static_assert(sizeof(tWeatherPacket) == 8, "tWeatherPacket: error");
+
+ struct tTimerPacket
+ {
+ uint8 type;
+ uint32 timer;
};
+ static_assert(sizeof(tTimerPacket) == 8, "tTimerPacket: error");
+ struct tPedHeaderPacket
+ {
+ uint8 type;
+ uint8 index;
+ uint16 mi;
+ uint8 pedtype;
+ private:
+ uint8 __align[3];
+ };
+ static_assert(sizeof(tPedHeaderPacket) == 8, "tPedHeaderPacket: error");
+
+ struct tBulletTracePacket
+ {
+ uint8 type;
+ uint8 frames;
+ uint8 lifetime;
+ uint8 index;
+ CVector inf;
+ CVector sup;
+ };
+ static_assert(sizeof(tBulletTracePacket) == 28, "tBulletTracePacket: error");
+
+ struct tEndOfFramePacket
+ {
+ uint8 type;
+ private:
+ uint8 __align[3];
+ };
+ static_assert(sizeof(tEndOfFramePacket) == 4, "tEndOfFramePacket: error");
+
+private:
static uint8 &Mode;
+ static CAddressInReplayBuffer &Record;
+ static CAddressInReplayBuffer &Playback;
+ static uint8 *&pBuf0;
+ static CAutomobile *&pBuf1;
+ static uint8 *&pBuf2;
+ static CPlayerPed *&pBuf3;
+ static uint8 *&pBuf4;
+ static CCutsceneHead *&pBuf5;
+ static uint8 *&pBuf6;
+ static CPtrNode *&pBuf7;
+ static uint8 *&pBuf8;
+ static CEntryInfoNode *&pBuf9;
+ static uint8 *&pBuf10;
+ static CDummyPed *&pBuf11;
+ static CBlip *&pRadarBlips;
+ static CCamera *&pStoredCam;
+ static CSector *&pWorld1;
+ static CReference *&pEmptyReferences;
+ static CStoredDetailedAnimationState *&pPedAnims;
+ static CPickup *&pPickups;
+ static CReference *&pReferences;
+ static uint8 (&BufferStatus)[8];
+ static uint8 (&Buffers)[8][100000];
static bool &bPlayingBackFromFile;
+ static bool &bReplayEnabled;
+ static uint32 &SlowMotion;
+ static uint32 &FramesActiveLookAroundCam;
+ static bool &bDoLoadSceneWhenDone;
+public:
+ static void Init(void);
+ static void DisableReplays(void);
+ static void EnableReplays(void);
+ static void Update(void);
+ static void FinishPlayback(void);
+ static void Shutdown(void);
static void Display(void);
+ static void TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene);
+ static void StreamAllNecessaryCarsAndPeds(void);
+ static bool ShouldStandardCameraBeProcessed(void);
+
+ inline static bool IsPlayingBack() { return Mode == MODE_PLAYBACK; }
+ inline static bool IsPlayingBackFromFile() { return bPlayingBackFromFile; }
+
+private:
+ static void RecordThisFrame(void);
+ static void StorePedUpdate(CPed *ped, int id);
+ static void StorePedAnimation(CPed *ped, CStoredAnimationState *state);
+ static void StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state);
+ static void ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer);
+ static void RetrievePedAnimation(CPed *ped, CStoredAnimationState *state);
+ static void RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state);
+ static void PlaybackThisFrame(void);
+ static void StoreCarUpdate(CVehicle *vehicle, int id);
+ static void ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer);
+ static bool PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer);
+ static void ProcessReplayCamera(void);
+ static void StoreStuffInMem(void);
+ static void RestoreStuffFromMem(void);
+ static void EmptyPedsAndVehiclePools(void);
+ static void EmptyAllPools(void);
+ static void MarkEverythingAsNew(void);
+ static void SaveReplayToHD(void);
+ static void FindFirstFocusCoordinate(CVector *coord);
+ static void ProcessLookAroundCam(void);
+ static size_t FindSizeOfPacket(uint8);
};
diff --git a/src/entities/CutsceneObject.cpp b/src/entities/CutsceneObject.cpp
index 1e665dd6..163d0513 100644
--- a/src/entities/CutsceneObject.cpp
+++ b/src/entities/CutsceneObject.cpp
@@ -74,7 +74,7 @@ CCutsceneObject::SetupLighting(void)
}else{
CVector coors = GetPosition();
float lighting = CPointLights::GenerateLightsAffectingObject(&coors);
- if(!m_flagB20 && lighting != 1.0f){
+ if(!bHasBlip && lighting != 1.0f){
SetAmbientAndDirectionalColours(lighting);
return true;
}
diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp
index 0ab1488d..d2b2577d 100644
--- a/src/entities/Entity.cpp
+++ b/src/entities/Entity.cpp
@@ -31,7 +31,7 @@ CEntity::CEntity(void)
bIsVisible = true;
bHasCollided = false;
bRenderScorched = false;
- m_flagB20 = false;
+ bHasBlip = false;
bIsBIGBuilding = false;
bRenderDamaged = false;
diff --git a/src/entities/Entity.h b/src/entities/Entity.h
index 95294ed8..0ce47428 100644
--- a/src/entities/Entity.h
+++ b/src/entities/Entity.h
@@ -5,6 +5,19 @@
struct CReference;
+enum eEntityFlags
+{
+ IS_UNK = 0,
+ CONTROL_POSTPONED,
+ IS_EXPLOSIONPROOF,
+ IS_VISIBLE,
+ IS_ON_GROUND,
+ REQUIRES_SCORCHED_LIGHTS,
+ HAS_BLIP,
+ IS_BIG_BUILDING,
+ HAS_BEEN_DAMAGED,
+};
+
enum eEntityType
{
ENTITY_TYPE_NOTHING = 0,
@@ -59,7 +72,7 @@ public:
uint32 bIsVisible : 1;
uint32 bHasCollided : 1; //
uint32 bRenderScorched : 1;
- uint32 m_flagB20 : 1; // bFlashing?
+ uint32 bHasBlip : 1;
uint32 bIsBIGBuilding : 1;
// VC inserts one more flag here: if drawdist <= 2000
uint32 bRenderDamaged : 1;
diff --git a/src/entities/Ped.h b/src/entities/Ped.h
index 660f3462..800c5bb9 100644
--- a/src/entities/Ped.h
+++ b/src/entities/Ped.h
@@ -166,7 +166,7 @@ public:
uint8 m_ped_flagI1 : 1;
uint8 m_ped_flagI2 : 1;
uint8 m_ped_flagI4 : 1;
- uint8 m_ped_flagI8 : 1;
+ uint8 bRecordedForReplay : 1;
uint8 m_ped_flagI10 : 1;
uint8 m_ped_flagI20 : 1;
uint8 m_ped_flagI40 : 1;
diff --git a/src/math/Matrix.h b/src/math/Matrix.h
index 10255af1..a93de636 100644
--- a/src/math/Matrix.h
+++ b/src/math/Matrix.h
@@ -155,6 +155,9 @@ public:
r.Normalise();
f = CrossProduct(u, r);
}
+ void CopyOnlyMatrix(CMatrix *other){
+ m_matrix = other->m_matrix;
+ }
};
inline CMatrix&
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 96e50f06..23a796e6 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -189,7 +189,7 @@ void CHud::Draw()
RwRenderStateSet(rwRENDERSTATESHADEMODE, (void*)rwSHADEMODEFLAT);
RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR);
- if (CReplay::Mode != 1) {
+ if (!CReplay::IsPlayingBack()) {
if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) {
bool Mode_RunAround = 0;
bool Mode_FirstPerson = 0;
@@ -1063,7 +1063,7 @@ WRAPPER void CHud::DrawAfterFade(void) { EAXJMP(0x509030); }
#else
void CHud::DrawAfterFade()
{
- if (CTimer::GetIsUserPaused() || CReplay::Mode == 1)
+ if (CTimer::GetIsUserPaused() || CReplay::IsPlayingBack())
return;
if (m_HelpMessage[0]) {
diff --git a/src/templates.h b/src/templates.h
index 65f92a2a..d1ef99f0 100644
--- a/src/templates.h
+++ b/src/templates.h
@@ -101,6 +101,27 @@ public:
n++;
return n;
}
+ void ClearStorage(uint8 **flags, U **entries){
+ delete[] flags;
+ delete[] entries;
+ *flags = nil;
+ *entries = nil;
+ }
+ void CopyBack(uint8 **flags, U **entries){
+ memcpy(m_flags, *flags, sizeof(Flags)*m_size);
+ memcpy(m_entries, *entries, sizeof(U)*m_size);
+ debug("Size copied:%d (%d)", sizeof(U)*m_size, sizeof(Flags)*m_size);
+ m_allocPtr = 0;
+ ClearStorage(flags, entries);
+ debug("CopyBack:%d (/%d)", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
+ }
+ void Store(uint8 **flags, U** entries){
+ *flags = (Flags*)malloc(sizeof(Flags)*m_size);
+ *entries = (U*)malloc(sizeof(U)*m_size);
+ memcpy(*flags, m_flags, sizeof(Flags)*m_size);
+ memcpy(*entries, m_entries, sizeof(U)*m_size);
+ debug("Stored:%d (/%d)", GetNoOfUsedSpaces(), m_size); /* Assumed inlining */
+ }
};
template<typename T>