From f7d5021ac59026435165e97aba869a76cfef1059 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Sat, 26 Sep 2020 21:10:23 +0300 Subject: [PATCH] VC replays --- src/animation/AnimManager.h | 1 + src/control/Garages.h | 1 + src/control/Replay.cpp | 551 ++++++++++++++++++++++++++++-------- src/control/Replay.h | 127 +++++++-- src/control/Script.cpp | 2 +- src/core/EventList.cpp | 4 + src/render/Particle.cpp | 4 + src/render/WaterLevel.cpp | 8 + src/vehicles/Boat.cpp | 4 + src/weapons/Explosion.cpp | 14 +- src/weapons/Explosion.h | 1 + vendor/opusfile | 2 +- 12 files changed, 574 insertions(+), 145 deletions(-) diff --git a/src/animation/AnimManager.h b/src/animation/AnimManager.h index 8658c056..a55577b1 100644 --- a/src/animation/AnimManager.h +++ b/src/animation/AnimManager.h @@ -139,4 +139,5 @@ public: static void LoadAnimFile(RwStream *stream, bool compress, char (*somename)[32] = nil); static void CreateAnimAssocGroups(void); static void RemoveLastAnimFile(void); + static CAnimBlendAssocGroup* GetAnimAssocGroups(void) { return ms_aAnimAssocGroups; } }; 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) { - new_v = new(vp->index << 8) CTrain(mi, 2); - } - else if (mi == MI_CHOPPER) { - new_v = new(vp->index << 8) CHeli(mi, 2); - } - else if (CModelInfo::IsBoatModel(mi)){ + 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); - } - else{ - new_v = new(vp->index << 8) CAutomobile(mi, 2); + break; + case VEHICLE_TYPE_TRAIN: + new_v = new(vp->index << 8) CTrain(mi, 2); + break; + case VEHICLE_TYPE_HELI: + new_v = new(vp->index << 8) CHeli(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, 48); + 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(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: diff --git a/src/core/EventList.cpp b/src/core/EventList.cpp index da0a5967..7eb1e186 100644 --- a/src/core/EventList.cpp +++ b/src/core/EventList.cpp @@ -230,7 +230,11 @@ CEventList::ReportCrimeForEvent(eEventType type, size_t crimeId, bool copsDontCa if(crime == CRIME_NONE) return; +#ifdef FIX_BUGS + CVector playerPedCoors = FindPlayerCoors(); +#else CVector playerPedCoors = FindPlayerPed()->GetPosition(); +#endif CVector playerCoors = FindPlayerCoors(); if(CWanted::WorkOutPolicePresence(playerCoors, 14.0f) != 0 || diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index db40781e..2f0c3809 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -1261,7 +1261,11 @@ void CParticle::Update() { if ( CTimer::GetFrameCounter() & 10 ) { +#ifdef FIX_BUGS + if ( FindPlayerPed() && FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN ) +#else if ( FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_MINIGUN ) +#endif { AddParticle(PARTICLE_HEATHAZE, particle->m_vecPosition, CVector(0.0f, 0.0f, 0.0f)); } diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 13f52334..efcb6c14 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -2745,7 +2745,11 @@ CWaterLevel::RenderSeaBirds() void CWaterLevel::RenderShipsOnHorizon() { +#ifdef FIX_BUGS + CVector cur_pos = FindPlayerCoors(); +#else CVector cur_pos = FindPlayerPed()->GetPosition(); +#endif static CVector prev_pos(0.0f, 0.0f, 0.0f); static CVector prev_front(0.0f, 0.0f, 0.0f); @@ -2847,7 +2851,11 @@ CWaterLevel::HandleSeaLifeForms() void CWaterLevel::HandleBeachToysStuff(void) { +#ifdef FIX_BUGS + CVector cur_pos = FindPlayerCoors(); +#else CVector cur_pos = FindPlayerPed()->GetPosition(); +#endif static bool bBeachBallInit = true; static CVector FirstBeachBallPos = cur_pos; diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 086a5002..1664ffd0 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -132,7 +132,11 @@ CBoat::ProcessControl(void) if(bRenderScorched) m_fBuoyancy *= 0.99f; +#ifdef FIX_BUGS + if(FindPlayerPed() && FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && GetModelIndex() == MI_PREDATOR){ +#else if(FindPlayerPed()->m_pWanted->m_nWantedLevel > 0 && GetModelIndex() == MI_PREDATOR){ +#endif CVehicle *playerVeh = FindPlayerVehicle(); if(playerVeh && playerVeh->GetVehicleAppearance() == VEHICLE_APPEARANCE_BOAT && (AutoPilot.m_nCarMission == MISSION_RAMPLAYER_FARAWAY || diff --git a/src/weapons/Explosion.cpp b/src/weapons/Explosion.cpp index 74af1375..5d4b8f80 100644 --- a/src/weapons/Explosion.cpp +++ b/src/weapons/Explosion.cpp @@ -31,6 +31,16 @@ void CExplosion::Initialise() { debug("Initialising CExplosion...\n"); + ClearAllExplosions(); + AudioHandle = DMAudio.CreateEntity(AUDIOTYPE_EXPLOSION, (void*)1); + if (AudioHandle >= 0) + DMAudio.SetEntityStatus(AudioHandle, true); + debug("CExplosion ready\n"); +} + +void +CExplosion::ClearAllExplosions() +{ for (int i = 0; i < ARRAY_SIZE(gaExplosion); i++) { gaExplosion[i].m_ExplosionType = EXPLOSION_GRENADE; gaExplosion[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f); @@ -44,10 +54,6 @@ CExplosion::Initialise() gaExplosion[i].m_fStartTime = 0.0f; gaExplosion[i].m_bIsBoat = false; } - AudioHandle = DMAudio.CreateEntity(AUDIOTYPE_EXPLOSION, (void*)1); - if (AudioHandle >= 0) - DMAudio.SetEntityStatus(AudioHandle, true); - debug("CExplosion ready\n"); } void diff --git a/src/weapons/Explosion.h b/src/weapons/Explosion.h index cfa75ec1..f709012e 100644 --- a/src/weapons/Explosion.h +++ b/src/weapons/Explosion.h @@ -37,6 +37,7 @@ class CExplosion float m_fZshift; public: static void Initialise(); + static void ClearAllExplosions(); static void Shutdown(); static int8 GetExplosionActiveCounter(uint8 id); static void ResetExplosionActiveCounter(uint8 id); diff --git a/vendor/opusfile b/vendor/opusfile index 6452e838..f94a1764 160000 --- a/vendor/opusfile +++ b/vendor/opusfile @@ -1 +1 @@ -Subproject commit 6452e838e68e8f4fc0b3599523c760ac6276ce89 +Subproject commit f94a1764b0dcdd84ee8c13c040de9f4c1a67e4df