From ec1d14971c9bb1d751c0256093483d621dd719b8 Mon Sep 17 00:00:00 2001 From: Nikolay Korolev Date: Wed, 27 May 2020 00:25:12 +0300 Subject: mission replay --- src/control/GameLogic.cpp | 26 ++++++- src/control/Script.cpp | 147 ++++++++++++++++++++++++++++++++++++++++ src/control/Script.h | 19 ++++++ src/core/Frontend.cpp | 19 ++++++ src/core/Frontend.h | 6 +- src/core/MenuScreens.h | 10 ++- src/core/Pools.cpp | 43 ++++++++++++ src/core/config.h | 2 + src/save/GenericGameStorage.cpp | 45 ++++++++++++ src/save/GenericGameStorage.h | 8 ++- src/save/PCSave.cpp | 5 +- 11 files changed, 325 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp index abb5c5f3..ae26dd05 100644 --- a/src/control/GameLogic.cpp +++ b/src/control/GameLogic.cpp @@ -83,12 +83,20 @@ CGameLogic::Update() } break; case WBSTATE_WASTED: +#ifdef MISSION_REPLAY + if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) { +#else if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) { +#endif TheCamera.SetFadeColour(200, 200, 200); TheCamera.Fade(2.0f, FADE_OUT); } +#ifdef MISSION_REPLAY + if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) { +#else if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) { +#endif pPlayerInfo.m_WBState = WBSTATE_PLAYING; if (pPlayerInfo.m_bGetOutOfHospitalFree) { pPlayerInfo.m_bGetOutOfHospitalFree = false; @@ -131,11 +139,19 @@ CGameLogic::Update() } break; case WBSTATE_BUSTED: +#ifdef MISSION_REPLAY + if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) { +#else if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) { +#endif TheCamera.SetFadeColour(0, 0, 0); TheCamera.Fade(2.0f, FADE_OUT); } +#ifdef MISSION_REPLAY + if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) { +#else if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) { +#endif pPlayerInfo.m_WBState = WBSTATE_PLAYING; int takeMoney; @@ -203,11 +219,19 @@ CGameLogic::Update() } break; case WBSTATE_FAILED_CRITICAL_MISSION: - if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800 && CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800) { +#ifdef MISSION_REPLAY + if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > AddExtraDeathDelay() + 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= AddExtraDeathDelay() + 0x800)) { +#else + if ((CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime > 0x800) && (CTimer::GetPreviousTimeInMilliseconds() - pPlayerInfo.m_nWBTime <= 0x800)) { +#endif TheCamera.SetFadeColour(0, 0, 0); TheCamera.Fade(2.0f, FADE_OUT); } +#ifdef MISSION_REPLAY + if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) { +#else if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) { +#endif pPlayerInfo.m_WBState = WBSTATE_PLAYING; if (pPlayerInfo.m_pPed->bInVehicle) { CVehicle *pVehicle = pPlayerInfo.m_pPed->m_pMyVehicle; diff --git a/src/control/Script.cpp b/src/control/Script.cpp index 406b11b7..549f53ad 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -28,6 +28,9 @@ #include "Gangs.h" #include "Garages.h" #include "General.h" +#ifdef MISSION_REPLAY +#include "GenericGameStorage.h" +#endif #include "HandlingMgr.h" #include "Heli.h" #include "Hud.h" @@ -128,6 +131,38 @@ uint16 CTheScripts::CommandsExecuted; uint16 CTheScripts::ScriptsUpdated; int32 ScriptParams[32]; +#ifdef MISSION_REPLAY + +static const char* nonMissionScripts[] = { + "copcar", + "ambulan", + "taxi", + "firetru", + "rampage", + "t4x4_1", + "t4x4_2", + "t4x4_3", + "rc1", + "rc2", + "rc3", + "rc4", + "hj", + "usj", + "mayhem" +}; + +int AllowMissionReplay; +uint32 NextMissionDelay; +uint32 MissionStartTime; +uint32 WaitForMissionActivate; +uint32 WaitForSave; +float oldTargetX; +float oldTargetY; +int missionRetryScriptIndex; +bool doingMissionRetry; + +#endif + const uint32 CRunningScript::nSaveStructSize = #ifdef COMPATIBLE_SAVES @@ -666,6 +701,41 @@ void CTheScripts::Process() if (UseTextCommands == 1) UseTextCommands = 0; } + +#ifdef MISSION_REPLAY + static uint32 TimeToWaitTill; + switch (AllowMissionReplay) { + case 2: + AllowMissionReplay = 3; + TimeToWaitTill = CTimer::GetTimeInMilliseconds() + (AddExtraDeathDelay() > 1000 ? 4000 : 2500); + break; + case 3: + if (TimeToWaitTill < CTimer::GetTimeInMilliseconds()) + AllowMissionReplay = 4; + break; + case 4: + AllowMissionReplay = 5; + RetryMission(0, 0); + case 6: + AllowMissionReplay = 7; + TimeToWaitTill = CTimer::GetTimeInMilliseconds() + 500; + case 7: + if (TimeToWaitTill < CTimer::GetTimeInMilliseconds()) { + AllowMissionReplay = 0; + return; + } + break; + } + if (WaitForMissionActivate) { + if (WaitForMissionActivate > CTimer::GetTimeInMilliseconds()) + return; + WaitForMissionActivate = 0; + WaitForSave = CTimer::GetTimeInMilliseconds() + 3000; + } + if (WaitForSave && WaitForSave > CTimer::GetTimeInMilliseconds()) + WaitForSave = 0; +#endif + CRunningScript* script = pActiveScripts; while (script != nil){ CRunningScript* next = script->GetNext(); @@ -1239,6 +1309,17 @@ int8 CRunningScript::ProcessCommands0To99(int32 command) CTheScripts::bAlreadyRunningAMissionScript = false; RemoveScriptFromList(&CTheScripts::pActiveScripts); AddScriptToList(&CTheScripts::pIdleScripts); +#ifdef MISSION_REPLAY + if (m_bMissionFlag) { + CPlayerInfo* pPlayerInfo = &CWorld::Players[CWorld::PlayerInFocus]; + if (pPlayerInfo->m_pPed->GetPedState() != PED_DEAD && pPlayerInfo->m_WBState == WBSTATE_PLAYING && !m_bDeatharrestExecuted) + SaveGameForPause(1); + oldTargetX = oldTargetY = 0.0f; + if (AllowMissionReplay == 1) + AllowMissionReplay = 2; + // I am fairly sure they forgot to set return value here + } +#endif return 1; case COMMAND_START_NEW_SCRIPT: { @@ -2149,7 +2230,14 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) CollectParameters(&m_nIp, 2); CVehicle* car = CPools::GetVehiclePool()->GetAt(ScriptParams[0]); assert(car); +#if defined MISSION_REPLAY && defined SIMPLIER_MISSIONS + car->AutoPilot.m_nCruiseSpeed = *(float*)&ScriptParams[1]; + if (missionRetryScriptIndex == 40 && car->GetModelIndex() == MI_CHEETAH) // Turismo + car->AutoPilot.m_nCruiseSpeed = 8 * car->AutoPilot.m_nCruiseSpeed / 10; + car->AutoPilot.m_nCruiseSpeed = Min(car->AutoPilot.m_nCruiseSpeed, 60.0f * car->pHandling->Transmission.fUnkMaxVelocity); +#else car->AutoPilot.m_nCruiseSpeed = Min(*(float*)&ScriptParams[1], 60.0f * car->pHandling->Transmission.fUnkMaxVelocity); +#endif return 0; } case COMMAND_SET_CAR_DRIVING_STYLE: @@ -2219,6 +2307,10 @@ int8 CRunningScript::ProcessCommands100To199(int32 command) case COMMAND_PRINT_BIG: { wchar* key = TheText.Get((char*)&CTheScripts::ScriptSpace[m_nIp]); +#ifdef MISSION_REPLAY + if (strcmp((char*)&CTheScripts::ScriptSpace[m_nIp], "M_FAIL") == 0 && CanAllowMissionReplay()) + AllowMissionReplay = 1; +#endif m_nIp += KEY_LENGTH_IN_SCRIPT; CollectParameters(&m_nIp, 2); CMessages::AddBigMessage(key, ScriptParams[0], ScriptParams[1] - 1); @@ -8479,6 +8571,10 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) case COMMAND_MAKE_PLAYER_SAFE_FOR_CUTSCENE: { CollectParameters(&m_nIp, 1); +#ifdef MISSION_REPLAY + AllowMissionReplay = 0; + SaveGameForPause(3); +#endif CPlayerInfo* pPlayerInfo = &CWorld::Players[ScriptParams[0]]; CPad::GetPad(ScriptParams[0])->DisablePlayerControls |= PLAYERCONTROL_DISABLED_80; pPlayerInfo->MakePlayerSafe(true); @@ -8685,6 +8781,11 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command) case COMMAND_LOAD_AND_LAUNCH_MISSION_INTERNAL: { CollectParameters(&m_nIp, 1); +#ifdef MISSION_REPLAY + missionRetryScriptIndex = ScriptParams[0]; + if (missionRetryScriptIndex == 19) + CStats::LastMissionPassedName[0] = '\0'; +#endif CTimer::Suspend(); int offset = CTheScripts::MultiScriptArray[ScriptParams[0]]; CFileMgr::ChangeDir("\\"); @@ -11074,6 +11175,12 @@ void CRunningScript::DoDeatharrestCheck() CPlayerInfo* pPlayer = &CWorld::Players[CWorld::PlayerInFocus]; if (!pPlayer->IsRestartingAfterDeath() && !pPlayer->IsRestartingAfterArrest() && !CTheScripts::UpsideDownCars.AreAnyCarsUpsideDown()) return; +#ifdef MISSION_REPLAY + if (AllowMissionReplay != 0) + return; + if (CanAllowMissionReplay()) + AllowMissionReplay = 1; +#endif assert(m_nStackPointer > 0); while (m_nStackPointer > 1) --m_nStackPointer; @@ -11755,3 +11862,43 @@ void CRunningScript::Load(uint8*& buf) prev = p; #endif } + +#ifdef MISSION_REPLAY + +bool CRunningScript::CanAllowMissionReplay() +{ + if (AllowMissionReplay) + return false; + if (CStats::LastMissionPassedName[0] == '\0') + return false; + for (int i = 0; i < ARRAY_SIZE(nonMissionScripts); i++) { + if (strcmp(m_abScriptName, nonMissionScripts[i]) == 0) + return false; + } + return true; +} + +uint32 AddExtraDeathDelay() +{ + if (missionRetryScriptIndex == 63) + return 7000; + if (missionRetryScriptIndex == 64) + return 4000; + return 1000; +} + +void RetryMission(int type, int unk) +{ + if (type == 0) { + doingMissionRetry = true; + FrontEndMenuManager.m_nCurrScreen = MENUPAGE_MISSION_RETRY; + FrontEndMenuManager.RequestFrontEndStartUp(); + } + else if (type == 2) { + doingMissionRetry = false; + AllowMissionReplay = 6; + CTheScripts::MissionCleanup.Process(); + } +} + +#endif diff --git a/src/control/Script.h b/src/control/Script.h index acab66cc..743fad99 100644 --- a/src/control/Script.h +++ b/src/control/Script.h @@ -372,6 +372,9 @@ private: friend class CRunningScript; friend class CHud; friend void CMissionCleanup::Process(); +#ifdef FIX_BUGS + friend void RetryMission(int, int); +#endif }; @@ -479,6 +482,10 @@ private: void CharInAreaCheckCommand(int32, uint32*); void CarInAreaCheckCommand(int32, uint32*); +#ifdef MISSION_REPLAY + bool CanAllowMissionReplay(); +#endif + float LimitAngleOnCircle(float angle) { return angle < 0.0f ? angle + 360.0f : angle; } bool ThisIsAValidRandomPed(uint32 pedtype) { @@ -502,3 +509,15 @@ private: } } }; + +#ifdef MISSION_REPLAY +extern int AllowMissionReplay; +extern uint32 WaitForMissionActivate; +extern uint32 WaitForSave; +extern uint32 MissionStartTime; +extern int missionRetryScriptIndex; +extern bool doingMissionRetry; + +uint32 AddExtraDeathDelay(); +void RetryMission(int, int); +#endif diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp index d58d0576..b291886f 100644 --- a/src/core/Frontend.cpp +++ b/src/core/Frontend.cpp @@ -3497,6 +3497,13 @@ CMenuManager::Process(void) SaveLoadFileError_SetUpErrorScreen(); } if (m_nCurrScreen == MENUPAGE_LOADING_IN_PROGRESS) { +#ifdef MISSION_REPLAY + if (doingMissionRetry) { + RetryMission(2, 0); + m_nCurrSaveSlot = SLOT_COUNT; + doingMissionRetry = false; + } +#endif if (CheckSlotDataValid(m_nCurrSaveSlot)) { TheCamera.m_bUseMouse3rdPerson = m_ControlMethod == CONTROL_STANDARD; if (m_PrefsVsyncDisp != m_PrefsVsync) @@ -4661,6 +4668,18 @@ CMenuManager::ProcessButtonPresses(void) DMAudio.PlayFrontEndTrack(m_PrefsRadioStation, 1); OutputDebugString("STARTED PLAYING FRONTEND AUDIO TRACK"); break; +#ifdef MISSION_REPLAY + case MENUACTION_REJECT_RETRY: + doingMissionRetry = false; + AllowMissionReplay = 0; + RequestFrontEndShutDown(); + break; + case MENUACTION_UNK114: + doingMissionRetry = false; + RequestFrontEndShutDown(); + RetryMission(2, 0); + return; +#endif } } ProcessOnOffMenuOptions(); diff --git a/src/core/Frontend.h b/src/core/Frontend.h index 89517528..b65a60f1 100644 --- a/src/core/Frontend.h +++ b/src/core/Frontend.h @@ -245,7 +245,7 @@ enum eMenuScreen MENUPAGE_SKIN_SELECT = 54, MENUPAGE_KEYBOARD_CONTROLS = 55, MENUPAGE_MOUSE_CONTROLS = 56, - MENUPAGE_57 = 57, // mission failed, wanna restart page in mobile + MENUPAGE_MISSION_RETRY = 57, MENUPAGE_58 = 58, #ifdef MENU_MAP MENUPAGE_MAP = 59, @@ -366,6 +366,10 @@ enum eMenuAction MENUACTION_UNK108, MENUACTION_UNK109, MENUACTION_UNK110, + MENUACTION_UNK111, + MENUACTION_UNK112, + MENUACTION_REJECT_RETRY, + MENUACTION_UNK114, #ifdef MORE_LANGUAGES MENUACTION_LANG_PL, MENUACTION_LANG_RUS, diff --git a/src/core/MenuScreens.h b/src/core/MenuScreens.h index 6c2ebdb8..339ae2ce 100644 --- a/src/core/MenuScreens.h +++ b/src/core/MenuScreens.h @@ -445,11 +445,19 @@ const CMenuScreen aScreens[] = { MENUACTION_MOUSESTEER, "FET_MST", SAVESLOT_NONE, MENUPAGE_MOUSE_CONTROLS, MENUACTION_CHANGEMENU, "FEDS_TB", SAVESLOT_NONE, MENUPAGE_NONE, }, + // MENUPAGE_MISSION_RETRY = 57 +#ifdef MISSION_REPLAY - // MENUPAGE_57 = 57 + { "M_FAIL", 1, MENUPAGE_DISABLED, MENUPAGE_DISABLED, 0, 0, + MENUACTION_LABEL, "FESZ_RM", SAVESLOT_NONE, MENUPAGE_NONE, + MENUACTION_CHANGEMENU, "FEM_YES", SAVESLOT_NONE, MENUPAGE_LOADING_IN_PROGRESS, + MENUACTION_REJECT_RETRY, "FEM_NO", SAVESLOT_NONE, MENUPAGE_NONE + }, +#else { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0, // mission failed, wanna restart page in mobile }, +#endif // MENUPAGE_58 = 58 { "", 0, MENUPAGE_NONE, MENUPAGE_NONE, 0, 0, diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp index 17b9e08d..bd0814d0 100644 --- a/src/core/Pools.cpp +++ b/src/core/Pools.cpp @@ -4,6 +4,9 @@ #include "Boat.h" #include "CarCtrl.h" +#ifdef MISSION_REPLAY +#include "GenericGameStorage.h" +#endif #include "Population.h" #include "ProjectileInfo.h" #include "Streaming.h" @@ -206,11 +209,24 @@ INITSAVEBUF if (pVehicle->pPassengers[j]) bHasPassenger = true; } +#ifdef MISSION_REPLAY + bool bForceSaving = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pMyVehicle == pVehicle && IsQuickSave; +#ifdef FIX_BUGS + if ((!pVehicle->pDriver && !bHasPassenger) || bForceSaving) { +#else + if (!pVehicle->pDriver && !bHasPassenger) { +#endif + if (pVehicle->IsCar() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) + ++nNumCars; + if (pVehicle->IsBoat() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) + ++nNumBoats; +#else if (!pVehicle->pDriver && !bHasPassenger) { if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) ++nNumCars; if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) ++nNumBoats; +#endif } } *size = nNumCars * (sizeof(uint32) + sizeof(int16) + sizeof(int32) + CAutomobile::nSaveStructSize) + sizeof(int) + @@ -226,23 +242,42 @@ INITSAVEBUF if (pVehicle->pPassengers[j]) bHasPassenger = true; } +#ifdef MISSION_REPLAY + bool bForceSaving = CWorld::Players[CWorld::PlayerInFocus].m_pPed->m_pMyVehicle == pVehicle && IsQuickSave; +#endif +#if defined FIX_BUGS && defined MISSION_REPLAY + if ((!pVehicle->pDriver && !bHasPassenger) || bForceSaving) { +#else if (!pVehicle->pDriver && !bHasPassenger) { +#endif #ifdef COMPATIBLE_SAVES +#ifdef MISSION_REPLAY + if ((pVehicle->IsCar() || pVehicle->IsBoat()) && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) { +#else if ((pVehicle->IsCar() || pVehicle->IsBoat()) && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { +#endif WriteSaveBuf(buf, pVehicle->m_vehType); WriteSaveBuf(buf, pVehicle->GetModelIndex()); WriteSaveBuf(buf, GetVehicleRef(pVehicle)); pVehicle->Save(buf); } +#else +#ifdef MISSION_REPLAY + if (pVehicle->IsCar() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) { #else if (pVehicle->IsCar() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { +#endif WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); WriteSaveBuf(buf, pVehicle->GetModelIndex()); WriteSaveBuf(buf, GetVehicleRef(pVehicle)); memcpy(buf, pVehicle, sizeof(CAutomobile)); SkipSaveBuf(buf, sizeof(CAutomobile)); } +#ifdef MISSION_REPLAY + if (pVehicle->IsBoat() && (pVehicle->VehicleCreatedBy == MISSION_VEHICLE || bForceSaving)) { +#else if (pVehicle->IsBoat() && pVehicle->VehicleCreatedBy == MISSION_VEHICLE) { +#endif WriteSaveBuf(buf, (uint32)pVehicle->m_vehType); WriteSaveBuf(buf, pVehicle->GetModelIndex()); WriteSaveBuf(buf, GetVehicleRef(pVehicle)); @@ -400,7 +435,11 @@ INITSAVEBUF CPed* pPed = GetPedPool()->GetSlot(i); if (!pPed) continue; +#ifdef MISSION_REPLAY + if ((!pPed->bInVehicle || (pPed == CWorld::Players[CWorld::PlayerInFocus].m_pPed && IsQuickSave)) && pPed->m_nPedType == PEDTYPE_PLAYER1) +#else if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) +#endif nNumPeds++; } *size = sizeof(int) + nNumPeds * (sizeof(uint32) + sizeof(int16) + sizeof(int) + CPlayerPed::nSaveStructSize + @@ -410,7 +449,11 @@ INITSAVEBUF CPed* pPed = GetPedPool()->GetSlot(i); if (!pPed) continue; +#ifdef MISSION_REPLAY + if ((!pPed->bInVehicle || (pPed == CWorld::Players[CWorld::PlayerInFocus].m_pPed && IsQuickSave)) && pPed->m_nPedType == PEDTYPE_PLAYER1) { +#else if (!pPed->bInVehicle && pPed->m_nPedType == PEDTYPE_PLAYER1) { +#endif CopyToBuf(buf, pPed->m_nPedType); CopyToBuf(buf, pPed->m_modelIndex); int32 ref = GetPedRef(pPed); diff --git a/src/core/config.h b/src/core/config.h index f43067d7..5ad12fba 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -227,6 +227,8 @@ enum Config { #define USE_DEBUG_SCRIPT_LOADER // makes game load main_freeroam.scm by default #define USE_MEASUREMENTS_IN_METERS // makes game use meters instead of feet in script #define USE_PRECISE_MEASUREMENT_CONVERTION // makes game convert feet to meeters more precisely +#define MISSION_REPLAY // mobile feature +//#define SIMPLIER_MISSIONS // apply simplifications from mobile #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp index 8aae4011..eff0f2ff 100644 --- a/src/save/GenericGameStorage.cpp +++ b/src/save/GenericGameStorage.cpp @@ -42,6 +42,11 @@ const uint32 SIZE_OF_ONE_GAME_IN_BYTES = 201729; +#ifdef MISSION_REPLAY +int8 IsQuickSave; +const int PAUSE_SAVE_SLOT = SLOT_COUNT; +#endif + char DefaultPCSaveFileName[260]; char ValidSaveName[260]; char LoadFileName[256]; @@ -134,7 +139,12 @@ GenericSave(int file) WriteDataToBufferPointer(buf, saveName); GetLocalTime(&saveTime); WriteDataToBufferPointer(buf, saveTime); +#ifdef MISSION_REPLAY + int32 data = IsQuickSave << 24 | SIZE_OF_ONE_GAME_IN_BYTES; + WriteDataToBufferPointer(buf, data); +#else WriteDataToBufferPointer(buf, SIZE_OF_ONE_GAME_IN_BYTES); +#endif WriteDataToBufferPointer(buf, CGame::currLevel); WriteDataToBufferPointer(buf, TheCamera.GetPosition().x); WriteDataToBufferPointer(buf, TheCamera.GetPosition().y); @@ -240,6 +250,9 @@ GenericLoad() uint8 *buf; int32 file; uint32 size; +#ifdef MISSION_REPLAY + int8 qs; +#endif int32 saveSize; CPad *currPad; @@ -254,6 +267,9 @@ GenericLoad() ReadDataFromFile(file, work_buff, size); buf = (work_buff + 0x40); ReadDataFromBufferPointer(buf, saveSize); +#ifdef MISSION_REPLAY // a hack to keep compatibility but get new data from save + qs = saveSize >> 24; +#endif ReadDataFromBufferPointer(buf, CGame::currLevel); ReadDataFromBufferPointer(buf, TheCamera.GetMatrix().GetPosition().x); ReadDataFromBufferPointer(buf, TheCamera.GetMatrix().GetPosition().y); @@ -296,6 +312,11 @@ GenericLoad() ReadDataFromBufferPointer(buf, TheCamera.PedZoomIndicator); #endif assert(buf - work_buff == SIZE_OF_SIMPLEVARS); +#ifdef MISSION_REPLAY + WaitForSave = 0; + if (FrontEndMenuManager.m_nCurrSaveSlot == PAUSE_SAVE_SLOT && qs == 3) + WaitForMissionActivate = CTimer::GetTimeInMilliseconds() + 2000; +#endif ReadDataFromBlock("Loading Scripts \n", CTheScripts::LoadAllScripts); // Load the rest @@ -563,3 +584,27 @@ align4bytes(int32 size) { return (size + 3) & 0xFFFFFFFC; } + +#ifdef MISSION_REPLAY + +void DisplaySaveResult(int unk, char* name) +{} + +bool SaveGameForPause(int type) +{ + if (AllowMissionReplay != 0 || type != 3 && WaitForSave > CTimer::GetTimeInMilliseconds()) + return false; + WaitForSave = 0; + if (gGameState != GS_PLAYING_GAME || CTheScripts::IsPlayerOnAMission() || CStats::LastMissionPassedName[0] == '\0') { + DisplaySaveResult(3, CStats::LastMissionPassedName); + return false; + } + IsQuickSave = type; + MissionStartTime = 0; + int res = PcSaveHelper.SaveSlot(PAUSE_SAVE_SLOT); + PcSaveHelper.PopulateSlotInfo(); + IsQuickSave = 0; + DisplaySaveResult(res, CStats::LastMissionPassedName); + return true; +} +#endif diff --git a/src/save/GenericGameStorage.h b/src/save/GenericGameStorage.h index b913c305..ee8a52a1 100644 --- a/src/save/GenericGameStorage.h +++ b/src/save/GenericGameStorage.h @@ -40,4 +40,10 @@ extern uint32 TimeToStayFadedBeforeFadeOut; extern char SaveFileNameJustSaved[260]; // 8F2570 -const char TopLineEmptyFile[] = "THIS FILE IS NOT VALID YET"; \ No newline at end of file +const char TopLineEmptyFile[] = "THIS FILE IS NOT VALID YET"; + +#ifdef MISSION_REPLAY +extern int8 IsQuickSave; // originally int + +bool SaveGameForPause(int); +#endif diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp index 3dc80f73..3103c7ab 100644 --- a/src/save/PCSave.cpp +++ b/src/save/PCSave.cpp @@ -41,7 +41,10 @@ C_PcSave::SaveSlot(int32 slot) _psGetUserFilesFolder(); int file = CFileMgr::OpenFile(ValidSaveName, "wb"); if (file != 0) { - DoGameSpecificStuffBeforeSave(); +#ifdef MISSION_REPLAY + if (!IsQuickSave) +#endif + DoGameSpecificStuffBeforeSave(); if (GenericSave(file)) { if (!!CFileMgr::CloseFile(file)) nErrorCode = SAVESTATUS_ERR_SAVE_CLOSE; -- cgit v1.2.3