summaryrefslogtreecommitdiffstats
path: root/src/control
diff options
context:
space:
mode:
authorNikolay Korolev <nickvnuk@gmail.com>2020-09-26 20:10:23 +0200
committerNikolay Korolev <nickvnuk@gmail.com>2020-09-26 20:10:23 +0200
commitf7d5021ac59026435165e97aba869a76cfef1059 (patch)
tree1a57b2e0491be1505f20f99aa38e84232619b53a /src/control
parentFix coronas reflections (diff)
downloadre3-f7d5021ac59026435165e97aba869a76cfef1059.tar
re3-f7d5021ac59026435165e97aba869a76cfef1059.tar.gz
re3-f7d5021ac59026435165e97aba869a76cfef1059.tar.bz2
re3-f7d5021ac59026435165e97aba869a76cfef1059.tar.lz
re3-f7d5021ac59026435165e97aba869a76cfef1059.tar.xz
re3-f7d5021ac59026435165e97aba869a76cfef1059.tar.zst
re3-f7d5021ac59026435165e97aba869a76cfef1059.zip
Diffstat (limited to 'src/control')
-rw-r--r--src/control/Garages.h1
-rw-r--r--src/control/Replay.cpp549
-rw-r--r--src/control/Replay.h127
-rw-r--r--src/control/Script.cpp2
4 files changed, 540 insertions, 139 deletions
diff --git a/src/control/Garages.h b/src/control/Garages.h
index 79905ede..43f40261 100644
--- a/src/control/Garages.h
+++ b/src/control/Garages.h
@@ -300,5 +300,6 @@ private:
static bool IsThisGarageTypeSafehouse(eGarageType type) { return FindSafeHouseIndexForGarageType(type) >= 0; }
friend class cAudioManager;
+ friend class CReplay;
friend class CGarage;
};
diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp
index 80c05f31..4ae1cf1b 100644
--- a/src/control/Replay.cpp
+++ b/src/control/Replay.cpp
@@ -1,15 +1,22 @@
#include "common.h"
+#include "AnimBlendAssocGroup.h"
#include "AnimBlendAssociation.h"
+#include "Bike.h"
#include "Boat.h"
#include "SpecialFX.h"
#include "CarCtrl.h"
#include "CivilianPed.h"
+#include "CopPed.h"
#include "Wanted.h"
#include "Clock.h"
#include "DMAudio.h"
#include "Draw.h"
+#include "Explosion.h"
#include "FileMgr.h"
+#include "Fire.h"
+#include "Frontend.h"
+#include "Garages.h"
#include "Heli.h"
#include "main.h"
#include "Matrix.h"
@@ -17,12 +24,15 @@
#include "ModelInfo.h"
#include "Object.h"
#include "Pad.h"
+#include "Particle.h"
#include "PedAttractor.h"
#include "Phones.h"
#include "Pickups.h"
#include "Plane.h"
#include "Pools.h"
#include "Population.h"
+#include "Projectile.h"
+#include "ProjectileInfo.h"
#include "Replay.h"
#include "References.h"
#include "Pools.h"
@@ -30,6 +40,7 @@
#include "RwHelper.h"
#include "CutsceneMgr.h"
#include "Skidmarks.h"
+#include "Stinger.h"
#include "Streaming.h"
#include "Timer.h"
#include "Train.h"
@@ -103,6 +114,31 @@ bool CReplay::bPlayerInRCBuggy;
float CReplay::fDistanceLookAroundCam;
float CReplay::fBetaAngleLookAroundCam;
float CReplay::fAlphaAngleLookAroundCam;
+int CReplay::ms_nNumCivMale_Stored;
+int CReplay::ms_nNumCivFemale_Stored;
+int CReplay::ms_nNumCop_Stored;
+int CReplay::ms_nNumEmergency_Stored;
+int CReplay::ms_nNumGang1_Stored;
+int CReplay::ms_nNumGang2_Stored;
+int CReplay::ms_nNumGang3_Stored;
+int CReplay::ms_nNumGang4_Stored;
+int CReplay::ms_nNumGang5_Stored;
+int CReplay::ms_nNumGang6_Stored;
+int CReplay::ms_nNumGang7_Stored;
+int CReplay::ms_nNumGang8_Stored;
+int CReplay::ms_nNumGang9_Stored;
+int CReplay::ms_nNumDummy_Stored;
+int CReplay::ms_nTotalCarPassengerPeds_Stored;
+int CReplay::ms_nTotalCivPeds_Stored;
+int CReplay::ms_nTotalGangPeds_Stored;
+int CReplay::ms_nTotalPeds_Stored;
+int CReplay::ms_nTotalMissionPeds_Stored;
+uint8* CReplay::pGarages;
+CFire* CReplay::FireArray;
+uint32 CReplay::NumOfFires;
+uint8* CReplay::paProjectileInfo;
+uint8* CReplay::paProjectiles;
+uint8 CReplay::CurrArea;
#ifdef FIX_BUGS
int CReplay::nHandleOfPlayerPed[NUMPLAYERS];
#endif
@@ -119,9 +155,11 @@ static void(*CBArray[])(CAnimBlendAssociation*, void*) =
&CPed::FinishedAttackCB,
&CPed::FinishFightMoveCB, &PhonePutDownCB, &PhonePickUpCB, &CPed::PedAnimDoorCloseRollingCB, &CPed::FinishJumpCB,
&CPed::PedLandCB, &CPed::RestoreHeadingRateCB, &CPed::PedSetQuickDraggedOutCarPositionCB, &CPed::PedSetDraggedOutCarPositionCB,
- &CPed::FinishedReloadCB, &StartTalkingOnMobileCB, &FinishTalkingOnMobileCB
+ &CPed::PedSetPreviousStateCB, &CPed::FinishedReloadCB, /*&CPed::PedSetGetInCarPositionCB, TODO(MIAMI)*/
+ &CPed::PedAnimShuffleCB, &CPed::DeleteSunbatheIdleAnimCB, &StartTalkingOnMobileCB, &FinishTalkingOnMobileCB
};
+// --MIAMI: Done
static uint8 FindCBFunctionID(void(*f)(CAnimBlendAssociation*, void*))
{
for (int i = 0; i < sizeof(CBArray) / sizeof(*CBArray); i++){
@@ -132,11 +170,13 @@ static uint8 FindCBFunctionID(void(*f)(CAnimBlendAssociation*, void*))
return 0;
}
+// --MIAMI: Done
static void(*FindCBFunction(uint8 id))(CAnimBlendAssociation*, void*)
{
return CBArray[id];
}
+// --MIAMI: Done
static void ApplyPanelDamageToCar(uint32 panels, CAutomobile* vehicle, bool flying)
{
if(vehicle->Damage.GetPanelStatus(VEHPANEL_FRONT_LEFT) != CDamageManager::GetPanelStatus(panels, VEHPANEL_FRONT_LEFT)){
@@ -169,6 +209,7 @@ static void ApplyPanelDamageToCar(uint32 panels, CAutomobile* vehicle, bool flyi
}
}
+// --MIAMI: Done
void PrintElementsInPtrList(void)
{
for (CPtrNode* node = CWorld::GetBigBuildingList(LEVEL_GENERIC).first; node; node = node->next) {
@@ -176,6 +217,7 @@ void PrintElementsInPtrList(void)
}
}
+// --MIAMI: Done
void CReplay::Init(void)
{
pBuf0 = nil;
@@ -215,23 +257,29 @@ void CReplay::Init(void)
SlowMotion = 1;
FramesActiveLookAroundCam = 0;
bDoLoadSceneWhenDone = false;
+ MarkEverythingAsNew();
}
+// --MIAMI: Done
void CReplay::DisableReplays(void)
{
bReplayEnabled = false;
}
+// --MIAMI: Done
void CReplay::EnableReplays(void)
{
bReplayEnabled = true;
}
void PlayReplayFromHD(void);
+// --MIAMI: Done
void CReplay::Update(void)
{
- if (CCutsceneMgr::IsCutsceneProcessing() || CTimer::GetIsPaused() || CScriptPaths::IsOneActive())
+ if (CCutsceneMgr::IsCutsceneProcessing() || CPad::GetPad(0)->ArePlayerControlsDisabled() || CScriptPaths::IsOneActive() || FrontEndMenuManager.GetIsMenuActive()) {
+ Init();
return;
+ }
switch (Mode){
case MODE_RECORD:
RecordThisFrame();
@@ -260,15 +308,19 @@ void CReplay::Update(void)
}
}
+// --MIAMI: Done except TODO
void CReplay::RecordThisFrame(void)
{
-#ifdef FIX_REPLAY_BUGS
- uint32 memory_required = sizeof(tGeneralPacket) + sizeof(tClockPacket) + sizeof(tWeatherPacket) + sizeof(tTimerPacket);
+ uint32 memory_required = sizeof(tGeneralPacket) + sizeof(tClockPacket) + sizeof(tWeatherPacket) + sizeof(tTimerPacket) + sizeof(tMiscPacket);
CVehiclePool* vehiclesT = CPools::GetVehiclePool();
for (int i = 0; i < vehiclesT->GetSize(); i++) {
CVehicle* v = vehiclesT->GetSlot(i);
- if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN)
- memory_required += sizeof(tVehicleUpdatePacket);
+ if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN) {
+ if (v->IsBike())
+ memory_required += sizeof(tBikeUpdatePacket);
+ else
+ memory_required += sizeof(tVehicleUpdatePacket);
+ }
}
CPedPool* pedsT = CPools::GetPedPool();
for (int i = 0; i < pedsT->GetSize(); i++) {
@@ -286,17 +338,8 @@ void CReplay::RecordThisFrame(void)
memory_required += sizeof(tBulletTracePacket);
}
memory_required += sizeof(tEndOfFramePacket) + 1; // 1 for Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
- if (Record.m_nOffset + memory_required > REPLAYBUFFERSIZE) {
- Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
- BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK;
- Record.m_bSlot = (Record.m_bSlot + 1) % NUM_REPLAYBUFFERS;
- BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD;
- Record.m_pBase = Buffers[Record.m_bSlot];
- Record.m_nOffset = 0;
- *Record.m_pBase = REPLAYPACKET_END;
- MarkEverythingAsNew();
- }
-#endif
+ if (Record.m_nOffset + memory_required > REPLAYBUFFERSIZE - 16)
+ GoToNextBlock();
tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset];
general->type = REPLAYPACKET_GENERAL;
general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix());
@@ -321,8 +364,12 @@ void CReplay::RecordThisFrame(void)
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);
+ if (v && v->m_rwObject && v->GetModelIndex() != MI_AIRTRAIN && v->GetModelIndex() != MI_TRAIN) {
+ if (v->IsBike())
+ StoreBikeUpdate(v, i);
+ else
+ StoreCarUpdate(v, i);
+ }
}
CPedPool* peds = CPools::GetPedPool();
for (int i = 0; i < peds->GetSize(); i++) {
@@ -352,17 +399,23 @@ void CReplay::RecordThisFrame(void)
bt->sup = CBulletTraces::aTraces[i].m_vecTargetPos;
Record.m_nOffset += sizeof(*bt);
}
+ tMiscPacket* misc = (tMiscPacket*)&Record.m_pBase[Record.m_nOffset];
+ misc->type = REPLAYPACKET_MISC;
+ misc->cam_shake_start = TheCamera.m_uiCamShakeStart;
+ misc->cam_shake_strength = TheCamera.m_fCamShakeForce;
+ misc->cur_area = CGame::currArea;
+ //misc->special_fx_flags; // TODO(MIAMI)!!!
+ Record.m_nOffset += sizeof(*misc);
tEndOfFramePacket* eof = (tEndOfFramePacket*)&Record.m_pBase[Record.m_nOffset];
eof->type = REPLAYPACKET_ENDOFFRAME;
Record.m_nOffset += sizeof(*eof);
Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
-#ifndef FIX_REPLAY_BUGS
- if (Record.m_nOffset <= REPLAYBUFFERSIZE - 3000){
- /* Unsafe assumption which can cause buffer overflow
- * if size of next frame exceeds 3000 bytes.
- * Most notably it causes various timecyc errors. */
- return;
- }
+}
+
+// --MIAMI: Done
+void CReplay::GoToNextBlock(void)
+{
+ Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
BufferStatus[Record.m_bSlot] = REPLAYBUFFER_PLAYBACK;
Record.m_bSlot = (Record.m_bSlot + 1) % NUM_REPLAYBUFFERS;
BufferStatus[Record.m_bSlot] = REPLAYBUFFER_RECORD;
@@ -370,9 +423,32 @@ void CReplay::RecordThisFrame(void)
Record.m_nOffset = 0;
*Record.m_pBase = REPLAYPACKET_END;
MarkEverythingAsNew();
-#endif
}
+// --MIAMI: Done
+void CReplay::RecordParticle(tParticleType type, const CVector& vecPos, const CVector& vecDir, float fSize, const RwRGBA& color)
+{
+ if (Record.m_nOffset > REPLAYBUFFERSIZE - 16 - sizeof(tParticlePacket))
+ GoToNextBlock();
+ tParticlePacket* pp = (tParticlePacket*)&Record.m_pBase[Record.m_nOffset];
+ pp->type = REPLAYPACKET_PARTICLE;
+ pp->particle_type = type;
+ pp->pos_x = 4.0f * vecPos.x;
+ pp->pos_y = 4.0f * vecPos.y;
+ pp->pos_z = 4.0f * vecPos.z;
+ pp->dir_x = 120.0f * clamp(vecDir.x, -1.0f, 1.0f);
+ pp->dir_y = 120.0f * clamp(vecDir.y, -1.0f, 1.0f);
+ pp->dir_z = 120.0f * clamp(vecDir.z, -1.0f, 1.0f);
+ pp->size = fSize;
+ pp->r = color.red;
+ pp->g = color.green;
+ pp->b = color.blue;
+ pp->a = color.alpha;
+ Record.m_nOffset += sizeof(tParticlePacket);
+ Record.m_pBase[Record.m_nOffset] = REPLAYPACKET_END;
+}
+
+// --MIAMI: Done
void CReplay::StorePedUpdate(CPed *ped, int id)
{
tPedUpdatePacket* pp = (tPedUpdatePacket*)&Record.m_pBase[Record.m_nOffset];
@@ -381,6 +457,7 @@ void CReplay::StorePedUpdate(CPed *ped, int id)
pp->heading = 128.0f / PI * ped->m_fRotationCur;
pp->matrix.CompressFromFullMatrix(ped->GetMatrix());
pp->assoc_group_id = ped->m_animGroup;
+ pp->is_visible = ped->bIsVisible;
/* Would be more sane to use GetJustIndex(ped->m_pMyVehicle) in following assignment */
if (ped->InVehicle())
pp->vehicle_index = (CPools::GetVehiclePool()->GetIndex(ped->m_pMyVehicle) >> 8) + 1;
@@ -391,6 +468,7 @@ void CReplay::StorePedUpdate(CPed *ped, int id)
Record.m_nOffset += sizeof(tPedUpdatePacket);
}
+// --MIAMI: Done
void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
{
CAnimBlendAssociation* second;
@@ -400,21 +478,25 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
state->animId = main->animId;
state->time = 255.0f / 4.0f * clamp(main->currentTime, 0.0f, 4.0f);
state->speed = 255.0f / 3.0f * clamp(main->speed, 0.0f, 3.0f);
+ state->groupId = main->groupId;
}else{
state->animId = 3;
state->time = 0;
state->speed = 85;
+ state->groupId = 0;
}
if (second) {
state->secAnimId = second->animId;
state->secTime = 255.0f / 4.0f * clamp(second->currentTime, 0.0f, 4.0f);
state->secSpeed = 255.0f / 3.0f * clamp(second->speed, 0.0f, 3.0f);
state->blendAmount = 255.0f / 2.0f * clamp(blend_amount, 0.0f, 2.0f);
+ state->secGroupId = second->groupId;
}else{
state->secAnimId = 0;
state->secTime = 0;
state->secSpeed = 0;
state->blendAmount = 0;
+ state->secGroupId = 0;
}
CAnimBlendAssociation* partial = RpAnimBlendClumpGetMainPartialAssociation((RpClump*)ped->m_rwObject);
if (partial) {
@@ -422,14 +504,17 @@ void CReplay::StorePedAnimation(CPed *ped, CStoredAnimationState *state)
state->partAnimTime = 255.0f / 4.0f * clamp(partial->currentTime, 0.0f, 4.0f);
state->partAnimSpeed = 255.0f / 3.0f * clamp(partial->speed, 0.0f, 3.0f);
state->partBlendAmount = 255.0f / 2.0f * clamp(partial->blendAmount, 0.0f, 2.0f);
+ state->partGroupId = partial->groupId;
}else{
state->partAnimId = 0;
state->partAnimTime = 0;
state->partAnimSpeed = 0;
state->partBlendAmount = 0;
+ state->partGroupId = 0;
}
}
+// --MIAMI: Done
void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
{
for (int i = 0; i < NUM_MAIN_ANIMS_IN_REPLAY; i++){
@@ -439,10 +524,9 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
state->aCurTime[i] = 255.0f / 4.0f * clamp(assoc->currentTime, 0.0f, 4.0f);
state->aSpeed[i] = 255.0f / 3.0f * clamp(assoc->speed, 0.0f, 3.0f);
state->aBlendAmount[i] = 255.0f / 2.0f * clamp(assoc->blendAmount, 0.0f, 2.0f);
-#ifdef FIX_REPLAY_BUGS
state->aBlendDelta[i] = 127.0f / 32.0f * clamp(assoc->blendDelta, -16.0f, 16.0f);
-#endif
state->aFlags[i] = assoc->flags;
+ state->aGroupId[i] = assoc->groupId;
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
state->aFunctionCallbackID[i] = FindCBFunctionID(assoc->callback);
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH)
@@ -456,6 +540,7 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
state->aSpeed[i] = 85;
state->aFunctionCallbackID[i] = 0;
state->aFlags[i] = 0;
+ state->aGroupId[i] = 0;
}
}
for (int i = 0; i < NUM_PARTIAL_ANIMS_IN_REPLAY; i++) {
@@ -465,10 +550,9 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
state->aCurTime2[i] = 255.0f / 4.0f * clamp(assoc->currentTime, 0.0f, 4.0f);
state->aSpeed2[i] = 255.0f / 3.0f * clamp(assoc->speed, 0.0f, 3.0f);
state->aBlendAmount2[i] = 255.0f / 2.0f * clamp(assoc->blendAmount, 0.0f, 2.0f);
-#ifdef FIX_REPLAY_BUGS
state->aBlendDelta2[i] = 127.0f / 16.0f * clamp(assoc->blendDelta, -16.0f, 16.0f);
-#endif
state->aFlags2[i] = assoc->flags;
+ state->aGroupId2[i] = assoc->groupId;
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH || assoc->callbackType == CAnimBlendAssociation::CB_DELETE) {
state->aFunctionCallbackID2[i] = FindCBFunctionID(assoc->callback);
if (assoc->callbackType == CAnimBlendAssociation::CB_FINISH)
@@ -483,10 +567,12 @@ void CReplay::StoreDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState
state->aSpeed2[i] = 85;
state->aFunctionCallbackID2[i] = 0;
state->aFlags2[i] = 0;
+ state->aGroupId2[i] = 0;
}
}
}
+// --MIAMI: Done
void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayBuffer *buffer)
{
tPedUpdatePacket *pp = (tPedUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
@@ -504,7 +590,7 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB
ped->GetMatrix() += CMatrix(interpolation) * ped_matrix;
if (pp->vehicle_index) {
ped->m_pMyVehicle = CPools::GetVehiclePool()->GetSlot(pp->vehicle_index - 1);
- ped->bInVehicle = pp->vehicle_index;
+ ped->bInVehicle = true;
}
else {
ped->m_pMyVehicle = nil;
@@ -515,6 +601,9 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB
if (ped == FindPlayerPed())
((CPlayerPed*)ped)->ReApplyMoveAnims();
}
+ ped->bIsVisible = pp->is_visible;
+ if (FramesActiveLookAroundCam && ped->m_nPedType == PEDTYPE_PLAYER1)
+ ped->bIsVisible = true;
RetrievePedAnimation(ped, &pp->anim_state);
ped->RemoveWeaponModel(-1);
if (pp->weapon_model != (uint16)-1) {
@@ -528,12 +617,25 @@ void CReplay::ProcessPedUpdate(CPed *ped, float interpolation, CAddressInReplayB
buffer->m_nOffset += sizeof(tPedUpdatePacket);
}
+// --MIAMI: Done
+bool HasAnimGroupLoaded(uint8 group)
+{
+ CAnimBlendAssocGroup* pGroup = &CAnimManager::GetAnimAssocGroups()[group];
+ return pGroup->animBlock && pGroup->animBlock->isLoaded;
+}
+
+// --MIAMI: Done
void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
{
- CAnimBlendAssociation* anim1 = CAnimManager::BlendAnimation(
- (RpClump*)ped->m_rwObject,
- (state->animId > 3) ? ASSOCGRP_STD : ped->m_animGroup,
- (AnimationId)state->animId, 100.0f);
+ CAnimBlendAssociation* anim1;
+ if (state->animId <= 3)
+ anim1 = CAnimManager::BlendAnimation(
+ (RpClump*)ped->m_rwObject, ped->m_animGroup, (AnimationId)state->animId, 100.0f);
+ else if (HasAnimGroupLoaded(state->groupId))
+ anim1 = CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, (AssocGroupId)state->groupId, (AnimationId)state->animId, 100.0f);
+ else
+ anim1 = CAnimManager::BlendAnimation((RpClump*)ped->m_rwObject, ASSOCGRP_STD, ANIM_WALK, 100.0f);
+
anim1->SetCurrentTime(state->time * 4.0f / 255.0f);
anim1->speed = state->speed * 3.0f / 255.0f;
anim1->SetBlend(1.0f, 1.0f);
@@ -544,7 +646,7 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
float blend = state->blendAmount * 2.0f / 255.0f;
CAnimBlendAssociation* anim2 = CAnimManager::BlendAnimation(
(RpClump*)ped->m_rwObject,
- (state->secAnimId > 3) ? ASSOCGRP_STD : ped->m_animGroup,
+ (state->secAnimId > 3) ? (AssocGroupId)state->secGroupId : ped->m_animGroup,
(AnimationId)state->secAnimId, 100.0f);
anim2->SetCurrentTime(time);
anim2->speed = speed;
@@ -556,9 +658,9 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
float time = state->partAnimTime * 4.0f / 255.0f;
float speed = state->partAnimSpeed * 3.0f / 255.0f;
float blend = state->partBlendAmount * 2.0f / 255.0f;
- if (blend > 0.0f && state->partAnimId != ANIM_IDLE_STANCE){
+ if (blend > 0.0f && state->partAnimId != ANIM_IDLE_STANCE && HasAnimGroupLoaded(state->partGroupId)){
CAnimBlendAssociation* anim3 = CAnimManager::BlendAnimation(
- (RpClump*)ped->m_rwObject, ASSOCGRP_STD, (AnimationId)state->partAnimId, 1000.0f);
+ (RpClump*)ped->m_rwObject, (AssocGroupId)state->partGroupId, (AnimationId)state->partAnimId, 1000.0f);
anim3->SetCurrentTime(time);
anim3->speed = speed;
anim3->SetBlend(blend, 0.0f);
@@ -566,35 +668,23 @@ void CReplay::RetrievePedAnimation(CPed *ped, CStoredAnimationState *state)
}
}
+// --MIAMI: Done
void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationState *state)
{
-#ifdef FIX_REPLAY_BUGS
CAnimBlendAssociation* assoc;
for (int i = 0; ((assoc = RpAnimBlendClumpGetMainAssociation_N(ped->GetClump(), i))); i++)
assoc->SetBlend(0.0f, -1.0f);
for (int i = 0; ((assoc = RpAnimBlendClumpGetMainPartialAssociation_N(ped->GetClump(), i))); i++)
assoc->SetBlend(0.0f, -1.0f);
-#endif
for (int i = 0; i < NUM_MAIN_ANIMS_IN_REPLAY; i++) {
if (state->aAnimId[i] == NUM_ANIMS)
continue;
-#ifdef FIX_REPLAY_BUGS
CAnimBlendAssociation* anim = CAnimManager::AddAnimation(ped->GetClump(),
- state->aAnimId[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
+ state->aAnimId[i] > 3 ? (AssocGroupId)state->aGroupId[i] : ped->m_animGroup,
(AnimationId)state->aAnimId[i]);
-#else
- CAnimBlendAssociation* anim = CAnimManager::BlendAnimation(
- (RpClump*)ped->m_rwObject,
- state->aAnimId[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
- (AnimationId)state->aAnimId[i], 100.0f);
-#endif
anim->SetCurrentTime(state->aCurTime[i] * 4.0f / 255.0f);
anim->speed = state->aSpeed[i] * 3.0f / 255.0f;
-#ifdef FIX_REPLAY_BUGS
anim->SetBlend(state->aBlendAmount[i] * 2.0f / 255.0f, state->aBlendDelta[i] * 16.0f / 127.0f);
-#else
- anim->SetBlend(state->aBlendAmount[i], 1.0f);
-#endif
anim->flags = state->aFlags[i];
uint8 callback = state->aFunctionCallbackID[i];
if (!callback)
@@ -607,23 +697,12 @@ void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationSt
for (int i = 0; i < NUM_PARTIAL_ANIMS_IN_REPLAY; i++) {
if (state->aAnimId2[i] == NUM_ANIMS)
continue;
-#ifdef FIX_REPLAY_BUGS
CAnimBlendAssociation* anim = CAnimManager::AddAnimation(ped->GetClump(),
- state->aAnimId2[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
+ state->aAnimId2[i] > 3 ? (AssocGroupId)state->aGroupId2[i] : ped->m_animGroup,
(AnimationId)state->aAnimId2[i]);
-#else
- CAnimBlendAssociation* anim = CAnimManager::BlendAnimation(
- (RpClump*)ped->m_rwObject,
- state->aAnimId2[i] > 3 ? ASSOCGRP_STD : ped->m_animGroup,
- (AnimationId)state->aAnimId2[i], 100.0f);
-#endif
anim->SetCurrentTime(state->aCurTime2[i] * 4.0f / 255.0f);
anim->speed = state->aSpeed2[i] * 3.0f / 255.0f;
-#ifdef FIX_REPLAY_BUGS
anim->SetBlend(state->aBlendAmount2[i] * 2.0f / 255.0f, state->aBlendDelta2[i] * 16.0f / 127.0f);
-#else
- anim->SetBlend(state->aBlendAmount2[i], 1.0f);
-#endif
anim->flags = state->aFlags2[i];
uint8 callback = state->aFunctionCallbackID2[i];
if (!callback)
@@ -635,6 +714,7 @@ void CReplay::RetrieveDetailedPedAnimation(CPed *ped, CStoredDetailedAnimationSt
}
}
+// --MIAMI: Done
void CReplay::PlaybackThisFrame(void)
{
static int FrameSloMo = 0;
@@ -662,7 +742,7 @@ void CReplay::PlaybackThisFrame(void)
// next two functions are only found in mobile version
// most likely they were optimized out for being unused
-
+// --MIAMI: Done
void CReplay::TriggerPlaybackLastCoupleOfSeconds(uint32 start, uint8 cam_mode, float cam_x, float cam_y, float cam_z, uint32 slomo)
{
if (Mode != MODE_RECORD)
@@ -674,6 +754,7 @@ void CReplay::TriggerPlaybackLastCoupleOfSeconds(uint32 start, uint8 cam_mode, f
Mode = MODE_RECORD;
}
+// --MIAMI: Done
bool CReplay::FastForwardToTime(uint32 start)
{
uint32 timer = 0;
@@ -683,6 +764,7 @@ bool CReplay::FastForwardToTime(uint32 start)
return true;
}
+// --MIAMI: Done
void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
{
tVehicleUpdatePacket* vp = (tVehicleUpdatePacket*)&Record.m_pBase[Record.m_nOffset];
@@ -716,9 +798,40 @@ void CReplay::StoreCarUpdate(CVehicle *vehicle, int id)
vp->door_status |= BIT(i);
}
}
+ if (vehicle->GetModelIndex() == MI_SKIMMER)
+ vp->skimmer_speed = 50.0f * ((CBoat*)vehicle)->m_fMovingSpeed;
+ vp->render_scorched = vehicle->bRenderScorched;
+ vp->vehicle_type = vehicle->m_vehType;
Record.m_nOffset += sizeof(tVehicleUpdatePacket);
}
+// --MIAMI: Done
+void CReplay::StoreBikeUpdate(CVehicle* vehicle, int id)
+{
+ CBike* bike = (CBike*)vehicle;
+ tBikeUpdatePacket* vp = (tBikeUpdatePacket*)&Record.m_pBase[Record.m_nOffset];
+ vp->type = REPLAYPACKET_BIKE;
+ vp->index = id;
+ vp->matrix.CompressFromFullMatrix(vehicle->GetMatrix());
+ vp->health = vehicle->m_fHealth / 4.0f; /* Not anticipated that health can be > 1000. */
+ vp->acceleration = vehicle->m_fGasPedal * 100.0f;
+ for (int i = 0; i < 4; i++) {
+ vp->wheel_susp_dist[i] = 50.0f * bike->m_aSuspensionSpringRatio[i];
+ vp->wheel_rotation[i] = 128.0f / PI * bike->m_aWheelRotation[i];
+ }
+ vp->velocityX = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().x)); /* 8000!? */
+ vp->velocityY = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().y));
+ vp->velocityZ = 8000.0f * Max(-4.0f, Min(4.0f, vehicle->GetMoveSpeed().z));
+ vp->mi = vehicle->GetModelIndex();
+ vp->primary_color = vehicle->m_currentColour1;
+ vp->secondary_color = vehicle->m_currentColour2;
+ vp->wheel_state = 50.0f * vehicle->m_fSteerAngle;
+ vp->lean_angle = 50.0f * bike->m_fLeanLRAngle;
+ vp->wheel_angle = 50.0f * bike->m_fWheelAngle;
+ Record.m_nOffset += sizeof(tBikeUpdatePacket);
+}
+
+// --MIAMI: Done
void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer)
{
tVehicleUpdatePacket* vp = (tVehicleUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
@@ -755,7 +868,7 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
car->Damage.SetDoorStatus(DOOR_FRONT_LEFT, DOOR_STATUS_SWINGING);
if (vp->door_angles[1])
car->Damage.SetDoorStatus(DOOR_FRONT_RIGHT, DOOR_STATUS_SWINGING);
- if (vp->door_status & 1 && car->Damage.GetDoorStatus(DOOR_BONNET) != DOOR_STATUS_MISSING){
+ if (vp->door_status & 1 && car->Damage.GetDoorStatus(DOOR_BONNET) != DOOR_STATUS_MISSING) {
car->Damage.SetDoorStatus(DOOR_BONNET, DOOR_STATUS_MISSING);
car->SetDoorDamage(CAR_BONNET, DOOR_BONNET, true);
}
@@ -779,28 +892,56 @@ void CReplay::ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressI
car->Damage.SetDoorStatus(DOOR_REAR_RIGHT, DOOR_STATUS_MISSING);
car->SetDoorDamage(CAR_DOOR_RR, DOOR_REAR_RIGHT, true);
}
- vehicle->bEngineOn = true;
- if (vehicle->IsCar())
- ((CAutomobile*)vehicle)->m_nDriveWheelsOnGround = 4;
- CWorld::Remove(vehicle);
- CWorld::Add(vehicle);
- if (vehicle->IsBoat())
- ((CBoat*)vehicle)->m_bIsAnchored = false;
}
+ vehicle->bEngineOn = true;
+ if (vehicle->IsCar())
+ ((CAutomobile*)vehicle)->m_nDriveWheelsOnGround = 4;
+ CWorld::Remove(vehicle);
+ CWorld::Add(vehicle);
+ if (vehicle->IsBoat())
+ ((CBoat*)vehicle)->m_bIsAnchored = false;
+ vehicle->bRenderScorched = vp->render_scorched;
+ if (vehicle->GetModelIndex() == MI_SKIMMER)
+ ((CBoat*)vehicle)->m_fMovingSpeed = vp->skimmer_speed / 50.0f;
}
-bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer){
- /* Mistake. Not even sure what this is even doing here...
- * PlayerWanted is a backup to restore at the end of replay.
- * Setting current wanted pointer to it makes it useless.
- * Causes picking up bribes in replays reducing wanted level bug.
- * Obviously fact of picking them up is a bug on its own,
- * but it doesn't cancel this one.
- */
-#ifndef FIX_REPLAY_BUGS
- FindPlayerPed()->m_pWanted = &PlayerWanted;
-#endif
+// --MIAMI: Done
+void CReplay::ProcessBikeUpdate(CVehicle* vehicle, float interpolation, CAddressInReplayBuffer* buffer)
+{
+ CBike* bike = (CBike*)vehicle;
+ tBikeUpdatePacket* vp = (tBikeUpdatePacket*)&buffer->m_pBase[buffer->m_nOffset];
+ if (!vehicle) {
+ printf("Replay:Car wasn't there");
+ return;
+ }
+ CMatrix vehicle_matrix;
+ vp->matrix.DecompressIntoFullMatrix(vehicle_matrix);
+ vehicle->GetMatrix() = vehicle->GetMatrix() * CMatrix(1.0f - interpolation);
+ vehicle->GetMatrix().GetPosition() *= (1.0f - interpolation);
+ vehicle->GetMatrix() += CMatrix(interpolation) * vehicle_matrix;
+ vehicle->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f);
+ vehicle->m_fHealth = 4 * vp->health;
+ vehicle->m_fGasPedal = vp->acceleration / 100.0f;
+ vehicle->m_vecMoveSpeed = CVector(vp->velocityX / 8000.0f, vp->velocityY / 8000.0f, vp->velocityZ / 8000.0f);
+ vehicle->m_fSteerAngle = vp->wheel_state / 50.0f;
+ vehicle->bEngineOn = true;
+ for (int i = 0; i < 4; i++) {
+ bike->m_aSuspensionSpringRatio[i] = vp->wheel_susp_dist[i] / 50.0f;
+ bike->m_aWheelRotation[i] = vp->wheel_rotation[i] / (128.0f / PI);
+ // NB: technically last assignment overflows - there are 2 wheels of bike
+ // however it saves two useful fields; this looks like unrolled loop, not sequential assignments
+ }
+ bike->m_fLeanLRAngle = vp->lean_angle / 50.0f;
+ bike->m_fWheelAngle = vp->wheel_angle / 50.0f;
+ bike->bLeanMatrixClean = false;
+ bike->CalculateLeanMatrix();
+ CWorld::Remove(vehicle);
+ CWorld::Add(vehicle);
+}
+// --MIAMI: Done
+bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer)
+{
CBulletTraces::Init();
float split = 1.0f - interpolation;
int ped_min_index = 0; /* Optimization due to peds and vehicles placed in buffer sequentially. */
@@ -846,21 +987,25 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
CStreaming::RequestModel(mi, 0);
}
else {
-// TODO(MIAMI): don't hardcode model indices
- if (mi == MI_DEADDODO || mi == MI_AIRTRAIN) {
- new_v = new(vp->index << 8) CPlane(mi, 2);
- }
- else if (mi == MI_TRAIN) {
+ switch (vp->vehicle_type) {
+ case VEHICLE_TYPE_CAR:
+ new_v = new(vp->index << 8) CAutomobile(mi, 2);
+ break;
+ case VEHICLE_TYPE_BOAT:
+ new_v = new(vp->index << 8) CBoat(mi, 2);
+ break;
+ case VEHICLE_TYPE_TRAIN:
new_v = new(vp->index << 8) CTrain(mi, 2);
- }
- else if (mi == MI_CHOPPER) {
+ break;
+ case VEHICLE_TYPE_HELI:
new_v = new(vp->index << 8) CHeli(mi, 2);
- }
- else if (CModelInfo::IsBoatModel(mi)){
- new_v = new(vp->index << 8) CBoat(mi, 2);
- }
- else{
- new_v = new(vp->index << 8) CAutomobile(mi, 2);
+ break;
+ case VEHICLE_TYPE_PLANE:
+ new_v = new(vp->index << 8) CPlane(mi, 2);
+ break;
+ case VEHICLE_TYPE_BIKE: // not possible
+ new_v = new(vp->index << 8) CBike(mi, 2);
+ break;
}
new_v->SetStatus(STATUS_PLAYER_PLAYBACKFROMBUFFER);
vp->matrix.DecompressIntoFullMatrix(new_v->GetMatrix());
@@ -873,15 +1018,51 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
buffer->m_nOffset += sizeof(tVehicleUpdatePacket);
break;
}
+ case REPLAYPACKET_BIKE:
+ {
+ tBikeUpdatePacket* vp = (tBikeUpdatePacket*)&ptr[offset];
+ for (int i = vehicle_min_index; i < vp->index; i++) {
+ CVehicle* v = CPools::GetVehiclePool()->GetSlot(i);
+ if (!v)
+ continue;
+ /* Removing vehicles not present in this frame. */
+ CWorld::Remove(v);
+ delete v;
+ }
+ vehicle_min_index = vp->index + 1;
+ CVehicle* v = CPools::GetVehiclePool()->GetSlot(vp->index);
+ CVehicle* new_v;
+ if (!v) {
+ int mi = vp->mi;
+ if (CStreaming::ms_aInfoForModel[mi].m_loadState != 1) {
+ CStreaming::RequestModel(mi, 0);
+ }
+ else {
+ new_v = new(vp->index << 8) CBike(mi, 2);
+ new_v->SetStatus(STATUS_PLAYER_PLAYBACKFROMBUFFER);
+ vp->matrix.DecompressIntoFullMatrix(new_v->GetMatrix());
+ new_v->m_currentColour1 = vp->primary_color;
+ new_v->m_currentColour2 = vp->secondary_color;
+ CWorld::Add(new_v);
+ }
+ }
+ ProcessBikeUpdate(CPools::GetVehiclePool()->GetSlot(vp->index), interpolation, buffer);
+ buffer->m_nOffset += sizeof(tBikeUpdatePacket);
+ break;
+ }
case REPLAYPACKET_PED_HEADER:
{
tPedHeaderPacket* ph = (tPedHeaderPacket*)&ptr[offset];
if (!CPools::GetPedPool()->GetSlot(ph->index)) {
- if (CStreaming::ms_aInfoForModel[ph->mi].m_loadState != 1) {
+ if (!CStreaming::HasModelLoaded(ph->mi) || (ph->mi >= MI_SPECIAL01 && ph->mi < MI_LAST_PED)) {
CStreaming::RequestModel(ph->mi, 0);
}
else {
- CPed* new_p = new(ph->index << 8) CCivilianPed((ePedType)ph->pedtype, ph->mi);
+ CPed* new_p;
+ if (ph->pedtype != PEDTYPE_PLAYER1)
+ new_p = new(ph->index << 8) CCivilianPed((ePedType)ph->pedtype, ph->mi);
+ else
+ new_p = new(ph->index << 8) CPlayerPed();
new_p->SetStatus(STATUS_PLAYER_PLAYBACKFROMBUFFER);
new_p->GetMatrix().SetUnity();
CWorld::Add(new_p);
@@ -964,6 +1145,31 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
CBulletTraces::aTraces[pb->index].m_vecCurrentPos = pb->inf;
CBulletTraces::aTraces[pb->index].m_vecTargetPos = pb->sup;
buffer->m_nOffset += sizeof(tBulletTracePacket);
+ break;
+ }
+ case REPLAYPACKET_PARTICLE:
+ {
+ tParticlePacket* pp = (tParticlePacket*)&ptr[offset];
+ CVector pos(pp->pos_x / 4.0f, pp->pos_y / 4.0f, pp->pos_z / 4.0f);
+ CVector dir(pp->dir_x / 120.0f, pp->dir_y / 120.0f, pp->dir_z / 120.0f);
+ RwRGBA color;
+ color.red = pp->r;
+ color.green = pp->g;
+ color.blue = pp->b;
+ color.alpha = pp->a;
+ CParticle::AddParticle((tParticleType)pp->particle_type, pos, dir, nil, pp->size, color);
+ buffer->m_nOffset += sizeof(tParticlePacket);
+ break;
+ }
+ case REPLAYPACKET_MISC:
+ {
+ tMiscPacket* pm = (tMiscPacket*)&ptr[offset];
+ TheCamera.m_uiCamShakeStart = pm->cam_shake_start;
+ TheCamera.m_fCamShakeForce = pm->cam_shake_strength;
+ // TODO(MIAMI): SpecialFX
+ CGame::currArea = pm->cur_area;
+ buffer->m_nOffset += sizeof(tMiscPacket);
+ break;
}
default:
break;
@@ -990,6 +1196,7 @@ bool CReplay::PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, flo
return false;
}
+// --MIAMI: Done
void CReplay::FinishPlayback(void)
{
if (Mode != MODE_PLAYBACK)
@@ -1012,6 +1219,7 @@ void CReplay::FinishPlayback(void)
DMAudio.SetMusicFadeVol(127);
}
+// --MIAMI: Done
void CReplay::EmptyReplayBuffer(void)
{
if (Mode == MODE_PLAYBACK)
@@ -1027,6 +1235,7 @@ void CReplay::EmptyReplayBuffer(void)
MarkEverythingAsNew();
}
+// --MIAMI: Done
void CReplay::ProcessReplayCamera(void)
{
switch (CameraMode) {
@@ -1071,6 +1280,9 @@ void CReplay::ProcessReplayCamera(void)
RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera));
}
+extern CWeaponEffects gCrossHair;
+
+// --MIAMI: Done except TODO
void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float cam_z, bool load_scene)
{
if (Mode != MODE_RECORD)
@@ -1087,6 +1299,8 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND);
DMAudio.SetEffectsFadeVol(0);
DMAudio.SetMusicFadeVol(0);
+ CEscalators::Shutdown();
+ // TODO(MIAMI): CWaterCreatures::RemoveAll();
int current;
for (current = 0; current < NUM_REPLAYBUFFERS; current++)
if (BufferStatus[current] == REPLAYBUFFER_RECORD)
@@ -1119,8 +1333,16 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca
}
if (cam_mode == REPLAYCAMMODE_ASSTORED)
TheCamera.CarZoomIndicator = CAM_ZOOM_CINEMATIC;
+ gCrossHair.m_bActive = false;
+ CExplosion::ClearAllExplosions();
+ CPlaneBanners::Init();
+#ifndef FIX_BUGS // this doesn't do anything useful and accesses destroyed player ped
+ TheCamera.Restore();
+#endif
+ CDraw::SetFOV(70.0f);
}
+// --MIAMI: Done
void CReplay::StoreStuffInMem(void)
{
#ifdef FIX_BUGS
@@ -1166,9 +1388,28 @@ void CReplay::StoreStuffInMem(void)
OldWeatherType = CWeather::OldWeatherType;
NewWeatherType = CWeather::NewWeatherType;
WeatherInterpolationValue = CWeather::InterpolationValue;
+ CurrArea = CGame::currArea;
TimeStepNonClipped = CTimer::GetTimeStepNonClipped();
TimeStep = CTimer::GetTimeStep();
TimeScale = CTimer::GetTimeScale();
+ ms_nNumCivMale_Stored = CPopulation::ms_nNumCivMale;
+ ms_nNumCivFemale_Stored = CPopulation::ms_nNumCivFemale;
+ ms_nNumCop_Stored = CPopulation::ms_nNumCop;
+ ms_nNumEmergency_Stored = CPopulation::ms_nNumEmergency;
+ ms_nNumGang1_Stored = CPopulation::ms_nNumGang1;
+ ms_nNumGang2_Stored = CPopulation::ms_nNumGang2;
+ ms_nNumGang3_Stored = CPopulation::ms_nNumGang3;
+ ms_nNumGang4_Stored = CPopulation::ms_nNumGang4;
+ ms_nNumGang5_Stored = CPopulation::ms_nNumGang5;
+ ms_nNumGang6_Stored = CPopulation::ms_nNumGang6;
+ ms_nNumGang7_Stored = CPopulation::ms_nNumGang7;
+ ms_nNumGang8_Stored = CPopulation::ms_nNumGang8;
+ ms_nNumGang9_Stored = CPopulation::ms_nNumGang9;
+ ms_nNumDummy_Stored = CPopulation::ms_nNumDummy;
+ ms_nTotalCivPeds_Stored = CPopulation::ms_nTotalCivPeds;
+ ms_nTotalGangPeds_Stored = CPopulation::ms_nTotalGangPeds;
+ ms_nTotalPeds_Stored = CPopulation::ms_nTotalPeds;
+ ms_nTotalMissionPeds_Stored = CPopulation::ms_nTotalMissionPeds;
int size = CPools::GetPedPool()->GetSize();
pPedAnims = new CStoredDetailedAnimationState[size];
for (int i = 0; i < size; i++) {
@@ -1176,9 +1417,19 @@ void CReplay::StoreStuffInMem(void)
if (ped)
StoreDetailedPedAnimation(ped, &pPedAnims[i]);
}
+ pGarages = new uint8[sizeof(CGarages::aGarages)];
+ memcpy(pGarages, CGarages::aGarages, sizeof(CGarages::aGarages));
+ FireArray = new CFire[NUM_FIRES];
+ memcpy(FireArray, gFireManager.m_aFires, sizeof(gFireManager.m_aFires));
+ NumOfFires = gFireManager.m_nTotalFires;
+ paProjectileInfo = new uint8[sizeof(gaProjectileInfo)];
+ memcpy(paProjectileInfo, gaProjectileInfo, sizeof(gaProjectileInfo));
+ paProjectiles = new uint8[sizeof(CProjectileInfo::ms_apProjectile)];
+ memcpy(paProjectiles, CProjectileInfo::ms_apProjectile, sizeof(CProjectileInfo::ms_apProjectile));
CScriptPaths::Save_ForReplay();
}
+// --MIAMI: Done
void CReplay::RestoreStuffFromMem(void)
{
CPools::GetVehiclePool()->CopyBack(pBuf0, pBuf1);
@@ -1241,8 +1492,14 @@ void CReplay::RestoreStuffFromMem(void)
CStreaming::LoadAllRequestedModels(false);
ped->m_weapons[j].Initialise(ped->m_weapons[j].m_eWeaponType, ped->m_weapons[j].m_nAmmoTotal);
}
- if (ped->m_wepModelID >= 0)
+ if (ped->m_wepModelID >= 0) {
+ ped->m_pWeaponModel = nil;
+ if (ped->IsPlayer())
+ ((CPlayerPed*)ped)->m_pMinigunTopAtomic = nil;
ped->AddWeaponModel(ped->m_wepModelID);
+ }
+ if (ped->m_nPedType == PEDTYPE_COP)
+ ((CCopPed*)ped)->m_pStinger = new CStinger;
}
i = CPools::GetVehiclePool()->GetSize();
while (--i >= 0) {
@@ -1255,14 +1512,26 @@ void CReplay::RestoreStuffFromMem(void)
vehicle->m_rwObject = nil;
vehicle->m_modelIndex = -1;
vehicle->SetModelIndex(mi);
- if (mi == MI_DODO){
- CAutomobile* dodo = (CAutomobile*)vehicle;
- RpAtomicSetFlags((RpAtomic*)GetFirstObject(dodo->m_aCarNodes[CAR_WHEEL_LF]), 0);
- CMatrix tmp1;
- tmp1.Attach(RwFrameGetMatrix(dodo->m_aCarNodes[CAR_WHEEL_RF]), false);
- CMatrix tmp2(RwFrameGetMatrix(dodo->m_aCarNodes[CAR_WHEEL_LF]), false);
- tmp1.GetPosition() += CVector(tmp2.GetPosition().x + 0.1f, 0.0f, tmp2.GetPosition().z);
- tmp1.UpdateRW();
+ if (vehicle->IsCar()) {
+ CAutomobile* car = (CAutomobile*)vehicle;
+ if (mi == MI_DODO) {
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_LF]), 0);
+ CMatrix tmp1;
+ tmp1.Attach(RwFrameGetMatrix(car->m_aCarNodes[CAR_WHEEL_RF]), false);
+ CMatrix tmp2(RwFrameGetMatrix(car->m_aCarNodes[CAR_WHEEL_LF]), false);
+ tmp1.GetPosition() += CVector(tmp2.GetPosition().x + 0.1f, 0.0f, tmp2.GetPosition().z);
+ tmp1.UpdateRW();
+ }
+ else if (mi == MI_HUNTER) {
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_LF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_RF]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }
+ else if (vehicle->IsRealHeli()) {
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_LB]), 0);
+ RpAtomicSetFlags((RpAtomic*)GetFirstObject(car->m_aCarNodes[CAR_WHEEL_RB]), 0);
+ }
}
if (vehicle->IsCar()){
CAutomobile* car = (CAutomobile*)vehicle;
@@ -1309,14 +1578,10 @@ void CReplay::RestoreStuffFromMem(void)
if (!object)
continue;
int mi = object->GetModelIndex();
- CStreaming::RequestModel(mi, 0);
- CStreaming::LoadAllRequestedModels(false);
object->m_rwObject = nil;
object->m_modelIndex = -1;
- object->SetModelIndex(mi);
+ object->SetModelIndexNoCreate(mi);
object->GetMatrix().m_attachment = nil;
- if (RwObjectGetType(object->m_rwObject) == rpATOMIC)
- object->GetMatrix().AttachRW(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)object->m_rwObject)), false);
}
i = CPools::GetDummyPool()->GetSize();
while (--i >= 0) {
@@ -1324,15 +1589,12 @@ void CReplay::RestoreStuffFromMem(void)
if (!dummy)
continue;
int mi = dummy->GetModelIndex();
- CStreaming::RequestModel(mi, 0);
- CStreaming::LoadAllRequestedModels(false);
dummy->m_rwObject = nil;
dummy->m_modelIndex = -1;
- dummy->SetModelIndex(mi);
+ dummy->SetModelIndexNoCreate(mi);
dummy->GetMatrix().m_attachment = nil;
- if (RwObjectGetType(dummy->m_rwObject) == rpATOMIC)
- dummy->GetMatrix().AttachRW(RwFrameGetMatrix(RpAtomicGetFrame((RpAtomic*)dummy->m_rwObject)), false);
}
+ ++ClockMinutes;
CTimer::SetTimeInMilliseconds(Time1);
CTimer::SetTimeInMillisecondsNonClipped(Time2);
CTimer::SetPreviousTimeInMilliseconds(Time3);
@@ -1345,6 +1607,25 @@ void CReplay::RestoreStuffFromMem(void)
CWeather::OldWeatherType = OldWeatherType;
CWeather::NewWeatherType = NewWeatherType;
CWeather::InterpolationValue = WeatherInterpolationValue;
+ CGame::currArea = CurrArea;
+ CPopulation::ms_nNumCivMale = ms_nNumCivMale_Stored;
+ CPopulation::ms_nNumCivFemale = ms_nNumCivFemale_Stored;
+ CPopulation::ms_nNumCop = ms_nNumCop_Stored;
+ CPopulation::ms_nNumEmergency = ms_nNumEmergency_Stored;
+ CPopulation::ms_nNumGang1 = ms_nNumGang1_Stored;
+ CPopulation::ms_nNumGang2 = ms_nNumGang2_Stored;
+ CPopulation::ms_nNumGang3 = ms_nNumGang3_Stored;
+ CPopulation::ms_nNumGang4 = ms_nNumGang4_Stored;
+ CPopulation::ms_nNumGang5 = ms_nNumGang5_Stored;
+ CPopulation::ms_nNumGang6 = ms_nNumGang6_Stored;
+ CPopulation::ms_nNumGang7 = ms_nNumGang7_Stored;
+ CPopulation::ms_nNumGang8 = ms_nNumGang8_Stored;
+ CPopulation::ms_nNumGang9 = ms_nNumGang9_Stored;
+ CPopulation::ms_nNumDummy = ms_nNumDummy_Stored;
+ CPopulation::ms_nTotalCivPeds = ms_nTotalCivPeds_Stored;
+ CPopulation::ms_nTotalGangPeds = ms_nTotalGangPeds_Stored;
+ CPopulation::ms_nTotalPeds = ms_nTotalPeds_Stored;
+ CPopulation::ms_nTotalMissionPeds = ms_nTotalMissionPeds_Stored;
for (int i = 0; i < CPools::GetPedPool()->GetSize(); i++) {
CPed* ped = CPools::GetPedPool()->GetSlot(i);
if (!ped)
@@ -1353,12 +1634,27 @@ void CReplay::RestoreStuffFromMem(void)
}
delete[] pPedAnims;
pPedAnims = nil;
+ memcpy(CGarages::aGarages, pGarages, sizeof(CGarages::aGarages));
+ delete[] pGarages;
+ pGarages = nil;
+ memcpy(gFireManager.m_aFires, FireArray, sizeof(gFireManager.m_aFires));
+ delete[] FireArray;
+ FireArray = nil;
+ gFireManager.m_nTotalFires = NumOfFires;
+ memcpy(gaProjectileInfo, paProjectileInfo, sizeof(gaProjectileInfo));
+ delete[] paProjectileInfo;
+ paProjectileInfo = nil;
+ memcpy(CProjectileInfo::ms_apProjectile, paProjectiles, sizeof(CProjectileInfo::ms_apProjectile));
+ delete[] paProjectiles;
+ paProjectiles = nil;
CScriptPaths::Load_ForReplay();
+ CExplosion::ClearAllExplosions();
DMAudio.ChangeMusicMode(MUSICMODE_FRONTEND);
DMAudio.SetRadioInCar(OldRadioStation);
DMAudio.ChangeMusicMode(MUSICMODE_GAME);
}
+// --MIAMI: Done
void CReplay::EmptyPedsAndVehiclePools(void)
{
int i = CPools::GetVehiclePool()->GetSize();
@@ -1379,6 +1675,7 @@ void CReplay::EmptyPedsAndVehiclePools(void)
}
}
+// --MIAMI: Done
void CReplay::EmptyAllPools(void)
{
EmptyPedsAndVehiclePools();
@@ -1400,6 +1697,7 @@ void CReplay::EmptyAllPools(void)
}
}
+// --MIAMI: Done
void CReplay::MarkEverythingAsNew(void)
{
int i = CPools::GetVehiclePool()->GetSize();
@@ -1449,6 +1747,7 @@ void CReplay::SaveReplayToHD(void)
CFileMgr::SetDir("");
}
+// --MIAMI: Done
void PlayReplayFromHD(void)
{
CFileMgr::SetDirMyDocuments();
@@ -1481,6 +1780,7 @@ void PlayReplayFromHD(void)
CReplay::StreamAllNecessaryCarsAndPeds();
}
+// --MIAMI: Done
void CReplay::StreamAllNecessaryCarsAndPeds(void)
{
for (int slot = 0; slot < NUM_REPLAYBUFFERS; slot++) {
@@ -1491,6 +1791,9 @@ void CReplay::StreamAllNecessaryCarsAndPeds(void)
case REPLAYPACKET_VEHICLE:
CStreaming::RequestModel(((tVehicleUpdatePacket*)&Buffers[slot][offset])->mi, 0);
break;
+ case REPLAYPACKET_BIKE:
+ CStreaming::RequestModel(((tBikeUpdatePacket*)&Buffers[slot][offset])->mi, 0);
+ break;
case REPLAYPACKET_PED_HEADER:
CStreaming::RequestModel(((tPedHeaderPacket*)&Buffers[slot][offset])->mi, 0);
break;
@@ -1502,6 +1805,7 @@ void CReplay::StreamAllNecessaryCarsAndPeds(void)
CStreaming::LoadAllRequestedModels(false);
}
+// --MIAMI: Done
void CReplay::FindFirstFocusCoordinate(CVector *coord)
{
*coord = CVector(0.0f, 0.0f, 0.0f);
@@ -1517,6 +1821,7 @@ void CReplay::FindFirstFocusCoordinate(CVector *coord)
}
}
+// --MIAMI: Done
bool CReplay::ShouldStandardCameraBeProcessed(void)
{
if (Mode != MODE_PLAYBACK)
@@ -1526,6 +1831,7 @@ bool CReplay::ShouldStandardCameraBeProcessed(void)
return FindPlayerVehicle() != nil;
}
+// --MIAMI: Done
void CReplay::ProcessLookAroundCam(void)
{
if (!bAllowLookAroundCam)
@@ -1582,11 +1888,13 @@ void CReplay::ProcessLookAroundCam(void)
RwFrameUpdateObjects(RwCameraGetFrame(TheCamera.m_pRwCamera));
}
+// --MIAMI: Done
size_t CReplay::FindSizeOfPacket(uint8 type)
{
switch (type) {
case REPLAYPACKET_END: return 4;
case REPLAYPACKET_VEHICLE: return sizeof(tVehicleUpdatePacket);
+ case REPLAYPACKET_BIKE: return sizeof(tBikeUpdatePacket);
case REPLAYPACKET_PED_HEADER: return sizeof(tPedHeaderPacket);
case REPLAYPACKET_PED_UPDATE: return sizeof(tPedUpdatePacket);
case REPLAYPACKET_GENERAL: return sizeof(tGeneralPacket);
@@ -1595,11 +1903,14 @@ size_t CReplay::FindSizeOfPacket(uint8 type)
case REPLAYPACKET_ENDOFFRAME: return 4;
case REPLAYPACKET_TIMER: return sizeof(tTimerPacket);
case REPLAYPACKET_BULLET_TRACES:return sizeof(tBulletTracePacket);
+ case REPLAYPACKET_PARTICLE: return sizeof(tParticlePacket);
+ case REPLAYPACKET_MISC: return sizeof(tMiscPacket);
default: assert(false); break;
}
return 0;
}
+// --MIAMI: Done (function didn't change since III and we already had it modified)
void CReplay::Display()
{
static int TimeCount = 0;
diff --git a/src/control/Replay.h b/src/control/Replay.h
index fd484017..42d6ad1a 100644
--- a/src/control/Replay.h
+++ b/src/control/Replay.h
@@ -2,6 +2,7 @@
#include "Pools.h"
#include "World.h"
+#include "WeaponEffects.h"
#include "ParticleType.h"
#ifdef FIX_BUGS
@@ -25,14 +26,17 @@ struct CStoredAnimationState
uint8 animId;
uint8 time;
uint8 speed;
+ uint8 groupId;
uint8 secAnimId;
uint8 secTime;
uint8 secSpeed;
+ uint8 secGroupId;
uint8 blendAmount;
uint8 partAnimId;
uint8 partAnimTime;
uint8 partAnimSpeed;
uint8 partBlendAmount;
+ uint8 partGroupId;
};
enum {
@@ -46,20 +50,18 @@ struct CStoredDetailedAnimationState
uint8 aCurTime[NUM_MAIN_ANIMS_IN_REPLAY];
uint8 aSpeed[NUM_MAIN_ANIMS_IN_REPLAY];
uint8 aBlendAmount[NUM_MAIN_ANIMS_IN_REPLAY];
-#ifdef FIX_REPLAY_BUGS
int8 aBlendDelta[NUM_MAIN_ANIMS_IN_REPLAY];
-#endif
uint8 aFunctionCallbackID[NUM_MAIN_ANIMS_IN_REPLAY];
uint16 aFlags[NUM_MAIN_ANIMS_IN_REPLAY];
+ uint8 aGroupId[NUM_MAIN_ANIMS_IN_REPLAY];
uint8 aAnimId2[NUM_PARTIAL_ANIMS_IN_REPLAY];
uint8 aCurTime2[NUM_PARTIAL_ANIMS_IN_REPLAY];
uint8 aSpeed2[NUM_PARTIAL_ANIMS_IN_REPLAY];
uint8 aBlendAmount2[NUM_PARTIAL_ANIMS_IN_REPLAY];
-#ifdef FIX_REPLAY_BUGS
int8 aBlendDelta2[NUM_PARTIAL_ANIMS_IN_REPLAY];
-#endif
uint8 aFunctionCallbackID2[NUM_PARTIAL_ANIMS_IN_REPLAY];
uint16 aFlags2[NUM_PARTIAL_ANIMS_IN_REPLAY];
+ uint8 aGroupId2[NUM_PARTIAL_ANIMS_IN_REPLAY];
};
void PlayReplayFromHD(void);
@@ -73,21 +75,24 @@ class CReplay
enum {
REPLAYCAMMODE_ASSTORED = 0,
- REPLAYCAMMODE_TOPDOWN = 1,
- REPLAYCAMMODE_FIXED = 2
+ REPLAYCAMMODE_TOPDOWN,
+ REPLAYCAMMODE_FIXED
};
enum {
REPLAYPACKET_END = 0,
- REPLAYPACKET_VEHICLE = 1,
- REPLAYPACKET_PED_HEADER = 2,
- REPLAYPACKET_PED_UPDATE = 3,
- REPLAYPACKET_GENERAL = 4,
- REPLAYPACKET_CLOCK = 5,
- REPLAYPACKET_WEATHER = 6,
- REPLAYPACKET_ENDOFFRAME = 7,
- REPLAYPACKET_TIMER = 8,
- REPLAYPACKET_BULLET_TRACES = 9
+ REPLAYPACKET_VEHICLE,
+ REPLAYPACKET_BIKE,
+ REPLAYPACKET_PED_HEADER,
+ REPLAYPACKET_PED_UPDATE,
+ REPLAYPACKET_GENERAL,
+ REPLAYPACKET_CLOCK,
+ REPLAYPACKET_WEATHER,
+ REPLAYPACKET_ENDOFFRAME,
+ REPLAYPACKET_TIMER,
+ REPLAYPACKET_BULLET_TRACES,
+ REPLAYPACKET_PARTICLE,
+ REPLAYPACKET_MISC
};
enum {
@@ -176,8 +181,9 @@ class CReplay
int8 vehicle_index;
CStoredAnimationState anim_state;
CCompressedMatrixNotAligned matrix;
- int8 assoc_group_id;
uint16 weapon_model;
+ int8 assoc_group_id;
+ bool is_visible;
};
VALIDATE_SIZE(tPedUpdatePacket, 40);
@@ -203,8 +209,64 @@ class CReplay
uint8 door_status;
uint8 primary_color;
uint8 secondary_color;
+ bool render_scorched;
+ int8 skimmer_speed;
+ int8 vehicle_type;
+
+ };
+ VALIDATE_SIZE(tVehicleUpdatePacket, 52);
+
+ struct tBikeUpdatePacket
+ {
+ uint8 type;
+ uint8 index;
+ uint8 health;
+ uint8 acceleration;
+ CCompressedMatrixNotAligned matrix;
+ int8 door_angles[2];
+ uint16 mi;
+ int8 velocityX;
+ int8 velocityY;
+ int8 velocityZ;
+ int8 wheel_state;
+ uint8 wheel_susp_dist[4];
+ uint8 wheel_rotation[4];
+ uint8 primary_color;
+ uint8 secondary_color;
+ int8 lean_angle;
+ int8 wheel_angle;
+
+ };
+ VALIDATE_SIZE(tBikeUpdatePacket, 44);
+
+ struct tParticlePacket
+ {
+ uint8 type;
+ uint8 particle_type;
+ int8 dir_x;
+ int8 dir_y;
+ int8 dir_z;
+ uint8 r;
+ uint8 g;
+ uint8 b;
+ uint8 a;
+ int16 pos_x;
+ int16 pos_y;
+ int16 pos_z;
+ float size;
+ };
+ VALIDATE_SIZE(tParticlePacket, 20);
+
+ struct tMiscPacket
+ {
+ uint8 type;
+ uint32 cam_shake_start;
+ float cam_shake_strength;
+ uint8 cur_area;
+ uint8 special_fx_flags;
};
- VALIDATE_SIZE(tVehicleUpdatePacket, 48);
+
+ VALIDATE_SIZE(tMiscPacket, 16);
private:
static uint8 Mode;
@@ -269,6 +331,31 @@ private:
static float fDistanceLookAroundCam;
static float fAlphaAngleLookAroundCam;
static float fBetaAngleLookAroundCam;
+ static int ms_nNumCivMale_Stored;
+ static int ms_nNumCivFemale_Stored;
+ static int ms_nNumCop_Stored;
+ static int ms_nNumEmergency_Stored;
+ static int ms_nNumGang1_Stored;
+ static int ms_nNumGang2_Stored;
+ static int ms_nNumGang3_Stored;
+ static int ms_nNumGang4_Stored;
+ static int ms_nNumGang5_Stored;
+ static int ms_nNumGang6_Stored;
+ static int ms_nNumGang7_Stored;
+ static int ms_nNumGang8_Stored;
+ static int ms_nNumGang9_Stored;
+ static int ms_nNumDummy_Stored;
+ static int ms_nTotalCarPassengerPeds_Stored;
+ static int ms_nTotalCivPeds_Stored;
+ static int ms_nTotalGangPeds_Stored;
+ static int ms_nTotalPeds_Stored;
+ static int ms_nTotalMissionPeds_Stored;
+ static uint8* pGarages;
+ static CFire* FireArray;
+ static uint32 NumOfFires;
+ static uint8* paProjectileInfo;
+ static uint8* paProjectiles;
+ static uint8 CurrArea;
#ifdef FIX_BUGS
static int nHandleOfPlayerPed[NUMPLAYERS];
#endif
@@ -288,8 +375,7 @@ public:
static bool IsPlayingBack() { return Mode == MODE_PLAYBACK; }
static bool IsPlayingBackFromFile() { return bPlayingBackFromFile; }
- static void RecordParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, float fSize, RwRGBA const&color)
- { } //TODO
+ static void RecordParticle(tParticleType type, CVector const& vecPos, CVector const& vecDir, float fSize, RwRGBA const& color);
private:
static void RecordThisFrame(void);
static void StorePedUpdate(CPed *ped, int id);
@@ -302,7 +388,9 @@ private:
static void TriggerPlaybackLastCoupleOfSeconds(uint32, uint8, float, float, float, uint32);
static bool FastForwardToTime(uint32);
static void StoreCarUpdate(CVehicle *vehicle, int id);
+ static void StoreBikeUpdate(CVehicle* vehicle, int id);
static void ProcessCarUpdate(CVehicle *vehicle, float interpolation, CAddressInReplayBuffer *buffer);
+ static void ProcessBikeUpdate(CVehicle* vehicle, float interpolation, CAddressInReplayBuffer* buffer);
static bool PlayBackThisFrameInterpolation(CAddressInReplayBuffer *buffer, float interpolation, uint32 *pTimer);
static void ProcessReplayCamera(void);
static void StoreStuffInMem(void);
@@ -314,6 +402,7 @@ private:
static void FindFirstFocusCoordinate(CVector *coord);
static void ProcessLookAroundCam(void);
static size_t FindSizeOfPacket(uint8);
+ static void GoToNextBlock(void);
/* Absolute nonsense, but how could this function end up being outside of class? */
friend void PlayReplayFromHD(void);
diff --git a/src/control/Script.cpp b/src/control/Script.cpp
index 5cd20001..f5391527 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -10102,7 +10102,7 @@ int8 CRunningScript::ProcessCommands900To999(int32 command)
CBaseModelInfo* pInfo = CModelInfo::GetModelInfo(model);
script_assert(pInfo->GetModelType() == MITYPE_VEHICLE);
CVehicleModelInfo* pVehicleInfo = (CVehicleModelInfo*)pInfo;
- if (pVehicleInfo->m_vehicleType != VEHICLE_TYPE_CAR) {
+ if (pVehicleInfo->m_vehicleType == VEHICLE_TYPE_CAR || pVehicleInfo->m_vehicleType == VEHICLE_TYPE_BIKE) {
switch (model) {
case MI_LANDSTAL:
case MI_LINERUN: