summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/control/GameLogic.cpp29
-rw-r--r--src/control/Script.cpp151
-rw-r--r--src/control/Script.h22
-rw-r--r--src/core/Game.cpp5
-rw-r--r--src/core/Pools.cpp43
-rw-r--r--src/core/World.cpp4
-rw-r--r--src/core/config.h9
-rw-r--r--src/core/main.cpp8
-rw-r--r--src/core/main.h3
-rw-r--r--src/core/re3.cpp105
-rw-r--r--src/render/WaterLevel.cpp7
-rw-r--r--src/render/WaterLevel.h1
-rw-r--r--src/save/GenericGameStorage.cpp45
-rw-r--r--src/save/GenericGameStorage.h6
-rw-r--r--src/save/PCSave.cpp5
-rw-r--r--src/skel/glfw/glfw.cpp2
-rw-r--r--src/vehicles/Automobile.cpp17
17 files changed, 445 insertions, 17 deletions
diff --git a/src/control/GameLogic.cpp b/src/control/GameLogic.cpp
index 6cfaa042..a98315e2 100644
--- a/src/control/GameLogic.cpp
+++ b/src/control/GameLogic.cpp
@@ -117,12 +117,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;
@@ -168,11 +176,16 @@ 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);
}
+
if (!CTheScripts::IsPlayerOnAMission() && pPlayerInfo.m_nBustedAudioStatus == 0) {
if (CGeneral::GetRandomNumberInRange(0, 4) == 0)
pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_DONE;
@@ -191,8 +204,12 @@ CGameLogic::Update()
DMAudio.PlayLoadedMissionAudio(); // TODO: argument is 0
pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_DONE;
}
-
+
+#ifdef MISSION_REPLAY
+ if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= AddExtraDeathDelay() + 0x1000) {
+#else
if (CTimer::GetTimeInMilliseconds() - pPlayerInfo.m_nWBTime >= 0x1000) {
+#endif
#ifdef FIX_BUGS
pPlayerInfo.m_nBustedAudioStatus = BUSTEDAUDIO_NONE;
#endif
@@ -266,11 +283,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 bfc778ba..d238f276 100644
--- a/src/control/Script.cpp
+++ b/src/control/Script.cpp
@@ -29,6 +29,9 @@
#include "GameLogic.h"
#include "Garages.h"
#include "General.h"
+#ifdef MISSION_REPLAY
+#include "GenericGameStorage.h"
+#endif
#include "HandlingMgr.h"
#include "Heli.h"
#include "Hud.h"
@@ -130,6 +133,38 @@ uint16 CTheScripts::NumberOfExclusiveMissionScripts;
bool CTheScripts::bPlayerHasMetDebbieHarry;
bool CTheScripts::bPlayerIsInTheStatium;
+#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
@@ -768,6 +803,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();
@@ -1340,6 +1410,17 @@ int8 CRunningScript::ProcessCommands0To99(int32 command)
RemoveScriptFromList(&CTheScripts::pActiveScripts);
AddScriptToList(&CTheScripts::pIdleScripts);
m_bIsActive = false;
+#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:
{
@@ -2265,7 +2346,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:
@@ -2335,6 +2423,10 @@ int8 CRunningScript::ProcessCommands100To199(int32 command)
case COMMAND_PRINT_BIG:
{
wchar* key = CTheScripts::GetTextByKeyFromScript(&m_nIp);
+#ifdef MISSION_REPLAY
+ if (strcmp((char*)&CTheScripts::ScriptSpace[m_nIp], "M_FAIL") == 0 && CanAllowMissionReplay())
+ AllowMissionReplay = 1;
+#endif
CollectParameters(&m_nIp, 2);
CMessages::AddBigMessage(key, ScriptParams[0], ScriptParams[1] - 1);
return 0;
@@ -8778,6 +8870,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);
@@ -9020,6 +9116,11 @@ int8 CRunningScript::ProcessCommands1000To1099(int32 command)
CollectParameters(&m_nIp, 1);
if (CTheScripts::NumberOfExclusiveMissionScripts > 0 && ScriptParams[0] <= UINT16_MAX - 2)
return 0;
+#ifdef MISSION_REPLAY
+ missionRetryScriptIndex = ScriptParams[0];
+ if (missionRetryScriptIndex == 19)
+ CStats::LastMissionPassedName[0] = '\0';
+#endif
CTimer::Suspend();
int offset = CTheScripts::MultiScriptArray[ScriptParams[0]];
#ifdef USE_DEBUG_SCRIPT_LOADER
@@ -12781,8 +12882,8 @@ void CRunningScript::LocateCharCarCommand(int32 command, uint32* pIp)
case COMMAND_LOCATE_CHAR_ON_FOOT_CAR_3D:
result = !pPed->bInVehicle;
break;
- case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_2D:
- case COMMAND_LOCATE_CHAR_IN_CAR_CHAR_3D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_CAR_2D:
+ case COMMAND_LOCATE_CHAR_IN_CAR_CAR_3D:
result = pPed->bInVehicle;
break;
default:
@@ -13597,6 +13698,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;
@@ -14243,3 +14350,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 68d1dc7b..3044e770 100644
--- a/src/control/Script.h
+++ b/src/control/Script.h
@@ -379,6 +379,9 @@ private:
friend class CHud;
friend void CMissionCleanup::Process();
friend class CColStore;
+#ifdef FIX_BUGS
+ friend void RetryMission(int, int);
+#endif
};
@@ -491,6 +494,10 @@ private:
void LocateObjectCommand(int32, uint32*);
void ObjectInAreaCheckCommand(int32, uint32*);
+#ifdef MISSION_REPLAY
+ bool CanAllowMissionReplay();
+#endif
+
float LimitAngleOnCircle(float angle) { return angle < 0.0f ? angle + 360.0f : angle; }
bool ThisIsAValidRandomPed(uint32 pedtype, int civ, int gang, int criminal) {
@@ -523,4 +530,19 @@ private:
#ifdef USE_DEBUG_SCRIPT_LOADER
extern int scriptToLoad;
+#endif
+#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
+
+#ifdef USE_DEBUG_SCRIPT_LOADER
+extern int scriptToLoad;
#endif \ No newline at end of file
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index a25f99d0..3f75b46b 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -88,8 +88,6 @@
#include "Occlusion.h"
#include "debugmenu.h"
-
-
eLevelName CGame::currLevel;
int32 CGame::currArea;
bool CGame::bDemoMode = true;
@@ -237,6 +235,9 @@ bool CGame::InitialiseOnceAfterRW(void)
DMAudio.SetMusicFadeVol(127);
CWorld::Players[0].SetPlayerSkin(FrontEndMenuManager.m_PrefsSkinFile);
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ CustomFrontendOptionsPopulate();
+#endif
return true;
}
diff --git a/src/core/Pools.cpp b/src/core/Pools.cpp
index 6838ef8e..6e3799f4 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<uint32>(buf, pVehicle->m_vehType);
WriteSaveBuf<int16>(buf, pVehicle->GetModelIndex());
WriteSaveBuf<int32>(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/World.cpp b/src/core/World.cpp
index 06108c5c..53d36854 100644
--- a/src/core/World.cpp
+++ b/src/core/World.cpp
@@ -122,14 +122,14 @@ CWorld::ClearExcitingStuffFromArea(const CVector &pos, float radius, bool bRemov
for(int32 i = 0; i < pedPool->GetSize(); i++) {
CPed *pPed = pedPool->GetSlot(i);
if(pPed && !pPed->IsPlayer() && pPed->CanBeDeleted() &&
- CVector2D(pPed->GetPosition() - pos).MagnitudeSqr() < radius) {
+ CVector2D(pPed->GetPosition() - pos).MagnitudeSqr() < SQR(radius)) {
CPopulation::RemovePed(pPed);
}
}
CVehiclePool *VehiclePool = CPools::GetVehiclePool();
for(int32 i = 0; i < VehiclePool->GetSize(); i++) {
CVehicle *pVehicle = VehiclePool->GetSlot(i);
- if(pVehicle && CVector2D(pVehicle->GetPosition() - pos).MagnitudeSqr() < radius &&
+ if(pVehicle && CVector2D(pVehicle->GetPosition() - pos).MagnitudeSqr() < SQR(radius) &&
!pVehicle->bIsLocked && pVehicle->CanBeDeleted()) {
if(pVehicle->pDriver) {
CPopulation::RemovePed(pVehicle->pDriver);
diff --git a/src/core/config.h b/src/core/config.h
index 907d93cb..b0ef3f67 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -194,7 +194,7 @@ enum Config {
# define NO_CDCHECK
# define CHATTYSPLASH // print what the game is loading
# define DEBUGMENU
-//# define TIMEBARS // print debug timers
+# define TIMEBARS // print debug timers
#endif
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
@@ -202,6 +202,8 @@ enum Config {
#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible
#define FIX_HIGH_FPS_BUGS_ON_FRONTEND
+// Rendering/display
+#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
// Just debug menu entries
#ifdef DEBUGMENU
#define TOGGLEABLE_BETA_FEATURES // not too many things
@@ -240,13 +242,16 @@ enum Config {
// #define CIRCLE_BACK_BUTTON
#define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better.
#define BETA_SLIDING_TEXT
+//#define CUSTOM_FRONTEND_OPTIONS
#define LEGACY_MENU_OPTIONS
#define MUCH_SHORTER_OUTRO_SCREEN
// Script
-#define USE_DEBUG_SCRIPT_LOADER // makes game load main_freeroam.scm by default
+#define USE_DEBUG_SCRIPT_LOADER // Loads main.scm by default. Hold R for main_freeroam.scm and D for main_d.scm
#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
// Replay
//#define DONT_FIX_REPLAY_BUGS // keeps various bugs in CReplay, some of which are fairly cool!
diff --git a/src/core/main.cpp b/src/core/main.cpp
index d95e7404..547d3b37 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -73,6 +73,9 @@ float FramesPerSecond = 30.0f;
bool gbPrintShite = false;
bool gbModelViewer;
+#ifdef TIMEBARS
+bool gbShowTimebars;
+#endif
int32 frameCount;
@@ -95,7 +98,6 @@ void TheGame(void);
void DebugMenuPopulate(void);
#endif
-
void
ValidateVersion()
{
@@ -1095,8 +1097,10 @@ Idle(void *arg)
#endif
// CCredits::Render(); // They added it to function above and also forgot it here
+
#ifdef TIMEBARS
- tbDisplay();
+ if (gbShowTimebars)
+ tbDisplay();
#endif
DoRWStuffEndOfFrame();
diff --git a/src/core/main.h b/src/core/main.h
index 32a880d6..9ad4ed1c 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -14,6 +14,9 @@ extern wchar gUString[256];
extern wchar gUString2[256];
extern bool gbPrintShite;
extern bool gbModelViewer;
+#ifdef TIMEBARS
+extern bool gbShowTimebars;
+#endif
class CSprite2d;
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 458ec6d6..302f4fc1 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -28,6 +28,9 @@
#include "Radar.h"
#include "debugmenu.h"
#include "Frontend.h"
+#include "Text.h"
+#include "WaterLevel.h"
+#include "main.h"
#ifndef _WIN32
#include "assert.h"
@@ -67,6 +70,100 @@ mysrand(unsigned int seed)
myrand_seed = seed;
}
+#ifdef CUSTOM_FRONTEND_OPTIONS
+#include "frontendoption.h"
+#include "platform.h"
+
+void ReloadFrontendOptions(void)
+{
+ RemoveCustomFrontendOptions();
+ CustomFrontendOptionsPopulate();
+}
+
+#ifdef MORE_LANGUAGES
+void LangPolSelect(int8 action)
+{
+ if (action == FEOPTION_ACTION_SELECT) {
+ FrontEndMenuManager.m_PrefsLanguage = LANGUAGE_POLISH;
+ FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
+ FrontEndMenuManager.InitialiseChangedLanguageSettings();
+ FrontEndMenuManager.SaveSettings();
+ }
+}
+
+void LangRusSelect(int8 action)
+{
+ if (action == FEOPTION_ACTION_SELECT) {
+ FrontEndMenuManager.m_PrefsLanguage = LANGUAGE_RUSSIAN;
+ FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
+ FrontEndMenuManager.InitialiseChangedLanguageSettings();
+ FrontEndMenuManager.SaveSettings();
+ }
+}
+
+void LangJapSelect(int8 action)
+{
+ if (action == FEOPTION_ACTION_SELECT) {
+ FrontEndMenuManager.m_PrefsLanguage = LANGUAGE_JAPANESE;
+ FrontEndMenuManager.m_bFrontEnd_ReloadObrTxtGxt = true;
+ FrontEndMenuManager.InitialiseChangedLanguageSettings();
+ FrontEndMenuManager.SaveSettings();
+ }
+}
+#endif
+
+#ifdef IMPROVED_VIDEOMODE
+void ScreenModeChange(int8 displayedValue)
+{
+ if (displayedValue != FrontEndMenuManager.m_nPrefsWindowed) {
+ FrontEndMenuManager.m_nPrefsWindowed = displayedValue;
+ _psSelectScreenVM(FrontEndMenuManager.m_nPrefsVideoMode); // apply same resolution
+ FrontEndMenuManager.SetHelperText(0);
+ FrontEndMenuManager.SaveSettings();
+ }
+}
+#endif
+
+#ifdef FREE_CAM
+void ToggleFreeCam(int8 action)
+{
+ if (action == FEOPTION_ACTION_SELECT) {
+ TheCamera.bFreeCam = !TheCamera.bFreeCam;
+ FrontEndMenuManager.SaveSettings();
+ }
+}
+#endif
+
+// Reloaded on language change, so you can use hardcoded wchar* and TheText.Get with peace of mind
+void
+CustomFrontendOptionsPopulate(void)
+{
+#ifdef MORE_LANGUAGES
+ FrontendOptionSetPosition(MENUPAGE_LANGUAGE_SETTINGS);
+ FrontendOptionAddDynamic(TheText.Get("FEL_POL"), nil, LangPolSelect, nil);
+ FrontendOptionAddDynamic(TheText.Get("FEL_RUS"), nil, LangRusSelect, nil);
+ FrontendOptionAddDynamic(TheText.Get("FEL_JAP"), nil, LangJapSelect, nil);
+#endif
+
+#ifdef IMPROVED_VIDEOMODE
+ static const wchar *screenModes[] = { (wchar*)L"FULLSCREEN", (wchar*)L"WINDOWED" };
+ FrontendOptionSetPosition(MENUPAGE_GRAPHICS_SETTINGS, 8);
+ FrontendOptionAddSelect(TheText.Get("SCRFOR"), screenModes, 2, (int8*)&FrontEndMenuManager.m_nPrefsWindowed, true, ScreenModeChange, nil);
+#endif
+
+#ifdef MENU_MAP
+ FrontendOptionSetPosition(MENUPAGE_PAUSE_MENU, 2);
+ FrontendOptionAddRedirect(TheText.Get("FEG_MAP"), MENUPAGE_MAP);
+#endif
+
+#ifdef FREE_CAM
+ static const wchar *text = (wchar*)L"TOGGLE FREE CAM";
+ FrontendOptionSetPosition(MENUPAGE_CONTROLLER_PC, 1);
+ FrontendOptionAddDynamic(text, nil, ToggleFreeCam, nil);
+#endif
+}
+#endif
+
#ifdef DEBUGMENU
void WeaponCheat();
void HealthCheat();
@@ -380,6 +477,7 @@ DebugMenuPopulate(void)
DebugMenuAddVarBool8("Render", "Don't render Peds", &gbDontRenderPeds, nil);
DebugMenuAddVarBool8("Render", "Don't render Vehicles", &gbDontRenderVehicles, nil);
DebugMenuAddVarBool8("Render", "Don't render Objects", &gbDontRenderObjects, nil);
+ DebugMenuAddVarBool8("Render", "Don't Render Water", &gbDontRenderWater, nil);
DebugMenuAddVarBool8("Debug", "Edit on", &CSceneEdit::m_bEditOn, nil);
#ifdef MENU_MAP
@@ -394,12 +492,19 @@ DebugMenuPopulate(void)
DebugMenuAddVarBool8("Debug", "Script Heli On", &CHeli::ScriptHeliOn, nil);
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ DebugMenuAddCmd("Debug", "Reload custom frontend options", ReloadFrontendOptions);
+#endif
DebugMenuAddCmd("Debug", "Start Credits", CCredits::Start);
DebugMenuAddCmd("Debug", "Stop Credits", CCredits::Stop);
#ifdef RELOADABLES
DebugMenuAddCmd("Reload", "HUD.TXD", CHud::ReloadTXD);
#endif
+ DebugMenuAddVarBool8("Debug", "Show DebugStuffInRelease", &gbDebugStuffInRelease, nil);
+#ifdef TIMEBARS
+ DebugMenuAddVarBool8("Debug", "Show Timebars", &gbShowTimebars, nil);
+#endif
extern bool PrintDebugCode;
extern int16 DebugCamMode;
diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp
index e6dbb9c4..0fd1e076 100644
--- a/src/render/WaterLevel.cpp
+++ b/src/render/WaterLevel.cpp
@@ -55,6 +55,8 @@ int32 CWaterLevel::m_nRenderWaterLayers;
RpAtomic *CWaterLevel::ms_pWavyAtomic;
RpAtomic *CWaterLevel::ms_pMaskAtomic;
+//"Custom" Donīt Render Water Toggle
+bool gbDontRenderWater;
RwTexture *gpWaterTex;
@@ -591,6 +593,11 @@ SectorRadius(float fSize)
void
CWaterLevel::RenderWater()
{
+//"Custom" Donīt Render Water Toggle
+#ifndef MASTER
+ if (gbDontRenderWater)
+ return;
+#endif
bool bUseCamEndX = false;
bool bUseCamStartY = false;
diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h
index 69f90745..5b02d54f 100644
--- a/src/render/WaterLevel.h
+++ b/src/render/WaterLevel.h
@@ -88,6 +88,7 @@ enum eBeachToy
};
extern RwRaster* gpWaterRaster;
+extern bool gbDontRenderWater;
class CEntity;
diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp
index 8ae3ffed..0f583221 100644
--- a/src/save/GenericGameStorage.cpp
+++ b/src/save/GenericGameStorage.cpp
@@ -43,6 +43,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];
@@ -136,7 +141,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);
@@ -244,6 +254,9 @@ GenericLoad()
uint8 *buf;
int32 file;
uint32 size;
+#ifdef MISSION_REPLAY
+ int8 qs;
+#endif
int32 saveSize;
CPad *currPad;
@@ -258,6 +271,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);
@@ -300,6 +316,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
@@ -566,3 +587,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 2d83385b..069ba7cd 100644
--- a/src/save/GenericGameStorage.h
+++ b/src/save/GenericGameStorage.h
@@ -42,3 +42,9 @@ extern uint32 TimeToStayFadedBeforeFadeOut;
extern char SaveFileNameJustSaved[260]; // 8F2570
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 29d8eb71..da8134fc 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;
diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp
index 407418c7..a7194c0c 100644
--- a/src/skel/glfw/glfw.cpp
+++ b/src/skel/glfw/glfw.cpp
@@ -1747,7 +1747,7 @@ void CapturePad(RwInt32 padID)
void joysChangeCB(int jid, int event)
{
- if (event == GLFW_CONNECTED)
+ if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid))
{
if (PSGLOBAL(joy1id) == -1)
PSGLOBAL(joy1id) = jid;
diff --git a/src/vehicles/Automobile.cpp b/src/vehicles/Automobile.cpp
index d146ffca..dea03730 100644
--- a/src/vehicles/Automobile.cpp
+++ b/src/vehicles/Automobile.cpp
@@ -3119,6 +3119,17 @@ CAutomobile::ProcessControlInputs(uint8 pad)
m_fSteerAngle = DEGTORAD(pHandling->fSteeringLock) * fValue;
if(bComedyControls){
+#if 0 // old comedy controls from PS2 - same as bike's
+ if(((CTimer::GetTimeInMilliseconds() >> 10) & 0xF) < 12)
+ m_fGasPedal = 1.0f;
+ if((((CTimer::GetTimeInMilliseconds() >> 10)+6) & 0xF) < 12)
+ m_fBrakePedal = 0.0f;
+ bIsHandbrakeOn = false;
+ if(CTimer::GetTimeInMilliseconds() & 0x800)
+ m_fSteerAngle += 0.08f;
+ else
+ m_fSteerAngle -= 0.03f;
+#else
int rnd = CGeneral::GetRandomNumber() % 10;
switch(m_comedyControlState){
case 0:
@@ -3138,8 +3149,10 @@ CAutomobile::ProcessControlInputs(uint8 pad)
m_comedyControlState = 0;
break;
}
- }else
+ }else{
m_comedyControlState = 0;
+#endif
+ }
// Brake if player isn't in control
// BUG: game always uses pad 0 here
@@ -3429,8 +3442,6 @@ CAutomobile::HydraulicControl(void)
if(m_hydraulicState < 20 && m_fVelocityChangeForAudio > 0.2f){
if(m_hydraulicState == 0){
m_hydraulicState = 20;
- for(i = 0; i < 4; i++)
- m_aWheelPosition[i] -= 0.06f;
DMAudio.PlayOneShot(m_audioEntityId, SOUND_CAR_HYDRAULIC_1, 0.0f);
setPrevRatio = true;
}else{